summaryrefslogtreecommitdiff
path: root/packages/pasjpeg/examples/jpegtran.pas
diff options
context:
space:
mode:
Diffstat (limited to 'packages/pasjpeg/examples/jpegtran.pas')
-rw-r--r--packages/pasjpeg/examples/jpegtran.pas642
1 files changed, 642 insertions, 0 deletions
diff --git a/packages/pasjpeg/examples/jpegtran.pas b/packages/pasjpeg/examples/jpegtran.pas
new file mode 100644
index 0000000000..c238d7966c
--- /dev/null
+++ b/packages/pasjpeg/examples/jpegtran.pas
@@ -0,0 +1,642 @@
+Program JpegTran;
+
+{ This file contains a command-line user interface for JPEG transcoding.
+ It is very similar to cjpeg.c, but provides lossless transcoding between
+ different JPEG file formats. }
+
+{ Original: jpegtran.c ; Copyright (C) 1995-1996, Thomas G. Lane. }
+
+{$define TWO_FILE_COMMANDLINE}
+
+{$I jconfig.inc}
+
+uses
+ jdeferr,
+ jerror,
+ jmorecfg,
+ jpeglib,
+ cdjpeg, { Common decls for cjpeg/djpeg applications }
+ jdatasrc, JDatadst, transupp, JCTrans, JDtrans,
+ JdAPImin, JcAPImin, JcParam,
+ RdSwitch;
+
+
+{ Argument-parsing code.
+ The switch parser is designed to be useful with DOS-style command line
+ syntax, ie, intermixed switches and file names, where only the switches
+ to the left of a given file name affect processing of that file.
+ The main program in this file doesn't actually use this capability... }
+
+
+var
+ progname, { program name for error messages }
+ outfilename : string; { for -outfile switch }
+ copyoption : JCOPY_OPTION; { -copy switch }
+ transformoption : jpeg_transform_info; { image transformation options }
+
+procedure Stop(errcode : int);
+begin
+ Halt(errcode);
+end;
+
+{LOCAL}
+procedure usage;
+{ complain about bad command line }
+begin
+ Write(output, 'usage: ',progname,' [switches] ');
+{$ifdef TWO_FILE_COMMANDLINE}
+ WriteLn(output, 'inputfile outputfile');
+{$else}
+ WriteLn(output, '[inputfile]');
+{$endif}
+
+ WriteLn(output, 'Switches (names may be abbreviated):');
+ WriteLn(' -copy none Copy no extra markers from source file');
+ WriteLn(' -copy comments Copy only comment markers (default)');
+ WriteLn(' -copy all Copy all extra markers');
+{$ifdef ENTROPY_OPT_SUPPORTED}
+ WriteLn(' -optimize Optimize Huffman table (smaller file, but slow compression)');
+{$endif}
+{$ifdef C_PROGRESSIVE_SUPPORTED}
+ WriteLn(' -progressive Create progressive JPEG file');
+{$endif}
+{$ifdef TRANSFORMS_SUPPORTED}
+ WriteLn('Switches for modifying the image:');
+ WriteLn(' -grayscale Reduce to grayscale (omit color data)');
+ WriteLn(' -flip [horizontal|vertical] Mirror image (left-right or top-bottom)');
+ WriteLn(' -rotate [90|180|270] Rotate image (degrees clockwise)');
+ WriteLn(' -transpose Transpose image');
+ WriteLn(' -transverse Transverse transpose image');
+ WriteLn(' -trim Drop non-transformable edge blocks');
+ {$ifdef CROP_SUPPORTED}
+ WriteLn(' -cut WxH+X+Y Cut out a subset of the image');
+ {$endif}
+{$endif} { TRANSFORMS_SUPPORTED }
+ WriteLn('Switches for advanced users:');
+ WriteLn(' -restart N Set restart interval in rows, or in blocks with B');
+ WriteLn(' -maxmemory N Maximum memory to use (in kbytes)');
+ WriteLn(' -outfile name Specify name for output file');
+ WriteLn(' -verbose or -debug Emit debug output');
+ WriteLn('Switches for wizards:');
+{$ifdef C_ARITH_CODING_SUPPORTED}
+ WriteLn(' -arithmetic Use arithmetic coding');
+{$endif}
+{$ifdef C_MULTISCAN_FILES_SUPPORTED}
+ WriteLn(' -scans file Create multi-scan JPEG per script file');
+{$endif}
+ Stop(EXIT_FAILURE);
+end;
+
+{LOCAL}
+procedure select_transform (transform : JXFORM_CODE);
+{ Silly little routine to detect multiple transform options,
+ which we can't handle. }
+
+begin
+{$ifdef TRANSFORMS_SUPPORTED}
+ if (transformoption.transform = JXFORM_NONE) or
+ (transformoption.transform = transform) then
+ transformoption.transform := transform
+ else
+ begin
+ WriteLn(progname, ': can only do one image transformation at a time');
+ usage;
+ end;
+{$else}
+ WriteLn(progname, ': sorry, image transformation was not compiled');
+ exit(EXIT_FAILURE);
+{$endif}
+end;
+
+{LOCAL}
+function parse_switches (cinfo : j_compress_ptr;
+ last_file_arg_seen: int;
+ for_real : boolean ) : int;
+const
+ printed_version : boolean = FALSE;
+
+{ Parse optional switches.
+ Returns argv[] index of first file-name argument (= argc if none).
+ Any file names with indexes <= last_file_arg_seen are ignored;
+ they have presumably been processed in a previous iteration.
+ (Pass 0 for last_file_arg_seen on the first or only iteration.)
+ for_real is FALSE on the first (dummy) pass; we may skip any expensive
+ processing. }
+var
+ argn,
+ argc : int;
+ arg : string;
+
+ simple_progressive : boolean;
+const
+ scansarg : string = ''; { saves -scans parm if any }
+var
+ lval : long;
+ ch : char;
+ code : integer;
+begin
+ { Set up default JPEG parameters. }
+ simple_progressive := FALSE;
+ outfilename := '';
+ cinfo^.err^.trace_level := 0;
+ copyoption := JCOPYOPT_DEFAULT;
+ transformoption.transform := JXFORM_NONE;
+ transformoption.trim := FALSE;
+ transformoption.force_grayscale := FALSE;
+ cinfo^.err^.trace_level := 0;
+
+ { Scan command line options, adjust parameters }
+
+ argn := 0;
+ argc := ParamCount;
+
+ while argn < argc do
+ begin
+ Inc(argn);
+ arg := ParamStr(argn);
+ if (arg[1] <> '-') then
+ begin
+ { Not a switch, must be a file name argument }
+ if (argn <= last_file_arg_seen) then
+ begin
+ outfilename := ''; { -outfile applies to just one input file }
+ continue; { ignore this name if previously processed }
+ end;
+ break; { else done parsing switches }
+ end;
+ {Inc(arg); - advance past switch marker character }
+
+ if (keymatch(arg, '-arithmetic', 1)) then
+ begin
+ { Use arithmetic coding. }
+{$ifdef C_ARITH_CODING_SUPPORTED}
+ cinfo^.arith_code := TRUE;
+{$else}
+ WriteLn(output, progname, ': sorry, arithmetic coding not supported');
+ Stop(EXIT_FAILURE);
+{$endif}
+ end
+ else
+ if keymatch(arg, '-copy', 2) then
+ begin { Select which extra markers to copy. }
+ Inc(argn);
+ if (argn >= argc) then { advance to next argument }
+ usage;
+ if (keymatch(ParamStr(argn), 'none', 1)) then
+ copyoption := JCOPYOPT_NONE
+ else
+ if (keymatch(ParamStr(argn), 'comments', 1)) then
+ copyoption := JCOPYOPT_COMMENTS
+ else
+ if (keymatch(ParamStr(argn), 'all', 1)) then
+ copyoption := JCOPYOPT_ALL
+ else
+ usage;
+ end
+ else
+ if keymatch(arg, '-debug', 2) or keymatch(arg, '-verbose', 2) then
+ begin
+ { Enable debug printouts. }
+ { On first -d, print version identification }
+
+ if (not printed_version) then
+ begin
+ WriteLn('PASJPEG Group''s JPEGTRAN translation version ',
+ JVERSION, JCOPYRIGHT, JNOTICE);
+ printed_version := TRUE;
+ end;
+ Inc(cinfo^.err^.trace_level);
+ end
+ else
+ {$ifdef CROP_SUPPORTED}
+ if keymatch(arg, '-cut', 2) then
+ begin
+ { Cut out a region of the image specified by an X geometry-like string }
+ p : PChar;
+
+ Inc(argn);
+ if (argn >= argc) then
+ usage;
+ select_transform(JXFORM_CUT);
+
+ arg := ParamStr(argn);
+ px := Pos('x', arg);
+ if ( px = 'x') then
+ usage;
+ arg_w := Copy(arg, 1, px-1);
+ Val(arg_w, lval, code);
+ if (code <> 0) then
+ usage;
+
+ transformoption.newwidth := lval;
+ arg_w := Copy(arg, px+1, Length(arg));
+ Val(arg_w, lval, code);
+ if (code <> 0) then
+ usage;
+
+ transformoption.newheight := lval;
+ if (p^ <> '+') and (p^ <> '-') then
+ usage;
+ arg_w := Copy(arg, px+1, Length(arg));
+ Val(arg_w, lval, code);
+ if (code <> 0) then
+ usage;
+
+ transformoption.xoffs := lval;
+ arg_w := Copy(arg, px+1, Length(arg));
+ Val(arg_w, lval, code);
+ if (code <> 0) then
+ usage;
+
+ if (p^ <> '+') and (p^ <> '-') then
+ usage;
+ transformoption.yoffs := lval;
+
+ if (transformoption.newwidth=0) or (transformoption.newheight=0) then
+ begin
+ WriteLn(progname,': degenerate -cut size in ', argv[argn]);
+ exit(EXIT_FAILURE);
+ end
+ end
+ else
+ {$endif}
+ if keymatch(arg, '-flip', 2) then
+ begin { Mirror left-right or top-bottom. }
+ Inc(argn);
+ if (argn >= argc) then { advance to next argument }
+ usage;
+ if keymatch(ParamStr(argn), 'horizontal', 2) then
+ select_transform(JXFORM_FLIP_H)
+ else
+ if keymatch(ParamStr(argn), 'vertical', 2) then
+ select_transform(JXFORM_FLIP_V)
+ else
+ usage;
+ end
+ else
+ if keymatch(arg, '-grayscale', 2) or
+ keymatch(arg, '-greyscale',2) then
+ begin { Force to grayscale. }
+ {$ifdef TRANSFORMS_SUPPORTED}
+ transformoption.force_grayscale := TRUE;
+ {$else}
+ select_transform(JXFORM_NONE); { force an error }
+ {$endif}
+ end
+ else
+ if keymatch(arg, '-maxmemory', 4) then
+ begin
+ { Maximum memory in Kb (or Mb with 'm'). }
+ ch := 'x';
+
+ Inc(argn);
+ if (argn >= argc) then { advance to next argument }
+ usage;
+
+ arg := ParamStr(argn);
+ if (length(arg) > 1) and (arg[length(arg)] in ['m','M']) then
+ begin
+ ch := arg[length(arg)];
+ arg := Copy(arg, 1, Length(arg)-1);
+ end;
+ Val(arg, lval, code);
+ if (code <> 0) then
+ usage;
+ if (ch = 'm') or (ch = 'M') then
+ lval := lval * long(1000);
+ cinfo^.mem^.max_memory_to_use := lval * long(1000);
+ end
+ else
+ if keymatch(arg, '-optimize', 2) or
+ keymatch(arg, '-optimise', 2) then
+ begin
+ { Enable entropy parm optimization. }
+ {$ifdef ENTROPY_OPT_SUPPORTED}
+ cinfo^.optimize_coding := TRUE;
+ {$else}
+ WriteLn(output, progname,
+ ': sorry, entropy optimization was not compiled');
+ Stop(EXIT_FAILURE);
+ {$endif}
+
+ end
+ else
+ if keymatch(arg, '-outfile', 5) then
+ begin
+ { Set output file name. }
+ Inc(argn);
+ if (argn >= argc) then { advance to next argument }
+ usage;
+ outfilename := ParamStr(argn); { save it away for later use }
+ end
+ else
+ if keymatch(arg, '-progressive', 2) then
+ begin
+ { Select simple progressive mode. }
+ {$ifdef C_PROGRESSIVE_SUPPORTED}
+ simple_progressive := TRUE;
+ { We must postpone execution until num_components is known. }
+ {$else}
+ WriteLn(output, progname,
+ ': sorry, progressive output was not compiled');
+ Stop(EXIT_FAILURE);
+ {$endif}
+ end
+ else
+ if keymatch(arg, '-restart', 2) then
+ begin
+ ch := 'x';
+ { Restart interval in MCU rows (or in MCUs with 'b'). }
+ Inc(argn);
+ if (argn >= argc) then { advance to next argument }
+ usage;
+ arg := ParamStr(argn);
+ if (length(arg) > 1) and (arg[length(arg)] in ['b','B']) then
+ begin
+ ch := arg[length(arg)];
+ arg := Copy(arg, 1, Length(arg)-1);
+ end;
+
+ Val(arg, lval, code);
+ if (code <> 1) or (lval < 0) or (lval > Long(65535)) then
+ usage;
+
+ if (ch = 'b') or (ch = 'B') then
+ begin
+ cinfo^.restart_interval := uint(lval);
+ cinfo^.restart_in_rows := 0; { else prior '-restart n' overrides me }
+ end
+ else
+ begin
+ cinfo^.restart_in_rows := int(lval);
+ { restart_interval will be computed during startup }
+ end;
+
+ end
+ else
+ if keymatch(arg, '-rotate', 3) then
+ begin { Rotate 90, 180, or 270 degrees (measured clockwise). }
+ Inc(argn);
+ if (argn >= argc) then { advance to next argument }
+ usage;
+ if (keymatch(ParamStr(argn), '90', 2)) then
+ select_transform(JXFORM_ROT_90)
+ else
+ if keymatch(ParamStr(argn), '180', 3) then
+ select_transform(JXFORM_ROT_180)
+ else
+ if keymatch(ParamStr(argn), '270', 3) then
+ select_transform(JXFORM_ROT_270)
+ else
+ usage;
+ end
+ else
+ if keymatch(arg, '-scans', 2) then
+ begin
+ { Set scan script. }
+ {$ifdef C_MULTISCAN_FILES_SUPPORTED}
+ Inc(argn);
+ if (argn >= argc) then { advance to next argument }
+ usage;
+ scansarg := ParamStr(argn);
+ { We must postpone reading the file in case -progressive appears. }
+ {$else}
+ WriteLn(output, progname,
+ ': sorry, multi-scan output was not compiled');
+ Stop(EXIT_FAILURE);
+ {$endif}
+ end
+ else
+ if keymatch(arg, '-transpose', 2) then
+ { Transpose (across UL-to-LR axis). }
+ select_transform(JXFORM_TRANSPOSE)
+ else
+ if keymatch(arg, '-transverse', 7) then
+ { Transverse transpose (across UR-to-LL axis). }
+ select_transform(JXFORM_TRANSVERSE)
+ else
+ if keymatch(arg, '-trim', 4) then
+ { Trim off any partial edge MCUs that
+ the transform can't handle. }
+ transformoption.trim := TRUE
+ else
+ usage; { bogus switch }
+ end;
+
+ { Post-switch-scanning cleanup }
+
+ if (for_real) then
+ begin
+
+{$ifdef C_PROGRESSIVE_SUPPORTED}
+ if (simple_progressive) then { process -progressive; -scans can override }
+ jpeg_simple_progression(cinfo);
+{$endif}
+
+{$ifdef C_MULTISCAN_FILES_SUPPORTED}
+ if (scansarg <> '') then { process -scans if it was present }
+ begin
+ WriteLn('Scripts are not supported in PasJPEG.');
+ {if not read_scan_script(cinfo, scansarg) then
+ usage;
+ }
+ end;
+{$endif}
+ end;
+
+ parse_switches := argn; { return index of next arg (file name) }
+end;
+
+
+{ The main program. }
+
+{main (int argc, char **argv)}
+var
+ srcinfo : jpeg_decompress_struct;
+ dstinfo : jpeg_compress_struct;
+ jsrcerr, jdsterr : jpeg_error_mgr;
+{$ifdef PROGRESS_REPORT}
+ progress : cdjpeg_progress_mgr;
+{$endif}
+ src_coef_arrays,
+ dst_coef_arrays : jvirt_barray_tbl_ptr;
+ file_index : int;
+ input_file : FILE;
+ output_file : FILE;
+begin
+ { On Mac, fetch a command line. }
+{$ifdef USE_CCOMMAND}
+ argc := ccommand(@argv);
+{$endif}
+
+ progname := ParamStr(0);
+
+ { Initialize the JPEG decompression object with default error handling. }
+ srcinfo.err := jpeg_std_error(jsrcerr);
+ jpeg_create_decompress(@srcinfo);
+ { Initialize the JPEG compression object with default error handling. }
+ dstinfo.err := jpeg_std_error(jdsterr);
+ jpeg_create_compress(@dstinfo);
+
+ { Now safe to enable signal catcher.
+ Note: we assume only the decompression object will have virtual arrays. }
+
+{$ifdef NEED_SIGNAL_CATCHER}
+ enable_signal_catcher(j_common_ptr(@srcinfo));
+{$endif}
+
+ { Scan command line to find file names.
+ It is convenient to use just one switch-parsing routine, but the switch
+ values read here are mostly ignored; we will rescan the switches after
+ opening the input file. Also note that most of the switches affect the
+ destination JPEG object, so we parse into that and then copy over what
+ needs to affects the source too. }
+
+ file_index := parse_switches(@dstinfo, 0, FALSE);
+ jsrcerr.trace_level := jdsterr.trace_level;
+ srcinfo.mem^.max_memory_to_use := dstinfo.mem^.max_memory_to_use;
+
+{$ifdef TWO_FILE_COMMANDLINE}
+ { Must have either -outfile switch or explicit output file name }
+ if (outfilename = '') then
+ begin
+ if (file_index <> ParamCount-1) then
+ begin
+ WriteLn(output, progname, ': must name one input and one output file');
+ usage;
+ end;
+ outfilename := ParamStr(file_index+1);
+ end
+ else
+ begin
+ if (file_index <> ParamCount-1) then
+ begin
+ WriteLn(output, progname, ': must name one input and one output file');
+ usage;
+ end;
+ end;
+{$else}
+ { Unix style: expect zero or one file name }
+ if (file_index < argc-1) then
+ begin
+ WriteLn(output, progname, ': only one input file');
+ usage;
+ end;
+{$endif} { TWO_FILE_COMMANDLINE }
+
+ { Open the input file. }
+ if (file_index < ParamCount) then
+ begin
+ assign(input_file, ParamStr(file_index));
+ {$I-}
+ reset(input_file, 1);
+ {$IFDEF IoCheck} {$I+} {$ENDIF}
+ if (IOresult <> 0) then
+ begin
+ WriteLn(output, progname, ': can''t open ', ParamStr(file_index));
+ Stop(EXIT_FAILURE);
+ end;
+ end
+ else
+ begin
+ { default input file is stdin }
+ assign(input_file, '');
+ reset(input_file, 1);
+ end;
+
+ { Open the output file. }
+ if (outfilename <> '') then
+ begin
+ assign(output_file, outfilename);
+ {$I-}
+ rewrite(output_file, 1);
+ {$IFDEF IoCheck} {$I+} {$ENDIF}
+ if (IOresult <> 0) then
+ begin
+ WriteLn(output, progname, ': can''t open ', outfilename);
+ Stop(EXIT_FAILURE);
+ end;
+ end
+ else
+ begin
+ { default output file is stdout }
+ assign(output_file, '');
+ rewrite(output_file, 1);
+ end;
+
+{$ifdef PROGRESS_REPORT}
+ start_progress_monitor(j_common_ptr(@dstinfo), @progress);
+{$endif}
+
+ { Specify data source for decompression }
+ jpeg_stdio_src(@srcinfo, @input_file);
+
+ { Enable saving of extra markers that we want to copy }
+ jcopy_markers_setup(@srcinfo, copyoption);
+
+ { Read file header }
+ {void} jpeg_read_header(@srcinfo, TRUE);
+
+ { Any space needed by a transform option must be requested before
+ jpeg_read_coefficients so that memory allocation will be done right. }
+
+{$ifdef TRANSFORMS_SUPPORTED}
+ jtransform_request_workspace(@srcinfo, transformoption);
+{$endif}
+
+ { Read source file as DCT coefficients }
+ src_coef_arrays := jpeg_read_coefficients(@srcinfo);
+
+ { Initialize destination compression parameters from source values }
+ jpeg_copy_critical_parameters(@srcinfo, @dstinfo);
+
+ { Adjust destination parameters if required by transform options;
+ also find out which set of coefficient arrays will hold the output. }
+
+{$ifdef TRANSFORMS_SUPPORTED}
+ dst_coef_arrays := jtransform_adjust_parameters(@srcinfo, @dstinfo,
+ src_coef_arrays,
+ transformoption);
+{$else}
+ dst_coef_arrays := src_coef_arrays;
+{$endif}
+
+ { Adjust default compression parameters by re-parsing the options }
+ file_index := parse_switches(@dstinfo, 0, TRUE);
+
+ { Specify data destination for compression }
+ jpeg_stdio_dest(@dstinfo, @output_file);
+
+ { Start compressor (note no image data is actually written here) }
+ jpeg_write_coefficients(@dstinfo, dst_coef_arrays);
+
+ { Copy to the output file any extra markers that we want to preserve }
+ jcopy_markers_execute(@srcinfo, @dstinfo, copyoption);
+
+ { Execute image transformation, if any }
+{$ifdef TRANSFORMS_SUPPORTED}
+ jtransform_execute_transformation(@srcinfo, @dstinfo,
+ src_coef_arrays,
+ transformoption);
+{$endif}
+
+ { Finish compression and release memory }
+ jpeg_finish_compress(@dstinfo);
+ jpeg_destroy_compress(@dstinfo);
+ {void} jpeg_finish_decompress(@srcinfo);
+ jpeg_destroy_decompress(@srcinfo);
+
+ { Close files, if we opened them }
+ close(input_file);
+ close(output_file);
+
+{$ifdef PROGRESS_REPORT}
+ end_progress_monitor(j_common_ptr(@dstinfo));
+{$endif}
+
+ { All done. }
+ if jsrcerr.num_warnings + jdsterr.num_warnings <> 0 then
+ Stop(EXIT_WARNING)
+ else
+ Stop(EXIT_SUCCESS);
+end.