cjpeg.pas 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745
  1. Program cjpeg;
  2. { Original: cjpeg.c ; Copyright (C) 1991-1996, Thomas G. Lane. }
  3. { This file contains a command-line user interface for the JPEG compressor. }
  4. { Two different command line styles are permitted, depending on the
  5. compile-time switch TWO_FILE_COMMANDLINE:
  6. cjpeg [options] inputfile outputfile
  7. cjpeg [options] [inputfile]
  8. In the second style, output is always to standard output, which you'd
  9. normally redirect to a file or pipe to some other program. Input is
  10. either from a named file or from standard input (typically redirected).
  11. The second style is convenient on Unix but is unhelpful on systems that
  12. don't support pipes. Also, you MUST use the first style if your system
  13. doesn't do binary I/O to stdin/stdout.
  14. To simplify script writing, the "-outfile" switch is provided. The syntax
  15. cjpeg [options] -outfile outputfile inputfile
  16. works regardless of which command line style is used. }
  17. {$I jconfig.inc}
  18. uses
  19. jmorecfg,
  20. cdjpeg, { Common decls for cjpeg/djpeg applications }
  21. {jversion,} { for version message }
  22. jpeglib,
  23. jerror,
  24. jinclude, JDataDst,
  25. JcAPImin, JcAPIstd, JcParam,
  26. {$ifdef TARGA_SUPPORTED} rdtarga, {$endif}
  27. {$ifdef BMP_SUPPORTED} rdbmp, {$endif}
  28. {$ifdef PPM_SUPPORTED} rdppm, {$endif}
  29. {$ifdef EXT_SWITCH} rdswitch, {$endif}
  30. {cderror,}
  31. jdeferr;
  32. { This routine determines what format the input file is,
  33. and selects the appropriate input-reading module.
  34. To determine which family of input formats the file belongs to,
  35. we may look only at the first byte of the file, since C does not
  36. guarantee that more than one character can be pushed back with ungetc.
  37. Looking at additional bytes would require one of these approaches:
  38. 1) assume we can fseek() the input file (fails for piped input);
  39. 2) assume we can push back more than one character (works in
  40. some C implementations, but unportable);
  41. 3) provide our own buffering (breaks input readers that want to use
  42. stdio directly, such as the RLE library);
  43. or 4) don't put back the data, and modify the input_init methods to assume
  44. they start reading after the start of file (also breaks RLE library).
  45. #1 is attractive for MS-DOS but is untenable on Unix.
  46. The most portable solution for file types that can't be identified by their
  47. first byte is to make the user tell us what they are. This is also the
  48. only approach for "raw" file types that contain only arbitrary values.
  49. We presently apply this method for Targa files. Most of the time Targa
  50. files start with $00, so we recognize that case. Potentially, however,
  51. a Targa file could start with any byte value (byte 0 is the length of the
  52. seldom-used ID field), so we provide a switch to force Targa input mode. }
  53. var
  54. is_targa : boolean; { records user -targa switch }
  55. function GetFirstChar(cinfo : j_compress_ptr;
  56. fptr : fileptr) : char;
  57. var
  58. c : char;
  59. begin
  60. if JFREAD(fptr, @c, 1) <> 1 then
  61. ERREXIT(j_common_ptr(cinfo), JERR_INPUT_EMPTY);
  62. Seek(fptr^, 0); { Nomssi: probably not portable }
  63. if (IOresult <> 0) then
  64. ERREXIT(j_common_ptr(cinfo), JERR_UNGETC_FAILED);
  65. GetFirstChar := c;
  66. end;
  67. {LOCAL}
  68. function select_file_type (cinfo : j_compress_ptr;
  69. var infile : FILE) : cjpeg_source_ptr;
  70. var
  71. c : char;
  72. begin
  73. if (is_targa) then
  74. begin
  75. {$ifdef TARGA_SUPPORTED}
  76. select_file_type := jinit_read_targa(cinfo);
  77. exit;
  78. {$else}
  79. ERREXIT(j_common_ptr(cinfo), JERR_TGA_NOTCOMP);
  80. {$endif}
  81. end;
  82. c := GetFirstChar(cinfo, @infile);
  83. select_file_type := NIL; { suppress compiler warnings }
  84. case c of
  85. {$ifdef BMP_SUPPORTED}
  86. 'B': select_file_type := jinit_read_bmp(cinfo);
  87. {$endif}
  88. {$ifdef GIF_SUPPORTED}
  89. 'G': select_file_type := jinit_read_gif(cinfo);
  90. {$endif}
  91. {$ifdef PPM_SUPPORTED}
  92. 'P': select_file_type := jinit_read_ppm(cinfo);
  93. {$endif}
  94. {$ifdef RLE_SUPPORTED}
  95. 'R': select_file_type := jinit_read_rle(cinfo);
  96. {$endif}
  97. {$ifdef TARGA_SUPPORTED}
  98. char($00): select_file_type := jinit_read_targa(cinfo);
  99. {$endif}
  100. else
  101. ERREXIT(j_common_ptr(cinfo), JERR_UNKNOWN_FORMAT);
  102. end;
  103. end;
  104. { Argument-parsing code.
  105. The switch parser is designed to be useful with DOS-style command line
  106. syntax, ie, intermixed switches and file names, where only the switches
  107. to the left of a given file name affect processing of that file.
  108. The main program in this file doesn't actually use this capability... }
  109. var
  110. progname, { program name for error messages }
  111. outfilename : string[79]; { for -outfile switch }
  112. {LOCAL}
  113. procedure usage;
  114. { complain about bad command line }
  115. begin
  116. Write(output, 'usage: ', progname, ' [switches] ');
  117. {$ifdef TWO_FILE_COMMANDLINE}
  118. WriteLn(output, 'inputfile outputfile');
  119. {$else}
  120. WriteLn(output, '[inputfile]');
  121. {$endif}
  122. WriteLn(output, 'Switches (names may be abbreviated):');
  123. WriteLn(output, ' -quality N Compression quality (0..100; 5-95 is useful range)');
  124. WriteLn(output, ' -grayscale Create monochrome JPEG file');
  125. {$ifdef ENTROPY_OPT_SUPPORTED}
  126. WriteLn(output, ' -optimize Optimize Huffman table (smaller file, but slow compression)');
  127. {$endif}
  128. {$ifdef C_PROGRESSIVE_SUPPORTED}
  129. WriteLn(output, ' -progressive Create progressive JPEG file');
  130. {$endif}
  131. {$ifdef TARGA_SUPPORTED}
  132. WriteLn(output, ' -targa Input file is Targa format (usually not needed)');
  133. {$endif}
  134. WriteLn(output, 'Switches for advanced users:');
  135. {$ifdef DCT_ISLOW_SUPPORTED}
  136. if (JDCT_DEFAULT = JDCT_ISLOW) then
  137. WriteLn(output, ' -dct int Use integer DCT method (default)')
  138. else
  139. WriteLn(output, ' -dct int Use integer DCT method');
  140. {$endif}
  141. {$ifdef DCT_IFAST_SUPPORTED}
  142. if (JDCT_DEFAULT = JDCT_IFAST) then
  143. WriteLn(output, ' -dct fast Use fast integer DCT (less accurate) (default)')
  144. else
  145. WriteLn(output, ' -dct fast Use fast integer DCT (less accurate)');
  146. {$endif}
  147. {$ifdef DCT_FLOAT_SUPPORTED}
  148. if (JDCT_DEFAULT = JDCT_FLOAT) then
  149. WriteLn(output, ' -dct float Use floating-point DCT method (default)')
  150. else
  151. WriteLn(output, ' -dct float Use floating-point DCT method');
  152. {$endif}
  153. WriteLn(output, ' -restart N Set restart interval in rows, or in blocks with B');
  154. {$ifdef INPUT_SMOOTHING_SUPPORTED}
  155. WriteLn(output, ' -smooth N Smooth dithered input (N=1..100 is strength)');
  156. {$endif}
  157. WriteLn(output, ' -maxmemory N Maximum memory to use (in kbytes)');
  158. WriteLn(output, ' -outfile name Specify name for output file');
  159. WriteLn(output, ' -verbose or -debug Emit debug output');
  160. {$IFDEF EXT_SWITCH}
  161. WriteLn(output, 'Switches for wizards:');
  162. {$ifdef C_ARITH_CODING_SUPPORTED}
  163. WriteLn(output, ' -arithmetic Use arithmetic coding');
  164. {$endif}
  165. WriteLn(output, ' -baseline Force baseline output');
  166. WriteLn(output, ' -qtables file Use quantization tables given in file');
  167. WriteLn(output, ' -qslots N[,...] Set component quantization tables');
  168. WriteLn(output, ' -sample HxV[,...] Set component sampling factors');
  169. {$ifdef C_MULTISCAN_FILES_SUPPORTED}
  170. WriteLn(output, ' -scans file Create multi-scan JPEG per script file');
  171. {$endif}
  172. {$ENDIF}
  173. Halt(EXIT_FAILURE);
  174. end;
  175. {LOCAL}
  176. function parse_switches (cinfo : j_compress_ptr;
  177. last_file_arg_seen : int;
  178. for_real : boolean) : int;
  179. { Parse optional switches.
  180. Returns argv[] index of first file-name argument (== argc if none).
  181. Any file names with indexes <= last_file_arg_seen are ignored;
  182. they have presumably been processed in a previous iteration.
  183. (Pass 0 for last_file_arg_seen on the first or only iteration.)
  184. for_real is FALSE on the first (dummy) pass; we may skip any expensive
  185. processing. }
  186. var
  187. argn,
  188. argc : int;
  189. arg : string;
  190. var
  191. value : int;
  192. code : integer;
  193. var
  194. quality : int; { -quality parameter }
  195. q_scale_factor : int; { scaling percentage for -qtables }
  196. force_baseline : boolean;
  197. simple_progressive : boolean;
  198. qtablefile, { saves -qtables filename if any }
  199. qslotsarg, { saves -qslots parm if any }
  200. samplearg, { saves -sample parm if any }
  201. scansarg : string; { saves -scans parm if any }
  202. var
  203. lval : long;
  204. ch : char;
  205. const
  206. printed_version : boolean = FALSE;
  207. begin
  208. qtablefile := '';
  209. qslotsarg := '';
  210. samplearg := '';
  211. scansarg := '';
  212. { Set up default JPEG parameters. }
  213. { Note that default -quality level need not, and does not,
  214. match the default scaling for an explicit -qtables argument. }
  215. quality := 75; { default -quality value }
  216. q_scale_factor := 100; { default to no scaling for -qtables }
  217. force_baseline := FALSE; { by default, allow 16-bit quantizers }
  218. simple_progressive := FALSE;
  219. is_targa := FALSE;
  220. outfilename := '';
  221. cinfo^.err^.trace_level := 0;
  222. { Scan command line options, adjust parameters }
  223. argn := 0;
  224. argc := ParamCount;
  225. while argn < argc do
  226. begin
  227. Inc(argn);
  228. arg := ParamStr(argn);
  229. if (arg[1] <> '-') then
  230. begin
  231. { Not a switch, must be a file name argument }
  232. if (argn <= last_file_arg_seen) then
  233. begin
  234. outfilename := ''; { -outfile applies to just one input file }
  235. continue; { ignore this name if previously processed }
  236. end;
  237. break; { else done parsing switches }
  238. end;
  239. {Inc(arg); - advance past switch marker character }
  240. if (keymatch(arg, '-arithmetic', 2)) then
  241. begin
  242. { Use arithmetic coding. }
  243. {$ifdef C_ARITH_CODING_SUPPORTED}
  244. cinfo^.arith_code := TRUE;
  245. {$else}
  246. WriteLn(output, progname, ': sorry, arithmetic coding not supported');
  247. Halt(EXIT_FAILURE);
  248. {$endif}
  249. end
  250. else
  251. if (keymatch(arg, '-baseline', 2)) then
  252. begin
  253. { Force baseline output (8-bit quantizer values). }
  254. force_baseline := TRUE;
  255. end
  256. else
  257. if (keymatch(arg, '-dct', 3)) then
  258. begin
  259. { Select DCT algorithm. }
  260. Inc(argn);
  261. if (argn >= argc) then { advance to next argument }
  262. usage;
  263. if (keymatch(ParamStr(argn), 'int', 1)) then
  264. begin
  265. cinfo^.dct_method := JDCT_ISLOW;
  266. end
  267. else
  268. if (keymatch(ParamStr(argn), 'fast', 2)) then
  269. begin
  270. cinfo^.dct_method := JDCT_IFAST;
  271. end
  272. else
  273. if (keymatch(ParamStr(argn), 'float', 2)) then
  274. begin
  275. cinfo^.dct_method := JDCT_FLOAT;
  276. end
  277. else
  278. usage;
  279. end
  280. else
  281. if keymatch(arg, '-debug', 2) or keymatch(arg, '-verbose', 2) then
  282. begin
  283. { Enable debug printouts. }
  284. { On first -d, print version identification }
  285. if (not printed_version) then
  286. begin
  287. WriteLn(output, 'Independent JPEG Group''s CJPEG, version ', JVERSION);
  288. WriteLn(output, JCOPYRIGHT);
  289. WriteLn(output, JNOTICE);
  290. printed_version := TRUE;
  291. end;
  292. Inc(cinfo^.err^.trace_level);
  293. end
  294. else
  295. if (keymatch(arg, '-grayscale', 3)) or (keymatch(arg, '-greyscale',3)) then
  296. begin
  297. { Force a monochrome JPEG file to be generated. }
  298. jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
  299. end
  300. else
  301. if (keymatch(arg, '-maxmemory', 4)) then
  302. begin
  303. ch := 'x';
  304. Inc(argn);
  305. if (argn >= argc) then { advance to next argument }
  306. usage;
  307. arg := ParamStr(argn);
  308. if (length(arg) > 1) and (arg[length(arg)] in ['m','M']) then
  309. begin
  310. ch := arg[length(arg)];
  311. arg := Copy(arg, 1, Length(arg)-1);
  312. end;
  313. Val(arg, lval, code);
  314. if (code <> 1) then
  315. usage;
  316. if (ch = 'm') or (ch = 'M') then
  317. lval := lval * long(1000);
  318. cinfo^.mem^.max_memory_to_use := lval * long(1000);
  319. end
  320. else
  321. if (keymatch(arg, '-optimize', 2)) or (keymatch(arg, '-optimise', 2)) then
  322. begin
  323. { Enable entropy parm optimization. }
  324. {$ifdef ENTROPY_OPT_SUPPORTED}
  325. cinfo^.optimize_coding := TRUE;
  326. {$else}
  327. WriteLn(output, progname, ': sorry, entropy optimization was not compiled');
  328. exit(EXIT_FAILURE);
  329. {$endif}
  330. end
  331. else
  332. if (keymatch(arg, '-outfile', 5)) then
  333. begin
  334. { Set output file name. }
  335. Inc(argn);
  336. if (argn >= argc) then { advance to next argument }
  337. usage;
  338. outfilename := ParamStr(argn); { save it away for later use }
  339. end
  340. else
  341. if (keymatch(arg, '-progressive', 2)) then
  342. begin
  343. { Select simple progressive mode. }
  344. {$ifdef C_PROGRESSIVE_SUPPORTED}
  345. simple_progressive := TRUE;
  346. { We must postpone execution until num_components is known. }
  347. {$else}
  348. WriteLn(output, progname, ': sorry, progressive output was not compiled');
  349. Halt(EXIT_FAILURE);
  350. {$endif}
  351. end
  352. else
  353. if (keymatch(arg, '-quality', 2)) then
  354. begin
  355. { Quality factor (quantization table scaling factor). }
  356. Inc(argn);
  357. if (argn >= argc) then { advance to next argument }
  358. usage;
  359. Val(ParamStr(argn), quality, code);
  360. if code <> 0 then
  361. usage;
  362. { Change scale factor in case -qtables is present. }
  363. q_scale_factor := jpeg_quality_scaling(quality);
  364. end
  365. else
  366. if (keymatch(arg, '-qslots', 3)) then
  367. begin
  368. { Quantization table slot numbers. }
  369. Inc(argn);
  370. if (argn >= argc) then { advance to next argument }
  371. usage;
  372. qslotsarg := ParamStr(argn);
  373. { Must delay setting qslots until after we have processed any
  374. colorspace-determining switches, since jpeg_set_colorspace sets
  375. default quant table numbers. }
  376. end
  377. else
  378. if (keymatch(arg, '-qtables', 3)) then
  379. begin
  380. { Quantization tables fetched from file. }
  381. Inc(argn);
  382. if (argn >= argc) then { advance to next argument }
  383. usage;
  384. qtablefile := ParamStr(argn);
  385. { We postpone actually reading the file in case -quality comes later. }
  386. end
  387. else
  388. if (keymatch(arg, '-restart', 2)) then
  389. begin
  390. { Restart interval in MCU rows (or in MCUs with 'b'). }
  391. ch := 'x';
  392. Inc(argn);
  393. if (argn >= argc) then { advance to next argument }
  394. usage;
  395. arg := ParamStr(argn);
  396. if (length(arg) > 1) and (arg[length(arg)] in ['b','B']) then
  397. begin
  398. ch := arg[length(arg)];
  399. arg := Copy(arg, 1, Length(arg)-1);
  400. end;
  401. Val(arg, lval, Code);
  402. if (code <> 1) then
  403. usage;
  404. if (lval < 0) or (lval > long(65535)) then
  405. usage;
  406. if (ch = 'b') or (ch = 'B') then
  407. begin
  408. cinfo^.restart_interval := uInt (lval);
  409. cinfo^.restart_in_rows := 0; { else prior '-restart n' overrides me }
  410. end
  411. else
  412. begin
  413. cinfo^.restart_in_rows := int (lval);
  414. { restart_interval will be computed during startup }
  415. end;
  416. end
  417. else
  418. if (keymatch(arg, '-sample', 3)) then
  419. begin
  420. { Set sampling factors. }
  421. Inc(argn);
  422. if (argn >= argc) then { advance to next argument }
  423. usage;
  424. samplearg := ParamStr(argn);
  425. { Must delay setting sample factors until after we have processed any
  426. colorspace-determining switches, since jpeg_set_colorspace sets
  427. default sampling factors. }
  428. end
  429. else
  430. if (keymatch(arg, '-scans', 3)) then
  431. begin
  432. { Set scan script. }
  433. {$ifdef C_MULTISCAN_FILES_SUPPORTED}
  434. Inc(argn);
  435. if (argn >= argc) then { advance to next argument }
  436. usage;
  437. scansarg := ParamStr(argn);
  438. { We must postpone reading the file in case -progressive appears. }
  439. {$else}
  440. WriteLn(output, progname, ': sorry, multi-scan output was not compiled');
  441. Halt(EXIT_FAILURE);
  442. {$endif}
  443. end
  444. else
  445. if (keymatch(arg, '-smooth', 3)) then
  446. begin
  447. { Set input smoothing factor. }
  448. Inc(argn);
  449. if (argn >= argc) then { advance to next argument }
  450. usage;
  451. Val(ParamStr(argn), value, code);
  452. if (value < 0) or (value > 100)
  453. or (code <> 0) then
  454. usage;
  455. cinfo^.smoothing_factor := value;
  456. end
  457. else
  458. if (keymatch(arg, '-targa', 2)) then
  459. begin
  460. { Input file is Targa format. }
  461. is_targa := TRUE;
  462. end
  463. else
  464. begin
  465. usage; { bogus switch }
  466. end;
  467. end;
  468. { Post-switch-scanning cleanup }
  469. if (for_real) then
  470. begin
  471. { Set quantization tables for selected quality. }
  472. { Some or all may be overridden if -qtables is present. }
  473. jpeg_set_quality(cinfo, quality, force_baseline);
  474. {$IFDEF EXT_SWITCH}
  475. if (qtablefile <> '') then { process -qtables if it was present }
  476. if (not read_quant_tables(cinfo, qtablefile,
  477. q_scale_factor, force_baseline)) then
  478. usage;
  479. if (qslotsarg <> '') then { process -qslots if it was present }
  480. if (not set_quant_slots(cinfo, qslotsarg)) then
  481. usage;
  482. if (samplearg <> '') then { process -sample if it was present }
  483. if (not set_sample_factors(cinfo, samplearg)) then
  484. usage;
  485. {$ENDIF}
  486. {$ifdef C_PROGRESSIVE_SUPPORTED}
  487. if (simple_progressive) then { process -progressive; -scans can override }
  488. jpeg_simple_progression(cinfo);
  489. {$endif}
  490. {$IFDEF EXT_SWITCH}
  491. {$ifdef C_MULTISCAN_FILES_SUPPORTED}
  492. if (scansarg <> '') then { process -scans if it was present }
  493. if (not read_scan_script(cinfo, scansarg)) then
  494. usage;
  495. {$endif}
  496. {$ENDIF}
  497. end;
  498. parse_switches := argn; { return index of next arg (file name) }
  499. end;
  500. { The main program. }
  501. var
  502. cinfo : jpeg_compress_struct;
  503. jerr : jpeg_error_mgr;
  504. {$ifdef PROGRESS_REPORT}
  505. progress : cdjpeg_progress_mgr;
  506. {$endif}
  507. file_index : int;
  508. src_mgr : cjpeg_source_ptr;
  509. input_file : FILE;
  510. output_file : FILE;
  511. num_scanlines : JDIMENSION;
  512. var
  513. argc : int;
  514. begin
  515. argc := ParamCount;
  516. progname := ParamStr(0);
  517. { Initialize the JPEG compression object with default error handling. }
  518. cinfo.err := jpeg_std_error(jerr);
  519. jpeg_create_compress(@cinfo);
  520. { Add some application-specific error messages (from cderror.h) }
  521. {jerr.addon_message_table := cdjpeg_message_table;}
  522. jerr.first_addon_message := JMSG_FIRSTADDONCODE;
  523. jerr.last_addon_message := JMSG_LASTADDONCODE;
  524. { Now safe to enable signal catcher. }
  525. {$ifdef NEED_SIGNAL_CATCHER}
  526. enable_signal_catcher(j_common_ptr ( @cinfo);
  527. {$endif}
  528. { Initialize JPEG parameters.
  529. Much of this may be overridden later.
  530. In particular, we don't yet know the input file's color space,
  531. but we need to provide some value for jpeg_set_defaults() to work. }
  532. cinfo.in_color_space := JCS_RGB; { arbitrary guess }
  533. jpeg_set_defaults(@cinfo);
  534. { Scan command line to find file names.
  535. It is convenient to use just one switch-parsing routine, but the switch
  536. values read here are ignored; we will rescan the switches after opening
  537. the input file. }
  538. file_index := parse_switches(@cinfo, 0, FALSE);
  539. {$ifdef TWO_FILE_COMMANDLINE}
  540. { Must have either -outfile switch or explicit output file name }
  541. if (outfilename = '') then
  542. begin
  543. if (file_index <> argc-2+1) then
  544. begin
  545. WriteLn(output, progname, ': must name one input and one output file');
  546. usage;
  547. end;
  548. outfilename := ParamStr(file_index+1);
  549. end
  550. else
  551. begin
  552. if (file_index <> argc-1) then
  553. begin
  554. WriteLn(output, progname, ': must name one input and one output file');
  555. usage;
  556. end;
  557. end;
  558. {$else}
  559. { Unix style: expect zero or one file name }
  560. if (file_index < argc-1) then
  561. begin
  562. WriteLn(output, progname, ': only one input file');
  563. usage;
  564. end;
  565. {$endif} { TWO_FILE_COMMANDLINE }
  566. { Open the input file. }
  567. if (file_index < argc) then
  568. begin
  569. Assign(input_file, ParamStr(file_index));
  570. {$I-}
  571. Reset(input_file, 1);
  572. {$ifdef IOcheck} {$I+} {$endif}
  573. if (IOresult <> 0) then
  574. begin
  575. WriteLn(output, progname, ': can''t open ', ParamStr(file_index));
  576. Halt(EXIT_FAILURE);
  577. end;
  578. end
  579. else
  580. begin
  581. WriteLn(output, progname, ': no input file');
  582. Halt(EXIT_FAILURE);
  583. end;
  584. { Open the output file. }
  585. if (outfilename <> '') then
  586. begin
  587. Assign(output_file, outfilename);
  588. {$I-}
  589. Reset(output_file, 1);
  590. {$ifdef IOcheck} {$I+} {$endif}
  591. if (IOresult = 0) then
  592. begin
  593. WriteLn(output, outfilename, ': already exists.');
  594. close(output_file);
  595. Halt(EXIT_FAILURE);
  596. end;
  597. {$I-}
  598. ReWrite(output_file, 1);
  599. {$ifdef IOcheck} {$I+} {$endif}
  600. if (IOresult <> 0) then
  601. begin
  602. WriteLn(output, progname, ': can''t create ', outfilename);
  603. Halt(EXIT_FAILURE);
  604. end;
  605. end
  606. else
  607. begin
  608. WriteLn(output, progname, ': no output file');
  609. Halt(EXIT_FAILURE);
  610. end;
  611. {$ifdef PROGRESS_REPORT}
  612. start_progress_monitor(j_common_ptr (@cinfo), @progress);
  613. {$endif}
  614. { Figure out the input file format, and set up to read it. }
  615. src_mgr := select_file_type(@cinfo, input_file);
  616. src_mgr^.input_file := @input_file;
  617. { Read the input file header to obtain file size & colorspace. }
  618. src_mgr^.start_input (@cinfo, src_mgr);
  619. { Now that we know input colorspace, fix colorspace-dependent defaults }
  620. jpeg_default_colorspace(@cinfo);
  621. { Adjust default compression parameters by re-parsing the options }
  622. file_index := parse_switches(@cinfo, 0, TRUE);
  623. { Specify data destination for compression }
  624. jpeg_stdio_dest(@cinfo, @output_file);
  625. { Start compressor }
  626. jpeg_start_compress(@cinfo, TRUE);
  627. { Process data }
  628. while (cinfo.next_scanline < cinfo.image_height) do
  629. begin
  630. num_scanlines := src_mgr^.get_pixel_rows (@cinfo, src_mgr);
  631. {void} jpeg_write_scanlines(@cinfo, src_mgr^.buffer, num_scanlines);
  632. end;
  633. { Finish compression and release memory }
  634. src_mgr^.finish_input (@cinfo, src_mgr);
  635. jpeg_finish_compress(@cinfo);
  636. jpeg_destroy_compress(@cinfo);
  637. { Close files, if we opened them }
  638. close(input_file);
  639. close(output_file);
  640. {$ifdef PROGRESS_REPORT}
  641. end_progress_monitor(j_common_ptr (@cinfo));
  642. {$endif}
  643. { All done. }
  644. if jerr.num_warnings <> 0 then
  645. Halt(EXIT_WARNING)
  646. else
  647. Halt(EXIT_SUCCESS);
  648. end.