1 /*-----------------------------------------------------------------------
2 This file is part of aaphoto.
3
4 aaphoto is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3 of the License, or
7 (at your option) any later version.
8
9 aaphoto is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16 ------------------------------------------------------------------------*/
17
18
19 /* #define __BMP_ONLY__ */
20 /* #define __OPENMP__ */
21
22
23
24 /* --------------------------------------------------- */
25 /* ----------- Auto Adjust Photo --------------------- */
26 /* ----------- András Horváth (C) 2006-2013 ---------- */
27 /* ----------- Hungary, http://log69.com ------------- */
28 /* --------------------------------------------------- */
29
30 /*
31 aaphoto Changelog:
32 --------------------
33 2013/09/30 - aaphoto v0.43 - new aaRGB v0.65 version update (see aaRGB changelog)
34 2012/02/20 - aaphoto v0.42 - tiny fix to set PNG compression manually and make it compatible with new version of libpng
35 2011/01/26 - aaphoto v0.41 - new aaRGB v0.64 version update (see aaRGB changelog)
36 - add -- switch to mark the end of option list for posix compatibility
37 - fix some warnings given by -Wextra compile option
38 2010/12/18 - aaphoto v0.40 - new aaRGB v0.63 version update
39 - fix some warning messages during build
40 - some changes in documentation
41 - error message when --verbose switch is used with no other ones to avoid misunderstanding
42 that other switches are still needed (aaphoto -V file)
43 2010/09/14 - aaphoto v0.39 - new aaRGB v0.62 version update
44 - bugfix: an ugly misconception in my paralleled code caused weird behavior when using more threads
45 - bugfix: BMP image writer function didn't zero out the BMP align bytes in file buffer
46 therefore the same output differed in some cases
47 - bugfix: PNG image reader function stored the unreliable values of pixel resolution
48 when the type was unknown
49 - rewrite the code to suffice the ISO C90 ANSI standard C form (GCC -pedantic option)
50 - new windows platform patch of libjasper for static build to replace mkstemp() function call
51 because it is not yet supported under MinGW
52 - some changes in documentation
53 - new default LDFLAG -lgomp for OpenMP
54 - update all build scripts for Debian 6 platform
55 2010/07/18 - aaphoto v0.38 - add verbose message showing presence of alpha channel in PNG images
56 - bugfix: fix compile with only BMP support
57 - fix some warning messages during build
58 - remove unnecessary __WIN32__ macro
59 2010/05/10 - aaphoto v0.37 - add OpenMP support for multi processing, all possible time intensive codes paralleled
60 __OPENMP__ directive and -fopenmp option are needed at compile time (supported since GCC v4.2)
61 (not available on windows platform yet)
62 - new -t, --threads switch added to manually set the number of working threads
63 - new aaRGB v0.61 version update
64 - bugfix: exif info was left out after last version's change in JPEG handling
65 - improve exif handling and verbose messages
66 - refine additional verbose messages
67 - remove pgx file type support because it is outdated
68 - some changes in documentation
69 - some minor code cleanup and bugfixes
70 2010/03/16 - aaphoto v0.36 - bugfix: fix for tmpfile() patches of libjasper and libjpeg (windows platform only)
71 when running more than one instances of aaphoto at a time
72 they all used the same temporary files and therefore the images became corrupt
73 - bugfix: it doesn't ask for administrative privileges anymore while running in an admin account
74 under vista and windows 7 (windows platform only)
75 - bugfix: the --rotate180 switch didn't turn the middle line in images with odd heights
76 - rewrite JPEG format handling entirely to be able to handle extra parameters in this format
77 separately, now libjpeg is used directly instead of libjasper for reading / writing JPEG images
78 so libjpeg is a new dependency from now, formerly only libjasper was depended on it
79 - restore original DPI values of images in BMP, JPEG and PNG formats during conversion
80 - refine program messages
81 - print the time elapsed in seconds since program start in verbose mode if not zero
82 - print extra infos of bitmap dimension, resolution and color depth in verbose mode
83 2010/02/25 - aaphoto v0.35 - bugfix: possible buffer overflows fixed
84 2010/02/19 - aaphoto v0.34 - __UNIX__ macro removed from Makefile, not needed anymore
85 - bugfix: static binary update with patches of libjasper and libjpeg
86 1) sleep() function missing on mingw32 platform
87 2) bad implementation of tmpfile() function on windows platform
88 it tries to create temporary files in the root of current directory
89 instead of the system temporary path so that causes failure for unprivileged users
90 who don't have permissions to write there
91 - update: changes in new version of libpng 1.4.0, aaio.c updated as necessary
92 png_check_sig() function replaced with png_sig_cmp()
93 setjmp(png_ptr->jmpbuf) has been deprecated, changed to setjmp(png_jmpbuf(png_ptr))
94 see more at http://www.libpng.org/pub/png/src/libpng-1.2.x-to-1.4.x-summary.txt
95 2010/01/10 - aaphoto v0.33 - some changes in documentation
96 - bugfix: unfreed space caused memory leak
97 - bugfix: uninitialized variable caused --resize to misbehave
98 - fix: change of return values in procedures to reflect standard exit codes
99 now it has a sense to run something like "aaphoto image.jpg && echo OK"
100 formerly return codes meant opposite
101 - fix a warning message during compile time, an include was missing
102 - boundary check of fixed size arrays added for safety reasons
103 - the --speed switch removed, it made the code less platform independent and was fussy anyway
104 - error messages printed to stderr instead of stdout from now
105 - more verbose error messages on failure of image load
106 2009/10/18 - aaphoto v0.32 - new aaRGB v0.60 version update
107 - new --noexif switch added to save new image without exif info
108 - new --bmp switch added for BMP format output
109 - new -o, --output switch added for alternate directory output
110 2009/08/23 - aaphoto v0.31 - bugfix: __BMP_ONLY__ directive is fixed in source code
111 - bugfix: writing of BMP images could result in corrupt BMP structure
112 - code cleanup in BMP write function
113 - parameters of switches also work with spaces between them
114 - new aaRGB v0.59 version update
115 2009/02/22 - aaphoto v0.30 - implement PNG format (RGB and Gray images read / write with alpha channel support)
116 - bugfix: reading corrupt exif info in JPEG files could get into an infinite loop
117 - bugfix: length of exif info was determined wrongly
118 - rework of the parameters and switches parsing part
119 - lots of code cleanup
120 - most of the comments in code translated to english
121 - print messages get flushed out with fflush now during process
122 - the --info switch removed
123 - the -o switch removed for safety reasons, --overwrite still available
124 - the -h switch added for unix compatibility
125 - the -j1 and -j2 switch removed, --jpg and --jp2 still available
126 - the --png switch is now new for PNG output
127 - the -s switch changed from --speed to --silent for compatibility
128 - the --mute switch changed to -s, --silent and --quiet for unix / posix compatibility
129 - the -V, --verbose switch is now new for more detailed output during image process
130 - the --test switch now turns the --autoadjust switch on by default
131 - the -d, --description and -l, --license switches removed
132 - thanks to Rezső Páder (rezso.net) for the suggestions for the option switches
133 - new aaRGB v0.58 version update
134 2008/02/02 - aaphoto v0.29 - bugfix: color space variable was not defined during the load of BMP format
135 - bugfix: BMP format handling fixed for JPEG conversion
136 - grayscale images can also be used as an input
137 - increase file name buffer for processing files in folders
138 - Exif meta data information is now restored during conversion in JPEG images
139 2007/08/11 - aaphoto v0.28 - new aaRGB v0.57 version update
140 - bugfix: remove extra slashes from the end of folders
141 2007/07/04 - aaphoto v0.27 - new aaRGB v0.56 version update v0.56 with "Apply only on selection" function
142 2007/05/26 - aaphoto v0.26 - bugfix: Win32 version crashed during JPEG-2000 conversion
143 2007/05/19 - aaphoto v0.25 - expand functions: rotate 90, 180, 270, flip x, flip y
144 2007/05/01 - aaphoto v0.24 - improve timing values
145 - input parameter can be folders beside files too
146 - bitmap info parameter now works with bmp too
147 - simplify parameter input: no --autoadjust parameter needed from now, default is on
148 2007/04/03 - aaphoto v0.23 - new aaRGB v0.55 version update
149 2007/04/01 - aaphoto v0.22 - new aaRGB v0.54 version update
150 2007/03/30 - aaphoto v0.21 - create bmp_only macro in source code for other platforms
151 - bug fixes
152 2007/03/29 - aaphoto v0.20 - new aaRGB v0.53 version update
153 2007/02/25 - aaphoto v0.19 - extra information output within image for testing purposes
154 2007/02/22 - aaphoto v0.18 - custom code for BMP input/output
155 2007/01/24 - aaphoto v0.17 - implement JasPer encoder for further image formats
156 2007/01/04 - aaphoto v0.16 - stable working command-line version for linux environment with BMP format support
157
158 aaphoto end of Changelog.
159
160 */
161
162
163
164
165 /* global constants and variables */
166
167 #define max_char 1024
168 #define max_file_name_buffer 4096 * 1024
169
170 int file_counter;
171 char *file_name;
172
173 unsigned char *file_name_buffer;
174 long file_name_counter;
175 long file_name_buffer_pointer;
176
177 unsigned char *bitmap_buffer;
178 unsigned long bitmap_width;
179 unsigned long bitmap_height;
180
181 double xdpi;
182 double ydpi;
183 int udpi;
184
185 int bitmap_format_bmp_clrspc_type;
186 int bitmap_format_jpg_clrspc_type;
187 int bitmap_format_jpg_file_type;
188 int bitmap_format_png_clrspc_type;
189 int bitmap_format_png_interlace_type;
190 int bitmap_format_png_compression_type;
191 int bitmap_format_png_filter_type;
192
193
194 char *exif_buffer;
195 long exif_buffer_length;
196 long exif_file_length;
197 int exif_flag;
198
199 int opt_help;
200 int opt_version;
201 int opt_autoadjust;
202 int opt_overwrite;
203 int opt_jpg;
204 int opt_jp2;
205 int opt_png;
206 int opt_bmp;
207 int opt_resize;
208 int opt_resize_percent;
209 int opt_rotate90;
210 int opt_rotate180;
211 int opt_rotate270;
212 int opt_flipx;
213 int opt_flipy;
214 int opt_output;
215 char opt_output_path [max_char];
216 int opt_quality;
217 int opt_threads;
218 int opt_verbose;
219 int opt_recursive;
220 int opt_quiet;
221 int opt_test;
222 int opt_noexif;
223 int opt_doubledash;
224
225 int char_temp_x;
226 int char_temp_y;
227
228 int mytime;
229
230
231 /* OpenMP */
232 int max_cpus;
233 int max_threads;
234 int max_num_threads;
235 int opt_openmp;
236 #ifdef __OPENMP__
237 #include <omp.h>
238 #endif
239
240
241 /* file name separation character */
242 char slsh='/';
243
244
245 #ifndef __BMP_ONLY__
246 #include <jasper/jasper.h>
247 #include <png.h>
248 #include <jpeglib.h>
249 #endif
250
251 #include <stdio.h>
252 #include <stdlib.h>
253 #include <ctype.h>
254 #include <dirent.h>
255 #include <time.h>
256 /*#include <stddir.h> */
257
258 #include "aaio.c"
259 #include "aargb.c"
260 #include "aaresize.c"
261
262
263
264
PRINT_VERSION(void)265 void PRINT_VERSION(void){
266 STRING_PRINT("Auto Adjust Photo\n");
267 STRING_PRINT("Copyright (C) 2006-2013 Andras Horvath\n");
268 STRING_PRINT("E-mail: mail@log69.com - suggestions & feedbacks are welcome\n");
269 STRING_PRINT("URL: http://log69.com - the official site\n");
270 STRING_PRINT("aaphoto (command-line) version - v0.43\n");
271 STRING_PRINT("aaRGB (color-correction engine) version - v0.65\n");
272 STRING_PRINT("last update = 26/09/2013\n");
273 STRING_PRINT("\n");
274 #ifndef __BMP_ONLY__
275 STRING_PRINT("The following libraries are used by this program:\n");
276 #ifdef __OPENMP__
277 STRING_PRINT("libgomp - OpenMP for parallel programming, http://gcc.gnu.org/onlinedocs/libgomp/\n");
278 #endif
279 STRING_PRINT("libjasper - JasPer software, http://www.ece.uvic.ca/~mdadams/jasper/\n");
280 STRING_PRINT("libjpeg - IJG JPEG software, http://www.ijg.org/\n");
281 STRING_PRINT("libpng - PNG software, http://www.libpng.org/\n");
282 STRING_PRINT("libz - Compression library, http://www.zlib.net/\n");
283 #endif
284 #ifdef __BMP_ONLY__
285 #ifdef __OPENMP__
286 STRING_PRINT("The following libraries are used by this program:\n");
287 STRING_PRINT("libgomp - OpenMP for parallel programming, http://gcc.gnu.org/onlinedocs/libgomp/\n");
288 STRING_PRINT("\n");
289 #endif
290 STRING_PRINT("BMP_ONLY version. Only BMP format is supported here.\n");
291 #endif
292 STRING_PRINT("\n");
293 }
294
295
296
PRINT_DESCRIPTION(void)297 void PRINT_DESCRIPTION(void){
298 STRING_PRINT("[DESCRIPTION]\n");
299 STRING_PRINT("Auto Adjust Photo is a tiny command-line image manipulation tool ");
300 STRING_PRINT("for automatic color correction of photos. ");
301 STRING_PRINT("It tries to make the picture look better. ");
302 STRING_PRINT("The program does this by analyzing the input image and then sets the ");
303 STRING_PRINT("most optimal contrast, gamma, color balance and saturation for it.\n");
304 STRING_PRINT("\n");
305 }
306
307
308
PRINT_LICENSE(void)309 void PRINT_LICENSE(void){
310 STRING_PRINT("[LICENSE]\n");
311 STRING_PRINT("This program is free software; you can redistribute it and/or modify ");
312 STRING_PRINT("it under the terms of the GNU General Public License as published by ");
313 STRING_PRINT("the Free Software Foundation; either version 3 of the License, or ");
314 STRING_PRINT("(at your option) any later version.\n");
315 STRING_PRINT("\n");
316 STRING_PRINT("This program is distributed in the hope that it will be useful, ");
317 STRING_PRINT("but WITHOUT ANY WARRANTY; without even the implied warranty of ");
318 STRING_PRINT("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ");
319 STRING_PRINT("GNU General Public License for more details.\n");
320 STRING_PRINT("\n");
321 STRING_PRINT("You should have received a copy of the GNU General Public License ");
322 STRING_PRINT("along with this program. If not, see <http://www.gnu.org/licenses/>.\n");
323 STRING_PRINT("\n");
324 }
325
326
327
PRINT_HELP(void)328 void PRINT_HELP(void){
329 STRING_PRINT("[HELP]\n");
330 STRING_PRINT("USAGE: aaphoto [options] [source files]\n");
331 STRING_PRINT("\n");
332 STRING_PRINT("The following image types are supported (thanks to JasPer, JPEG and PNG):\n");
333 STRING_PRINT("mif, pnm / pgm / ppm, bmp, ras, jp2, jpc, jpg, png\n");
334 STRING_PRINT("\n");
335 STRING_PRINT("Quality settings can be applied only to jp2, jpc, jpg formats\n");
336 STRING_PRINT("\n");
337 STRING_PRINT("The following options are supported:\n");
338 STRING_PRINT(" -h --help Print this help\n");
339 STRING_PRINT(" -v --version Print version information\n");
340 STRING_PRINT(" -a --autoadjust Auto adjust the colors of the image\n");
341 STRING_PRINT(" -o --output Set output directory\n");
342 STRING_PRINT(" --overwrite Overwrite mode, the original source file is replaced\n");
343 STRING_PRINT(" --jpg JPEG image output\n");
344 STRING_PRINT(" --jp2 JPEG 2000 image output\n");
345 STRING_PRINT(" --png PNG image output with alpha channel support\n");
346 STRING_PRINT(" --bmp BMP image output\n");
347 STRING_PRINT(" -r --resize Resize image taking the longer side in % or pixels\n");
348 STRING_PRINT(" --rotate90 Rotate image with 90 degrees clockwise\n");
349 STRING_PRINT(" --rotate180 Rotate image with 180 degrees\n");
350 STRING_PRINT(" --rotate270 Rotate image with 90 degrees counter-clockwise\n");
351 STRING_PRINT(" --flipx Mirror image horizontally\n");
352 STRING_PRINT(" --flipy Mirror image vertically\n");
353 STRING_PRINT(" --noexif Save image without EXIF info\n");
354 STRING_PRINT(" -q --quality Set image quality from 1 to 100\n");
355 STRING_PRINT(" -t --threads Set number of working threads (default: autodetect)\n");
356 STRING_PRINT(" -s --silent Silent mode, no information printed during operation\n");
357 STRING_PRINT(" --quiet ...same as above\n");
358 STRING_PRINT(" -V --verbose Print verbose information about processing\n");
359 /* STRING_PRINT(" -R --recursive Recursive directory search\n"); */
360 STRING_PRINT(" --test Print detailed test information into image\n");
361 STRING_PRINT("\n");
362 STRING_PRINT("EXAMPLES:\n");
363 STRING_PRINT(" aaphoto image.jpg\n");
364 STRING_PRINT(" aaphoto -a -r600 -q85 *.jpg\n");
365 STRING_PRINT(" aaphoto mydir\n");
366 STRING_PRINT(" aaphoto -V --resize70% image.png\n");
367 STRING_PRINT(" aaphoto --quality60 image.jp2\n");
368 STRING_PRINT("\n");
369 STRING_PRINT("REMARKS:\n");
370 STRING_PRINT("- auto adjust parameter is set by default without any other parameters\n");
371 STRING_PRINT("- _new file name will be generated without --overwrite parameter\n");
372 STRING_PRINT("- every file is processed on directory input but not recursively\n");
373 STRING_PRINT("- order of parameters does not matter\n");
374 STRING_PRINT("- resize value can be set in percentage too\n");
375 STRING_PRINT("- resize parameter should be less or equal than original\n");
376 STRING_PRINT("- resize uses the best (and slowest) resampling method\n");
377 STRING_PRINT("- default jpeg compression quality is 95%\n");
378 STRING_PRINT("- EXIF information is restored in jpeg images by default\n");
379 STRING_PRINT("- number of threads is set to the number of online processors by default\n");
380 STRING_PRINT("\n");
381 }
382
383
384
MAIN_RESIZE(void)385 int MAIN_RESIZE(void)
386 {
387 /* if there is an Alpha channel beside the RGB too (clrspc_type says) */
388 /* then i use the alpha flag to notify the resize function */
389 int alpha_flag = 0;
390 if ((bitmap_format_png_clrspc_type == 4) || (bitmap_format_png_clrspc_type == 6)){
391 alpha_flag = 1; }
392
393 if (opt_resize){
394
395 unsigned long opr = opt_resize;
396 /* calculate resize in percentage */
397 if (opt_resize_percent){
398 if (bitmap_width > bitmap_height) { opr = bitmap_width * opr / 100; }
399 else { opr = bitmap_height * opr / 100; }
400 }
401
402 /* if the new size is bigger or equal than the original size, then no process is done */
403 if (!((opr > bitmap_width) && (opr > bitmap_height))){
404
405 unsigned long new_width, new_height;
406 if (bitmap_width > bitmap_height){
407 new_width = opr;
408 new_height = bitmap_height * opr / bitmap_width;
409 }
410 else{
411 new_width = bitmap_width * opr / bitmap_height;
412 new_height = opr;
413 }
414
415 if (new_width < 1) new_width = 1;
416 if (new_height < 1) new_height = 1;
417
418 if (RESIZE(&bitmap_buffer, &bitmap_width, &bitmap_height, new_width, new_height, alpha_flag)){
419 STRING_PRINT("\n"); STRING_PRINTE("error: memory allocation error\n"); return 1; }
420
421 }
422
423 /* else { */
424 /* STRING_PRINT("\n"); STRING_PRINTE("error: resize parameter too big, " */
425 /* "target size should be less or equal than original\n"); return 1; } */
426
427 }
428
429 /* Rotate and Flip calls */
430 if (opt_rotate90) { if (ROTATE90(&bitmap_buffer, &bitmap_width, &bitmap_height, alpha_flag))
431 { STRING_PRINT("\n"); STRING_PRINTE("error: memory allocation error\n"); return 1; } }
432 if (opt_rotate180) { if (ROTATE180(&bitmap_buffer, &bitmap_width, &bitmap_height, alpha_flag))
433 { STRING_PRINT("\n"); STRING_PRINTE("error: memory allocation error\n"); return 1; } }
434 if (opt_rotate270) { if (ROTATE270(&bitmap_buffer, &bitmap_width, &bitmap_height, alpha_flag))
435 { STRING_PRINT("\n"); STRING_PRINTE("error: memory allocation error\n"); return 1; } }
436 if (opt_flipx) { if (FLIPX(&bitmap_buffer, &bitmap_width, &bitmap_height, alpha_flag))
437 { STRING_PRINT("\n"); STRING_PRINTE("error: memory allocation error\n"); return 1; } }
438 if (opt_flipy) { if (FLIPY(&bitmap_buffer, &bitmap_width, &bitmap_height, alpha_flag))
439 { STRING_PRINT("\n"); STRING_PRINTE("error: memory allocation error\n"); return 1; } }
440
441
442 return 0;
443 }
444
445
446
447
MAIN_AARGB(void)448 void MAIN_AARGB(void)
449 {
450 /* AARGB_NORMAL(bitmap_buffer, bitmap_width, bitmap_height); */
451 AARGB_MAIN(bitmap_buffer, bitmap_width, bitmap_height, 0, 0, bitmap_width-1, bitmap_height-1, 0, 0, opt_test);
452 }
453
454
455
456
MAIN_RUN(char * file_name)457 int MAIN_RUN(char *file_name)
458 {
459 int result, res;
460 char file_name_new [max_char];
461
462 /* store the unix time here in seconds */
463 mytime = time(NULL);
464
465 /* print info */ STRING_PRINTV("verbose mode on\n");
466
467 /* print info */ STRING_PRINTV("available processors ");
468 /* print info */ STRING_PRINTVD(max_cpus);
469 /* print info */ STRING_PRINTV2("\n");
470 if (opt_openmp){
471 /* print info */ STRING_PRINTV("requested threads ");
472 /* print info */ STRING_PRINTVD(max_threads);
473 /* print info */ STRING_PRINTV2("\n"); }
474 else{
475 /* print info */ STRING_PRINTV("no multi processing support\n"); }
476
477
478 /* print info */ if (!(opt_verbose)) STRING_PRINT(file_name);
479 /* print info */ /* STRING_PRINTV(file_name); STRING_PRINTV2("\n"); */
480 /* print info */ STRING_PRINTV(file_name); if (opt_verbose) STRING_PRINT("\n");
481 /* print info */ STRING_PRINTV("loading\n");
482
483 /* try to load image */
484 result = 0;
485 result = BITMAP_LOAD(file_name);
486 switch (result) {
487 case 2:
488 STRING_PRINT("\n");
489 STRING_PRINTE("error: file ");
490 STRING_PRINTE(file_name);
491 STRING_PRINTE(" does not exist\n");
492 return 1;
493 break;
494 case 1:
495 STRING_PRINT("\n");
496 STRING_PRINTE("error: file ");
497 STRING_PRINTE(file_name);
498 STRING_PRINTE(" cannot be loaded\n");
499 return 1;
500 break;
501 }
502
503 /* determine new file name */
504 res = GET_FILE_NAME_NEW(file_name, file_name_new);
505 if (res > 0){
506 if (res == 1){
507 /* error code 1 for existing file name */
508 STRING_PRINT("\n");
509 STRING_PRINTE("error: file already exists with the new name ");
510 STRING_PRINTE(file_name_new); STRING_PRINTE("\n"); return 1; }
511 else {
512 /* error code 255 for array boundary error */
513 STRING_PRINT("\n");
514 STRING_PRINTE("error: file name error at file ");
515 STRING_PRINTE(file_name);
516 STRING_PRINTE("\n");
517 return 1; }
518 }
519
520 /* print info */ if (!(opt_verbose)) STRING_PRINT(" .");
521 if (opt_autoadjust){
522 /* print info */ STRING_PRINTV("auto adjusting colors\n");
523 MAIN_AARGB();
524 }
525
526 /* print info */ if (!(opt_verbose)) STRING_PRINT(" .");
527 if ((opt_resize) || (opt_rotate90) || (opt_rotate180) || (opt_rotate270) || (opt_flipx) || (opt_flipy))
528 { if (MAIN_RESIZE()) return 1; }
529
530 /* print info */ if (!(opt_verbose)) STRING_PRINT(" .");
531 /* print info */ STRING_PRINTV("saving\n");
532 if (BITMAP_SAVE(file_name_new)){ STRING_PRINT("\n");
533 STRING_PRINTE("error: file ");
534 STRING_PRINTE(file_name);
535 STRING_PRINTE(" cannot be saved\n");
536 return 1; }
537
538 /* print info */ if (!(opt_verbose)) STRING_PRINT(" done\n");
539 /* print info */ STRING_PRINTV("done\n");
540
541 return 0;
542 }
543
544
545
546
MAIN_ARGUMENTS_READ(int argc,char ** argv)547 int MAIN_ARGUMENTS_READ(int argc, char **argv)
548 {
549 int result, opt_wrong, opt_wrong_total, opt_counter;
550 int opt_quality_space_flag;
551 int opt_threads_space_flag;
552 int opt_resize_space_flag;
553 int opt_output_space_flag;
554
555 opt_help = 0;
556 opt_version = 0;
557 opt_autoadjust = 0;
558 opt_overwrite = 0;
559 opt_noexif = 0;
560 opt_jpg = 0;
561 opt_jp2 = 0;
562 opt_png = 0;
563 opt_bmp = 0;
564 opt_resize = 0;
565 opt_rotate90 = 0;
566 opt_rotate180 = 0;
567 opt_rotate270 = 0;
568 opt_flipx = 0;
569 opt_flipy = 0;
570 opt_resize_percent = 0;
571 opt_output = 0;
572 opt_quality = 0;
573 opt_threads = 0;
574 opt_verbose = 0;
575 opt_recursive = 0;
576 opt_quiet = 0;
577 opt_test = 0;
578 opt_doubledash = 0;
579
580 result = 0; /* store the result value of the MAIN_RUN function */
581
582 opt_wrong = 1;
583 opt_wrong_total = 0;
584 opt_counter = 0;
585
586 opt_quality_space_flag = 0;
587 opt_threads_space_flag = 0;
588 opt_resize_space_flag = 0;
589 opt_output_space_flag = 0;
590
591 if (argc >= 2) {
592 char *myarg;
593
594 argc--;
595 while (argc--){
596 /*printf("%s\n", *argv); */
597
598 opt_wrong = 1;
599 myarg = *argv++;
600 myarg = *argv;
601
602 if ((opt_doubledash == 0) && ((myarg[0] == '-') || (opt_quality_space_flag) || (opt_threads_space_flag)
603 || (opt_resize_space_flag) || (opt_output_space_flag))) {
604
605 /* check switches */
606 if (!STRING_COMPARE(myarg, "--\0")){
607 opt_wrong = 0; opt_doubledash = 1; }
608 if ((!STRING_COMPARE(myarg, "-h\0")) || (!STRING_COMPARE(myarg, "--help\0"))){
609 opt_wrong = 0; opt_help = 1; }
610 if ((!STRING_COMPARE(myarg, "-v\0")) || (!STRING_COMPARE(myarg, "--version\0"))){
611 opt_wrong = 0; opt_version = 1; }
612 if ((!STRING_COMPARE(myarg, "-a\0")) || (!STRING_COMPARE(myarg, "--autoadjust\0"))){
613 opt_wrong = 0; opt_autoadjust = 1; }
614 if (!STRING_COMPARE(myarg, "--overwrite\0")){
615 opt_wrong = 0; opt_overwrite = 1; }
616 if (!STRING_COMPARE(myarg, "--noexif\0")){
617 opt_wrong = 0; opt_noexif = 1; }
618 if (!STRING_COMPARE(myarg, "--jpg\0")){
619 opt_wrong = 0; opt_jpg = 1; }
620 if (!STRING_COMPARE(myarg, "--jp2\0")){
621 opt_wrong = 0; opt_jp2 = 1; }
622 if (!STRING_COMPARE(myarg, "--png\0")){
623 opt_wrong = 0; opt_png = 1; }
624 if (!STRING_COMPARE(myarg, "--bmp\0")){
625 opt_wrong = 0; opt_bmp = 1; }
626 /* if ((!STRING_COMPARE(myarg, "-R\0")) || (!STRING_COMPARE(myarg, "--recursive\0"))){ */
627 /* opt_wrong = 0; opt_recursive = 1; } */
628 if ((!STRING_COMPARE(myarg, "-s\0")) || (!STRING_COMPARE(myarg, "--silent\0"))
629 || (!STRING_COMPARE(myarg, "--quiet\0"))){
630 opt_wrong = 0; opt_quiet = 1; }
631 if ((!STRING_COMPARE(myarg, "-V\0")) || (!STRING_COMPARE(myarg, "--verbose\0"))){
632 opt_wrong = 0; opt_verbose = 1; }
633 if (!STRING_COMPARE(myarg, "--test\0")){
634 opt_wrong = 0; opt_test = 1; opt_autoadjust = 1; }
635
636
637 /* check --output switch */
638
639 /* check if there was space between the --output switch and its parameter */
640 /* and if the parameter needs to be parsed separately */
641 if (opt_output_space_flag){
642 DIR * dp;
643 int char_offs, i;
644 char output_ending;
645
646 opt_output_space_flag = 0;
647
648 char_offs = 0;
649 i = 0;
650 output_ending = '\0';
651 while ((myarg[char_offs+i]) && (i < max_char)){
652 opt_output_path[i] = myarg[char_offs+i];
653 output_ending = opt_output_path[i];
654 i++;
655 }
656 /* check if output path ends with slash character */
657 /* if not, then append it */
658 if (output_ending != slsh){
659 opt_output_path [i] = slsh;
660 i++;
661 }
662 opt_output_path [i] = 0;
663
664 /* check if specified output directory is a dir and if it exists */
665 dp = opendir(opt_output_path);
666 if (dp == NULL){
667 STRING_PRINTE("error: bad directory parameter\n"); return 1; }
668
669 opt_output = 1;
670 opt_wrong = 0;
671 }
672
673 if ((!STRING_COMPARE_FIX(myarg, "-o", 2)) || (!STRING_COMPARE_FIX(myarg, "--output", 8))){
674 int char_offs, i;
675
676 if (!STRING_COMPARE_FIX(myarg, "--output", 8)){
677 char_offs = 8;
678 }
679 else{
680 char_offs = 2;
681 }
682
683 i = 0;
684 /* check if there is space between the switch and its parameter */
685 if (myarg[char_offs+i] == 0){
686 opt_output_space_flag = 1;
687 opt_wrong = 0;
688 }
689 else{
690 DIR * dp;
691
692 char output_ending = '\0';
693 while ((myarg[char_offs+i]) && (i < max_char)){
694 opt_output_path[i] = myarg[char_offs+i];
695 output_ending = opt_output_path[i];
696 i++;
697 }
698 /* check if output path ends with slash character */
699 /* if not, then append it */
700 if (output_ending != slsh){
701 opt_output_path [i] = slsh;
702 i++;
703 }
704 opt_output_path [i] = 0;
705
706 /* check if specified output directory is a dir and if it exists */
707 dp = opendir(opt_output_path);
708 if (dp == NULL){
709 STRING_PRINTE("error: bad directory parameter\n"); return 1; }
710
711 opt_output = 1;
712 opt_wrong = 0;
713 }
714
715 }
716
717 /* check --quality switch */
718
719 /* check if there was space between the --quality switch and its parameter */
720 /* and if the parameter needs to be parsed separately */
721 if (opt_quality_space_flag){
722 char num [8+1];
723 int num_max, num_offs, i;
724
725 opt_quality_space_flag = 0;
726 num_max = 8;
727 num_offs = 0;
728 i = 0;
729 while ((myarg[num_offs+i]) && (i < num_max)){
730 num[i] = myarg[num_offs+i];
731 i++;
732 }
733 num [i] = 0;
734 if (i >= num_max){ STRING_PRINTE("error: bad parameters\n"); return 1; }
735 if (STRING_CONVERT_TO_INTEGER(num, &opt_quality)){
736 STRING_PRINTE("error: bad parameters\n"); return 1; }
737
738 if ((opt_quality >= 1) && (opt_quality <= 100)){ opt_wrong = 0; }
739 else{ STRING_PRINTE("error: bad parameters\n"); return 1; }
740 }
741
742 if ((!STRING_COMPARE_FIX(myarg, "-q", 2)) || (!STRING_COMPARE_FIX(myarg, "--quality", 9))){
743 char num [8+1];
744 int num_max, num_offs, i;
745
746 num_max = 8;
747 if (!STRING_COMPARE_FIX(myarg, "--quality", 9)){
748 num_offs = 9;
749 }
750 else{
751 num_offs = 2;
752 }
753
754 i = 0;
755 /* check if there is space between the switch and its parameter */
756 if (myarg[num_offs+i] == 0){
757 opt_quality_space_flag = 1;
758 opt_wrong = 0;
759 }
760 else{
761 while ((myarg[num_offs+i]) && (i < num_max)){
762 num[i] = myarg[num_offs+i];
763 i++;
764 }
765 num [i] = 0;
766 if (i >= num_max){ STRING_PRINTE("error: bad parameters\n"); return 1; }
767
768 if (STRING_CONVERT_TO_INTEGER(num, &opt_quality)){
769 STRING_PRINTE("error: bad parameters\n"); return 1; }
770 if ((opt_quality >= 1) && (opt_quality <= 100)){ opt_wrong = 0; }
771 else{ STRING_PRINTE("error: bad parameters\n"); return 1; }
772 }
773
774 }
775
776 /* check --threads switch */
777
778 /* check if there was space between the --threads switch and its parameter */
779 /* and if the parameter needs to be parsed separately */
780 if (opt_threads_space_flag){
781 char num [8+1];
782 int num_max, num_offs, i;
783
784 opt_threads_space_flag = 0;
785 num_max = 8;
786 num_offs = 0;
787 i = 0;
788 while ((myarg[num_offs+i]) && (i < num_max)){
789 num[i] = myarg[num_offs+i];
790 i++;
791 }
792 num [i] = 0;
793 if (i >= num_max){ STRING_PRINTE("error: bad parameters\n"); return 1; }
794 if (STRING_CONVERT_TO_INTEGER(num, &opt_threads)){
795 STRING_PRINTE("error: bad parameters\n"); return 1; }
796
797 if ((opt_threads >= 1) && (opt_threads <= max_num_threads)){ opt_wrong = 0; }
798 else{
799 STRING_PRINTE("error: bad parameters, threads value must be between 1 and ");
800 STRING_PRINTED(max_num_threads);
801 STRING_PRINTE("\n");
802 return 1; }
803
804 max_threads = opt_threads;
805 }
806
807 if ((!STRING_COMPARE_FIX(myarg, "-t", 2)) || (!STRING_COMPARE_FIX(myarg, "--threads", 9))){
808 char num [8+1];
809 int num_max, num_offs, i;
810
811 num_max = 8;
812 if (!STRING_COMPARE_FIX(myarg, "--threads", 9)){
813 num_offs = 9;
814 }
815 else{
816 num_offs = 2;
817 }
818
819 i = 0;
820 /* check if there is space between the switch and its parameter */
821 if (myarg[num_offs+i] == 0){
822 opt_threads_space_flag = 1;
823 opt_wrong = 0;
824 }
825 else{
826 while ((myarg[num_offs+i]) && (i < num_max)){
827 num[i] = myarg[num_offs+i];
828 i++;
829 }
830 num [i] = 0;
831 if (i >= num_max){ STRING_PRINTE("error: bad parameters\n"); return 1; }
832
833 if (STRING_CONVERT_TO_INTEGER(num, &opt_threads)){
834 STRING_PRINTE("error: bad parameters\n"); return 1; }
835 if ((opt_threads >= 1) && (opt_threads <= max_num_threads)){ opt_wrong = 0; }
836 else{
837 STRING_PRINTE("error: bad parameters, threads value must be between 1 and ");
838 STRING_PRINTED(max_num_threads);
839 STRING_PRINTE("\n");
840 return 1; }
841
842 max_threads = opt_threads;
843 }
844
845 }
846
847 /* check --resize switch */
848
849 /* check if there was space between the --resize switch and its parameter */
850 /* and if the parameter needs to be parsed separately */
851 if (opt_resize_space_flag){
852 char num [16+1];
853 int num_max, num_offs, i;
854
855 opt_resize_space_flag = 0;
856
857 num_max = 16;
858 num_offs = 0;
859 i = 0;
860 while ((myarg[num_offs+i]) && (myarg[num_offs+i] != '%') && (i < num_max)){
861 num[i] = myarg[num_offs+i];
862 i++;
863 }
864 num [i] = 0;
865 if (i >= num_max){ STRING_PRINTE("error: bad parameters\n"); return 1; }
866 /* is the resize value entered in percentage? */
867 if (myarg[num_offs+i] == '%') opt_resize_percent = 1;
868
869 if (STRING_CONVERT_TO_INTEGER(num, &opt_resize)){
870 STRING_PRINTE("error: bad parameters\n"); return 1; }
871
872 if (opt_resize_percent){
873 if ((opt_resize >= 1) && (opt_resize <= 100)){ opt_wrong = 0; }
874 else{ STRING_PRINTE("error: bad parameters\n"); return 1; }
875 }
876 else{
877 if ((opt_resize >= 1) && (opt_resize <= 100000)){ opt_wrong = 0; }
878 else{ STRING_PRINTE("error: bad parameters\n"); return 1; }
879 }
880 }
881
882 if ((!STRING_COMPARE_FIX(myarg, "-r", 2)) || (!STRING_COMPARE_FIX(myarg, "--resize", 8))){
883 int i;
884
885 char num [16+1] = "";
886 int num_max = 16;
887 int num_offs;
888 if (!STRING_COMPARE_FIX(myarg, "--resize", 8)){
889 num_offs = 8;
890 }
891 else{
892 num_offs = 2;
893 }
894
895 i = 0;
896 /* check if there is space between the switch and its parameter */
897
898 if (myarg[num_offs+i] == 0){
899 opt_resize_space_flag = 1;
900 opt_wrong = 0;
901 }
902 else{
903 while ((myarg[num_offs+i]) && (myarg[num_offs+i] != '%') && (i < num_max)){
904 num[i] = myarg[num_offs+i];
905 i++;
906 }
907 num [i] = 0;
908 if (i >= num_max){ STRING_PRINTE("error: bad parameters\n"); return 1; }
909 /* is the resize value entered in percentage? */
910 if (myarg[num_offs+i] == '%') opt_resize_percent = 1;
911
912 if (STRING_CONVERT_TO_INTEGER(num, &opt_resize)){
913 STRING_PRINTE("error: bad parameters\n"); return 1; }
914
915 if (opt_resize_percent){
916 if ((opt_resize >= 1) && (opt_resize <= 100)){ opt_wrong = 0; }
917 else{ STRING_PRINTE("error: bad parameters\n"); return 1; }
918 }
919 else{
920 if ((opt_resize >= 1) && (opt_resize <= 100000)){ opt_wrong = 0; }
921 else{ STRING_PRINTE("error: bad parameters\n"); return 1; }
922 }
923 }
924
925 }
926
927 /* check --rotate and --flip switches */
928 if (!STRING_COMPARE(myarg, "--rotate90\0")){ opt_wrong = 0; opt_rotate90 = 1; }
929 if (!STRING_COMPARE(myarg, "--rotate180\0")){ opt_wrong = 0; opt_rotate180 = 1; }
930 if (!STRING_COMPARE(myarg, "--rotate270\0")){ opt_wrong = 0; opt_rotate270 = 1; }
931 if (!STRING_COMPARE(myarg, "--flipx\0")){ opt_wrong = 0; opt_flipx = 1; }
932 if (!STRING_COMPARE(myarg, "--flipy\0")){ opt_wrong = 0; opt_flipy = 1; }
933
934 /* remember if there were switches but entered wrongly */
935 if (opt_wrong){ opt_wrong_total = 1; }
936 else{ opt_counter++; }
937 }
938 else {
939 /* expand the file list that contains the files to be processed one by one */
940 FILE_LIST_ADD(myarg);
941 }
942
943 }
944
945 /* error message if wrong parameters */
946 /* error message on missing extra parameter too */
947 if ((opt_wrong_total) || (opt_quality_space_flag) || (opt_threads_space_flag) || (opt_resize_space_flag) || (opt_output_space_flag)){
948 STRING_PRINTE("error: bad parameters\n"); return 1; }
949 else{
950
951 /* check if only 1 type of output format is specified on input */
952 int cnt = 0;
953 if (opt_jpg) cnt++;
954 if (opt_jp2) cnt++;
955 if (opt_png) cnt++;
956 if (opt_bmp) cnt++;
957 if (cnt > 1){
958 STRING_PRINTE("error: only one output format allowed\n");
959 return 1; }
960
961 /* manage info switches */
962 if (opt_version) { PRINT_VERSION(); PRINT_LICENSE(); }
963 if (opt_help) { PRINT_DESCRIPTION(); PRINT_HELP(); }
964
965 /* check if --verbose switch is used alone? */
966 cnt = 0;
967 cnt += opt_help;
968 cnt += opt_version;
969 cnt += opt_autoadjust;
970 cnt += opt_output;
971 cnt += opt_overwrite;
972 cnt += opt_jpg;
973 cnt += opt_jp2;
974 cnt += opt_png;
975 cnt += opt_bmp;
976 cnt += opt_resize;
977 cnt += opt_rotate90;
978 cnt += opt_rotate180;
979 cnt += opt_rotate270;
980 cnt += opt_flipx;
981 cnt += opt_flipy;
982 cnt += opt_noexif;
983 cnt += opt_quality;
984 cnt += opt_test;
985
986 if ((opt_verbose) && (cnt <= 0)) {
987 STRING_PRINTE("error: verbose option flag needs more switches\n");
988 return 1;
989 }
990
991 /* AUTOADJUST DEFAULT = 1 IF NO OTHER PARAMETER EXCEPT FILE NAME */
992 /* if only file names specified, then --autoadjust parameter is turned on by default */
993 if (((opt_counter <= 0) && (file_name_counter > 0)) ||
994 ((opt_counter == 1) && (opt_doubledash) && (file_name_counter > 0)))
995 { opt_autoadjust = 1; opt_counter++; }
996
997 /* Main process of the switches (load -> process -> save) */
998 /* ------------------------------------------------------------------ */
999 /* check switches that need file name as input */
1000 if ((opt_autoadjust) ||
1001 (opt_overwrite ) ||
1002 (opt_noexif ) ||
1003 (opt_jpg ) ||
1004 (opt_jp2 ) ||
1005 (opt_png ) ||
1006 (opt_bmp ) ||
1007 (opt_resize ) ||
1008 (opt_rotate90 ) ||
1009 (opt_rotate180 ) ||
1010 (opt_rotate270 ) ||
1011 (opt_flipx ) ||
1012 (opt_flipy ) ||
1013 (opt_output ) ||
1014 (opt_quality ) ||
1015 (opt_recursive ) ||
1016 (opt_test )){
1017
1018 /* were there any file names on input? */
1019 if (file_name_counter > 0){
1020
1021 /* no error messages during the process with 1 or less file names */
1022 /*if (file_name_counter > 1) opt_quiet = 1; */
1023
1024 /* process them one by one when at least 1 or more input files */
1025 char tt[max_char];
1026 int c = 0;
1027 int d;
1028 int i;
1029 for (i=0; i<file_name_counter; i++){
1030 d = 0;
1031 while (file_name_buffer[c]){
1032 if (d >= max_char) return 255;
1033 if (c >= max_file_name_buffer) return 255;
1034 tt[d] = file_name_buffer[c];
1035 d++;
1036 c++;
1037 }
1038 tt[d] = 0; d++; c++;
1039 /* -------------------------------------------------------- */
1040 if (MAIN_RUN(tt)) { result = 1; }
1041 /* -------------------------------------------------------- */
1042 }
1043 }
1044
1045 /* error here, because no input file names were specified */
1046 else {
1047 STRING_PRINTE("error: file name missing\n");
1048 return 1;
1049 }
1050 }
1051 }
1052 }
1053
1054 /* if no switches or file names or any parameters were specified, */
1055 /* (the argument counter = 1 which is the command name itself) */
1056 /* then print something */
1057 else {
1058 /*PRINT_VERSION(); */
1059 /*PRINT_DESCRIPTION(); */
1060 /*PRINT_LICENSE(); */
1061 /*PRINT_HELP(); */
1062
1063 STRING_PRINTE("No parameters specified. Use -h (--help) for more information\n");
1064 }
1065
1066 return result;
1067 }
1068
1069
1070
1071
MAIN_INIT(void)1072 int MAIN_INIT(void)
1073 {
1074 /* store the unix time here in seconds */
1075 mytime = time(NULL);
1076
1077 /* OpenMP */
1078 /* define the maximum number of threads, this is important to set it in the beginning already */
1079 /* cause fixed arrays will have to be defined knowing that value */
1080 max_cpus = 1;
1081 max_threads = 1;
1082 max_num_threads = 1024;
1083 opt_openmp = 0;
1084 #ifdef __OPENMP__
1085 /* is there openmp support? */
1086 opt_openmp = 1;
1087 /* get the number of available processors to know maximum number of threads */
1088 max_cpus = omp_get_num_procs();
1089 max_threads = max_cpus;
1090 /* set it to minimum 1 */
1091 if (max_threads < 1){ max_threads = 1; }
1092 #endif
1093
1094 /* number of files */
1095 file_counter = 0;
1096 /* number of files stored in file_name_buffer */
1097 file_name_counter = 0;
1098 /* pointer pointing to the end of the file names read from the files that are stored in file_name_buffer */
1099 /* it is the offset pointer pointing to the next file name */
1100 file_name_buffer_pointer = 0;
1101 /* allocate memory */
1102 file_name_buffer = malloc(max_file_name_buffer * sizeof (*file_name_buffer));
1103 if (file_name_buffer == 0){
1104 STRING_PRINTE("error: memory allocation failure\n"); return 1; }
1105
1106 #ifndef __BMP_ONLY__
1107 bitmap_format_png_interlace_type = PNG_INTERLACE_NONE;
1108 bitmap_format_png_compression_type = PNG_COMPRESSION_TYPE_DEFAULT;
1109 bitmap_format_png_filter_type = PNG_FILTER_TYPE_DEFAULT;
1110 #endif
1111
1112 /* set default image resolution */
1113 /* 2835 dots per meter is equal to 72 dots per inch */
1114 xdpi = 2835;
1115 ydpi = 2835;
1116 udpi = 1;
1117
1118 return 0;
1119 }
1120
1121
1122
main(int argc,char ** argv)1123 int main(int argc, char **argv)
1124 {
1125 int result;
1126
1127 if (MAIN_INIT()) return 1;
1128
1129 result = 0;
1130 if (MAIN_ARGUMENTS_READ(argc, argv)){ result = 1; }
1131
1132 free(file_name_buffer);
1133
1134 return result;
1135 }
1136