-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.cpp
More file actions
309 lines (229 loc) · 8.07 KB
/
main.cpp
File metadata and controls
309 lines (229 loc) · 8.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#define STB_IMAGE_STATIC
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_STATIC
#define STB_IMAGE_WRITE_IMPLEMENTATION
#define _CRT_SECURE_NO_WARNINGS
#define HAVE_STRUCT_TIMESPEC
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<stb_image.h>
#include<stb_image_resize.h>
#include<stb_image_write.h>
#include<Windows.h>
#include<io.h>
#include<array>
#include<vector>
#include<thread>
#include"error_macro.h"
unsigned char* pixel = nullptr;//画像データを入れる
int in_image_x = 0, in_image_y = 0, in_image_bpp = 0;
std::array<char, 1024> file_name = {};//入力ファイル名を入れておく
int file_no = 1;//ファイル番号割り当て用
const int default_bpp = 3;
const size_t limit_size = 1024 * 1024 * 2;
class image_data {//画像データを管理するクラス
public:
//リサイズ先画像関係
int out_image_x = 0;
int out_image_y = 0;
private:
//リサイズ先画像関係
unsigned char* out_pixel = nullptr;
int image_no = 0;//ファイル番号を入れる
size_t file_size = 0;
std::array<char, 1024> name_buf = {};//仮ファイル名を入れる
public:
void resize(void) {
try {//リサイズ先のメモリを確保
out_pixel = new unsigned char[4000 * 1170 * default_bpp * sizeof(unsigned char)];
}
catch (std::bad_alloc) {
ERROR_PRINT("MEM_ERROR", -1)
}
stbir_resize_uint8(pixel, in_image_x, in_image_y, 0, out_pixel, out_image_x, out_image_y, 0, default_bpp);
}
void image_output(void) {
name_buf.fill('\0');
sprintf(&name_buf.front(), "%s%03d", &file_name.front(), image_no);//仮名で出力
if (out_pixel) {
stbi_write_png(&name_buf.front(), out_image_x, out_image_y, default_bpp, out_pixel, 0);
delete[] out_pixel;
out_pixel = nullptr;
}
}
void get_filesize(void) {
FILE* fp = nullptr;
fp = fopen(&name_buf.front(), "r");
if (!fp) {
ERROR_PRINT("file_not_open", -2)
}
file_size = _filelengthi64(_fileno(fp));
fclose(fp);
}
_inline size_t return_filesize(void) {//file_sizeを読みだし専用にする関数
return file_size;
}
_inline int set_fileno(int no) {//file_noを一度だけ書き込みする関数
if ((no > 0) && (image_no == 0)) {
image_no = no;
return 0;
} else {
return -1;
}
}
void image_rename(void) {
std::array<char, 1024> str_buf = {};//リサイズ後ファイル名を入れる
str_buf = name_buf;
str_buf[strlen(&str_buf.front()) + 1 - 7] = '\0';//.pngxxxを消す
sprintf(&str_buf.front(), "%s_2MB.png", &str_buf.front());//_2MB.pngを付けたす
rename(&name_buf.front(), &str_buf.front());
}
~image_data() {
if (out_pixel) {//まだ解放されてないなら解放
delete[] out_pixel;
}
remove(&name_buf.front());//一時ファイルを消す
}
};
void image_resize(void* data) {
image_data* data_class = (image_data*)data;
data_class->set_fileno(file_no);
file_no++;
data_class->resize();
data_class->image_output();
data_class->get_filesize();
}
size_t get_filesize(char* filename) {
FILE* fp = nullptr;
size_t file_size = 0;
fp = fopen(filename, "r");
if (!fp) {
ERROR_PRINT("file_not_open", -2)
}
file_size = _filelengthi64(_fileno(fp));
fclose(fp);
return file_size;
}
int main(int argc, char** argv) {
//ドラッグされなかった時の処理
if (argc < 2) {
printf("ver:1.1\n");
printf("ファイルをドラッグして起動してください\n");
Sleep(5000);
return 0;
}
for (int i = 1; i < argc; i++) {
//ここからメイン処理
size_t in_image_size = get_filesize(argv[i]);
if (in_image_size < limit_size) {//もう2MB以下の物はスキップ
printf("%d枚目の2MB以下の画像をスキップしました。\n", i);
continue;
}
strcpy(&file_name.front(), argv[i]);//ファイル名をグローバル変数にコピー
pixel = stbi_load(argv[i], &in_image_x, &in_image_y, &in_image_bpp, 3);
if (!pixel) {
printf("%d枚目の画像の読み込みに失敗しました。\n", i);
continue;
}
printf("%d枚目の画像を読み込みました。\n", i);
int core_num = std::thread::hardware_concurrency();
int image_notch = in_image_x / 16;//小さい方に合わせる
if (image_notch > (in_image_y / 9)) {
image_notch = in_image_y / 9;
}
file_no = 0;//仮ファイル名カウンタカンスト対策
std::vector<image_data> image_vec(image_notch);//サイズを記録しておく配列
std::vector<std::thread*> thread_list(core_num);//スレッド情報を記録する配列
int th_count_create = 0;//処理枚数カウント(作成側)
int th_count_join = 0;//処理枚数カウント(join側)
int image_vec_num = 0;//最終的に処理した数
int limit_clear_no = ~0;//基準を満たした配列の番号
while (1) {//一次探索
for (int th_j = 0; th_j < core_num; th_j++) {//プロセッサぶんスレッド生成
if (th_count_create < image_notch) {//リサイズ値がマイナスしないように確認
if ((in_image_x - (16 * th_count_create) > 0) && (in_image_y - (9 * th_count_create) > 0)) {
image_vec[th_count_create].out_image_x = in_image_x - (16 * th_count_create);//インスタンスに情報を詰める
image_vec[th_count_create].out_image_y = in_image_y - (9 * th_count_create);
try {
std::thread* p_thread = new std::thread(image_resize, &image_vec[th_count_create]);//スレッド生成
thread_list[th_j] = p_thread;//スレッド情報を記録
th_count_create = th_count_create + core_num + 1;//プロセッサ数分開けて探索
}
catch (std::bad_alloc) {
ERROR_PRINT("MEM_ERROR", -1)
}
}
}
}
for (int th_j = 0; th_j < core_num; th_j++) {//スレッド処理が終わるのを待つ
if (th_count_join < image_notch) {
if ((in_image_x - (16 * th_count_join) > 0) && (in_image_y - (9 * th_count_join) > 0)) {
printf("\033[1K\033[0Gファイルを出力しておおまかに探索中。進捗%d%%。", (int)(th_count_join * 100) / image_notch);
fflush(stdout);
(*thread_list[th_j]).join();
if ((image_vec[th_count_join].return_filesize() < limit_size) && (limit_clear_no == ~0)) {//条件を満たしたかを確認
if (th_count_join == 0) {
limit_clear_no = th_count_join;//初期から条件を満たしたときの処理
} else {
limit_clear_no = th_count_join - (core_num + 1);//条件を満たす寸前の場所を記録
}
}
th_count_join = th_count_join + core_num + 1;
}
}
}
if (limit_clear_no < 0xffffffff) {//変数が書き換えられていたらbreak;
break;
}
}
printf("\033[1K\033[0Gファイルを出力しておおまかに探索中。進捗%d%%。\n", 100);
fflush(stdout);
th_count_create = limit_clear_no + 1;//未探索エリアを指定
th_count_join = limit_clear_no + 1;
//ここから二次探索(条件を満たすものがある場所の空白を埋めていく)
for (int th_j = 0; th_j < core_num; th_j++) {//プロセッサぶんスレッド生成
if (th_count_create < image_notch) {//リサイズ値がマイナスしないように確認
if ((in_image_x - (16 * th_count_create) > 0) && (in_image_y - (9 * th_count_create) > 0)) {
image_vec[th_count_create].out_image_x = in_image_x - (16 * th_count_create);
image_vec[th_count_create].out_image_y = in_image_y - (9 * th_count_create);
try {
std::thread* p_thread = new std::thread(image_resize, &image_vec[th_count_create]);//スレッド生成
thread_list[th_j] = p_thread;//スレッド情報を記録
th_count_create++;
}
catch (std::bad_alloc) {
ERROR_PRINT("MEM_ERROR", -1)
}
}
}
}
for (int th_j = 0; th_j < core_num; th_j++) {//スレッド処理が終わるのを待つ
if (th_count_join < image_notch) {
printf("\033[1K\033[0Gファイルを出力して詳細に探索中。進捗%d%%。", (int)(th_count_join * 100) / image_notch);
fflush(stdout);
(*thread_list[th_j]).join();
th_count_join++;
}
}
printf("\033[1K\033[0Gファイルを出力して詳細に探索中。進捗%d%%。\n", 100);
fflush(stdout);
stbi_image_free(pixel);
for (int j = limit_clear_no; j < limit_clear_no + core_num + 1; j++) {//条件内でいちばん大きいものを選択してリネーム
printf("\033[1K\033[0G条件に合う画像を探索中。進捗%d%%。", (int)(j * 100) / image_notch);
fflush(stdout);
if (image_vec[j].return_filesize() < limit_size) {
image_vec[j].image_rename();
printf("\033[1K\033[0G条件に合う画像を探索中。進捗%d%%。\n", 100);
fflush(stdout);
printf("%d枚目の画像を%3.2fMBで書き出しました。\n", i, (double)image_vec[j].return_filesize() * 2 / (limit_size));
fflush(stdout);
break;
}
}
}
printf("完了しました。ご利用ありがとうございました。\n");
fflush(stdout);
Sleep(5000);
}