Clean up the lossless JPEG feature

- Rename jpeg_simple_lossless() to jpeg_enable_lossless() and modify the
  function so that it stores the lossless parameters directly in the Ss
  and Al fields of jpeg_compress_struct rather than using a scan script.

- Move the cjpeg -lossless switch into "Switches for advanced users".

- Document the libjpeg API and run-time features that are unavailable in
  lossless mode, and ensure that all parameters, functions, and switches
  related to unavailable features are ignored or generate errors in
  lossless mode.

- Defer any action that depends on whether lossless mode is enabled
  until jpeg_start_compress()/jpeg_start_decompress() is called.

- Document the purpose of the point transform value.

- "Codec" stands for coder/decoder, so it is a bit awkward to say
  "lossless compression codec" and "lossless decompression codec".
  Use "lossless compressor" and "lossless decompressor" instead.

- Restore backward API/ABI compatibility with libjpeg v6b:

  * Move the new 'lossless' field from the exposed jpeg_compress_struct
    and jpeg_decompress_struct structures into the opaque
    jpeg_comp_master and jpeg_decomp_master structures, and allocate the
    master structures in the body of jpeg_create_compress() and
    jpeg_create_decompress().

  * Remove the new 'process' field from jpeg_compress_struct and
    jpeg_decompress_struct and replace it with the old
    'progressive_mode' field and the new 'lossless' field.

  * Remove the new 'data_unit' field from jpeg_compress_struct and
    jpeg_decompress_struct and replace it with a locally-computed
    data unit variable.

  * Restore the names of macros and fields that refer to DCT blocks, and
    document that they have a different meaning in lossless mode.  (Most
    of them aren't very meaningful in lossless mode anyhow.)

  * Remove the new alloc_darray() method from jpeg_memory_mgr and
    replace it with an internal macro that wraps the alloc_sarray()
    method.

  * Move the JDIFF* data types from jpeglib.h and jmorecfg.h into
    jpegint.h.

  * Remove the new 'codec' field from jpeg_compress_struct and
    jpeg_decompress_struct and instead reuse the existing internal
    coefficient control, forward/inverse DCT, and entropy
    encoding/decoding structures for lossless compression/decompression.

  * Repurpose existing error codes rather than introducing new ones.
    (The new JERR_BAD_RESTART and JWRN_MUST_DOWNSCALE codes remain,
    although JWRN_MUST_DOWNSCALE will probably be removed in
    libjpeg-turbo, since we have a different way of handling multiple
    data precisions.)

- Automatically enable lossless mode when a scan script with parameters
  that are only valid for lossless mode is detected, and document the
  use of scan scripts to generate lossless JPEG images.

- Move the sequential and shared Huffman routines back into jchuff.c and
  jdhuff.c, and document that those routines are shared with jclhuff.c
  and jdlhuff.c as well as with jcphuff.c and jdphuff.c.

- Move MAX_DIFF_BITS from jchuff.h into jclhuff.c, the only place where
  it is used.

- Move the predictor and scaler code into jclossls.c and jdlossls.c.

- Streamline register usage in the [un]differencers (inspired by similar
  optimizations in the color [de]converters.)

- Restructure the logic in a few places to reduce duplicated code.

- Ensure that all lossless-specific code is guarded by
  C_LOSSLESS_SUPPORTED or D_LOSSLESS_SUPPORTED and that the library can
  be built successfully if either or both of those macros is undefined.

- Remove all short forms of external names introduced by the lossless
  JPEG patch.  (These will not be needed by libjpeg-turbo, so there is
  no use cleaning them up.)

- Various wordsmithing, formatting, and punctuation tweaks

- Eliminate various compiler warnings.
This commit is contained in:
DRC
2022-11-08 15:01:18 -06:00
parent ec6e451d05
commit 217d1a75f5
67 changed files with 3171 additions and 3871 deletions

6
README
View File

@@ -74,9 +74,9 @@ remarkably high compression levels are possible if you can tolerate a
low-quality image. For more details, see the references, or just experiment low-quality image. For more details, see the references, or just experiment
with various compression settings. with various compression settings.
This software implements JPEG baseline, extended-sequential, progressive This software implements JPEG baseline, extended-sequential, progressive, and
and lossless compression processes. Provision is made for supporting all lossless compression processes. Provision is made for supporting all variants
variants of these processes, although some uncommon parameter settings aren't of these processes, although some uncommon parameter settings aren't
implemented yet. For legal reasons, we are not distributing code for the implemented yet. For legal reasons, we are not distributing code for the
arithmetic-coding variants of JPEG; see LEGAL ISSUES. We have made no arithmetic-coding variants of JPEG; see LEGAL ISSUES. We have made no
provision for supporting the hierarchical processes defined in the standard. provision for supporting the hierarchical processes defined in the standard.

5
TODO
View File

@@ -6,8 +6,3 @@ List of things to complete for lossless codec:
* How to check BITS_PER_JSAMPLE for lossy mode (ie, 16-bit data)? - * How to check BITS_PER_JSAMPLE for lossy mode (ie, 16-bit data)? -
see jdinput.c. see jdinput.c.
* Check comment blocks for errors/changes.
* Review new filenames. Try to avoid filename conflicts with possible JPEG-LS
codec.

View File

@@ -1,10 +1,8 @@
/* /*
* cdjpeg.h * cdjpeg.h
* *
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1997, Thomas G. Lane. * Copyright (C) 1994-1997, Thomas G. Lane.
* Lossless JPEG Modifications: * This file is part of the Independent JPEG Group's software.
* Copyright (C) 1999, Ken Murchison.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains common declarations for the sample applications * This file contains common declarations for the sample applications
@@ -137,7 +135,6 @@ EXTERN(boolean) read_quant_tables JPP((j_compress_ptr cinfo, char * filename,
EXTERN(boolean) read_scan_script JPP((j_compress_ptr cinfo, char * filename)); EXTERN(boolean) read_scan_script JPP((j_compress_ptr cinfo, char * filename));
EXTERN(boolean) set_quant_slots JPP((j_compress_ptr cinfo, char *arg)); EXTERN(boolean) set_quant_slots JPP((j_compress_ptr cinfo, char *arg));
EXTERN(boolean) set_sample_factors JPP((j_compress_ptr cinfo, char *arg)); EXTERN(boolean) set_sample_factors JPP((j_compress_ptr cinfo, char *arg));
EXTERN(boolean) set_simple_lossless JPP((j_compress_ptr cinfo, char *arg));
/* djpeg support routines (in rdcolmap.c) */ /* djpeg support routines (in rdcolmap.c) */

50
cjpeg.1
View File

@@ -1,4 +1,4 @@
.TH CJPEG 1 "27 April 1999" .TH CJPEG 1 "11 November 2022"
.SH NAME .SH NAME
cjpeg \- compress an image file to a JPEG file cjpeg \- compress an image file to a JPEG file
.SH SYNOPSIS .SH SYNOPSIS
@@ -62,13 +62,6 @@ decompression are unaffected by
.B \-progressive .B \-progressive
Create progressive JPEG file (see below). Create progressive JPEG file (see below).
.TP .TP
.BI \-lossless " psv[,Pt]"
Create a lossless JPEG file using the specified predictor selection value (1-7)
and optional point transform.
.B Caution:
lossless JPEG is not widely implemented, so many decoders will be
unable to view a lossless JPEG file at all.
.TP
.B \-targa .B \-targa
Input file is Targa format. Targa files that contain an "identification" Input file is Targa format. Targa files that contain an "identification"
field will not be automatically recognized by field will not be automatically recognized by
@@ -130,6 +123,43 @@ unable to view a progressive JPEG file at all.
.PP .PP
Switches for advanced users: Switches for advanced users:
.TP .TP
.BI \-lossless " psv[,Pt]"
Create a lossless JPEG file using the specified predictor selection value
(1 through 7) and optional point transform (0 through
.nh
.I precision
.hy
- 1, where
.nh
.I precision
.hy
is the JPEG data precision in bits). A point transform value of 0 (the
default) is necessary in order to create a fully lossless JPEG file. (A
non-zero point transform value right-shifts the input samples by the specified
number of bits, which is effectively a form of lossy color quantization.)
.B Caution:
lossless JPEG is not yet widely implemented, so many decoders will be unable to
view a lossless JPEG file at all. Note that the following features will be
unavailable when compressing or decompressing a lossless JPEG file:
.IP
- Quality/quantization table selection
.IP
- Color conversion (the JPEG image will use the same color space as the input
image)
.IP
- DCT/IDCT algorithm selection
.IP
- Smoothing
.IP
- Downsampling/upsampling
.IP
- IDCT scaling
.IP
- Transformations using
.B jpegtran
.IP
Any switches used to enable or configure those features will be ignored.
.TP
.B \-dct int .B \-dct int
Use integer DCT method (default). Use integer DCT method (default).
.TP .TP
@@ -145,8 +175,8 @@ machines, while the integer methods should give the same results everywhere.
The fast integer method is much less accurate than the other two. The fast integer method is much less accurate than the other two.
.TP .TP
.BI \-restart " N" .BI \-restart " N"
Emit a JPEG restart marker every N MCU rows, or every N MCU blocks if "B" is Emit a JPEG restart marker every N MCU rows, or every N MCU blocks (samples in
attached to the number. lossless mode) if "B" is attached to the number.
.B \-restart 0 .B \-restart 0
(the default) means no restart markers. (the default) means no restart markers.
.TP .TP

31
cjpeg.c
View File

@@ -5,6 +5,7 @@
* Copyright (C) 1991-1998, Thomas G. Lane. * Copyright (C) 1991-1998, Thomas G. Lane.
* Lossless JPEG Modifications: * Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison. * Copyright (C) 1999, Ken Murchison.
* Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains a command-line user interface for the JPEG compressor. * This file contains a command-line user interface for the JPEG compressor.
@@ -159,13 +160,13 @@ usage (void)
#ifdef C_PROGRESSIVE_SUPPORTED #ifdef C_PROGRESSIVE_SUPPORTED
fprintf(stderr, " -progressive Create progressive JPEG file\n"); fprintf(stderr, " -progressive Create progressive JPEG file\n");
#endif #endif
#ifdef C_LOSSLESS_SUPPORTED
fprintf(stderr, " -lossless psv[,Pt] Create lossless JPEG file\n");
#endif
#ifdef TARGA_SUPPORTED #ifdef TARGA_SUPPORTED
fprintf(stderr, " -targa Input file is Targa format (usually not needed)\n"); fprintf(stderr, " -targa Input file is Targa format (usually not needed)\n");
#endif #endif
fprintf(stderr, "Switches for advanced users:\n"); fprintf(stderr, "Switches for advanced users:\n");
#ifdef C_LOSSLESS_SUPPORTED
fprintf(stderr, " -lossless psv[,Pt] Create lossless JPEG file\n");
#endif
#ifdef DCT_ISLOW_SUPPORTED #ifdef DCT_ISLOW_SUPPORTED
fprintf(stderr, " -dct int Use integer DCT method%s\n", fprintf(stderr, " -dct int Use integer DCT method%s\n",
(JDCT_DEFAULT == JDCT_ISLOW ? " (default)" : "")); (JDCT_DEFAULT == JDCT_ISLOW ? " (default)" : ""));
@@ -214,6 +215,9 @@ parse_switches (j_compress_ptr cinfo, int argc, char **argv,
{ {
int argn; int argn;
char * arg; char * arg;
#ifdef C_LOSSLESS_SUPPORTED
int psv, pt = 0;
#endif
int quality; /* -quality parameter */ int quality; /* -quality parameter */
int q_scale_factor; /* scaling percentage for -qtables */ int q_scale_factor; /* scaling percentage for -qtables */
boolean force_baseline; boolean force_baseline;
@@ -222,7 +226,6 @@ parse_switches (j_compress_ptr cinfo, int argc, char **argv,
char * qslotsarg = NULL; /* saves -qslots parm if any */ char * qslotsarg = NULL; /* saves -qslots parm if any */
char * samplearg = NULL; /* saves -sample parm if any */ char * samplearg = NULL; /* saves -sample parm if any */
char * scansarg = NULL; /* saves -scans parm if any */ char * scansarg = NULL; /* saves -scans parm if any */
char * losslsarg = NULL; /* saves -lossless parm if any */
/* Set up default JPEG parameters. */ /* Set up default JPEG parameters. */
/* Note that default -quality level need not, and does not, /* Note that default -quality level need not, and does not,
@@ -294,12 +297,20 @@ parse_switches (j_compress_ptr cinfo, int argc, char **argv,
jpeg_set_colorspace(cinfo, JCS_GRAYSCALE); jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
} else if (keymatch(arg, "lossless", 1)) { } else if (keymatch(arg, "lossless", 1)) {
/* Select simple lossless mode. */ /* Enable lossless mode. */
#ifdef C_LOSSLESS_SUPPORTED #ifdef C_LOSSLESS_SUPPORTED
char ch = ',', *ptr;
if (++argn >= argc) /* advance to next argument */ if (++argn >= argc) /* advance to next argument */
usage(); usage();
losslsarg = argv[argn]; if (sscanf(argv[argn], "%d%c", &psv, &ch) < 1 || ch != ',')
/* We must postpone execution until num_components is known. */ usage();
ptr = argv[argn];
while (*ptr && *ptr++ != ',') /* advance to next segment of arg string */
;
if (*ptr)
sscanf(ptr, "%d", &pt);
jpeg_enable_lossless(cinfo, psv, pt);
#else #else
fprintf(stderr, "%s: sorry, lossless output was not compiled\n", fprintf(stderr, "%s: sorry, lossless output was not compiled\n",
progname); progname);
@@ -461,12 +472,6 @@ parse_switches (j_compress_ptr cinfo, int argc, char **argv,
jpeg_simple_progression(cinfo); jpeg_simple_progression(cinfo);
#endif #endif
#ifdef C_LOSSLESS_SUPPORTED
if (losslsarg != NULL) /* process -lossless if it was present */
if (! set_simple_lossless(cinfo, losslsarg))
usage();
#endif
#ifdef C_MULTISCAN_FILES_SUPPORTED #ifdef C_MULTISCAN_FILES_SUPPORTED
if (scansarg != NULL) /* process -scans if it was present */ if (scansarg != NULL) /* process -scans if it was present */
if (! read_scan_script(cinfo, scansarg)) if (! read_scan_script(cinfo, scansarg))

View File

@@ -1,9 +1,10 @@
IJG JPEG LIBRARY: FILE LIST IJG JPEG LIBRARY: FILE LIST
This file was part of the Independent JPEG Group's software: This file was part of the Independent JPEG Group's software:
Copyright (C) 1994-1997, Thomas G. Lane. Copyright (C) 1994-1998, Thomas G. Lane.
Lossless JPEG Modifications: Lossless JPEG Modifications:
Copyright (C) 1999, Ken Murchison. Copyright (C) 1999, Ken Murchison.
Copyright (C) 2022, D. R. Commander.
For conditions of distribution and use, see the accompanying README file. For conditions of distribution and use, see the accompanying README file.
@@ -31,7 +32,6 @@ jinclude.h Central include file used by all IJG .c files to reference
system include files. system include files.
jpegint.h JPEG library's internal data structures. jpegint.h JPEG library's internal data structures.
jlossls.h JPEG library's lossless codec data structures. jlossls.h JPEG library's lossless codec data structures.
jlossy.h JPEG library's lossy codec structures.
jchuff.h Private declarations for Huffman encoder modules. jchuff.h Private declarations for Huffman encoder modules.
jdhuff.h Private declarations for Huffman decoder modules. jdhuff.h Private declarations for Huffman decoder modules.
jdct.h Private declarations for forward & reverse DCT subsystems. jdct.h Private declarations for forward & reverse DCT subsystems.
@@ -68,30 +68,27 @@ Compression side of the library:
jcinit.c Initialization: determines which other modules to use. jcinit.c Initialization: determines which other modules to use.
jcmaster.c Master control: setup and inter-pass sequencing logic. jcmaster.c Master control: setup and inter-pass sequencing logic.
jcmainct.c Main buffer controller (preprocessor => JPEG compressor). jcmainct.c Main buffer controller (preprocessor => JPEG compressor).
jchuff.c Codec-independent Huffman entropy encoding routines.
jcprepct.c Preprocessor buffer controller. jcprepct.c Preprocessor buffer controller.
jccolor.c Color space conversion. jccolor.c Color space conversion.
jcsample.c Downsampling. jcsample.c Downsampling.
jchuff.c Shared Huffman entropy encoding routines.
jcmarker.c JPEG marker writing. jcmarker.c JPEG marker writing.
jdatadst.c Data destination manager for stdio output. jdatadst.c Data destination manager for stdio output.
Lossy (DCT) codec: Lossy (DCT) codec:
jlossy.c Lossy compressor proper.
jccoefct.c Buffer controller for DCT coefficient buffer. jccoefct.c Buffer controller for DCT coefficient buffer.
jcdctmgr.c DCT manager (DCT implementation selection & control). jcdctmgr.c DCT manager (DCT implementation selection & control).
jfdctint.c Forward DCT using slow-but-accurate integer method. jfdctint.c Forward DCT using slow-but-accurate integer method.
jfdctfst.c Forward DCT using faster, less accurate integer method. jfdctfst.c Forward DCT using faster, less accurate integer method.
jfdctflt.c Forward DCT using floating-point arithmetic. jfdctflt.c Forward DCT using floating-point arithmetic.
jcshuff.c Huffman entropy coding for sequential JPEG. jchuff.c Huffman entropy coding for sequential JPEG.
jcphuff.c Huffman entropy coding for progressive JPEG. jcphuff.c Huffman entropy coding for progressive JPEG.
Lossless (spatial) codec: Lossless (spatial) codec:
jclossls.c Lossless compressor proper.
jcdiffct.c Buffer controller for difference buffer. jcdiffct.c Buffer controller for difference buffer.
jcscale.c Point transformation. jclossls.c Prediction, sample differencing, and point transform
jcpred.c Sample predictor and differencer.
jclhuff.c Huffman entropy encoding for lossless JPEG. jclhuff.c Huffman entropy encoding for lossless JPEG.
Decompression side of the library: Decompression side of the library:
@@ -99,9 +96,9 @@ Decompression side of the library:
jdmaster.c Master control: determines which other modules to use. jdmaster.c Master control: determines which other modules to use.
jdinput.c Input controller: controls input processing modules. jdinput.c Input controller: controls input processing modules.
jdmainct.c Main buffer controller (JPEG decompressor => postprocessor). jdmainct.c Main buffer controller (JPEG decompressor => postprocessor).
jdhuff.c Codec-independent Huffman entropy decoding routines.
jdpostct.c Postprocessor buffer controller. jdpostct.c Postprocessor buffer controller.
jdmarker.c JPEG marker reading. jdmarker.c JPEG marker reading.
jdhuff.c Shared Huffman entropy decoding routines.
jdsample.c Upsampling. jdsample.c Upsampling.
jdcolor.c Color space conversion. jdcolor.c Color space conversion.
jdmerge.c Merged upsampling/color conversion (faster, lower quality). jdmerge.c Merged upsampling/color conversion (faster, lower quality).
@@ -112,9 +109,8 @@ jdatasrc.c Data source manager for stdio input.
Lossy (DCT) codec: Lossy (DCT) codec:
jdlossy.c Lossy decompressor proper.
jdcoefct.c Buffer controller for DCT coefficient buffer. jdcoefct.c Buffer controller for DCT coefficient buffer.
jdshuff.c Huffman entropy decoding for sequential JPEG. jdhuff.c Huffman entropy decoding for sequential JPEG.
jdphuff.c Huffman entropy decoding for progressive JPEG. jdphuff.c Huffman entropy decoding for progressive JPEG.
jddctmgr.c IDCT manager (IDCT implementation selection & control). jddctmgr.c IDCT manager (IDCT implementation selection & control).
jidctint.c Inverse DCT using slow-but-accurate integer method. jidctint.c Inverse DCT using slow-but-accurate integer method.
@@ -124,17 +120,15 @@ jidctred.c Inverse DCTs with reduced-size outputs.
Lossless (spatial) codec: Lossless (spatial) codec:
jdlossls.c Lossless decompressor proper. jddiffct.c Buffer controller for difference buffer.
jddiffct.c Buffer controller for difference buffers. jdlossls.c Prediction, sample undifferencing, point transform, and sample
scaling
jdlhuff.c Huffman entropy decoding for lossless JPEG. jdlhuff.c Huffman entropy decoding for lossless JPEG.
jdpred.c Sample predictor and undifferencer.
jdscale.c Point transformation, sample size scaling.
Support files for both compression and decompression: Support files for both compression and decompression:
jerror.c Standard error handling routines (application replaceable). jerror.c Standard error handling routines (application replaceable).
jmemmgr.c System-independent (more or less) memory management code. jmemmgr.c System-independent (more or less) memory management code.
jcodec.c Codec-independent utility routines.
jutils.c Miscellaneous utility routines. jutils.c Miscellaneous utility routines.
jmemmgr.c relies on a system-dependent memory management module. The IJG jmemmgr.c relies on a system-dependent memory management module. The IJG

View File

@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software: * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1998, Thomas G. Lane. * Copyright (C) 1994-1998, Thomas G. Lane.
* Lossless JPEG Modifications: * Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison. * Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains application interface code for the compression half * This file contains application interface code for the compression half
@@ -21,6 +21,7 @@
#define JPEG_INTERNALS #define JPEG_INTERNALS
#include "jinclude.h" #include "jinclude.h"
#include "jpeglib.h" #include "jpeglib.h"
#include "jcmaster.h"
/* /*
@@ -79,6 +80,14 @@ jpeg_CreateCompress (j_compress_ptr cinfo, int version, size_t structsize)
/* OK, I'm ready */ /* OK, I'm ready */
cinfo->global_state = CSTATE_START; cinfo->global_state = CSTATE_START;
/* The master struct is used to store extension parameters, so we allocate it
* here.
*/
cinfo->master = (struct jpeg_comp_master *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
SIZEOF(my_comp_master));
MEMZERO(cinfo->master, SIZEOF(my_comp_master));
} }
@@ -170,7 +179,7 @@ jpeg_finish_compress (j_compress_ptr cinfo)
/* We bypass the main controller and invoke coef controller directly; /* We bypass the main controller and invoke coef controller directly;
* all work is being done from the coefficient buffer. * all work is being done from the coefficient buffer.
*/ */
if (! (*cinfo->codec->compress_data) (cinfo, (JSAMPIMAGE) NULL)) if (! (*cinfo->coef->compress_data) (cinfo, (JSAMPIMAGE) NULL))
ERREXIT(cinfo, JERR_CANT_SUSPEND); ERREXIT(cinfo, JERR_CANT_SUSPEND);
} }
(*cinfo->master->finish_pass) (cinfo); (*cinfo->master->finish_pass) (cinfo);

View File

@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software: * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1996, Thomas G. Lane. * Copyright (C) 1994-1996, Thomas G. Lane.
* Lossless JPEG Modifications: * Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison. * Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains application interface code for the compression half * This file contains application interface code for the compression half
@@ -124,6 +124,9 @@ jpeg_write_raw_data (j_compress_ptr cinfo, JSAMPIMAGE data,
{ {
JDIMENSION lines_per_iMCU_row; JDIMENSION lines_per_iMCU_row;
if (cinfo->master->lossless)
ERREXIT(cinfo, JERR_NOTIMPL);
if (cinfo->global_state != CSTATE_RAW_OK) if (cinfo->global_state != CSTATE_RAW_OK)
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
if (cinfo->next_scanline >= cinfo->image_height) { if (cinfo->next_scanline >= cinfo->image_height) {
@@ -147,12 +150,12 @@ jpeg_write_raw_data (j_compress_ptr cinfo, JSAMPIMAGE data,
(*cinfo->master->pass_startup) (cinfo); (*cinfo->master->pass_startup) (cinfo);
/* Verify that at least one iMCU row has been passed. */ /* Verify that at least one iMCU row has been passed. */
lines_per_iMCU_row = cinfo->max_v_samp_factor * cinfo->data_unit; lines_per_iMCU_row = cinfo->max_v_samp_factor * DCTSIZE;
if (num_lines < lines_per_iMCU_row) if (num_lines < lines_per_iMCU_row)
ERREXIT(cinfo, JERR_BUFFER_SIZE); ERREXIT(cinfo, JERR_BUFFER_SIZE);
/* Directly compress the row. */ /* Directly compress the row. */
if (! (*cinfo->codec->compress_data) (cinfo, data)) { if (! (*cinfo->coef->compress_data) (cinfo, data)) {
/* If compressor did not consume the whole row, suspend processing. */ /* If compressor did not consume the whole row, suspend processing. */
return 0; return 0;
} }

View File

@@ -2,20 +2,19 @@
* jccoefct.c * jccoefct.c
* *
* This file was part of the Independent JPEG Group's software: * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1998, Thomas G. Lane. * Copyright (C) 1994-1997, Thomas G. Lane.
* Lossless JPEG Modifications: * Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison. * Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains the coefficient buffer controller for compression. * This file contains the coefficient buffer controller for compression.
* This controller is the top level of the JPEG compressor proper. * This controller is the top level of the lossy JPEG compressor proper.
* The coefficient buffer lies between forward-DCT and entropy encoding steps. * The coefficient buffer lies between forward-DCT and entropy encoding steps.
*/ */
#define JPEG_INTERNALS #define JPEG_INTERNALS
#include "jinclude.h" #include "jinclude.h"
#include "jpeglib.h" #include "jpeglib.h"
#include "jlossy.h" /* Private declarations for lossy codec */
/* We use a full-image coefficient buffer when doing Huffman optimization, /* We use a full-image coefficient buffer when doing Huffman optimization,
@@ -35,6 +34,8 @@
/* Private buffer controller object */ /* Private buffer controller object */
typedef struct { typedef struct {
struct jpeg_c_coef_controller pub; /* public fields */
JDIMENSION iMCU_row_num; /* iMCU row # within image */ JDIMENSION iMCU_row_num; /* iMCU row # within image */
JDIMENSION mcu_ctr; /* counts MCUs processed in current row */ JDIMENSION mcu_ctr; /* counts MCUs processed in current row */
int MCU_vert_offset; /* counts MCU rows within iMCU row */ int MCU_vert_offset; /* counts MCU rows within iMCU row */
@@ -42,20 +43,20 @@ typedef struct {
/* For single-pass compression, it's sufficient to buffer just one MCU /* For single-pass compression, it's sufficient to buffer just one MCU
* (although this may prove a bit slow in practice). We allocate a * (although this may prove a bit slow in practice). We allocate a
* workspace of C_MAX_DATA_UNITS_IN_MCU coefficient blocks, and reuse it for * workspace of C_MAX_BLOCKS_IN_MCU coefficient blocks, and reuse it for each
* each MCU constructed and sent. (On 80x86, the workspace is FAR even * MCU constructed and sent. (On 80x86, the workspace is FAR even though
* though it's not really very big; this is to keep the module interfaces * it's not really very big; this is to keep the module interfaces unchanged
* unchanged when a large coefficient buffer is necessary.) * when a large coefficient buffer is necessary.)
* In multi-pass modes, this array points to the current MCU's blocks * In multi-pass modes, this array points to the current MCU's blocks
* within the virtual arrays. * within the virtual arrays.
*/ */
JBLOCKROW MCU_buffer[C_MAX_DATA_UNITS_IN_MCU]; JBLOCKROW MCU_buffer[C_MAX_BLOCKS_IN_MCU];
/* In multi-pass modes, we need a virtual block array for each component. */ /* In multi-pass modes, we need a virtual block array for each component. */
jvirt_barray_ptr whole_image[MAX_COMPONENTS]; jvirt_barray_ptr whole_image[MAX_COMPONENTS];
} c_coef_controller; } my_coef_controller;
typedef c_coef_controller * c_coef_ptr; typedef my_coef_controller * my_coef_ptr;
/* Forward declarations */ /* Forward declarations */
@@ -73,8 +74,7 @@ LOCAL(void)
start_iMCU_row (j_compress_ptr cinfo) start_iMCU_row (j_compress_ptr cinfo)
/* Reset within-iMCU-row counters for a new row */ /* Reset within-iMCU-row counters for a new row */
{ {
j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
c_coef_ptr coef = (c_coef_ptr) lossyc->coef_private;
/* In an interleaved scan, an MCU row is the same as an iMCU row. /* In an interleaved scan, an MCU row is the same as an iMCU row.
* In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
@@ -101,8 +101,7 @@ start_iMCU_row (j_compress_ptr cinfo)
METHODDEF(void) METHODDEF(void)
start_pass_coef (j_compress_ptr cinfo, J_BUF_MODE pass_mode) start_pass_coef (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
{ {
j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
c_coef_ptr coef = (c_coef_ptr) lossyc->coef_private;
coef->iMCU_row_num = 0; coef->iMCU_row_num = 0;
start_iMCU_row(cinfo); start_iMCU_row(cinfo);
@@ -111,18 +110,18 @@ start_pass_coef (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
case JBUF_PASS_THRU: case JBUF_PASS_THRU:
if (coef->whole_image[0] != NULL) if (coef->whole_image[0] != NULL)
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
lossyc->pub.compress_data = compress_data; coef->pub.compress_data = compress_data;
break; break;
#ifdef FULL_COEF_BUFFER_SUPPORTED #ifdef FULL_COEF_BUFFER_SUPPORTED
case JBUF_SAVE_AND_PASS: case JBUF_SAVE_AND_PASS:
if (coef->whole_image[0] == NULL) if (coef->whole_image[0] == NULL)
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
lossyc->pub.compress_data = compress_first_pass; coef->pub.compress_data = compress_first_pass;
break; break;
case JBUF_CRANK_DEST: case JBUF_CRANK_DEST:
if (coef->whole_image[0] == NULL) if (coef->whole_image[0] == NULL)
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
lossyc->pub.compress_data = compress_output; coef->pub.compress_data = compress_output;
break; break;
#endif #endif
default: default:
@@ -145,8 +144,7 @@ start_pass_coef (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
METHODDEF(boolean) METHODDEF(boolean)
compress_data (j_compress_ptr cinfo, JSAMPIMAGE input_buf) compress_data (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
{ {
j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
c_coef_ptr coef = (c_coef_ptr) lossyc->coef_private;
JDIMENSION MCU_col_num; /* index of current MCU within row */ JDIMENSION MCU_col_num; /* index of current MCU within row */
JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1; JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1;
JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
@@ -178,7 +176,7 @@ compress_data (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
for (yindex = 0; yindex < compptr->MCU_height; yindex++) { for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
if (coef->iMCU_row_num < last_iMCU_row || if (coef->iMCU_row_num < last_iMCU_row ||
yoffset+yindex < compptr->last_row_height) { yoffset+yindex < compptr->last_row_height) {
(*lossyc->fdct_forward_DCT) (cinfo, compptr, (*cinfo->fdct->forward_DCT) (cinfo, compptr,
input_buf[compptr->component_index], input_buf[compptr->component_index],
coef->MCU_buffer[blkn], coef->MCU_buffer[blkn],
ypos, xpos, (JDIMENSION) blockcnt); ypos, xpos, (JDIMENSION) blockcnt);
@@ -205,7 +203,7 @@ compress_data (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
/* Try to write the MCU. In event of a suspension failure, we will /* Try to write the MCU. In event of a suspension failure, we will
* re-DCT the MCU on restart (a bit inefficient, could be fixed...) * re-DCT the MCU on restart (a bit inefficient, could be fixed...)
*/ */
if (! (*lossyc->entropy_encode_mcu) (cinfo, coef->MCU_buffer)) { if (! (*cinfo->entropy->encode_mcu) (cinfo, coef->MCU_buffer)) {
/* Suspension forced; update state counters and exit */ /* Suspension forced; update state counters and exit */
coef->MCU_vert_offset = yoffset; coef->MCU_vert_offset = yoffset;
coef->mcu_ctr = MCU_col_num; coef->mcu_ctr = MCU_col_num;
@@ -248,8 +246,7 @@ compress_data (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
METHODDEF(boolean) METHODDEF(boolean)
compress_first_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf) compress_first_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
{ {
j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
c_coef_ptr coef = (c_coef_ptr) lossyc->coef_private;
JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
JDIMENSION blocks_across, MCUs_across, MCUindex; JDIMENSION blocks_across, MCUs_across, MCUindex;
int bi, ci, h_samp_factor, block_row, block_rows, ndummy; int bi, ci, h_samp_factor, block_row, block_rows, ndummy;
@@ -270,10 +267,10 @@ compress_first_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
block_rows = compptr->v_samp_factor; block_rows = compptr->v_samp_factor;
else { else {
/* NB: can't use last_row_height here, since may not be set! */ /* NB: can't use last_row_height here, since may not be set! */
block_rows = (int) (compptr->height_in_data_units % compptr->v_samp_factor); block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
if (block_rows == 0) block_rows = compptr->v_samp_factor; if (block_rows == 0) block_rows = compptr->v_samp_factor;
} }
blocks_across = compptr->width_in_data_units; blocks_across = compptr->width_in_blocks;
h_samp_factor = compptr->h_samp_factor; h_samp_factor = compptr->h_samp_factor;
/* Count number of dummy blocks to be added at the right margin. */ /* Count number of dummy blocks to be added at the right margin. */
ndummy = (int) (blocks_across % h_samp_factor); ndummy = (int) (blocks_across % h_samp_factor);
@@ -284,7 +281,7 @@ compress_first_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
*/ */
for (block_row = 0; block_row < block_rows; block_row++) { for (block_row = 0; block_row < block_rows; block_row++) {
thisblockrow = buffer[block_row]; thisblockrow = buffer[block_row];
(*lossyc->fdct_forward_DCT) (cinfo, compptr, (*cinfo->fdct->forward_DCT) (cinfo, compptr,
input_buf[ci], thisblockrow, input_buf[ci], thisblockrow,
(JDIMENSION) (block_row * DCTSIZE), (JDIMENSION) (block_row * DCTSIZE),
(JDIMENSION) 0, blocks_across); (JDIMENSION) 0, blocks_across);
@@ -345,8 +342,7 @@ compress_first_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
METHODDEF(boolean) METHODDEF(boolean)
compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf) compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
{ {
j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
c_coef_ptr coef = (c_coef_ptr) lossyc->coef_private;
JDIMENSION MCU_col_num; /* index of current MCU within row */ JDIMENSION MCU_col_num; /* index of current MCU within row */
int blkn, ci, xindex, yindex, yoffset; int blkn, ci, xindex, yindex, yoffset;
JDIMENSION start_col; JDIMENSION start_col;
@@ -384,7 +380,7 @@ compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
} }
} }
/* Try to write the MCU. */ /* Try to write the MCU. */
if (! (*lossyc->entropy_encode_mcu) (cinfo, coef->MCU_buffer)) { if (! (*cinfo->entropy->encode_mcu) (cinfo, coef->MCU_buffer)) {
/* Suspension forced; update state counters and exit */ /* Suspension forced; update state counters and exit */
coef->MCU_vert_offset = yoffset; coef->MCU_vert_offset = yoffset;
coef->mcu_ctr = MCU_col_num; coef->mcu_ctr = MCU_col_num;
@@ -410,14 +406,13 @@ compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
GLOBAL(void) GLOBAL(void)
jinit_c_coef_controller (j_compress_ptr cinfo, boolean need_full_buffer) jinit_c_coef_controller (j_compress_ptr cinfo, boolean need_full_buffer)
{ {
j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; my_coef_ptr coef;
c_coef_ptr coef;
coef = (c_coef_ptr) coef = (my_coef_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(c_coef_controller)); SIZEOF(my_coef_controller));
lossyc->coef_private = (struct jpeg_c_coef_controller *) coef; cinfo->coef = (struct jpeg_c_coef_controller *) coef;
lossyc->coef_start_pass = start_pass_coef; coef->pub.start_pass = start_pass_coef;
/* Create the coefficient buffer. */ /* Create the coefficient buffer. */
if (need_full_buffer) { if (need_full_buffer) {
@@ -431,9 +426,9 @@ jinit_c_coef_controller (j_compress_ptr cinfo, boolean need_full_buffer)
ci++, compptr++) { ci++, compptr++) {
coef->whole_image[ci] = (*cinfo->mem->request_virt_barray) coef->whole_image[ci] = (*cinfo->mem->request_virt_barray)
((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
(JDIMENSION) jround_up((long) compptr->width_in_data_units, (JDIMENSION) jround_up((long) compptr->width_in_blocks,
(long) compptr->h_samp_factor), (long) compptr->h_samp_factor),
(JDIMENSION) jround_up((long) compptr->height_in_data_units, (JDIMENSION) jround_up((long) compptr->height_in_blocks,
(long) compptr->v_samp_factor), (long) compptr->v_samp_factor),
(JDIMENSION) compptr->v_samp_factor); (JDIMENSION) compptr->v_samp_factor);
} }
@@ -447,8 +442,8 @@ jinit_c_coef_controller (j_compress_ptr cinfo, boolean need_full_buffer)
buffer = (JBLOCKROW) buffer = (JBLOCKROW)
(*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
C_MAX_DATA_UNITS_IN_MCU * SIZEOF(JBLOCK)); C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK));
for (i = 0; i < C_MAX_DATA_UNITS_IN_MCU; i++) { for (i = 0; i < C_MAX_BLOCKS_IN_MCU; i++) {
coef->MCU_buffer[i] = buffer + i; coef->MCU_buffer[i] = buffer + i;
} }
coef->whole_image[0] = NULL; /* flag for no virtual arrays */ coef->whole_image[0] = NULL; /* flag for no virtual arrays */

View File

@@ -1,8 +1,10 @@
/* /*
* jccolor.c * jccolor.c
* *
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1996, Thomas G. Lane. * Copyright (C) 1991-1996, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software. * Lossless JPEG Modifications:
* Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains input colorspace conversion routines. * This file contains input colorspace conversion routines.
@@ -456,4 +458,13 @@ jinit_color_converter (j_compress_ptr cinfo)
cconvert->pub.color_convert = null_convert; cconvert->pub.color_convert = null_convert;
break; break;
} }
/* Prevent lossy color conversion in lossless mode */
if (cinfo->master->lossless) {
if ((cinfo->jpeg_color_space == JCS_GRAYSCALE &&
cinfo->in_color_space != JCS_GRAYSCALE) ||
(cinfo->jpeg_color_space != JCS_GRAYSCALE &&
cconvert->pub.color_convert != null_convert))
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
}
} }

View File

@@ -1,10 +1,8 @@
/* /*
* jcdctmgr.c * jcdctmgr.c
* *
* This file was part of the Independent JPEG Group's software: * Copyright (C) 1994-1996, Thomas G. Lane.
* Copyright (C) 1994-1998, Thomas G. Lane. * This file is part of the Independent JPEG Group's software.
* Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains the forward-DCT management logic. * This file contains the forward-DCT management logic.
@@ -16,13 +14,14 @@
#define JPEG_INTERNALS #define JPEG_INTERNALS
#include "jinclude.h" #include "jinclude.h"
#include "jpeglib.h" #include "jpeglib.h"
#include "jlossy.h" /* Private declarations for lossy codec */
#include "jdct.h" /* Private declarations for DCT subsystem */ #include "jdct.h" /* Private declarations for DCT subsystem */
/* Private subobject for this module */ /* Private subobject for this module */
typedef struct { typedef struct {
struct jpeg_forward_dct pub; /* public fields */
/* Pointer to the DCT routine actually in use */ /* Pointer to the DCT routine actually in use */
forward_DCT_method_ptr do_dct; forward_DCT_method_ptr do_dct;
@@ -37,9 +36,9 @@ typedef struct {
float_DCT_method_ptr do_float_dct; float_DCT_method_ptr do_float_dct;
FAST_FLOAT * float_divisors[NUM_QUANT_TBLS]; FAST_FLOAT * float_divisors[NUM_QUANT_TBLS];
#endif #endif
} fdct_controller; } my_fdct_controller;
typedef fdct_controller * fdct_ptr; typedef my_fdct_controller * my_fdct_ptr;
/* /*
@@ -54,8 +53,7 @@ typedef fdct_controller * fdct_ptr;
METHODDEF(void) METHODDEF(void)
start_pass_fdctmgr (j_compress_ptr cinfo) start_pass_fdctmgr (j_compress_ptr cinfo)
{ {
j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct;
fdct_ptr fdct = (fdct_ptr) lossyc->fdct_private;
int ci, qtblno, i; int ci, qtblno, i;
jpeg_component_info *compptr; jpeg_component_info *compptr;
JQUANT_TBL * qtbl; JQUANT_TBL * qtbl;
@@ -186,8 +184,7 @@ forward_DCT (j_compress_ptr cinfo, jpeg_component_info * compptr,
/* This version is used for integer DCT implementations. */ /* This version is used for integer DCT implementations. */
{ {
/* This routine is heavily used, so it's worth coding it tightly. */ /* This routine is heavily used, so it's worth coding it tightly. */
j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct;
fdct_ptr fdct = (fdct_ptr) lossyc->fdct_private;
forward_DCT_method_ptr do_dct = fdct->do_dct; forward_DCT_method_ptr do_dct = fdct->do_dct;
DCTELEM * divisors = fdct->divisors[compptr->quant_tbl_no]; DCTELEM * divisors = fdct->divisors[compptr->quant_tbl_no];
DCTELEM workspace[DCTSIZE2]; /* work area for FDCT subroutine */ DCTELEM workspace[DCTSIZE2]; /* work area for FDCT subroutine */
@@ -277,8 +274,7 @@ forward_DCT_float (j_compress_ptr cinfo, jpeg_component_info * compptr,
/* This version is used for floating-point DCT implementations. */ /* This version is used for floating-point DCT implementations. */
{ {
/* This routine is heavily used, so it's worth coding it tightly. */ /* This routine is heavily used, so it's worth coding it tightly. */
j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct;
fdct_ptr fdct = (fdct_ptr) lossyc->fdct_private;
float_DCT_method_ptr do_dct = fdct->do_float_dct; float_DCT_method_ptr do_dct = fdct->do_float_dct;
FAST_FLOAT * divisors = fdct->float_divisors[compptr->quant_tbl_no]; FAST_FLOAT * divisors = fdct->float_divisors[compptr->quant_tbl_no];
FAST_FLOAT workspace[DCTSIZE2]; /* work area for FDCT subroutine */ FAST_FLOAT workspace[DCTSIZE2]; /* work area for FDCT subroutine */
@@ -348,32 +344,31 @@ forward_DCT_float (j_compress_ptr cinfo, jpeg_component_info * compptr,
GLOBAL(void) GLOBAL(void)
jinit_forward_dct (j_compress_ptr cinfo) jinit_forward_dct (j_compress_ptr cinfo)
{ {
j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; my_fdct_ptr fdct;
fdct_ptr fdct;
int i; int i;
fdct = (fdct_ptr) fdct = (my_fdct_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(fdct_controller)); SIZEOF(my_fdct_controller));
lossyc->fdct_private = (struct jpeg_forward_dct *) fdct; cinfo->fdct = (struct jpeg_forward_dct *) fdct;
lossyc->fdct_start_pass = start_pass_fdctmgr; fdct->pub.start_pass = start_pass_fdctmgr;
switch (cinfo->dct_method) { switch (cinfo->dct_method) {
#ifdef DCT_ISLOW_SUPPORTED #ifdef DCT_ISLOW_SUPPORTED
case JDCT_ISLOW: case JDCT_ISLOW:
lossyc->fdct_forward_DCT = forward_DCT; fdct->pub.forward_DCT = forward_DCT;
fdct->do_dct = jpeg_fdct_islow; fdct->do_dct = jpeg_fdct_islow;
break; break;
#endif #endif
#ifdef DCT_IFAST_SUPPORTED #ifdef DCT_IFAST_SUPPORTED
case JDCT_IFAST: case JDCT_IFAST:
lossyc->fdct_forward_DCT = forward_DCT; fdct->pub.forward_DCT = forward_DCT;
fdct->do_dct = jpeg_fdct_ifast; fdct->do_dct = jpeg_fdct_ifast;
break; break;
#endif #endif
#ifdef DCT_FLOAT_SUPPORTED #ifdef DCT_FLOAT_SUPPORTED
case JDCT_FLOAT: case JDCT_FLOAT:
lossyc->fdct_forward_DCT = forward_DCT_float; fdct->pub.forward_DCT = forward_DCT_float;
fdct->do_float_dct = jpeg_fdct_float; fdct->do_float_dct = jpeg_fdct_float;
break; break;
#endif #endif

View File

@@ -2,15 +2,16 @@
* jcdiffct.c * jcdiffct.c
* *
* This file was part of the Independent JPEG Group's software: * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1998, Thomas G. Lane. * Copyright (C) 1994-1997, Thomas G. Lane.
* Lossless JPEG Modifications: * Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison. * Copyright (C) 1999, Ken Murchison.
* Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains the difference buffer controller for compression. * This file contains the difference buffer controller for compression.
* This controller is the top level of the lossless JPEG compressor proper. * This controller is the top level of the lossless JPEG compressor proper.
* The difference buffer lies between prediction/differencing and entropy * The difference buffer lies between the prediction/differencing and entropy
* encoding. * encoding steps.
*/ */
#define JPEG_INTERNALS #define JPEG_INTERNALS
@@ -38,20 +39,22 @@
/* Private buffer controller object */ /* Private buffer controller object */
typedef struct { typedef struct {
struct jpeg_c_coef_controller pub; /* public fields */
JDIMENSION iMCU_row_num; /* iMCU row # within image */ JDIMENSION iMCU_row_num; /* iMCU row # within image */
JDIMENSION mcu_ctr; /* counts MCUs processed in current row */ JDIMENSION mcu_ctr; /* counts MCUs processed in current row */
int MCU_vert_offset; /* counts MCU rows within iMCU row */ int MCU_vert_offset; /* counts MCU rows within iMCU row */
int MCU_rows_per_iMCU_row; /* number of such rows needed */ int MCU_rows_per_iMCU_row; /* number of such rows needed */
JSAMPROW cur_row[MAX_COMPONENTS]; /* row of point transformed samples */ JSAMPROW cur_row[MAX_COMPONENTS]; /* row of point-transformed samples */
JSAMPROW prev_row[MAX_COMPONENTS]; /* previous row of Pt'd samples */ JSAMPROW prev_row[MAX_COMPONENTS]; /* previous row of Pt'd samples */
JDIFFARRAY diff_buf[MAX_COMPONENTS]; /* iMCU row of differences */ JDIFFARRAY diff_buf[MAX_COMPONENTS]; /* iMCU row of differences */
/* In multi-pass modes, we need a virtual sample array for each component. */ /* In multi-pass modes, we need a virtual sample array for each component. */
jvirt_sarray_ptr whole_image[MAX_COMPONENTS]; jvirt_sarray_ptr whole_image[MAX_COMPONENTS];
} c_diff_controller; } my_diff_controller;
typedef c_diff_controller * c_diff_ptr; typedef my_diff_controller * my_diff_ptr;
/* Forward declarations */ /* Forward declarations */
@@ -69,8 +72,7 @@ LOCAL(void)
start_iMCU_row (j_compress_ptr cinfo) start_iMCU_row (j_compress_ptr cinfo)
/* Reset within-iMCU-row counters for a new row */ /* Reset within-iMCU-row counters for a new row */
{ {
j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; my_diff_ptr diff = (my_diff_ptr) cinfo->coef;
c_diff_ptr diff = (c_diff_ptr) losslsc->diff_private;
/* In an interleaved scan, an MCU row is the same as an iMCU row. /* In an interleaved scan, an MCU row is the same as an iMCU row.
* In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
@@ -97,8 +99,15 @@ start_iMCU_row (j_compress_ptr cinfo)
METHODDEF(void) METHODDEF(void)
start_pass_diff (j_compress_ptr cinfo, J_BUF_MODE pass_mode) start_pass_diff (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
{ {
j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; my_diff_ptr diff = (my_diff_ptr) cinfo->coef;
c_diff_ptr diff = (c_diff_ptr) losslsc->diff_private;
/* Because it is hitching a ride on the jpeg_forward_dct struct,
* start_pass_lossless() will be called at the start of the initial pass.
* This ensures that it will be called at the start of the Huffman
* optimization and output passes as well.
*/
if (pass_mode == JBUF_CRANK_DEST)
(*cinfo->fdct->start_pass) (cinfo);
diff->iMCU_row_num = 0; diff->iMCU_row_num = 0;
start_iMCU_row(cinfo); start_iMCU_row(cinfo);
@@ -107,18 +116,18 @@ start_pass_diff (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
case JBUF_PASS_THRU: case JBUF_PASS_THRU:
if (diff->whole_image[0] != NULL) if (diff->whole_image[0] != NULL)
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
losslsc->pub.compress_data = compress_data; diff->pub.compress_data = compress_data;
break; break;
#ifdef FULL_SAMP_BUFFER_SUPPORTED #ifdef FULL_SAMP_BUFFER_SUPPORTED
case JBUF_SAVE_AND_PASS: case JBUF_SAVE_AND_PASS:
if (diff->whole_image[0] == NULL) if (diff->whole_image[0] == NULL)
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
losslsc->pub.compress_data = compress_first_pass; diff->pub.compress_data = compress_first_pass;
break; break;
case JBUF_CRANK_DEST: case JBUF_CRANK_DEST:
if (diff->whole_image[0] == NULL) if (diff->whole_image[0] == NULL)
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
losslsc->pub.compress_data = compress_output; diff->pub.compress_data = compress_output;
break; break;
#endif #endif
default: default:
@@ -143,13 +152,12 @@ start_pass_diff (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
METHODDEF(boolean) METHODDEF(boolean)
compress_data (j_compress_ptr cinfo, JSAMPIMAGE input_buf) compress_data (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
{ {
j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; my_diff_ptr diff = (my_diff_ptr) cinfo->coef;
c_diff_ptr diff = (c_diff_ptr) losslsc->diff_private; lossless_comp_ptr losslessc = (lossless_comp_ptr) cinfo->fdct;
JDIMENSION MCU_col_num; /* index of current MCU within row */ JDIMENSION MCU_col_num; /* index of current MCU within row */
JDIMENSION MCU_count; /* number of MCUs encoded */ JDIMENSION MCU_count; /* number of MCUs encoded */
JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1;
JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
int comp, ci, yoffset, samp_row, samp_rows, samps_across; int ci, compi, yoffset, samp_row, samp_rows, samps_across;
jpeg_component_info *compptr; jpeg_component_info *compptr;
/* Loop to write as much as one whole iMCU row */ /* Loop to write as much as one whole iMCU row */
@@ -158,20 +166,20 @@ compress_data (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
MCU_col_num = diff->mcu_ctr; MCU_col_num = diff->mcu_ctr;
/* Scale and predict each scanline of the MCU-row separately. /* Scale and predict each scanline of the MCU row separately.
* *
* Note: We only do this if we are at the start of a MCU-row, ie, * Note: We only do this if we are at the start of an MCU row, ie,
* we don't want to reprocess a row suspended by the output. * we don't want to reprocess a row suspended by the output.
*/ */
if (MCU_col_num == 0) { if (MCU_col_num == 0) {
for (comp = 0; comp < cinfo->comps_in_scan; comp++) { for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[comp]; compptr = cinfo->cur_comp_info[ci];
ci = compptr->component_index; compi = compptr->component_index;
if (diff->iMCU_row_num < last_iMCU_row) if (diff->iMCU_row_num < last_iMCU_row)
samp_rows = compptr->v_samp_factor; samp_rows = compptr->v_samp_factor;
else { else {
/* NB: can't use last_row_height here, since may not be set! */ /* NB: can't use last_row_height here, since may not be set! */
samp_rows = (int) (compptr->height_in_data_units % compptr->v_samp_factor); samp_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
if (samp_rows == 0) samp_rows = compptr->v_samp_factor; if (samp_rows == 0) samp_rows = compptr->v_samp_factor;
else { else {
/* Fill dummy difference rows at the bottom edge with zeros, which /* Fill dummy difference rows at the bottom edge with zeros, which
@@ -179,30 +187,28 @@ compress_data (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
*/ */
for (samp_row = samp_rows; samp_row < compptr->v_samp_factor; for (samp_row = samp_rows; samp_row < compptr->v_samp_factor;
samp_row++) samp_row++)
MEMZERO(diff->diff_buf[ci][samp_row], MEMZERO(diff->diff_buf[compi][samp_row],
jround_up((long) compptr->width_in_data_units, jround_up((long) compptr->width_in_blocks,
(long) compptr->h_samp_factor) * SIZEOF(JDIFF)); (long) compptr->h_samp_factor) * SIZEOF(JDIFF));
} }
} }
samps_across = compptr->width_in_data_units; samps_across = compptr->width_in_blocks;
for (samp_row = 0; samp_row < samp_rows; samp_row++) { for (samp_row = 0; samp_row < samp_rows; samp_row++) {
(*losslsc->scaler_scale) (cinfo, (*losslessc->scaler_scale) (cinfo,
input_buf[ci][samp_row], input_buf[compi][samp_row],
diff->cur_row[ci], samps_across); diff->cur_row[compi],
(*losslsc->predict_difference[ci]) (cinfo, ci,
diff->cur_row[ci],
diff->prev_row[ci],
diff->diff_buf[ci][samp_row],
samps_across); samps_across);
SWAP_ROWS(diff->cur_row[ci], diff->prev_row[ci]); (*losslessc->predict_difference[compi])
(cinfo, compi, diff->cur_row[compi], diff->prev_row[compi],
diff->diff_buf[compi][samp_row], samps_across);
SWAP_ROWS(diff->cur_row[compi], diff->prev_row[compi]);
} }
} }
} }
/* Try to write the MCU row (or remaining portion of suspended MCU row). */
/* Try to write the MCU-row (or remaining portion of suspended MCU-row). */
MCU_count = MCU_count =
(*losslsc->entropy_encode_mcus) (cinfo, (*cinfo->entropy->encode_mcus) (cinfo,
diff->diff_buf, yoffset, MCU_col_num, diff->diff_buf, yoffset, MCU_col_num,
cinfo->MCUs_per_row - MCU_col_num); cinfo->MCUs_per_row - MCU_col_num);
if (MCU_count != cinfo->MCUs_per_row - MCU_col_num) { if (MCU_count != cinfo->MCUs_per_row - MCU_col_num) {
@@ -211,11 +217,9 @@ compress_data (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
diff->mcu_ctr += MCU_col_num; diff->mcu_ctr += MCU_col_num;
return FALSE; return FALSE;
} }
/* Completed an MCU row, but perhaps not an iMCU row */ /* Completed an MCU row, but perhaps not an iMCU row */
diff->mcu_ctr = 0; diff->mcu_ctr = 0;
} }
/* Completed the iMCU row, advance counters for next one */ /* Completed the iMCU row, advance counters for next one */
diff->iMCU_row_num++; diff->iMCU_row_num++;
start_iMCU_row(cinfo); start_iMCU_row(cinfo);
@@ -246,18 +250,17 @@ compress_data (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
METHODDEF(boolean) METHODDEF(boolean)
compress_first_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf) compress_first_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
{ {
j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; my_diff_ptr diff = (my_diff_ptr) cinfo->coef;
c_diff_ptr diff = (c_diff_ptr) losslsc->diff_private;
JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
JDIMENSION samps_across; JDIMENSION samps_across;
int ci, samp_row, samp_rows; int ci, samp_row, samp_rows;
JSAMPARRAY buffer[MAX_COMPONENTS]; JSAMPARRAY buffer;
jpeg_component_info *compptr; jpeg_component_info *compptr;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) { ci++, compptr++) {
/* Align the virtual buffers for this component. */ /* Align the virtual buffer for this component. */
buffer[ci] = (*cinfo->mem->access_virt_sarray) buffer = (*cinfo->mem->access_virt_sarray)
((j_common_ptr) cinfo, diff->whole_image[ci], ((j_common_ptr) cinfo, diff->whole_image[ci],
diff->iMCU_row_num * compptr->v_samp_factor, diff->iMCU_row_num * compptr->v_samp_factor,
(JDIMENSION) compptr->v_samp_factor, TRUE); (JDIMENSION) compptr->v_samp_factor, TRUE);
@@ -267,21 +270,20 @@ compress_first_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
samp_rows = compptr->v_samp_factor; samp_rows = compptr->v_samp_factor;
else { else {
/* NB: can't use last_row_height here, since may not be set! */ /* NB: can't use last_row_height here, since may not be set! */
samp_rows = (int) (compptr->height_in_data_units % compptr->v_samp_factor); samp_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
if (samp_rows == 0) samp_rows = compptr->v_samp_factor; if (samp_rows == 0) samp_rows = compptr->v_samp_factor;
} }
samps_across = compptr->width_in_data_units; samps_across = compptr->width_in_blocks;
/* Perform point transform scaling and prediction/differencing for all /* Perform point transform scaling and prediction/differencing for all
* non-dummy rows in this iMCU row. Each call on these functions * non-dummy rows in this iMCU row. Each call on these functions
* process a complete row of samples. * processes a complete row of samples.
*/ */
for (samp_row = 0; samp_row < samp_rows; samp_row++) { for (samp_row = 0; samp_row < samp_rows; samp_row++) {
MEMCOPY(buffer[ci][samp_row], input_buf[ci][samp_row], MEMCOPY(buffer[samp_row], input_buf[ci][samp_row],
samps_across * SIZEOF(JSAMPLE)); samps_across * SIZEOF(JSAMPLE));
} }
} }
/* NB: compress_output will increment iMCU_row_num if successful. /* NB: compress_output will increment iMCU_row_num if successful.
* A suspension return will result in redoing all the work above next time. * A suspension return will result in redoing all the work above next time.
*/ */
@@ -304,23 +306,19 @@ compress_first_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
METHODDEF(boolean) METHODDEF(boolean)
compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf) compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
{ {
j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; my_diff_ptr diff = (my_diff_ptr) cinfo->coef;
c_diff_ptr diff = (c_diff_ptr) losslsc->diff_private; int ci;
JDIMENSION MCU_col_num; /* index of current MCU within row */ JSAMPARRAY buffer[MAX_COMPS_IN_SCAN];
JDIMENSION MCU_count; /* number of MCUs encoded */
int comp, ci, yoffset;
JSAMPARRAY buffer[MAX_COMPONENTS];
jpeg_component_info *compptr; jpeg_component_info *compptr;
/* Align the virtual buffers for the components used in this scan. /* Align the virtual buffers for the components used in this scan.
* NB: during first pass, this is safe only because the buffers will * NB: during first pass, this is safe only because the buffers will
* already be aligned properly, so jmemmgr.c won't need to do any I/O. * already be aligned properly, so jmemmgr.c won't need to do any I/O.
*/ */
for (comp = 0; comp < cinfo->comps_in_scan; comp++) { for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[comp]; compptr = cinfo->cur_comp_info[ci];
ci = compptr->component_index; buffer[compptr->component_index] = (*cinfo->mem->access_virt_sarray)
buffer[ci] = (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo, diff->whole_image[compptr->component_index],
((j_common_ptr) cinfo, diff->whole_image[ci],
diff->iMCU_row_num * compptr->v_samp_factor, diff->iMCU_row_num * compptr->v_samp_factor,
(JDIMENSION) compptr->v_samp_factor, FALSE); (JDIMENSION) compptr->v_samp_factor, FALSE);
} }
@@ -338,28 +336,27 @@ compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
GLOBAL(void) GLOBAL(void)
jinit_c_diff_controller (j_compress_ptr cinfo, boolean need_full_buffer) jinit_c_diff_controller (j_compress_ptr cinfo, boolean need_full_buffer)
{ {
j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; my_diff_ptr diff;
c_diff_ptr diff;
int ci, row; int ci, row;
jpeg_component_info *compptr; jpeg_component_info *compptr;
diff = (c_diff_ptr) diff = (my_diff_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(c_diff_controller)); SIZEOF(my_diff_controller));
losslsc->diff_private = (void *) diff; cinfo->coef = (struct jpeg_c_coef_controller *) diff;
losslsc->diff_start_pass = start_pass_diff; diff->pub.start_pass = start_pass_diff;
/* Create the prediction row buffers. */ /* Create the prediction row buffers. */
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) { ci++, compptr++) {
diff->cur_row[ci] = *(*cinfo->mem->alloc_sarray) diff->cur_row[ci] = *(*cinfo->mem->alloc_sarray)
((j_common_ptr) cinfo, JPOOL_IMAGE, ((j_common_ptr) cinfo, JPOOL_IMAGE,
(JDIMENSION) jround_up((long) compptr->width_in_data_units, (JDIMENSION) jround_up((long) compptr->width_in_blocks,
(long) compptr->h_samp_factor), (long) compptr->h_samp_factor),
(JDIMENSION) 1); (JDIMENSION) 1);
diff->prev_row[ci] = *(*cinfo->mem->alloc_sarray) diff->prev_row[ci] = *(*cinfo->mem->alloc_sarray)
((j_common_ptr) cinfo, JPOOL_IMAGE, ((j_common_ptr) cinfo, JPOOL_IMAGE,
(JDIMENSION) jround_up((long) compptr->width_in_data_units, (JDIMENSION) jround_up((long) compptr->width_in_blocks,
(long) compptr->h_samp_factor), (long) compptr->h_samp_factor),
(JDIMENSION) 1); (JDIMENSION) 1);
} }
@@ -367,9 +364,9 @@ jinit_c_diff_controller (j_compress_ptr cinfo, boolean need_full_buffer)
/* Create the difference buffer. */ /* Create the difference buffer. */
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) { ci++, compptr++) {
diff->diff_buf[ci] = (*cinfo->mem->alloc_darray) diff->diff_buf[ci] =
((j_common_ptr) cinfo, JPOOL_IMAGE, ALLOC_DARRAY(JPOOL_IMAGE,
(JDIMENSION) jround_up((long) compptr->width_in_data_units, (JDIMENSION) jround_up((long) compptr->width_in_blocks,
(long) compptr->h_samp_factor), (long) compptr->h_samp_factor),
(JDIMENSION) compptr->v_samp_factor); (JDIMENSION) compptr->v_samp_factor);
/* Prefill difference rows with zeros. We do this because only actual /* Prefill difference rows with zeros. We do this because only actual
@@ -379,7 +376,7 @@ jinit_c_diff_controller (j_compress_ptr cinfo, boolean need_full_buffer)
*/ */
for (row = 0; row < compptr->v_samp_factor; row++) for (row = 0; row < compptr->v_samp_factor; row++)
MEMZERO(diff->diff_buf[ci][row], MEMZERO(diff->diff_buf[ci][row],
jround_up((long) compptr->width_in_data_units, jround_up((long) compptr->width_in_blocks,
(long) compptr->h_samp_factor) * SIZEOF(JDIFF)); (long) compptr->h_samp_factor) * SIZEOF(JDIFF));
} }
@@ -388,16 +385,13 @@ jinit_c_diff_controller (j_compress_ptr cinfo, boolean need_full_buffer)
#ifdef FULL_SAMP_BUFFER_SUPPORTED #ifdef FULL_SAMP_BUFFER_SUPPORTED
/* Allocate a full-image virtual array for each component, */ /* Allocate a full-image virtual array for each component, */
/* padded to a multiple of samp_factor differences in each direction. */ /* padded to a multiple of samp_factor differences in each direction. */
int ci;
jpeg_component_info *compptr;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) { ci++, compptr++) {
diff->whole_image[ci] = (*cinfo->mem->request_virt_sarray) diff->whole_image[ci] = (*cinfo->mem->request_virt_sarray)
((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
(JDIMENSION) jround_up((long) compptr->width_in_data_units, (JDIMENSION) jround_up((long) compptr->width_in_blocks,
(long) compptr->h_samp_factor), (long) compptr->h_samp_factor),
(JDIMENSION) jround_up((long) compptr->height_in_data_units, (JDIMENSION) jround_up((long) compptr->height_in_blocks,
(long) compptr->v_samp_factor), (long) compptr->v_samp_factor),
(JDIMENSION) compptr->v_samp_factor); (JDIMENSION) compptr->v_samp_factor);
} }

653
jchuff.c
View File

@@ -2,13 +2,19 @@
* jchuff.c * jchuff.c
* *
* This file was part of the Independent JPEG Group's software: * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1998, Thomas G. Lane. * Copyright (C) 1991-1997, Thomas G. Lane.
* Lossless JPEG Modifications: * Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison. * Copyright (C) 1999, Ken Murchison.
* Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains Huffman entropy decoding routines which are shared * This file contains Huffman entropy encoding routines.
* by the sequential, progressive and lossless decoders. *
* Much of the complexity here has to do with supporting output suspension.
* If the data destination module demands suspension, we want to be able to
* back up to the start of the current MCU. To do this, we copy state
* variables into local working storage, and update them back to the
* permanent JPEG objects only upon successful completion of an MCU.
*/ */
#define JPEG_INTERNALS #define JPEG_INTERNALS
@@ -17,9 +23,159 @@
#include "jchuff.h" /* Declarations shared with jc*huff.c */ #include "jchuff.h" /* Declarations shared with jc*huff.c */
/* Expanded entropy encoder object for Huffman encoding.
*
* The savable_state subrecord contains fields that change within an MCU,
* but must not be updated permanently until we complete the MCU.
*/
typedef struct {
INT32 put_buffer; /* current bit-accumulation buffer */
int put_bits; /* # of bits now in it */
int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */
} savable_state;
/* This macro is to work around compilers with missing or broken
* structure assignment. You'll need to fix this code if you have
* such a compiler and you change MAX_COMPS_IN_SCAN.
*/
#ifndef NO_STRUCT_ASSIGN
#define ASSIGN_STATE(dest,src) ((dest) = (src))
#else
#if MAX_COMPS_IN_SCAN == 4
#define ASSIGN_STATE(dest,src) \
((dest).put_buffer = (src).put_buffer, \
(dest).put_bits = (src).put_bits, \
(dest).last_dc_val[0] = (src).last_dc_val[0], \
(dest).last_dc_val[1] = (src).last_dc_val[1], \
(dest).last_dc_val[2] = (src).last_dc_val[2], \
(dest).last_dc_val[3] = (src).last_dc_val[3])
#endif
#endif
typedef struct {
struct jpeg_entropy_encoder pub; /* public fields */
savable_state saved; /* Bit buffer & DC state at start of MCU */
/* These fields are NOT loaded into local working state. */
unsigned int restarts_to_go; /* MCUs left in this restart interval */
int next_restart_num; /* next restart number to write (0-7) */
/* Pointers to derived tables (these workspaces have image lifespan) */
c_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS];
c_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS];
#ifdef ENTROPY_OPT_SUPPORTED /* Statistics tables for optimization */
long * dc_count_ptrs[NUM_HUFF_TBLS];
long * ac_count_ptrs[NUM_HUFF_TBLS];
#endif
} huff_entropy_encoder;
typedef huff_entropy_encoder * huff_entropy_ptr;
/* Working state while writing an MCU.
* This struct contains all the fields that are needed by subroutines.
*/
typedef struct {
JOCTET * next_output_byte; /* => next byte to write in buffer */
size_t free_in_buffer; /* # of byte spaces remaining in buffer */
savable_state cur; /* Current bit buffer & DC state */
j_compress_ptr cinfo; /* dump_buffer needs access to this */
} working_state;
/* Forward declarations */
METHODDEF(boolean) encode_mcu_huff JPP((j_compress_ptr cinfo,
JBLOCKROW *MCU_data));
METHODDEF(void) finish_pass_huff JPP((j_compress_ptr cinfo));
#ifdef ENTROPY_OPT_SUPPORTED
METHODDEF(boolean) encode_mcu_gather JPP((j_compress_ptr cinfo,
JBLOCKROW *MCU_data));
METHODDEF(void) finish_pass_gather JPP((j_compress_ptr cinfo));
#endif
/*
* Initialize for a Huffman-compressed scan.
* If gather_statistics is TRUE, we do not output anything during the scan,
* just count the Huffman symbols used and generate Huffman code tables.
*/
METHODDEF(void)
start_pass_huff (j_compress_ptr cinfo, boolean gather_statistics)
{
huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
int ci, dctbl, actbl;
jpeg_component_info * compptr;
if (gather_statistics) {
#ifdef ENTROPY_OPT_SUPPORTED
entropy->pub.encode_mcu = encode_mcu_gather;
entropy->pub.finish_pass = finish_pass_gather;
#else
ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif
} else {
entropy->pub.encode_mcu = encode_mcu_huff;
entropy->pub.finish_pass = finish_pass_huff;
}
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
dctbl = compptr->dc_tbl_no;
actbl = compptr->ac_tbl_no;
if (gather_statistics) {
#ifdef ENTROPY_OPT_SUPPORTED
/* Check for invalid table indexes */
/* (make_c_derived_tbl does this in the other path) */
if (dctbl < 0 || dctbl >= NUM_HUFF_TBLS)
ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, dctbl);
if (actbl < 0 || actbl >= NUM_HUFF_TBLS)
ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, actbl);
/* Allocate and zero the statistics tables */
/* Note that jpeg_gen_optimal_table expects 257 entries in each table! */
if (entropy->dc_count_ptrs[dctbl] == NULL)
entropy->dc_count_ptrs[dctbl] = (long *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
257 * SIZEOF(long));
MEMZERO(entropy->dc_count_ptrs[dctbl], 257 * SIZEOF(long));
if (entropy->ac_count_ptrs[actbl] == NULL)
entropy->ac_count_ptrs[actbl] = (long *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
257 * SIZEOF(long));
MEMZERO(entropy->ac_count_ptrs[actbl], 257 * SIZEOF(long));
#endif
} else {
/* Compute derived values for Huffman tables */
/* We may do this more than once for a table, but it's not expensive */
jpeg_make_c_derived_tbl(cinfo, TRUE, dctbl,
& entropy->dc_derived_tbls[dctbl]);
jpeg_make_c_derived_tbl(cinfo, FALSE, actbl,
& entropy->ac_derived_tbls[actbl]);
}
/* Initialize DC predictions to 0 */
entropy->saved.last_dc_val[ci] = 0;
}
/* Initialize bit buffer to empty */
entropy->saved.put_buffer = 0;
entropy->saved.put_bits = 0;
/* Initialize restart stuff */
entropy->restarts_to_go = cinfo->restart_interval;
entropy->next_restart_num = 0;
}
/* /*
* Compute the derived values for a Huffman table. * Compute the derived values for a Huffman table.
* This routine also performs some validation checks on the table. * This routine also performs some validation checks on the table.
*
* Note this is also used by jcphuff.c and jclhuff.c.
*/ */
GLOBAL(void) GLOBAL(void)
@@ -94,12 +250,12 @@ jpeg_make_c_derived_tbl (j_compress_ptr cinfo, boolean isDC, int tblno,
*/ */
MEMZERO(dtbl->ehufsi, SIZEOF(dtbl->ehufsi)); MEMZERO(dtbl->ehufsi, SIZEOF(dtbl->ehufsi));
/* This is also a convenient place to check for out-of-range /* This is also a convenient place to check for out-of-range and duplicated
* and duplicated VAL entries. We allow 0..255 for AC symbols * VAL entries. We allow 0..255 for AC symbols but only 0..15 for DC in
* but only 0..16 for DC. (We could constrain them further * lossy mode and 0..16 for DC in lossless mode. (We could constrain them
* based on data depth and mode, but this seems enough.) * further based on data depth and mode, but this seems enough.)
*/ */
maxsymbol = isDC ? 16 : 255; maxsymbol = isDC ? (cinfo->master->lossless ? 16 : 15) : 255;
for (p = 0; p < lastp; p++) { for (p = 0; p < lastp; p++) {
i = htbl->huffval[p]; i = htbl->huffval[p];
@@ -111,8 +267,418 @@ jpeg_make_c_derived_tbl (j_compress_ptr cinfo, boolean isDC, int tblno,
} }
/* Outputting bytes to the file */
/* Emit a byte, taking 'action' if must suspend. */
#define emit_byte(state,val,action) \
{ *(state)->next_output_byte++ = (JOCTET) (val); \
if (--(state)->free_in_buffer == 0) \
if (! dump_buffer(state)) \
{ action; } }
LOCAL(boolean)
dump_buffer (working_state * state)
/* Empty the output buffer; return TRUE if successful, FALSE if must suspend */
{
struct jpeg_destination_mgr * dest = state->cinfo->dest;
if (! (*dest->empty_output_buffer) (state->cinfo))
return FALSE;
/* After a successful buffer dump, must reset buffer pointers */
state->next_output_byte = dest->next_output_byte;
state->free_in_buffer = dest->free_in_buffer;
return TRUE;
}
/* Outputting bits to the file */
/* Only the right 24 bits of put_buffer are used; the valid bits are
* left-justified in this part. At most 16 bits can be passed to emit_bits
* in one call, and we never retain more than 7 bits in put_buffer
* between calls, so 24 bits are sufficient.
*/
INLINE
LOCAL(boolean)
emit_bits (working_state * state, unsigned int code, int size)
/* Emit some bits; return TRUE if successful, FALSE if must suspend */
{
/* This routine is heavily used, so it's worth coding tightly. */
register INT32 put_buffer = (INT32) code;
register int put_bits = state->cur.put_bits;
/* if size is 0, caller used an invalid Huffman table entry */
if (size == 0)
ERREXIT(state->cinfo, JERR_HUFF_MISSING_CODE);
put_buffer &= (((INT32) 1)<<size) - 1; /* mask off any extra bits in code */
put_bits += size; /* new number of bits in buffer */
put_buffer <<= 24 - put_bits; /* align incoming bits */
put_buffer |= state->cur.put_buffer; /* and merge with old buffer contents */
while (put_bits >= 8) {
int c = (int) ((put_buffer >> 16) & 0xFF);
emit_byte(state, c, return FALSE);
if (c == 0xFF) { /* need to stuff a zero byte? */
emit_byte(state, 0, return FALSE);
}
put_buffer <<= 8;
put_bits -= 8;
}
state->cur.put_buffer = put_buffer; /* update state variables */
state->cur.put_bits = put_bits;
return TRUE;
}
LOCAL(boolean)
flush_bits (working_state * state)
{
if (! emit_bits(state, 0x7F, 7)) /* fill any partial byte with ones */
return FALSE;
state->cur.put_buffer = 0; /* and reset bit-buffer to empty */
state->cur.put_bits = 0;
return TRUE;
}
/* Encode a single block's worth of coefficients */
LOCAL(boolean)
encode_one_block (working_state * state, JCOEFPTR block, int last_dc_val,
c_derived_tbl *dctbl, c_derived_tbl *actbl)
{
register int temp, temp2;
register int nbits;
register int k, r, i;
/* Encode the DC coefficient difference per section F.1.2.1 */
temp = temp2 = block[0] - last_dc_val;
if (temp < 0) {
temp = -temp; /* temp is abs value of input */
/* For a negative input, want temp2 = bitwise complement of abs(input) */
/* This code assumes we are on a two's complement machine */
temp2--;
}
/* Find the number of bits needed for the magnitude of the coefficient */
nbits = 0;
while (temp) {
nbits++;
temp >>= 1;
}
/* Check for out-of-range coefficient values.
* Since we're encoding a difference, the range limit is twice as much.
*/
if (nbits > MAX_COEF_BITS+1)
ERREXIT(state->cinfo, JERR_BAD_DCT_COEF);
/* Emit the Huffman-coded symbol for the number of bits */
if (! emit_bits(state, dctbl->ehufco[nbits], dctbl->ehufsi[nbits]))
return FALSE;
/* Emit that number of bits of the value, if positive, */
/* or the complement of its magnitude, if negative. */
if (nbits) /* emit_bits rejects calls with size 0 */
if (! emit_bits(state, (unsigned int) temp2, nbits))
return FALSE;
/* Encode the AC coefficients per section F.1.2.2 */
r = 0; /* r = run length of zeros */
for (k = 1; k < DCTSIZE2; k++) {
if ((temp = block[jpeg_natural_order[k]]) == 0) {
r++;
} else {
/* if run length > 15, must emit special run-length-16 codes (0xF0) */
while (r > 15) {
if (! emit_bits(state, actbl->ehufco[0xF0], actbl->ehufsi[0xF0]))
return FALSE;
r -= 16;
}
temp2 = temp;
if (temp < 0) {
temp = -temp; /* temp is abs value of input */
/* This code assumes we are on a two's complement machine */
temp2--;
}
/* Find the number of bits needed for the magnitude of the coefficient */
nbits = 1; /* there must be at least one 1 bit */
while ((temp >>= 1))
nbits++;
/* Check for out-of-range coefficient values */
if (nbits > MAX_COEF_BITS)
ERREXIT(state->cinfo, JERR_BAD_DCT_COEF);
/* Emit Huffman symbol for run length / number of bits */
i = (r << 4) + nbits;
if (! emit_bits(state, actbl->ehufco[i], actbl->ehufsi[i]))
return FALSE;
/* Emit that number of bits of the value, if positive, */
/* or the complement of its magnitude, if negative. */
if (! emit_bits(state, (unsigned int) temp2, nbits))
return FALSE;
r = 0;
}
}
/* If the last coef(s) were zero, emit an end-of-block code */
if (r > 0)
if (! emit_bits(state, actbl->ehufco[0], actbl->ehufsi[0]))
return FALSE;
return TRUE;
}
/*
* Emit a restart marker & resynchronize predictions.
*/
LOCAL(boolean)
emit_restart (working_state * state, int restart_num)
{
int ci;
if (! flush_bits(state))
return FALSE;
emit_byte(state, 0xFF, return FALSE);
emit_byte(state, JPEG_RST0 + restart_num, return FALSE);
/* Re-initialize DC predictions to 0 */
for (ci = 0; ci < state->cinfo->comps_in_scan; ci++)
state->cur.last_dc_val[ci] = 0;
/* The restart counter is not updated until we successfully write the MCU. */
return TRUE;
}
/*
* Encode and output one MCU's worth of Huffman-compressed coefficients.
*/
METHODDEF(boolean)
encode_mcu_huff (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
{
huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
working_state state;
int blkn, ci;
jpeg_component_info * compptr;
/* Load up working state */
state.next_output_byte = cinfo->dest->next_output_byte;
state.free_in_buffer = cinfo->dest->free_in_buffer;
ASSIGN_STATE(state.cur, entropy->saved);
state.cinfo = cinfo;
/* Emit restart marker if needed */
if (cinfo->restart_interval) {
if (entropy->restarts_to_go == 0)
if (! emit_restart(&state, entropy->next_restart_num))
return FALSE;
}
/* Encode the MCU data blocks */
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
ci = cinfo->MCU_membership[blkn];
compptr = cinfo->cur_comp_info[ci];
if (! encode_one_block(&state,
MCU_data[blkn][0], state.cur.last_dc_val[ci],
entropy->dc_derived_tbls[compptr->dc_tbl_no],
entropy->ac_derived_tbls[compptr->ac_tbl_no]))
return FALSE;
/* Update last_dc_val */
state.cur.last_dc_val[ci] = MCU_data[blkn][0][0];
}
/* Completed MCU, so update state */
cinfo->dest->next_output_byte = state.next_output_byte;
cinfo->dest->free_in_buffer = state.free_in_buffer;
ASSIGN_STATE(entropy->saved, state.cur);
/* Update restart-interval state too */
if (cinfo->restart_interval) {
if (entropy->restarts_to_go == 0) {
entropy->restarts_to_go = cinfo->restart_interval;
entropy->next_restart_num++;
entropy->next_restart_num &= 7;
}
entropy->restarts_to_go--;
}
return TRUE;
}
/*
* Finish up at the end of a Huffman-compressed scan.
*/
METHODDEF(void)
finish_pass_huff (j_compress_ptr cinfo)
{
huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
working_state state;
/* Load up working state ... flush_bits needs it */
state.next_output_byte = cinfo->dest->next_output_byte;
state.free_in_buffer = cinfo->dest->free_in_buffer;
ASSIGN_STATE(state.cur, entropy->saved);
state.cinfo = cinfo;
/* Flush out the last data */
if (! flush_bits(&state))
ERREXIT(cinfo, JERR_CANT_SUSPEND);
/* Update state */
cinfo->dest->next_output_byte = state.next_output_byte;
cinfo->dest->free_in_buffer = state.free_in_buffer;
ASSIGN_STATE(entropy->saved, state.cur);
}
/*
* Huffman coding optimization.
*
* We first scan the supplied data and count the number of uses of each symbol
* that is to be Huffman-coded. (This process MUST agree with the code above.)
* Then we build a Huffman coding tree for the observed counts.
* Symbols which are not needed at all for the particular image are not
* assigned any code, which saves space in the DHT marker as well as in
* the compressed data.
*/
#ifdef ENTROPY_OPT_SUPPORTED
/* Process a single block's worth of coefficients */
LOCAL(void)
htest_one_block (j_compress_ptr cinfo, JCOEFPTR block, int last_dc_val,
long dc_counts[], long ac_counts[])
{
register int temp;
register int nbits;
register int k, r;
/* Encode the DC coefficient difference per section F.1.2.1 */
temp = block[0] - last_dc_val;
if (temp < 0)
temp = -temp;
/* Find the number of bits needed for the magnitude of the coefficient */
nbits = 0;
while (temp) {
nbits++;
temp >>= 1;
}
/* Check for out-of-range coefficient values.
* Since we're encoding a difference, the range limit is twice as much.
*/
if (nbits > MAX_COEF_BITS+1)
ERREXIT(cinfo, JERR_BAD_DCT_COEF);
/* Count the Huffman symbol for the number of bits */
dc_counts[nbits]++;
/* Encode the AC coefficients per section F.1.2.2 */
r = 0; /* r = run length of zeros */
for (k = 1; k < DCTSIZE2; k++) {
if ((temp = block[jpeg_natural_order[k]]) == 0) {
r++;
} else {
/* if run length > 15, must emit special run-length-16 codes (0xF0) */
while (r > 15) {
ac_counts[0xF0]++;
r -= 16;
}
/* Find the number of bits needed for the magnitude of the coefficient */
if (temp < 0)
temp = -temp;
/* Find the number of bits needed for the magnitude of the coefficient */
nbits = 1; /* there must be at least one 1 bit */
while ((temp >>= 1))
nbits++;
/* Check for out-of-range coefficient values */
if (nbits > MAX_COEF_BITS)
ERREXIT(cinfo, JERR_BAD_DCT_COEF);
/* Count Huffman symbol for run length / number of bits */
ac_counts[(r << 4) + nbits]++;
r = 0;
}
}
/* If the last coef(s) were zero, emit an end-of-block code */
if (r > 0)
ac_counts[0]++;
}
/*
* Trial-encode one MCU's worth of Huffman-compressed coefficients.
* No data is actually output, so no suspension return is possible.
*/
METHODDEF(boolean)
encode_mcu_gather (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
{
huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
int blkn, ci;
jpeg_component_info * compptr;
/* Take care of restart intervals if needed */
if (cinfo->restart_interval) {
if (entropy->restarts_to_go == 0) {
/* Re-initialize DC predictions to 0 */
for (ci = 0; ci < cinfo->comps_in_scan; ci++)
entropy->saved.last_dc_val[ci] = 0;
/* Update restart state */
entropy->restarts_to_go = cinfo->restart_interval;
}
entropy->restarts_to_go--;
}
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
ci = cinfo->MCU_membership[blkn];
compptr = cinfo->cur_comp_info[ci];
htest_one_block(cinfo, MCU_data[blkn][0], entropy->saved.last_dc_val[ci],
entropy->dc_count_ptrs[compptr->dc_tbl_no],
entropy->ac_count_ptrs[compptr->ac_tbl_no]);
entropy->saved.last_dc_val[ci] = MCU_data[blkn][0][0];
}
return TRUE;
}
/* /*
* Generate the best Huffman code table for the given counts, fill htbl. * Generate the best Huffman code table for the given counts, fill htbl.
* Note this is also used by jcphuff.c and jclhuff.c.
* *
* The JPEG standard requires that no symbol be assigned a codeword of all * The JPEG standard requires that no symbol be assigned a codeword of all
* one bits (so that padding bits added at the end of a compressed segment * one bits (so that padding bits added at the end of a compressed segment
@@ -273,3 +839,74 @@ jpeg_gen_optimal_table (j_compress_ptr cinfo, JHUFF_TBL * htbl, long freq[])
/* Set sent_table FALSE so updated table will be written to JPEG file. */ /* Set sent_table FALSE so updated table will be written to JPEG file. */
htbl->sent_table = FALSE; htbl->sent_table = FALSE;
} }
/*
* Finish up a statistics-gathering pass and create the new Huffman tables.
*/
METHODDEF(void)
finish_pass_gather (j_compress_ptr cinfo)
{
huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
int ci, dctbl, actbl;
jpeg_component_info * compptr;
JHUFF_TBL **htblptr;
boolean did_dc[NUM_HUFF_TBLS];
boolean did_ac[NUM_HUFF_TBLS];
/* It's important not to apply jpeg_gen_optimal_table more than once
* per table, because it clobbers the input frequency counts!
*/
MEMZERO(did_dc, SIZEOF(did_dc));
MEMZERO(did_ac, SIZEOF(did_ac));
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
dctbl = compptr->dc_tbl_no;
actbl = compptr->ac_tbl_no;
if (! did_dc[dctbl]) {
htblptr = & cinfo->dc_huff_tbl_ptrs[dctbl];
if (*htblptr == NULL)
*htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo);
jpeg_gen_optimal_table(cinfo, *htblptr, entropy->dc_count_ptrs[dctbl]);
did_dc[dctbl] = TRUE;
}
if (! did_ac[actbl]) {
htblptr = & cinfo->ac_huff_tbl_ptrs[actbl];
if (*htblptr == NULL)
*htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo);
jpeg_gen_optimal_table(cinfo, *htblptr, entropy->ac_count_ptrs[actbl]);
did_ac[actbl] = TRUE;
}
}
}
#endif /* ENTROPY_OPT_SUPPORTED */
/*
* Module initialization routine for Huffman entropy encoding.
*/
GLOBAL(void)
jinit_huff_encoder (j_compress_ptr cinfo)
{
huff_entropy_ptr entropy;
int i;
entropy = (huff_entropy_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(huff_entropy_encoder));
cinfo->entropy = (struct jpeg_entropy_encoder *) entropy;
entropy->pub.start_pass = start_pass_huff;
/* Mark tables unallocated */
for (i = 0; i < NUM_HUFF_TBLS; i++) {
entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL;
#ifdef ENTROPY_OPT_SUPPORTED
entropy->dc_count_ptrs[i] = entropy->ac_count_ptrs[i] = NULL;
#endif
}
}

View File

@@ -1,10 +1,8 @@
/* /*
* jchuff.h * jchuff.h
* *
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1997, Thomas G. Lane. * Copyright (C) 1991-1997, Thomas G. Lane.
* Lossless JPEG Modifications: * This file is part of the Independent JPEG Group's software.
* Copyright (C) 1999, Ken Murchison.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains declarations for Huffman entropy encoding routines * This file contains declarations for Huffman entropy encoding routines
@@ -24,13 +22,6 @@
#define MAX_COEF_BITS 14 #define MAX_COEF_BITS 14
#endif #endif
/* The legal range of a spatial difference is
* -32767 .. +32768.
* Hence the magnitude should always fit in 16 bits.
*/
#define MAX_DIFF_BITS 16
/* Derived data constructed for each Huffman table */ /* Derived data constructed for each Huffman table */
typedef struct { typedef struct {

View File

@@ -5,6 +5,7 @@
* Copyright (C) 1991-1997, Thomas G. Lane. * Copyright (C) 1991-1997, Thomas G. Lane.
* Lossless JPEG Modifications: * Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison. * Copyright (C) 1999, Ken Murchison.
* Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains initialization logic for the JPEG compressor. * This file contains initialization logic for the JPEG compressor.
@@ -34,9 +35,6 @@ jinit_compress_master (j_compress_ptr cinfo)
/* Initialize master control (includes parameter checking/processing) */ /* Initialize master control (includes parameter checking/processing) */
jinit_c_master_control(cinfo, FALSE /* full compression */); jinit_c_master_control(cinfo, FALSE /* full compression */);
/* Initialize compression codec */
jinit_c_codec(cinfo);
/* Preprocessing */ /* Preprocessing */
if (! cinfo->raw_data_in) { if (! cinfo->raw_data_in) {
jinit_color_converter(cinfo); jinit_color_converter(cinfo);
@@ -44,6 +42,45 @@ jinit_compress_master (j_compress_ptr cinfo)
jinit_c_prep_controller(cinfo, FALSE /* never need full buffer here */); jinit_c_prep_controller(cinfo, FALSE /* never need full buffer here */);
} }
if (cinfo->master->lossless) {
#ifdef C_LOSSLESS_SUPPORTED
/* Prediction, sample differencing, and point transform */
jinit_lossless_compressor(cinfo);
/* Entropy encoding: either Huffman or arithmetic coding. */
if (cinfo->arith_code) {
ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
} else {
jinit_lhuff_encoder(cinfo);
}
/* Need a full-image difference buffer in any multi-pass mode. */
jinit_c_diff_controller(cinfo,
(boolean) (cinfo->num_scans > 1 || cinfo->optimize_coding));
#else
ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif
} else {
/* Forward DCT */
jinit_forward_dct(cinfo);
/* Entropy encoding: either Huffman or arithmetic coding. */
if (cinfo->arith_code) {
ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
} else {
if (cinfo->progressive_mode) {
#ifdef C_PROGRESSIVE_SUPPORTED
jinit_phuff_encoder(cinfo);
#else
ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif
} else
jinit_huff_encoder(cinfo);
}
/* Need a full-image coefficient buffer in any multi-pass mode. */
jinit_c_coef_controller(cinfo,
(boolean) (cinfo->num_scans > 1 || cinfo->optimize_coding));
}
jinit_c_main_controller(cinfo, FALSE /* never need full buffer here */); jinit_c_main_controller(cinfo, FALSE /* never need full buffer here */);
jinit_marker_writer(cinfo); jinit_marker_writer(cinfo);

View File

@@ -2,9 +2,10 @@
* jclhuff.c * jclhuff.c
* *
* This file was part of the Independent JPEG Group's software: * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1998, Thomas G. Lane. * Copyright (C) 1991-1997, Thomas G. Lane.
* Lossless JPEG Modifications: * Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison. * Copyright (C) 1999, Ken Murchison.
* Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains Huffman entropy encoding routines for lossless JPEG. * This file contains Huffman entropy encoding routines for lossless JPEG.
@@ -23,7 +24,17 @@
#include "jchuff.h" /* Declarations shared with jc*huff.c */ #include "jchuff.h" /* Declarations shared with jc*huff.c */
/* Expanded entropy encoder object for Huffman encoding. #ifdef C_LOSSLESS_SUPPORTED
/* The legal range of a spatial difference is
* -32767 .. +32768.
* Hence the magnitude should always fit in 16 bits.
*/
#define MAX_DIFF_BITS 16
/* Expanded entropy encoder object for Huffman encoding in lossless mode.
* *
* The savable_state subrecord contains fields that change within an MCU, * The savable_state subrecord contains fields that change within an MCU,
* but must not be updated permanently until we complete the MCU. * but must not be updated permanently until we complete the MCU.
@@ -54,6 +65,8 @@ typedef struct {
typedef struct { typedef struct {
struct jpeg_entropy_encoder pub; /* public fields */
savable_state saved; /* Bit buffer at start of MCU */ savable_state saved; /* Bit buffer at start of MCU */
/* These fields are NOT loaded into local working state. */ /* These fields are NOT loaded into local working state. */
@@ -64,19 +77,19 @@ typedef struct {
c_derived_tbl * derived_tbls[NUM_HUFF_TBLS]; c_derived_tbl * derived_tbls[NUM_HUFF_TBLS];
/* Pointers to derived tables to be used for each data unit within an MCU */ /* Pointers to derived tables to be used for each data unit within an MCU */
c_derived_tbl * cur_tbls[C_MAX_DATA_UNITS_IN_MCU]; c_derived_tbl * cur_tbls[C_MAX_BLOCKS_IN_MCU];
#ifdef ENTROPY_OPT_SUPPORTED /* Statistics tables for optimization */ #ifdef ENTROPY_OPT_SUPPORTED /* Statistics tables for optimization */
long * count_ptrs[NUM_HUFF_TBLS]; long * count_ptrs[NUM_HUFF_TBLS];
/* Pointers to stats tables to be used for each data unit within an MCU */ /* Pointers to stats tables to be used for each data unit within an MCU */
long * cur_counts[C_MAX_DATA_UNITS_IN_MCU]; long * cur_counts[C_MAX_BLOCKS_IN_MCU];
#endif #endif
/* Pointers to the proper input difference row for each group of data units /* Pointers to the proper input difference row for each group of data units
* within an MCU. For each component, there are Vi groups of Hi data units. * within an MCU. For each component, there are Vi groups of Hi data units.
*/ */
JDIFFROW input_ptr[C_MAX_DATA_UNITS_IN_MCU]; JDIFFROW input_ptr[C_MAX_BLOCKS_IN_MCU];
/* Number of input pointers in use for the current MCU. This is the sum /* Number of input pointers in use for the current MCU. This is the sum
* of all Vi in the MCU. * of all Vi in the MCU.
@@ -86,10 +99,10 @@ typedef struct {
/* Information used for positioning the input pointers within the input /* Information used for positioning the input pointers within the input
* difference rows. * difference rows.
*/ */
lhe_input_ptr_info input_ptr_info[C_MAX_DATA_UNITS_IN_MCU]; lhe_input_ptr_info input_ptr_info[C_MAX_BLOCKS_IN_MCU];
/* Index of the proper input pointer for each data unit within an MCU */ /* Index of the proper input pointer for each data unit within an MCU */
int input_ptr_index[C_MAX_DATA_UNITS_IN_MCU]; int input_ptr_index[C_MAX_BLOCKS_IN_MCU];
} lhuff_entropy_encoder; } lhuff_entropy_encoder;
@@ -131,23 +144,22 @@ METHODDEF(void) finish_pass_gather JPP((j_compress_ptr cinfo));
*/ */
METHODDEF(void) METHODDEF(void)
start_pass_huff (j_compress_ptr cinfo, boolean gather_statistics) start_pass_lhuff (j_compress_ptr cinfo, boolean gather_statistics)
{ {
j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; lhuff_entropy_ptr entropy = (lhuff_entropy_ptr) cinfo->entropy;
lhuff_entropy_ptr entropy = (lhuff_entropy_ptr) losslsc->entropy_private;
int ci, dctbl, sampn, ptrn, yoffset, xoffset; int ci, dctbl, sampn, ptrn, yoffset, xoffset;
jpeg_component_info * compptr; jpeg_component_info * compptr;
if (gather_statistics) { if (gather_statistics) {
#ifdef ENTROPY_OPT_SUPPORTED #ifdef ENTROPY_OPT_SUPPORTED
losslsc->entropy_encode_mcus = encode_mcus_gather; entropy->pub.encode_mcus = encode_mcus_gather;
losslsc->pub.entropy_finish_pass = finish_pass_gather; entropy->pub.finish_pass = finish_pass_gather;
#else #else
ERREXIT(cinfo, JERR_NOT_COMPILED); ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif #endif
} else { } else {
losslsc->entropy_encode_mcus = encode_mcus_huff; entropy->pub.encode_mcus = encode_mcus_huff;
losslsc->pub.entropy_finish_pass = finish_pass_huff; entropy->pub.finish_pass = finish_pass_huff;
} }
for (ci = 0; ci < cinfo->comps_in_scan; ci++) { for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
@@ -176,11 +188,9 @@ start_pass_huff (j_compress_ptr cinfo, boolean gather_statistics)
} }
/* Precalculate encoding info for each sample in an MCU of this scan */ /* Precalculate encoding info for each sample in an MCU of this scan */
for (sampn = 0, ptrn = 0; sampn < cinfo->data_units_in_MCU;) { for (sampn = 0, ptrn = 0; sampn < cinfo->blocks_in_MCU;) {
compptr = cinfo->cur_comp_info[cinfo->MCU_membership[sampn]]; compptr = cinfo->cur_comp_info[cinfo->MCU_membership[sampn]];
ci = compptr->component_index; ci = compptr->component_index;
/* ci = cinfo->MCU_membership[sampn];
compptr = cinfo->cur_comp_info[ci];*/
for (yoffset = 0; yoffset < compptr->MCU_height; yoffset++, ptrn++) { for (yoffset = 0; yoffset < compptr->MCU_height; yoffset++, ptrn++) {
/* Precalculate the setup info for each input pointer */ /* Precalculate the setup info for each input pointer */
entropy->input_ptr_info[ptrn].ci = ci; entropy->input_ptr_info[ptrn].ci = ci;
@@ -297,8 +307,6 @@ flush_bits (working_state * state)
LOCAL(boolean) LOCAL(boolean)
emit_restart (working_state * state, int restart_num) emit_restart (working_state * state, int restart_num)
{ {
int ci;
if (! flush_bits(state)) if (! flush_bits(state))
return FALSE; return FALSE;
@@ -312,7 +320,7 @@ emit_restart (working_state * state, int restart_num)
/* /*
* Encode and output one nMCU's worth of Huffman-compressed differences. * Encode and output nMCU MCUs' worth of Huffman-compressed differences.
*/ */
METHODDEF(JDIMENSION) METHODDEF(JDIMENSION)
@@ -320,11 +328,9 @@ encode_mcus_huff (j_compress_ptr cinfo, JDIFFIMAGE diff_buf,
JDIMENSION MCU_row_num, JDIMENSION MCU_col_num, JDIMENSION MCU_row_num, JDIMENSION MCU_col_num,
JDIMENSION nMCU) JDIMENSION nMCU)
{ {
j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; lhuff_entropy_ptr entropy = (lhuff_entropy_ptr) cinfo->entropy;
lhuff_entropy_ptr entropy = (lhuff_entropy_ptr) losslsc->entropy_private;
working_state state; working_state state;
int mcu_num, sampn, ci, yoffset, MCU_width, ptrn; int mcu_num, sampn, ci, yoffset, MCU_width, ptrn;
jpeg_component_info * compptr;
/* Load up working state */ /* Load up working state */
state.next_output_byte = cinfo->dest->next_output_byte; state.next_output_byte = cinfo->dest->next_output_byte;
@@ -351,8 +357,8 @@ encode_mcus_huff (j_compress_ptr cinfo, JDIFFIMAGE diff_buf,
for (mcu_num = 0; mcu_num < nMCU; mcu_num++) { for (mcu_num = 0; mcu_num < nMCU; mcu_num++) {
/* Inner loop handles the samples in the MCU */ /* Inner loop handles the samples in the MCU */
for (sampn = 0; sampn < cinfo->data_units_in_MCU; sampn++) { for (sampn = 0; sampn < cinfo->blocks_in_MCU; sampn++) {
register int temp, temp2, temp3; register int temp, temp2;
register int nbits; register int nbits;
c_derived_tbl *dctbl = entropy->cur_tbls[sampn]; c_derived_tbl *dctbl = entropy->cur_tbls[sampn];
@@ -380,7 +386,7 @@ encode_mcus_huff (j_compress_ptr cinfo, JDIFFIMAGE diff_buf,
/* Check for out-of-range difference values. /* Check for out-of-range difference values.
*/ */
if (nbits > MAX_DIFF_BITS) if (nbits > MAX_DIFF_BITS)
ERREXIT(cinfo, JERR_BAD_DIFF); ERREXIT(cinfo, JERR_BAD_DCT_COEF);
/* Emit the Huffman-coded symbol for the number of bits */ /* Emit the Huffman-coded symbol for the number of bits */
if (! emit_bits(&state, dctbl->ehufco[nbits], dctbl->ehufsi[nbits])) if (! emit_bits(&state, dctbl->ehufco[nbits], dctbl->ehufsi[nbits]))
@@ -422,8 +428,7 @@ encode_mcus_huff (j_compress_ptr cinfo, JDIFFIMAGE diff_buf,
METHODDEF(void) METHODDEF(void)
finish_pass_huff (j_compress_ptr cinfo) finish_pass_huff (j_compress_ptr cinfo)
{ {
j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; lhuff_entropy_ptr entropy = (lhuff_entropy_ptr) cinfo->entropy;
lhuff_entropy_ptr entropy = (lhuff_entropy_ptr) losslsc->entropy_private;
working_state state; working_state state;
/* Load up working state ... flush_bits needs it */ /* Load up working state ... flush_bits needs it */
@@ -457,7 +462,7 @@ finish_pass_huff (j_compress_ptr cinfo)
#ifdef ENTROPY_OPT_SUPPORTED #ifdef ENTROPY_OPT_SUPPORTED
/* /*
* Trial-encode one nMCU's worth of Huffman-compressed differences. * Trial-encode nMCU MCUs' worth of Huffman-compressed differences.
* No data is actually output, so no suspension return is possible. * No data is actually output, so no suspension return is possible.
*/ */
@@ -466,10 +471,8 @@ encode_mcus_gather (j_compress_ptr cinfo, JDIFFIMAGE diff_buf,
JDIMENSION MCU_row_num, JDIMENSION MCU_col_num, JDIMENSION MCU_row_num, JDIMENSION MCU_col_num,
JDIMENSION nMCU) JDIMENSION nMCU)
{ {
j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; lhuff_entropy_ptr entropy = (lhuff_entropy_ptr) cinfo->entropy;
lhuff_entropy_ptr entropy = (lhuff_entropy_ptr) losslsc->entropy_private;
int mcu_num, sampn, ci, yoffset, MCU_width, ptrn; int mcu_num, sampn, ci, yoffset, MCU_width, ptrn;
jpeg_component_info * compptr;
/* Take care of restart intervals if needed */ /* Take care of restart intervals if needed */
if (cinfo->restart_interval) { if (cinfo->restart_interval) {
@@ -492,10 +495,9 @@ encode_mcus_gather (j_compress_ptr cinfo, JDIFFIMAGE diff_buf,
for (mcu_num = 0; mcu_num < nMCU; mcu_num++) { for (mcu_num = 0; mcu_num < nMCU; mcu_num++) {
/* Inner loop handles the samples in the MCU */ /* Inner loop handles the samples in the MCU */
for (sampn = 0; sampn < cinfo->data_units_in_MCU; sampn++) { for (sampn = 0; sampn < cinfo->blocks_in_MCU; sampn++) {
register int temp; register int temp;
register int nbits; register int nbits;
c_derived_tbl *dctbl = entropy->cur_tbls[sampn];
long * counts = entropy->cur_counts[sampn]; long * counts = entropy->cur_counts[sampn];
/* Encode the difference per section H.1.2.2 */ /* Encode the difference per section H.1.2.2 */
@@ -519,7 +521,7 @@ encode_mcus_gather (j_compress_ptr cinfo, JDIFFIMAGE diff_buf,
/* Check for out-of-range difference values. /* Check for out-of-range difference values.
*/ */
if (nbits > MAX_DIFF_BITS) if (nbits > MAX_DIFF_BITS)
ERREXIT(cinfo, JERR_BAD_DIFF); ERREXIT(cinfo, JERR_BAD_DCT_COEF);
/* Count the Huffman symbol for the number of bits */ /* Count the Huffman symbol for the number of bits */
counts[nbits]++; counts[nbits]++;
@@ -537,8 +539,7 @@ encode_mcus_gather (j_compress_ptr cinfo, JDIFFIMAGE diff_buf,
METHODDEF(void) METHODDEF(void)
finish_pass_gather (j_compress_ptr cinfo) finish_pass_gather (j_compress_ptr cinfo)
{ {
j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; lhuff_entropy_ptr entropy = (lhuff_entropy_ptr) cinfo->entropy;
lhuff_entropy_ptr entropy = (lhuff_entropy_ptr) losslsc->entropy_private;
int ci, dctbl; int ci, dctbl;
jpeg_component_info * compptr; jpeg_component_info * compptr;
JHUFF_TBL **htblptr; JHUFF_TBL **htblptr;
@@ -566,30 +567,21 @@ finish_pass_gather (j_compress_ptr cinfo)
#endif /* ENTROPY_OPT_SUPPORTED */ #endif /* ENTROPY_OPT_SUPPORTED */
METHODDEF(boolean)
need_optimization_pass (j_compress_ptr cinfo)
{
return TRUE;
}
/* /*
* Module initialization routine for Huffman entropy encoding. * Module initialization routine for lossless mode Huffman entropy encoding.
*/ */
GLOBAL(void) GLOBAL(void)
jinit_lhuff_encoder (j_compress_ptr cinfo) jinit_lhuff_encoder (j_compress_ptr cinfo)
{ {
j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec;
lhuff_entropy_ptr entropy; lhuff_entropy_ptr entropy;
int i; int i;
entropy = (lhuff_entropy_ptr) entropy = (lhuff_entropy_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(lhuff_entropy_encoder)); SIZEOF(lhuff_entropy_encoder));
losslsc->entropy_private = (struct jpeg_entropy_encoder *) entropy; cinfo->entropy = (struct jpeg_entropy_encoder *) entropy;
losslsc->pub.entropy_start_pass = start_pass_huff; entropy->pub.start_pass = start_pass_lhuff;
losslsc->pub.need_optimization_pass = need_optimization_pass;
/* Mark tables unallocated */ /* Mark tables unallocated */
for (i = 0; i < NUM_HUFF_TBLS; i++) { for (i = 0; i < NUM_HUFF_TBLS; i++) {
@@ -599,3 +591,5 @@ jinit_lhuff_encoder (j_compress_ptr cinfo)
#endif #endif
} }
} }
#endif /* C_LOSSLESS_SUPPORTED */

View File

@@ -5,9 +5,11 @@
* Copyright (C) 1998, Thomas G. Lane. * Copyright (C) 1998, Thomas G. Lane.
* Lossless JPEG Modifications: * Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison. * Copyright (C) 1999, Ken Murchison.
* Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains the control logic for the lossless JPEG compressor. * This file contains prediction, sample differencing, and point transform
* routines for the lossless JPEG compressor.
*/ */
#define JPEG_INTERNALS #define JPEG_INTERNALS
@@ -15,66 +17,301 @@
#include "jpeglib.h" #include "jpeglib.h"
#include "jlossls.h" #include "jlossls.h"
#ifdef C_LOSSLESS_SUPPORTED #ifdef C_LOSSLESS_SUPPORTED
/************************** Sample differencing **************************/
/*
* In order to avoid a performance penalty for checking which predictor is
* being used and which row is being processed for each call of the
* undifferencer, and to promote optimization, we have separate differencing
* functions for each predictor selection value.
*
* We are able to avoid duplicating source code by implementing the predictors
* and differencers as macros. Each of the differencing functions is simply a
* wrapper around a DIFFERENCE macro with the appropriate PREDICTOR macro
* passed as an argument.
*/
/* Forward declarations */
LOCAL(void) reset_predictor JPP((j_compress_ptr cinfo, int ci));
/* Predictor for the first column of the first row: 2^(P-Pt-1) */
#define INITIAL_PREDICTORx (1 << (cinfo->data_precision - cinfo->Al - 1))
/* Predictor for the first column of the remaining rows: Rb */
#define INITIAL_PREDICTOR2 GETJSAMPLE(prev_row[0])
/*
* 1-Dimensional differencer routine.
*
* This macro implements the 1-D horizontal predictor (1). INITIAL_PREDICTOR
* is used as the special case predictor for the first column, which must be
* either INITIAL_PREDICTOR2 or INITIAL_PREDICTORx. The remaining samples
* use PREDICTOR1.
*/
#define DIFFERENCE_1D(INITIAL_PREDICTOR) \
lossless_comp_ptr losslessc = (lossless_comp_ptr) cinfo->fdct; \
boolean restart = FALSE; \
int samp, Ra; \
\
samp = GETJSAMPLE(*input_buf++); \
*diff_buf++ = samp - INITIAL_PREDICTOR; \
\
while (--width) { \
Ra = samp; \
samp = GETJSAMPLE(*input_buf++); \
*diff_buf++ = samp - PREDICTOR1; \
} \
\
/* Account for restart interval (no-op if not using restarts) */ \
if (cinfo->restart_interval) { \
if (--(losslessc->restart_rows_to_go[ci]) == 0) { \
reset_predictor(cinfo, ci); \
restart = TRUE; \
} \
}
/*
* 2-Dimensional differencer routine.
*
* This macro implements the 2-D horizontal predictors (#2-7). PREDICTOR2 is
* used as the special case predictor for the first column. The remaining
* samples use PREDICTOR, which is a function of Ra, Rb, and Rc.
*
* Because prev_row and output_buf may point to the same storage area (in an
* interleaved image with Vi=1, for example), we must take care to buffer Rb/Rc
* before writing the current reconstructed sample value into output_buf.
*/
#define DIFFERENCE_2D(PREDICTOR) \
lossless_comp_ptr losslessc = (lossless_comp_ptr) cinfo->fdct; \
int samp, Ra, Rb, Rc; \
\
Rb = GETJSAMPLE(*prev_row++); \
samp = GETJSAMPLE(*input_buf++); \
*diff_buf++ = samp - PREDICTOR2; \
\
while (--width) { \
Rc = Rb; \
Rb = GETJSAMPLE(*prev_row++); \
Ra = samp; \
samp = GETJSAMPLE(*input_buf++); \
*diff_buf++ = samp - PREDICTOR; \
} \
\
/* Account for restart interval (no-op if not using restarts) */ \
if (cinfo->restart_interval) { \
if (--losslessc->restart_rows_to_go[ci] == 0) \
reset_predictor(cinfo, ci); \
}
/*
* Differencers for the second and subsequent rows in a scan or restart
* interval. The first sample in the row is differenced using the vertical
* predictor (2). The rest of the samples are differenced using the predictor
* specified in the scan header.
*/
METHODDEF(void)
jpeg_difference1(j_compress_ptr cinfo, int ci,
JSAMPROW input_buf, JSAMPROW prev_row,
JDIFFROW diff_buf, JDIMENSION width)
{
DIFFERENCE_1D(INITIAL_PREDICTOR2);
(void)(restart);
}
METHODDEF(void)
jpeg_difference2(j_compress_ptr cinfo, int ci,
JSAMPROW input_buf, JSAMPROW prev_row,
JDIFFROW diff_buf, JDIMENSION width)
{
DIFFERENCE_2D(PREDICTOR2);
(void)(Ra);
(void)(Rc);
}
METHODDEF(void)
jpeg_difference3(j_compress_ptr cinfo, int ci,
JSAMPROW input_buf, JSAMPROW prev_row,
JDIFFROW diff_buf, JDIMENSION width)
{
DIFFERENCE_2D(PREDICTOR3);
(void)(Ra);
}
METHODDEF(void)
jpeg_difference4(j_compress_ptr cinfo, int ci,
JSAMPROW input_buf, JSAMPROW prev_row,
JDIFFROW diff_buf, JDIMENSION width)
{
DIFFERENCE_2D(PREDICTOR4);
}
METHODDEF(void)
jpeg_difference5(j_compress_ptr cinfo, int ci,
JSAMPROW input_buf, JSAMPROW prev_row,
JDIFFROW diff_buf, JDIMENSION width)
{
DIFFERENCE_2D(PREDICTOR5);
}
METHODDEF(void)
jpeg_difference6(j_compress_ptr cinfo, int ci,
JSAMPROW input_buf, JSAMPROW prev_row,
JDIFFROW diff_buf, JDIMENSION width)
{
DIFFERENCE_2D(PREDICTOR6);
}
METHODDEF(void)
jpeg_difference7(j_compress_ptr cinfo, int ci,
JSAMPROW input_buf, JSAMPROW prev_row,
JDIFFROW diff_buf, JDIMENSION width)
{
DIFFERENCE_2D(PREDICTOR7);
(void)(Rc);
}
/*
* Differencer for the first row in a scan or restart interval. The first
* sample in the row is differenced using the special predictor constant
* x=2^(P-Pt-1). The rest of the samples are differenced using the
* 1-D horizontal predictor (1).
*/
METHODDEF(void)
jpeg_difference_first_row(j_compress_ptr cinfo, int ci,
JSAMPROW input_buf, JSAMPROW prev_row,
JDIFFROW diff_buf, JDIMENSION width)
{
DIFFERENCE_1D(INITIAL_PREDICTORx);
/*
* Now that we have differenced the first row, we want to use the
* differencer that corresponds to the predictor specified in the
* scan header.
*
* Note that we don't do this if we have just reset the predictor
* for a new restart interval.
*/
if (! restart) {
switch (cinfo->Ss) {
case 1:
losslessc->predict_difference[ci] = jpeg_difference1;
break;
case 2:
losslessc->predict_difference[ci] = jpeg_difference2;
break;
case 3:
losslessc->predict_difference[ci] = jpeg_difference3;
break;
case 4:
losslessc->predict_difference[ci] = jpeg_difference4;
break;
case 5:
losslessc->predict_difference[ci] = jpeg_difference5;
break;
case 6:
losslessc->predict_difference[ci] = jpeg_difference6;
break;
case 7:
losslessc->predict_difference[ci] = jpeg_difference7;
break;
}
}
}
/*
* Reset predictor at the start of a pass or restart interval.
*/
LOCAL(void)
reset_predictor (j_compress_ptr cinfo, int ci)
{
lossless_comp_ptr losslessc = (lossless_comp_ptr) cinfo->fdct;
/* Initialize restart counter */
losslessc->restart_rows_to_go[ci] =
cinfo->restart_interval / cinfo->MCUs_per_row;
/* Set difference function to first row function */
losslessc->predict_difference[ci] = jpeg_difference_first_row;
}
/********************** Sample downscaling by 2^Pt ***********************/
METHODDEF(void)
simple_downscale(j_compress_ptr cinfo,
JSAMPROW input_buf, JSAMPROW output_buf, JDIMENSION width)
{
while (width--)
*output_buf++ = (JSAMPLE) RIGHT_SHIFT(GETJSAMPLE(*input_buf++), cinfo->Al);
}
METHODDEF(void)
noscale(j_compress_ptr cinfo,
JSAMPROW input_buf, JSAMPROW output_buf, JDIMENSION width)
{
MEMCOPY(output_buf, input_buf, width * SIZEOF(JSAMPLE));
return;
}
/* /*
* Initialize for a processing pass. * Initialize for a processing pass.
*/ */
METHODDEF(void) METHODDEF(void)
start_pass (j_compress_ptr cinfo, J_BUF_MODE pass_mode) start_pass_lossless (j_compress_ptr cinfo)
{ {
j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; lossless_comp_ptr losslessc = (lossless_comp_ptr) cinfo->fdct;
int ci;
(*losslsc->scaler_start_pass) (cinfo); /* Set scaler function based on Pt */
(*losslsc->predict_start_pass) (cinfo); if (cinfo->Al)
(*losslsc->diff_start_pass) (cinfo, pass_mode); losslessc->scaler_scale = simple_downscale;
else
losslessc->scaler_scale = noscale;
/* Check that the restart interval is an integer multiple of the number
* of MCUs in an MCU row.
*/
if (cinfo->restart_interval % cinfo->MCUs_per_row != 0)
ERREXIT2(cinfo, JERR_BAD_RESTART,
cinfo->restart_interval, cinfo->MCUs_per_row);
/* Set predictors for start of pass */
for (ci = 0; ci < cinfo->num_components; ci++)
reset_predictor(cinfo, ci);
} }
/* /*
* Initialize the lossless compression codec. * Initialize the lossless compressor.
* This is called only once, during master selection.
*/ */
GLOBAL(void) GLOBAL(void)
jinit_lossless_c_codec(j_compress_ptr cinfo) jinit_lossless_compressor(j_compress_ptr cinfo)
{ {
j_lossless_c_ptr losslsc; lossless_comp_ptr losslessc;
/* Create subobject in permanent pool */ /* Create subobject in permanent pool */
losslsc = (j_lossless_c_ptr) losslessc = (lossless_comp_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
SIZEOF(jpeg_lossless_c_codec)); SIZEOF(jpeg_lossless_compressor));
cinfo->codec = (struct jpeg_c_codec *) losslsc; cinfo->fdct = (struct jpeg_forward_dct *) losslessc;
losslessc->pub.start_pass = start_pass_lossless;
/* Initialize sub-modules */
/* Scaler */
jinit_c_scaler(cinfo);
/* Differencer */
jinit_differencer(cinfo);
/* Entropy encoding: either Huffman or arithmetic coding. */
if (cinfo->arith_code) {
ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
} else {
jinit_lhuff_encoder(cinfo);
}
/* Need a full-image difference buffer in any multi-pass mode. */
jinit_c_diff_controller(cinfo,
(boolean) (cinfo->num_scans > 1 ||
cinfo->optimize_coding));
/* Initialize method pointers.
*
* Note: entropy_start_pass and entropy_finish_pass are assigned in
* jclhuff.c and compress_data is assigned in jcdiffct.c.
*/
losslsc->pub.start_pass = start_pass;
} }
#endif /* C_LOSSLESS_SUPPORTED */ #endif /* C_LOSSLESS_SUPPORTED */

View File

@@ -1,78 +0,0 @@
/*
* jclossy.c
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1998, Thomas G. Lane.
* Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains the control logic for the lossy JPEG compressor.
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
#include "jlossy.h"
/*
* Initialize for a processing pass.
*/
METHODDEF(void)
start_pass (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
{
j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec;
(*lossyc->fdct_start_pass) (cinfo);
(*lossyc->coef_start_pass) (cinfo, pass_mode);
}
/*
* Initialize the lossy compression codec.
* This is called only once, during master selection.
*/
GLOBAL(void)
jinit_lossy_c_codec (j_compress_ptr cinfo)
{
j_lossy_c_ptr lossyc;
/* Create subobject in permanent pool */
lossyc = (j_lossy_c_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
SIZEOF(jpeg_lossy_c_codec));
cinfo->codec = (struct jpeg_c_codec *) lossyc;
/* Initialize sub-modules */
/* Forward DCT */
jinit_forward_dct(cinfo);
/* Entropy encoding: either Huffman or arithmetic coding. */
if (cinfo->arith_code) {
ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
} else {
if (cinfo->process == JPROC_PROGRESSIVE) {
#ifdef C_PROGRESSIVE_SUPPORTED
jinit_phuff_encoder(cinfo);
#else
ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif
} else
jinit_shuff_encoder(cinfo);
}
/* Need a full-image coefficient buffer in any multi-pass mode. */
jinit_c_coef_controller(cinfo,
(boolean) (cinfo->num_scans > 1 ||
cinfo->optimize_coding));
/* Initialize method pointers.
*
* Note: entropy_start_pass and entropy_finish_pass are assigned in
* jcshuff.c or jcphuff.c and compress_data is assigned in jccoefct.c.
*/
lossyc->pub.start_pass = start_pass;
}

View File

@@ -2,9 +2,10 @@
* jcmainct.c * jcmainct.c
* *
* This file was part of the Independent JPEG Group's software: * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1998, Thomas G. Lane. * Copyright (C) 1994-1996, Thomas G. Lane.
* Lossless JPEG Modifications: * Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison. * Copyright (C) 1999, Ken Murchison.
* Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains the main buffer controller for compression. * This file contains the main buffer controller for compression.
@@ -117,7 +118,7 @@ process_data_simple_main (j_compress_ptr cinfo,
JDIMENSION in_rows_avail) JDIMENSION in_rows_avail)
{ {
my_main_ptr main = (my_main_ptr) cinfo->main; my_main_ptr main = (my_main_ptr) cinfo->main;
int data_unit = cinfo->data_unit; int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
while (main->cur_iMCU_row < cinfo->total_iMCU_rows) { while (main->cur_iMCU_row < cinfo->total_iMCU_rows) {
/* Read input data if we haven't filled the main buffer yet */ /* Read input data if we haven't filled the main buffer yet */
@@ -135,7 +136,7 @@ process_data_simple_main (j_compress_ptr cinfo,
return; return;
/* Send the completed row to the compressor */ /* Send the completed row to the compressor */
if (! (*cinfo->codec->compress_data) (cinfo, main->buffer)) { if (! (*cinfo->coef->compress_data) (cinfo, main->buffer)) {
/* If compressor did not consume the whole row, then we must need to /* If compressor did not consume the whole row, then we must need to
* suspend processing and return to the application. In this situation * suspend processing and return to the application. In this situation
* we pretend we didn't yet consume the last input row; otherwise, if * we pretend we didn't yet consume the last input row; otherwise, if
@@ -177,7 +178,7 @@ process_data_buffer_main (j_compress_ptr cinfo,
int ci; int ci;
jpeg_component_info *compptr; jpeg_component_info *compptr;
boolean writing = (main->pass_mode != JBUF_CRANK_DEST); boolean writing = (main->pass_mode != JBUF_CRANK_DEST);
int data_unit = cinfo->data_unit; int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
while (main->cur_iMCU_row < cinfo->total_iMCU_rows) { while (main->cur_iMCU_row < cinfo->total_iMCU_rows) {
/* Realign the virtual buffers if at the start of an iMCU row. */ /* Realign the virtual buffers if at the start of an iMCU row. */
@@ -210,7 +211,7 @@ process_data_buffer_main (j_compress_ptr cinfo,
/* Emit data, unless this is a sink-only pass. */ /* Emit data, unless this is a sink-only pass. */
if (main->pass_mode != JBUF_SAVE_SOURCE) { if (main->pass_mode != JBUF_SAVE_SOURCE) {
if (! (*cinfo->codec->compress_data) (cinfo, main->buffer)) { if (! (*cinfo->coef->compress_data) (cinfo, main->buffer)) {
/* If compressor did not consume the whole row, then we must need to /* If compressor did not consume the whole row, then we must need to
* suspend processing and return to the application. In this situation * suspend processing and return to the application. In this situation
* we pretend we didn't yet consume the last input row; otherwise, if * we pretend we didn't yet consume the last input row; otherwise, if
@@ -251,7 +252,7 @@ jinit_c_main_controller (j_compress_ptr cinfo, boolean need_full_buffer)
my_main_ptr main; my_main_ptr main;
int ci; int ci;
jpeg_component_info *compptr; jpeg_component_info *compptr;
int data_unit = cinfo->data_unit; int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
main = (my_main_ptr) main = (my_main_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
@@ -274,8 +275,8 @@ jinit_c_main_controller (j_compress_ptr cinfo, boolean need_full_buffer)
ci++, compptr++) { ci++, compptr++) {
main->whole_image[ci] = (*cinfo->mem->request_virt_sarray) main->whole_image[ci] = (*cinfo->mem->request_virt_sarray)
((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
compptr->width_in_data_units * data_unit, compptr->width_in_blocks * data_unit,
(JDIMENSION) jround_up((long) compptr->height_in_data_units, (JDIMENSION) jround_up((long) compptr->height_in_blocks,
(long) compptr->v_samp_factor) * data_unit, (long) compptr->v_samp_factor) * data_unit,
(JDIMENSION) (compptr->v_samp_factor * data_unit)); (JDIMENSION) (compptr->v_samp_factor * data_unit));
} }
@@ -291,7 +292,7 @@ jinit_c_main_controller (j_compress_ptr cinfo, boolean need_full_buffer)
ci++, compptr++) { ci++, compptr++) {
main->buffer[ci] = (*cinfo->mem->alloc_sarray) main->buffer[ci] = (*cinfo->mem->alloc_sarray)
((j_common_ptr) cinfo, JPOOL_IMAGE, ((j_common_ptr) cinfo, JPOOL_IMAGE,
compptr->width_in_data_units * data_unit, compptr->width_in_blocks * data_unit,
(JDIMENSION) (compptr->v_samp_factor * data_unit)); (JDIMENSION) (compptr->v_samp_factor * data_unit));
} }
} }

View File

@@ -5,6 +5,7 @@
* Copyright (C) 1991-1998, Thomas G. Lane. * Copyright (C) 1991-1998, Thomas G. Lane.
* Lossless JPEG Modifications: * Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison. * Copyright (C) 1999, Ken Murchison.
* Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains routines to write JPEG datastream markers. * This file contains routines to write JPEG datastream markers.
@@ -324,7 +325,7 @@ emit_sos (j_compress_ptr cinfo)
emit_byte(cinfo, compptr->component_id); emit_byte(cinfo, compptr->component_id);
td = compptr->dc_tbl_no; td = compptr->dc_tbl_no;
ta = compptr->ac_tbl_no; ta = compptr->ac_tbl_no;
if (cinfo->process == JPROC_PROGRESSIVE) { if (cinfo->progressive_mode) {
/* Progressive mode: only DC or only AC tables are used in one scan; /* Progressive mode: only DC or only AC tables are used in one scan;
* furthermore, Huffman coding of DC refinement uses no table at all. * furthermore, Huffman coding of DC refinement uses no table at all.
* We emit 0 for unused field(s); this is recommended by the P&M text * We emit 0 for unused field(s); this is recommended by the P&M text
@@ -495,15 +496,14 @@ write_file_header (j_compress_ptr cinfo)
METHODDEF(void) METHODDEF(void)
write_frame_header (j_compress_ptr cinfo) write_frame_header (j_compress_ptr cinfo)
{ {
int ci, prec; int ci, prec = 0;
boolean is_baseline; boolean is_baseline;
jpeg_component_info *compptr; jpeg_component_info *compptr;
if (cinfo->process != JPROC_LOSSLESS) { if (! cinfo->master->lossless) {
/* Emit DQT for each quantization table. /* Emit DQT for each quantization table.
* Note that emit_dqt() suppresses any duplicate tables. * Note that emit_dqt() suppresses any duplicate tables.
*/ */
prec = 0;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) { ci++, compptr++) {
prec += emit_dqt(cinfo, compptr->quant_tbl_no); prec += emit_dqt(cinfo, compptr->quant_tbl_no);
@@ -514,8 +514,8 @@ write_frame_header (j_compress_ptr cinfo)
/* Check for a non-baseline specification. /* Check for a non-baseline specification.
* Note we assume that Huffman table numbers won't be changed later. * Note we assume that Huffman table numbers won't be changed later.
*/ */
if (cinfo->arith_code || cinfo->process != JPROC_SEQUENTIAL || if (cinfo->arith_code || cinfo->progressive_mode ||
cinfo->data_precision != 8) { cinfo->master->lossless || cinfo->data_precision != 8) {
is_baseline = FALSE; is_baseline = FALSE;
} else { } else {
is_baseline = TRUE; is_baseline = TRUE;
@@ -535,9 +535,9 @@ write_frame_header (j_compress_ptr cinfo)
if (cinfo->arith_code) { if (cinfo->arith_code) {
emit_sof(cinfo, M_SOF9); /* SOF code for arithmetic coding */ emit_sof(cinfo, M_SOF9); /* SOF code for arithmetic coding */
} else { } else {
if (cinfo->process == JPROC_PROGRESSIVE) if (cinfo->progressive_mode)
emit_sof(cinfo, M_SOF2); /* SOF code for progressive Huffman */ emit_sof(cinfo, M_SOF2); /* SOF code for progressive Huffman */
else if (cinfo->process == JPROC_LOSSLESS) else if (cinfo->master->lossless)
emit_sof(cinfo, M_SOF3); /* SOF code for lossless Huffman */ emit_sof(cinfo, M_SOF3); /* SOF code for lossless Huffman */
else if (is_baseline) else if (is_baseline)
emit_sof(cinfo, M_SOF0); /* SOF code for baseline implementation */ emit_sof(cinfo, M_SOF0); /* SOF code for baseline implementation */
@@ -572,7 +572,7 @@ write_scan_header (j_compress_ptr cinfo)
*/ */
for (i = 0; i < cinfo->comps_in_scan; i++) { for (i = 0; i < cinfo->comps_in_scan; i++) {
compptr = cinfo->cur_comp_info[i]; compptr = cinfo->cur_comp_info[i];
if (cinfo->process == JPROC_PROGRESSIVE) { if (cinfo->progressive_mode) {
/* Progressive mode: only DC or only AC tables are used in one scan */ /* Progressive mode: only DC or only AC tables are used in one scan */
if (cinfo->Ss == 0) { if (cinfo->Ss == 0) {
if (cinfo->Ah == 0) /* DC needs no table for refinement scan */ if (cinfo->Ah == 0) /* DC needs no table for refinement scan */
@@ -580,7 +580,7 @@ write_scan_header (j_compress_ptr cinfo)
} else { } else {
emit_dht(cinfo, compptr->ac_tbl_no, TRUE); emit_dht(cinfo, compptr->ac_tbl_no, TRUE);
} }
} else if (cinfo->process == JPROC_LOSSLESS) { } else if (cinfo->master->lossless) {
/* Lossless mode: only DC tables are used */ /* Lossless mode: only DC tables are used */
emit_dht(cinfo, compptr->dc_tbl_no, FALSE); emit_dht(cinfo, compptr->dc_tbl_no, FALSE);
} else { } else {

View File

@@ -2,9 +2,10 @@
* jcmaster.c * jcmaster.c
* *
* This file was part of the Independent JPEG Group's software: * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1998, Thomas G. Lane. * Copyright (C) 1991-1997, Thomas G. Lane.
* Lossless JPEG Modifications: * Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison. * Copyright (C) 1999, Ken Murchison.
* Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains master control logic for the JPEG compressor. * This file contains master control logic for the JPEG compressor.
@@ -16,29 +17,7 @@
#define JPEG_INTERNALS #define JPEG_INTERNALS
#include "jinclude.h" #include "jinclude.h"
#include "jpeglib.h" #include "jpeglib.h"
#include "jlossy.h" /* Private declarations for lossy codec */ #include "jcmaster.h"
/* Private state */
typedef enum {
main_pass, /* input data, also do first output step */
huff_opt_pass, /* Huffman code optimization pass */
output_pass /* data output pass */
} c_pass_type;
typedef struct {
struct jpeg_comp_master pub; /* public fields */
c_pass_type pass_type; /* the type of the current pass */
int pass_number; /* # of passes completed */
int total_passes; /* total # of passes needed */
int scan_number; /* current index in scan_info[] */
} my_comp_master;
typedef my_comp_master * my_master_ptr;
/* /*
@@ -53,7 +32,7 @@ initial_setup (j_compress_ptr cinfo)
jpeg_component_info *compptr; jpeg_component_info *compptr;
long samplesperrow; long samplesperrow;
JDIMENSION jd_samplesperrow; JDIMENSION jd_samplesperrow;
int data_unit = cinfo->data_unit; int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
/* Sanity check on image dimensions */ /* Sanity check on image dimensions */
if (cinfo->image_height <= 0 || cinfo->image_width <= 0 if (cinfo->image_height <= 0 || cinfo->image_width <= 0
@@ -99,13 +78,13 @@ initial_setup (j_compress_ptr cinfo)
ci++, compptr++) { ci++, compptr++) {
/* Fill in the correct component_index value; don't rely on application */ /* Fill in the correct component_index value; don't rely on application */
compptr->component_index = ci; compptr->component_index = ci;
/* For compression, we never do any codec-based processing. */ /* For compression, we never do DCT scaling. */
compptr->codec_data_unit = data_unit; compptr->DCT_scaled_size = data_unit;
/* Size in data units */ /* Size in data units */
compptr->width_in_data_units = (JDIMENSION) compptr->width_in_blocks = (JDIMENSION)
jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor, jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor,
(long) (cinfo->max_h_samp_factor * data_unit)); (long) (cinfo->max_h_samp_factor * data_unit));
compptr->height_in_data_units = (JDIMENSION) compptr->height_in_blocks = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor, jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor,
(long) (cinfo->max_v_samp_factor * data_unit)); (long) (cinfo->max_v_samp_factor * data_unit));
/* Size in samples */ /* Size in samples */
@@ -120,19 +99,16 @@ initial_setup (j_compress_ptr cinfo)
} }
/* Compute number of fully interleaved MCU rows (number of times that /* Compute number of fully interleaved MCU rows (number of times that
* main controller will call coefficient controller). * main controller will call coefficient or difference controller).
*/ */
cinfo->total_iMCU_rows = (JDIMENSION) cinfo->total_iMCU_rows = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height, jdiv_round_up((long) cinfo->image_height,
(long) (cinfo->max_v_samp_factor*data_unit)); (long) (cinfo->max_v_samp_factor*data_unit));
} }
#ifdef C_MULTISCAN_FILES_SUPPORTED
#if defined(C_MULTISCAN_FILES_SUPPORTED) || defined(C_LOSSLESS_SUPPORTED)
#define NEED_SCAN_SCRIPT #define NEED_SCAN_SCRIPT
#else
#ifdef C_LOSSLESS_SUPPORTED
#define NEED_SCAN_SCRIPT
#endif
#endif #endif
#ifdef NEED_SCAN_SCRIPT #ifdef NEED_SCAN_SCRIPT
@@ -140,7 +116,7 @@ initial_setup (j_compress_ptr cinfo)
LOCAL(void) LOCAL(void)
validate_script (j_compress_ptr cinfo) validate_script (j_compress_ptr cinfo)
/* Verify that the scan script in cinfo->scan_info[] is valid; also /* Verify that the scan script in cinfo->scan_info[] is valid; also
* determine whether it uses progressive JPEG, and set cinfo->process. * determine whether it uses progressive JPEG, and set cinfo->progressive_mode.
*/ */
{ {
const jpeg_scan_info * scanptr; const jpeg_scan_info * scanptr;
@@ -162,9 +138,10 @@ validate_script (j_compress_ptr cinfo)
#endif #endif
scanptr = cinfo->scan_info; scanptr = cinfo->scan_info;
if (cinfo->lossless) { if (scanptr->Ss != 0 && scanptr->Se == 0) {
#ifdef C_LOSSLESS_SUPPORTED #ifdef C_LOSSLESS_SUPPORTED
cinfo->process = JPROC_LOSSLESS; cinfo->master->lossless = TRUE;
cinfo->progressive_mode = FALSE;
for (ci = 0; ci < cinfo->num_components; ci++) for (ci = 0; ci < cinfo->num_components; ci++)
component_sent[ci] = FALSE; component_sent[ci] = FALSE;
#else #else
@@ -176,7 +153,8 @@ validate_script (j_compress_ptr cinfo)
*/ */
else if (scanptr->Ss != 0 || scanptr->Se != DCTSIZE2-1) { else if (scanptr->Ss != 0 || scanptr->Se != DCTSIZE2-1) {
#ifdef C_PROGRESSIVE_SUPPORTED #ifdef C_PROGRESSIVE_SUPPORTED
cinfo->process = JPROC_PROGRESSIVE; cinfo->progressive_mode = TRUE;
cinfo->master->lossless = FALSE;
last_bitpos_ptr = & last_bitpos[0][0]; last_bitpos_ptr = & last_bitpos[0][0];
for (ci = 0; ci < cinfo->num_components; ci++) for (ci = 0; ci < cinfo->num_components; ci++)
for (coefi = 0; coefi < DCTSIZE2; coefi++) for (coefi = 0; coefi < DCTSIZE2; coefi++)
@@ -185,7 +163,7 @@ validate_script (j_compress_ptr cinfo)
ERREXIT(cinfo, JERR_NOT_COMPILED); ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif #endif
} else { } else {
cinfo->process = JPROC_SEQUENTIAL; cinfo->progressive_mode = cinfo->master->lossless = FALSE;
for (ci = 0; ci < cinfo->num_components; ci++) for (ci = 0; ci < cinfo->num_components; ci++)
component_sent[ci] = FALSE; component_sent[ci] = FALSE;
} }
@@ -208,26 +186,7 @@ validate_script (j_compress_ptr cinfo)
Se = scanptr->Se; Se = scanptr->Se;
Ah = scanptr->Ah; Ah = scanptr->Ah;
Al = scanptr->Al; Al = scanptr->Al;
if (cinfo->process == JPROC_LOSSLESS) { if (cinfo->progressive_mode) {
#ifdef C_LOSSLESS_SUPPORTED
/* The JPEG spec simply gives the range 0..15 for Al (Pt), but that
* seems wrong: the upper bound ought to depend on data precision.
* Perhaps they really meant 0..N-1 for N-bit precision, which is what
* we allow here.
*/
if (Ss < 1 || Ss > 7 || /* predictor selector */
Se != 0 || Ah != 0 ||
Al < 0 || Al >= cinfo->data_precision) /* point transform */
ERREXIT1(cinfo, JERR_BAD_LOSSLESS_SCRIPT, scanno);
/* Make sure components are not sent twice */
for (ci = 0; ci < ncomps; ci++) {
thisi = scanptr->component_index[ci];
if (component_sent[thisi])
ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno);
component_sent[thisi] = TRUE;
}
#endif
} else if (cinfo->process == JPROC_PROGRESSIVE) {
#ifdef C_PROGRESSIVE_SUPPORTED #ifdef C_PROGRESSIVE_SUPPORTED
/* The JPEG spec simply gives the ranges 0..13 for Ah and Al, but that /* The JPEG spec simply gives the ranges 0..13 for Ah and Al, but that
* seems wrong: the upper bound ought to depend on data precision. * seems wrong: the upper bound ought to depend on data precision.
@@ -270,9 +229,25 @@ validate_script (j_compress_ptr cinfo)
} }
#endif #endif
} else { } else {
#ifdef C_LOSSLESS_SUPPORTED
if (cinfo->master->lossless) {
/* The JPEG spec simply gives the range 0..15 for Al (Pt), but that
* seems wrong: the upper bound ought to depend on data precision.
* Perhaps they really meant 0..N-1 for N-bit precision, which is what
* we allow here. Values greater than or equal to the data precision
* will result in a blank image.
*/
if (Ss < 1 || Ss > 7 || /* predictor selection value */
Se != 0 || Ah != 0 ||
Al < 0 || Al >= cinfo->data_precision) /* point transform */
ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
} else
#endif
{
/* For sequential JPEG, all progression parameters must be these: */ /* For sequential JPEG, all progression parameters must be these: */
if (Ss != 0 || Se != DCTSIZE2-1 || Ah != 0 || Al != 0) if (Ss != 0 || Se != DCTSIZE2-1 || Ah != 0 || Al != 0)
ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
}
/* Make sure components are not sent twice */ /* Make sure components are not sent twice */
for (ci = 0; ci < ncomps; ci++) { for (ci = 0; ci < ncomps; ci++) {
thisi = scanptr->component_index[ci]; thisi = scanptr->component_index[ci];
@@ -284,7 +259,7 @@ validate_script (j_compress_ptr cinfo)
} }
/* Now verify that everything got sent. */ /* Now verify that everything got sent. */
if (cinfo->process == JPROC_PROGRESSIVE) { if (cinfo->progressive_mode) {
#ifdef C_PROGRESSIVE_SUPPORTED #ifdef C_PROGRESSIVE_SUPPORTED
/* For progressive mode, we only check that at least some DC data /* For progressive mode, we only check that at least some DC data
* got sent for each component; the spec does not require that all bits * got sent for each component; the spec does not require that all bits
@@ -339,15 +314,7 @@ select_scan_parameters (j_compress_ptr cinfo)
for (ci = 0; ci < cinfo->num_components; ci++) { for (ci = 0; ci < cinfo->num_components; ci++) {
cinfo->cur_comp_info[ci] = &cinfo->comp_info[ci]; cinfo->cur_comp_info[ci] = &cinfo->comp_info[ci];
} }
if (cinfo->lossless) { if (! cinfo->master->lossless) {
#ifdef C_LOSSLESS_SUPPORTED
/* If we fall through to here, the user specified lossless, but did not
* provide a scan script.
*/
ERREXIT(cinfo, JERR_NO_LOSSLESS_SCRIPT);
#endif
} else {
cinfo->process = JPROC_SEQUENTIAL;
cinfo->Ss = 0; cinfo->Ss = 0;
cinfo->Se = DCTSIZE2-1; cinfo->Se = DCTSIZE2-1;
cinfo->Ah = 0; cinfo->Ah = 0;
@@ -364,7 +331,7 @@ per_scan_setup (j_compress_ptr cinfo)
{ {
int ci, mcublks, tmp; int ci, mcublks, tmp;
jpeg_component_info *compptr; jpeg_component_info *compptr;
int data_unit = cinfo->data_unit; int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
if (cinfo->comps_in_scan == 1) { if (cinfo->comps_in_scan == 1) {
@@ -372,24 +339,24 @@ per_scan_setup (j_compress_ptr cinfo)
compptr = cinfo->cur_comp_info[0]; compptr = cinfo->cur_comp_info[0];
/* Overall image size in MCUs */ /* Overall image size in MCUs */
cinfo->MCUs_per_row = compptr->width_in_data_units; cinfo->MCUs_per_row = compptr->width_in_blocks;
cinfo->MCU_rows_in_scan = compptr->height_in_data_units; cinfo->MCU_rows_in_scan = compptr->height_in_blocks;
/* For noninterleaved scan, always one block per MCU */ /* For noninterleaved scan, always one block per MCU */
compptr->MCU_width = 1; compptr->MCU_width = 1;
compptr->MCU_height = 1; compptr->MCU_height = 1;
compptr->MCU_data_units = 1; compptr->MCU_blocks = 1;
compptr->MCU_sample_width = data_unit; compptr->MCU_sample_width = data_unit;
compptr->last_col_width = 1; compptr->last_col_width = 1;
/* For noninterleaved scans, it is convenient to define last_row_height /* For noninterleaved scans, it is convenient to define last_row_height
* as the number of block rows present in the last iMCU row. * as the number of block rows present in the last iMCU row.
*/ */
tmp = (int) (compptr->height_in_data_units % compptr->v_samp_factor); tmp = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
if (tmp == 0) tmp = compptr->v_samp_factor; if (tmp == 0) tmp = compptr->v_samp_factor;
compptr->last_row_height = tmp; compptr->last_row_height = tmp;
/* Prepare array describing MCU composition */ /* Prepare array describing MCU composition */
cinfo->data_units_in_MCU = 1; cinfo->blocks_in_MCU = 1;
cinfo->MCU_membership[0] = 0; cinfo->MCU_membership[0] = 0;
} else { } else {
@@ -407,28 +374,28 @@ per_scan_setup (j_compress_ptr cinfo)
jdiv_round_up((long) cinfo->image_height, jdiv_round_up((long) cinfo->image_height,
(long) (cinfo->max_v_samp_factor*data_unit)); (long) (cinfo->max_v_samp_factor*data_unit));
cinfo->data_units_in_MCU = 0; cinfo->blocks_in_MCU = 0;
for (ci = 0; ci < cinfo->comps_in_scan; ci++) { for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci]; compptr = cinfo->cur_comp_info[ci];
/* Sampling factors give # of blocks of component in each MCU */ /* Sampling factors give # of blocks of component in each MCU */
compptr->MCU_width = compptr->h_samp_factor; compptr->MCU_width = compptr->h_samp_factor;
compptr->MCU_height = compptr->v_samp_factor; compptr->MCU_height = compptr->v_samp_factor;
compptr->MCU_data_units = compptr->MCU_width * compptr->MCU_height; compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height;
compptr->MCU_sample_width = compptr->MCU_width * data_unit; compptr->MCU_sample_width = compptr->MCU_width * data_unit;
/* Figure number of non-dummy blocks in last MCU column & row */ /* Figure number of non-dummy blocks in last MCU column & row */
tmp = (int) (compptr->width_in_data_units % compptr->MCU_width); tmp = (int) (compptr->width_in_blocks % compptr->MCU_width);
if (tmp == 0) tmp = compptr->MCU_width; if (tmp == 0) tmp = compptr->MCU_width;
compptr->last_col_width = tmp; compptr->last_col_width = tmp;
tmp = (int) (compptr->height_in_data_units % compptr->MCU_height); tmp = (int) (compptr->height_in_blocks % compptr->MCU_height);
if (tmp == 0) tmp = compptr->MCU_height; if (tmp == 0) tmp = compptr->MCU_height;
compptr->last_row_height = tmp; compptr->last_row_height = tmp;
/* Prepare array describing MCU composition */ /* Prepare array describing MCU composition */
mcublks = compptr->MCU_data_units; mcublks = compptr->MCU_blocks;
if (cinfo->data_units_in_MCU + mcublks > C_MAX_DATA_UNITS_IN_MCU) if (cinfo->blocks_in_MCU + mcublks > C_MAX_BLOCKS_IN_MCU)
ERREXIT(cinfo, JERR_BAD_MCU_SIZE); ERREXIT(cinfo, JERR_BAD_MCU_SIZE);
while (mcublks-- > 0) { while (mcublks-- > 0) {
cinfo->MCU_membership[cinfo->data_units_in_MCU++] = ci; cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci;
} }
} }
@@ -454,7 +421,6 @@ per_scan_setup (j_compress_ptr cinfo)
METHODDEF(void) METHODDEF(void)
prepare_for_pass (j_compress_ptr cinfo) prepare_for_pass (j_compress_ptr cinfo)
{ {
j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec;
my_master_ptr master = (my_master_ptr) cinfo->master; my_master_ptr master = (my_master_ptr) cinfo->master;
switch (master->pass_type) { switch (master->pass_type) {
@@ -469,8 +435,9 @@ prepare_for_pass (j_compress_ptr cinfo)
(*cinfo->downsample->start_pass) (cinfo); (*cinfo->downsample->start_pass) (cinfo);
(*cinfo->prep->start_pass) (cinfo, JBUF_PASS_THRU); (*cinfo->prep->start_pass) (cinfo, JBUF_PASS_THRU);
} }
(*cinfo->codec->entropy_start_pass) (cinfo, cinfo->optimize_coding); (*cinfo->fdct->start_pass) (cinfo);
(*cinfo->codec->start_pass) (cinfo, (*cinfo->entropy->start_pass) (cinfo, cinfo->optimize_coding);
(*cinfo->coef->start_pass) (cinfo,
(master->total_passes > 1 ? (master->total_passes > 1 ?
JBUF_SAVE_AND_PASS : JBUF_PASS_THRU)); JBUF_SAVE_AND_PASS : JBUF_PASS_THRU));
(*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU); (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU);
@@ -487,9 +454,10 @@ prepare_for_pass (j_compress_ptr cinfo)
/* Do Huffman optimization for a scan after the first one. */ /* Do Huffman optimization for a scan after the first one. */
select_scan_parameters(cinfo); select_scan_parameters(cinfo);
per_scan_setup(cinfo); per_scan_setup(cinfo);
if ((*cinfo->codec->need_optimization_pass) (cinfo) || cinfo->arith_code) { if (cinfo->Ss != 0 || cinfo->Ah == 0 || cinfo->arith_code ||
(*cinfo->codec->entropy_start_pass) (cinfo, TRUE); cinfo->master->lossless) {
(*cinfo->codec->start_pass) (cinfo, JBUF_CRANK_DEST); (*cinfo->entropy->start_pass) (cinfo, TRUE);
(*cinfo->coef->start_pass) (cinfo, JBUF_CRANK_DEST);
master->pub.call_pass_startup = FALSE; master->pub.call_pass_startup = FALSE;
break; break;
} }
@@ -507,8 +475,8 @@ prepare_for_pass (j_compress_ptr cinfo)
select_scan_parameters(cinfo); select_scan_parameters(cinfo);
per_scan_setup(cinfo); per_scan_setup(cinfo);
} }
(*cinfo->codec->entropy_start_pass) (cinfo, FALSE); (*cinfo->entropy->start_pass) (cinfo, FALSE);
(*cinfo->codec->start_pass) (cinfo, JBUF_CRANK_DEST); (*cinfo->coef->start_pass) (cinfo, JBUF_CRANK_DEST);
/* We emit frame/scan headers now */ /* We emit frame/scan headers now */
if (master->scan_number == 0) if (master->scan_number == 0)
(*cinfo->marker->write_frame_header) (cinfo); (*cinfo->marker->write_frame_header) (cinfo);
@@ -556,13 +524,12 @@ pass_startup (j_compress_ptr cinfo)
METHODDEF(void) METHODDEF(void)
finish_pass_master (j_compress_ptr cinfo) finish_pass_master (j_compress_ptr cinfo)
{ {
j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec;
my_master_ptr master = (my_master_ptr) cinfo->master; my_master_ptr master = (my_master_ptr) cinfo->master;
/* The entropy coder always needs an end-of-pass call, /* The entropy coder always needs an end-of-pass call,
* either to analyze statistics or to flush its output buffer. * either to analyze statistics or to flush its output buffer.
*/ */
(*lossyc->pub.entropy_finish_pass) (cinfo); (*cinfo->entropy->finish_pass) (cinfo);
/* Update state for next pass */ /* Update state for next pass */
switch (master->pass_type) { switch (master->pass_type) {
@@ -597,22 +564,13 @@ finish_pass_master (j_compress_ptr cinfo)
GLOBAL(void) GLOBAL(void)
jinit_c_master_control (j_compress_ptr cinfo, boolean transcode_only) jinit_c_master_control (j_compress_ptr cinfo, boolean transcode_only)
{ {
my_master_ptr master; my_master_ptr master = (my_master_ptr) cinfo->master;
master = (my_master_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(my_comp_master));
cinfo->master = (struct jpeg_comp_master *) master;
master->pub.prepare_for_pass = prepare_for_pass; master->pub.prepare_for_pass = prepare_for_pass;
master->pub.pass_startup = pass_startup; master->pub.pass_startup = pass_startup;
master->pub.finish_pass = finish_pass_master; master->pub.finish_pass = finish_pass_master;
master->pub.is_last_pass = FALSE; master->pub.is_last_pass = FALSE;
cinfo->data_unit = cinfo->lossless ? 1 : DCTSIZE;
/* Validate parameters, determine derived values */
initial_setup(cinfo);
if (cinfo->scan_info != NULL) { if (cinfo->scan_info != NULL) {
#ifdef NEED_SCAN_SCRIPT #ifdef NEED_SCAN_SCRIPT
validate_script(cinfo); validate_script(cinfo);
@@ -620,12 +578,32 @@ jinit_c_master_control (j_compress_ptr cinfo, boolean transcode_only)
ERREXIT(cinfo, JERR_NOT_COMPILED); ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif #endif
} else { } else {
cinfo->process = JPROC_SEQUENTIAL; cinfo->progressive_mode = FALSE;
cinfo->num_scans = 1; cinfo->num_scans = 1;
} }
if (cinfo->process == JPROC_PROGRESSIVE || /* TEMPORARY HACK ??? */ /* Disable smoothing and subsampling in lossless mode, since those are lossy
cinfo->process == JPROC_LOSSLESS) * algorithms. Set the JPEG colorspace to the input colorspace. Disable raw
* (downsampled) data input, because it isn't particularly useful without
* subsampling and has not been tested in lossless mode.
*/
if (cinfo->master->lossless) {
int ci;
jpeg_component_info * compptr;
cinfo->raw_data_in = FALSE;
cinfo->smoothing_factor = 0;
jpeg_default_colorspace(cinfo);
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++)
compptr->h_samp_factor = compptr->v_samp_factor = 1;
}
/* Validate parameters, determine derived values */
initial_setup(cinfo);
if (cinfo->progressive_mode || /* TEMPORARY HACK ??? */
cinfo->master->lossless)
cinfo->optimize_coding = TRUE; /* assume default tables no good for cinfo->optimize_coding = TRUE; /* assume default tables no good for
* progressive mode or lossless mode */ * progressive mode or lossless mode */

30
jcmaster.h Normal file
View File

@@ -0,0 +1,30 @@
/*
* jcmaster.h
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1995, Thomas G. Lane.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains master control structure for the JPEG compressor.
*/
/* Private state */
typedef enum {
main_pass, /* input data, also do first output step */
huff_opt_pass, /* Huffman code optimization pass */
output_pass /* data output pass */
} c_pass_type;
typedef struct {
struct jpeg_comp_master pub; /* public fields */
c_pass_type pass_type; /* the type of the current pass */
int pass_number; /* # of passes completed */
int total_passes; /* total # of passes needed */
int scan_number; /* current index in scan_info[] */
} my_comp_master;
typedef my_comp_master * my_master_ptr;

View File

@@ -1,55 +0,0 @@
/*
* jcodec.c
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1998, Thomas G. Lane.
* Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains utility functions for the JPEG codec(s).
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
#include "jlossy.h"
#include "jlossls.h"
/*
* Initialize the compression codec.
* This is called only once, during master selection.
*/
GLOBAL(void)
jinit_c_codec (j_compress_ptr cinfo)
{
if (cinfo->process == JPROC_LOSSLESS) {
#ifdef C_LOSSLESS_SUPPORTED
jinit_lossless_c_codec(cinfo);
#else
ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif
} else
jinit_lossy_c_codec(cinfo);
}
/*
* Initialize the decompression codec.
* This is called only once, during master selection.
*/
GLOBAL(void)
jinit_d_codec (j_decompress_ptr cinfo)
{
if (cinfo->process == JPROC_LOSSLESS) {
#ifdef D_LOSSLESS_SUPPORTED
jinit_lossless_d_codec(cinfo);
#else
ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif
} else
jinit_lossy_d_codec(cinfo);
}

115
jcparam.c
View File

@@ -5,6 +5,7 @@
* Copyright (C) 1991-1998, Thomas G. Lane. * Copyright (C) 1991-1998, Thomas G. Lane.
* Lossless JPEG Modifications: * Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison. * Copyright (C) 1999, Ken Murchison.
* Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains optional default-setting code for the JPEG compressor. * This file contains optional default-setting code for the JPEG compressor.
@@ -286,7 +287,6 @@ jpeg_set_defaults (j_compress_ptr cinfo)
/* Initialize everything not dependent on the color space */ /* Initialize everything not dependent on the color space */
cinfo->lossless = FALSE;
cinfo->data_precision = BITS_IN_JSAMPLE; cinfo->data_precision = BITS_IN_JSAMPLE;
/* Set up two quantization tables using default quality of 75 */ /* Set up two quantization tables using default quality of 75 */
jpeg_set_quality(cinfo, 75, TRUE); jpeg_set_quality(cinfo, 75, TRUE);
@@ -361,14 +361,14 @@ jpeg_set_defaults (j_compress_ptr cinfo)
GLOBAL(void) GLOBAL(void)
jpeg_default_colorspace (j_compress_ptr cinfo) jpeg_default_colorspace (j_compress_ptr cinfo)
{ {
if (cinfo->lossless)
jpeg_set_colorspace(cinfo, cinfo->in_color_space);
else { /* lossy */
switch (cinfo->in_color_space) { switch (cinfo->in_color_space) {
case JCS_GRAYSCALE: case JCS_GRAYSCALE:
jpeg_set_colorspace(cinfo, JCS_GRAYSCALE); jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
break; break;
case JCS_RGB: case JCS_RGB:
if (cinfo->master->lossless)
jpeg_set_colorspace(cinfo, JCS_RGB);
else
jpeg_set_colorspace(cinfo, JCS_YCbCr); jpeg_set_colorspace(cinfo, JCS_YCbCr);
break; break;
case JCS_YCbCr: case JCS_YCbCr:
@@ -386,7 +386,6 @@ jpeg_default_colorspace (j_compress_ptr cinfo)
default: default:
ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
} }
}
} }
@@ -440,16 +439,10 @@ jpeg_set_colorspace (j_compress_ptr cinfo, J_COLOR_SPACE colorspace)
cinfo->write_JFIF_header = TRUE; /* Write a JFIF marker */ cinfo->write_JFIF_header = TRUE; /* Write a JFIF marker */
cinfo->num_components = 3; cinfo->num_components = 3;
/* JFIF specifies component IDs 1,2,3 */ /* JFIF specifies component IDs 1,2,3 */
if (cinfo->lossless) {
SET_COMP(0, 1, 1,1, 0, 0,0);
SET_COMP(1, 2, 1,1, 1, 1,1);
SET_COMP(2, 3, 1,1, 1, 1,1);
} else { /* lossy */
/* We default to 2x2 subsamples of chrominance */ /* We default to 2x2 subsamples of chrominance */
SET_COMP(0, 1, 2,2, 0, 0,0); SET_COMP(0, 1, 2,2, 0, 0,0);
SET_COMP(1, 2, 1,1, 1, 1,1); SET_COMP(1, 2, 1,1, 1, 1,1);
SET_COMP(2, 3, 1,1, 1, 1,1); SET_COMP(2, 3, 1,1, 1, 1,1);
}
break; break;
case JCS_CMYK: case JCS_CMYK:
cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag CMYK */ cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag CMYK */
@@ -462,17 +455,10 @@ jpeg_set_colorspace (j_compress_ptr cinfo, J_COLOR_SPACE colorspace)
case JCS_YCCK: case JCS_YCCK:
cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag YCCK */ cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag YCCK */
cinfo->num_components = 4; cinfo->num_components = 4;
if (cinfo->lossless) {
SET_COMP(0, 1, 1,1, 0, 0,0);
SET_COMP(1, 2, 1,1, 1, 1,1);
SET_COMP(2, 3, 1,1, 1, 1,1);
SET_COMP(3, 4, 1,1, 0, 0,0);
} else { /* lossy */
SET_COMP(0, 1, 2,2, 0, 0,0); SET_COMP(0, 1, 2,2, 0, 0,0);
SET_COMP(1, 2, 1,1, 1, 1,1); SET_COMP(1, 2, 1,1, 1, 1,1);
SET_COMP(2, 3, 1,1, 1, 1,1); SET_COMP(2, 3, 1,1, 1, 1,1);
SET_COMP(3, 4, 2,2, 0, 0,0); SET_COMP(3, 4, 2,2, 0, 0,0);
}
break; break;
case JCS_UNKNOWN: case JCS_UNKNOWN:
cinfo->num_components = cinfo->input_components; cinfo->num_components = cinfo->input_components;
@@ -491,6 +477,21 @@ jpeg_set_colorspace (j_compress_ptr cinfo, J_COLOR_SPACE colorspace)
#ifdef C_PROGRESSIVE_SUPPORTED #ifdef C_PROGRESSIVE_SUPPORTED
LOCAL(jpeg_scan_info *)
fill_a_scan (jpeg_scan_info * scanptr, int ci,
int Ss, int Se, int Ah, int Al)
/* Support routine: generate one scan for specified component */
{
scanptr->comps_in_scan = 1;
scanptr->component_index[0] = ci;
scanptr->Ss = Ss;
scanptr->Se = Se;
scanptr->Ah = Ah;
scanptr->Al = Al;
scanptr++;
return scanptr;
}
LOCAL(jpeg_scan_info *) LOCAL(jpeg_scan_info *)
fill_scans (jpeg_scan_info * scanptr, int ncomps, fill_scans (jpeg_scan_info * scanptr, int ncomps,
int Ss, int Se, int Ah, int Al) int Ss, int Se, int Ah, int Al)
@@ -510,22 +511,6 @@ fill_scans (jpeg_scan_info * scanptr, int ncomps,
return scanptr; return scanptr;
} }
LOCAL(jpeg_scan_info *)
fill_a_scan (jpeg_scan_info * scanptr, int ci,
int Ss, int Se, int Ah, int Al)
/* Support routine: generate one scan for specified component */
{
scanptr->comps_in_scan = 1;
scanptr->component_index[0] = ci;
scanptr->Ss = Ss;
scanptr->Se = Se;
scanptr->Ah = Ah;
scanptr->Al = Al;
scanptr++;
return scanptr;
}
LOCAL(jpeg_scan_info *) LOCAL(jpeg_scan_info *)
fill_dc_scans (jpeg_scan_info * scanptr, int ncomps, int Ah, int Al) fill_dc_scans (jpeg_scan_info * scanptr, int ncomps, int Ah, int Al)
/* Support routine: generate interleaved DC scan if possible, else N scans */ /* Support routine: generate interleaved DC scan if possible, else N scans */
@@ -565,6 +550,11 @@ jpeg_simple_progression (j_compress_ptr cinfo)
if (cinfo->global_state != CSTATE_START) if (cinfo->global_state != CSTATE_START)
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
if (cinfo->master->lossless) {
cinfo->master->lossless = FALSE;
jpeg_default_colorspace(cinfo);
}
/* Figure space needed for script. Calculation must match code below! */ /* Figure space needed for script. Calculation must match code below! */
if (ncomps == 3 && cinfo->jpeg_color_space == JCS_YCbCr) { if (ncomps == 3 && cinfo->jpeg_color_space == JCS_YCbCr) {
/* Custom script for YCbCr color images. */ /* Custom script for YCbCr color images. */
@@ -634,56 +624,33 @@ jpeg_simple_progression (j_compress_ptr cinfo)
#ifdef C_LOSSLESS_SUPPORTED #ifdef C_LOSSLESS_SUPPORTED
/* /*
* Create a single-entry lossless-JPEG script containing all components. * Enable lossless mode.
* cinfo->num_components must be correct.
*/ */
GLOBAL(void) GLOBAL(void)
jpeg_simple_lossless (j_compress_ptr cinfo, int predictor, int point_transform) jpeg_enable_lossless (j_compress_ptr cinfo, int predictor_selection_value,
int point_transform)
{ {
int ncomps = cinfo->num_components;
int nscans = 1;
int ci;
jpeg_scan_info * scanptr;
/* Safety check to ensure start_compress not called yet. */ /* Safety check to ensure start_compress not called yet. */
if (cinfo->global_state != CSTATE_START) if (cinfo->global_state != CSTATE_START)
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
cinfo->lossless = TRUE; cinfo->master->lossless = TRUE;
cinfo->Ss = predictor_selection_value;
cinfo->Se = 0;
cinfo->Ah = 0;
cinfo->Al = point_transform;
/* Set jpeg_color_space. */ /* The JPEG spec simply gives the range 0..15 for Al (Pt), but that seems
jpeg_default_colorspace(cinfo); * wrong: the upper bound ought to depend on data precision. Perhaps they
* really meant 0..N-1 for N-bit precision, which is what we allow here.
/* Check to ensure that all components will fit in one scan. */ * Values greater than or equal to the data precision will result in a blank
if (cinfo->num_components > MAX_COMPS_IN_SCAN) * image.
ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components,
MAX_COMPS_IN_SCAN);
/* Allocate space for script.
* We need to put it in the permanent pool in case the application performs
* multiple compressions without changing the settings. To avoid a memory
* leak if jpeg_simple_lossless is called repeatedly for the same JPEG
* object, we try to re-use previously allocated space.
*/ */
if (cinfo->script_space == NULL || cinfo->script_space_size < nscans) { if (cinfo->Ss < 1 || cinfo->Ss > 7 ||
cinfo->script_space_size = nscans; cinfo->Al < 0 || cinfo->Al >= cinfo->data_precision)
cinfo->script_space = (jpeg_scan_info *) ERREXIT4(cinfo, JERR_BAD_PROGRESSION,
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al);
cinfo->script_space_size * SIZEOF(jpeg_scan_info));
}
scanptr = cinfo->script_space;
cinfo->scan_info = scanptr;
cinfo->num_scans = nscans;
/* Fill the script. */
scanptr->comps_in_scan = ncomps;
for (ci = 0; ci < ncomps; ci++)
scanptr->component_index[ci] = ci;
scanptr->Ss = predictor;
scanptr->Se = 0;
scanptr->Ah = 0;
scanptr->Al = point_transform;
} }
#endif /* C_LOSSLESS_SUPPORTED */ #endif /* C_LOSSLESS_SUPPORTED */

View File

@@ -2,7 +2,7 @@
* jcphuff.c * jcphuff.c
* *
* This file was part of the Independent JPEG Group's software: * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1995-1998, Thomas G. Lane. * Copyright (C) 1995-1997, Thomas G. Lane.
* Lossless JPEG Modifications: * Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison. * Copyright (C) 1999, Ken Murchison.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
@@ -17,7 +17,6 @@
#define JPEG_INTERNALS #define JPEG_INTERNALS
#include "jinclude.h" #include "jinclude.h"
#include "jpeglib.h" #include "jpeglib.h"
#include "jlossy.h" /* Private declarations for lossy codec */
#include "jchuff.h" /* Declarations shared with jc*huff.c */ #include "jchuff.h" /* Declarations shared with jc*huff.c */
#ifdef C_PROGRESSIVE_SUPPORTED #ifdef C_PROGRESSIVE_SUPPORTED
@@ -25,6 +24,8 @@
/* Expanded entropy encoder object for progressive Huffman encoding. */ /* Expanded entropy encoder object for progressive Huffman encoding. */
typedef struct { typedef struct {
struct jpeg_entropy_encoder pub; /* public fields */
/* Mode flag: TRUE for optimization, FALSE for actual data output */ /* Mode flag: TRUE for optimization, FALSE for actual data output */
boolean gather_statistics; boolean gather_statistics;
@@ -106,8 +107,7 @@ METHODDEF(void) finish_pass_gather_phuff JPP((j_compress_ptr cinfo));
METHODDEF(void) METHODDEF(void)
start_pass_phuff (j_compress_ptr cinfo, boolean gather_statistics) start_pass_phuff (j_compress_ptr cinfo, boolean gather_statistics)
{ {
j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyc->entropy_private;
boolean is_DC_band; boolean is_DC_band;
int ci, tbl; int ci, tbl;
jpeg_component_info * compptr; jpeg_component_info * compptr;
@@ -122,14 +122,14 @@ start_pass_phuff (j_compress_ptr cinfo, boolean gather_statistics)
/* Select execution routines */ /* Select execution routines */
if (cinfo->Ah == 0) { if (cinfo->Ah == 0) {
if (is_DC_band) if (is_DC_band)
lossyc->entropy_encode_mcu = encode_mcu_DC_first; entropy->pub.encode_mcu = encode_mcu_DC_first;
else else
lossyc->entropy_encode_mcu = encode_mcu_AC_first; entropy->pub.encode_mcu = encode_mcu_AC_first;
} else { } else {
if (is_DC_band) if (is_DC_band)
lossyc->entropy_encode_mcu = encode_mcu_DC_refine; entropy->pub.encode_mcu = encode_mcu_DC_refine;
else { else {
lossyc->entropy_encode_mcu = encode_mcu_AC_refine; entropy->pub.encode_mcu = encode_mcu_AC_refine;
/* AC refinement needs a correction bit buffer */ /* AC refinement needs a correction bit buffer */
if (entropy->bit_buffer == NULL) if (entropy->bit_buffer == NULL)
entropy->bit_buffer = (char *) entropy->bit_buffer = (char *)
@@ -138,9 +138,9 @@ start_pass_phuff (j_compress_ptr cinfo, boolean gather_statistics)
} }
} }
if (gather_statistics) if (gather_statistics)
lossyc->pub.entropy_finish_pass = finish_pass_gather_phuff; entropy->pub.finish_pass = finish_pass_gather_phuff;
else else
lossyc->pub.entropy_finish_pass = finish_pass_phuff; entropy->pub.finish_pass = finish_pass_phuff;
/* Only DC coefficients may be interleaved, so cinfo->comps_in_scan = 1 /* Only DC coefficients may be interleaved, so cinfo->comps_in_scan = 1
* for AC coefficients. * for AC coefficients.
@@ -378,8 +378,7 @@ emit_restart (phuff_entropy_ptr entropy, int restart_num)
METHODDEF(boolean) METHODDEF(boolean)
encode_mcu_DC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data) encode_mcu_DC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
{ {
j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyc->entropy_private;
register int temp, temp2; register int temp, temp2;
register int nbits; register int nbits;
int blkn, ci; int blkn, ci;
@@ -397,7 +396,7 @@ encode_mcu_DC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
emit_restart(entropy, entropy->next_restart_num); emit_restart(entropy, entropy->next_restart_num);
/* Encode the MCU data blocks */ /* Encode the MCU data blocks */
for (blkn = 0; blkn < cinfo->data_units_in_MCU; blkn++) { for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
block = MCU_data[blkn]; block = MCU_data[blkn];
ci = cinfo->MCU_membership[blkn]; ci = cinfo->MCU_membership[blkn];
compptr = cinfo->cur_comp_info[ci]; compptr = cinfo->cur_comp_info[ci];
@@ -466,8 +465,7 @@ encode_mcu_DC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
METHODDEF(boolean) METHODDEF(boolean)
encode_mcu_AC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data) encode_mcu_AC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
{ {
j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyc->entropy_private;
register int temp, temp2; register int temp, temp2;
register int nbits; register int nbits;
register int r, k; register int r, k;
@@ -574,8 +572,7 @@ encode_mcu_AC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
METHODDEF(boolean) METHODDEF(boolean)
encode_mcu_DC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data) encode_mcu_DC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
{ {
j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyc->entropy_private;
register int temp; register int temp;
int blkn; int blkn;
int Al = cinfo->Al; int Al = cinfo->Al;
@@ -590,7 +587,7 @@ encode_mcu_DC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
emit_restart(entropy, entropy->next_restart_num); emit_restart(entropy, entropy->next_restart_num);
/* Encode the MCU data blocks */ /* Encode the MCU data blocks */
for (blkn = 0; blkn < cinfo->data_units_in_MCU; blkn++) { for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
block = MCU_data[blkn]; block = MCU_data[blkn];
/* We simply emit the Al'th bit of the DC coefficient value. */ /* We simply emit the Al'th bit of the DC coefficient value. */
@@ -622,8 +619,7 @@ encode_mcu_DC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
METHODDEF(boolean) METHODDEF(boolean)
encode_mcu_AC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data) encode_mcu_AC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
{ {
j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyc->entropy_private;
register int temp; register int temp;
register int r, k; register int r, k;
int EOB; int EOB;
@@ -751,8 +747,7 @@ encode_mcu_AC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
METHODDEF(void) METHODDEF(void)
finish_pass_phuff (j_compress_ptr cinfo) finish_pass_phuff (j_compress_ptr cinfo)
{ {
j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyc->entropy_private;
entropy->next_output_byte = cinfo->dest->next_output_byte; entropy->next_output_byte = cinfo->dest->next_output_byte;
entropy->free_in_buffer = cinfo->dest->free_in_buffer; entropy->free_in_buffer = cinfo->dest->free_in_buffer;
@@ -773,8 +768,7 @@ finish_pass_phuff (j_compress_ptr cinfo)
METHODDEF(void) METHODDEF(void)
finish_pass_gather_phuff (j_compress_ptr cinfo) finish_pass_gather_phuff (j_compress_ptr cinfo)
{ {
j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyc->entropy_private;
boolean is_DC_band; boolean is_DC_band;
int ci, tbl; int ci, tbl;
jpeg_component_info * compptr; jpeg_component_info * compptr;
@@ -814,13 +808,6 @@ finish_pass_gather_phuff (j_compress_ptr cinfo)
} }
METHODDEF(boolean)
need_optimization_pass (j_compress_ptr cinfo)
{
return (cinfo->Ss != 0 || cinfo->Ah == 0);
}
/* /*
* Module initialization routine for progressive Huffman entropy encoding. * Module initialization routine for progressive Huffman entropy encoding.
*/ */
@@ -828,16 +815,14 @@ need_optimization_pass (j_compress_ptr cinfo)
GLOBAL(void) GLOBAL(void)
jinit_phuff_encoder (j_compress_ptr cinfo) jinit_phuff_encoder (j_compress_ptr cinfo)
{ {
j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec;
phuff_entropy_ptr entropy; phuff_entropy_ptr entropy;
int i; int i;
entropy = (phuff_entropy_ptr) entropy = (phuff_entropy_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(phuff_entropy_encoder)); SIZEOF(phuff_entropy_encoder));
lossyc->entropy_private = (struct jpeg_entropy_encoder *) entropy; cinfo->entropy = (struct jpeg_entropy_encoder *) entropy;
lossyc->pub.entropy_start_pass = start_pass_phuff; entropy->pub.start_pass = start_pass_phuff;
lossyc->pub.need_optimization_pass = need_optimization_pass;
/* Mark tables unallocated */ /* Mark tables unallocated */
for (i = 0; i < NUM_HUFF_TBLS; i++) { for (i = 0; i < NUM_HUFF_TBLS; i++) {

299
jcpred.c
View File

@@ -1,299 +0,0 @@
/*
* jcpred.c
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1998, Thomas G. Lane.
* Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains sample differencing for lossless JPEG.
*
* In order to avoid paying the performance penalty of having to check the
* predictor being used and the row being processed for each call of the
* undifferencer, and to promote optimization, we have separate differencing
* functions for each case.
*
* We are able to avoid duplicating source code by implementing the predictors
* and differencers as macros. Each of the differencing functions are
* simply wrappers around a DIFFERENCE macro with the appropriate PREDICTOR
* macro passed as an argument.
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
#include "jlossls.h" /* Private declarations for lossless codec */
#ifdef C_LOSSLESS_SUPPORTED
/* Private predictor object */
typedef struct {
/* MCU-rows left in the restart interval for each component */
unsigned int restart_rows_to_go[MAX_COMPONENTS];
} c_predictor;
typedef c_predictor * c_pred_ptr;
/* Forward declarations */
LOCAL(void) reset_predictor
JPP((j_compress_ptr cinfo, int ci));
METHODDEF(void) start_pass
JPP((j_compress_ptr cinfo));
/* Predictor for the first column of the first row: 2^(P-Pt-1) */
#define INITIAL_PREDICTORx (1 << (cinfo->data_precision - cinfo->Al - 1))
/* Predictor for the first column of the remaining rows: Rb */
#define INITIAL_PREDICTOR2 GETJSAMPLE(prev_row[0])
/*
* 1-Dimensional differencer routine.
*
* This macro implements the 1-D horizontal predictor (1). INITIAL_PREDICTOR
* is used as the special case predictor for the first column, which must be
* either INITIAL_PREDICTOR2 or INITIAL_PREDICTORx. The remaining samples
* use PREDICTOR1.
*/
#define DIFFERENCE_1D(INITIAL_PREDICTOR) \
j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; \
c_pred_ptr pred = (c_pred_ptr) losslsc->pred_private; \
boolean restart = FALSE; \
int xindex; \
int samp, Ra; \
\
samp = GETJSAMPLE(input_buf[0]); \
diff_buf[0] = samp - INITIAL_PREDICTOR; \
\
for (xindex = 1; xindex < width; xindex++) { \
Ra = samp; \
samp = GETJSAMPLE(input_buf[xindex]); \
diff_buf[xindex] = samp - PREDICTOR1; \
} \
\
/* Account for restart interval (no-op if not using restarts) */ \
if (cinfo->restart_interval) { \
if (--(pred->restart_rows_to_go[ci]) == 0) { \
reset_predictor(cinfo, ci); \
restart = TRUE; \
} \
}
/*
* 2-Dimensional differencer routine.
*
* This macro implements the 2-D horizontal predictors (#2-7). PREDICTOR2 is
* used as the special case predictor for the first column. The remaining
* samples use PREDICTOR, which is a function of Ra, Rb, Rc.
*
* Because prev_row and output_buf may point to the same storage area (in an
* interleaved image with Vi=1, for example), we must take care to buffer Rb/Rc
* before writing the current reconstructed sample value into output_buf.
*/
#define DIFFERENCE_2D(PREDICTOR) \
j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; \
c_pred_ptr pred = (c_pred_ptr) losslsc->pred_private; \
int xindex; \
int samp, Ra, Rb, Rc; \
\
Rb = GETJSAMPLE(prev_row[0]); \
samp = GETJSAMPLE(input_buf[0]); \
diff_buf[0] = samp - PREDICTOR2; \
\
for (xindex = 1; xindex < width; xindex++) { \
Rc = Rb; \
Rb = GETJSAMPLE(prev_row[xindex]); \
Ra = samp; \
samp = GETJSAMPLE(input_buf[xindex]); \
diff_buf[xindex] = samp - PREDICTOR; \
} \
\
/* Account for restart interval (no-op if not using restarts) */ \
if (cinfo->restart_interval) { \
if (--pred->restart_rows_to_go[ci] == 0) \
reset_predictor(cinfo, ci); \
}
/*
* Differencers for the all rows but the first in a scan or restart interval.
* The first sample in the row is differenced using the vertical
* predictor (2). The rest of the samples are differenced using the
* predictor specified in the scan header.
*/
METHODDEF(void)
jpeg_difference1(j_compress_ptr cinfo, int ci,
JSAMPROW input_buf, JSAMPROW prev_row,
JDIFFROW diff_buf, JDIMENSION width)
{
DIFFERENCE_1D(INITIAL_PREDICTOR2);
}
METHODDEF(void)
jpeg_difference2(j_compress_ptr cinfo, int ci,
JSAMPROW input_buf, JSAMPROW prev_row,
JDIFFROW diff_buf, JDIMENSION width)
{
DIFFERENCE_2D(PREDICTOR2);
}
METHODDEF(void)
jpeg_difference3(j_compress_ptr cinfo, int ci,
JSAMPROW input_buf, JSAMPROW prev_row,
JDIFFROW diff_buf, JDIMENSION width)
{
DIFFERENCE_2D(PREDICTOR3);
}
METHODDEF(void)
jpeg_difference4(j_compress_ptr cinfo, int ci,
JSAMPROW input_buf, JSAMPROW prev_row,
JDIFFROW diff_buf, JDIMENSION width)
{
DIFFERENCE_2D(PREDICTOR4);
}
METHODDEF(void)
jpeg_difference5(j_compress_ptr cinfo, int ci,
JSAMPROW input_buf, JSAMPROW prev_row,
JDIFFROW diff_buf, JDIMENSION width)
{
DIFFERENCE_2D(PREDICTOR5);
}
METHODDEF(void)
jpeg_difference6(j_compress_ptr cinfo, int ci,
JSAMPROW input_buf, JSAMPROW prev_row,
JDIFFROW diff_buf, JDIMENSION width)
{
DIFFERENCE_2D(PREDICTOR6);
}
METHODDEF(void)
jpeg_difference7(j_compress_ptr cinfo, int ci,
JSAMPROW input_buf, JSAMPROW prev_row,
JDIFFROW diff_buf, JDIMENSION width)
{
DIFFERENCE_2D(PREDICTOR7);
}
/*
* Differencer for the first row in a scan or restart interval. The first
* sample in the row is differenced using the special predictor constant
* x=2^(P-Pt-1). The rest of the samples are differenced using the
* 1-D horizontal predictor (1).
*/
METHODDEF(void)
jpeg_difference_first_row(j_compress_ptr cinfo, int ci,
JSAMPROW input_buf, JSAMPROW prev_row,
JDIFFROW diff_buf, JDIMENSION width)
{
DIFFERENCE_1D(INITIAL_PREDICTORx);
/*
* Now that we have differenced the first row, we want to use the
* differencer which corresponds to the predictor specified in the
* scan header.
*
* Note that we don't to do this if we have just reset the predictor
* for a new restart interval.
*/
if (!restart) {
switch (cinfo->Ss) {
case 1:
losslsc->predict_difference[ci] = jpeg_difference1;
break;
case 2:
losslsc->predict_difference[ci] = jpeg_difference2;
break;
case 3:
losslsc->predict_difference[ci] = jpeg_difference3;
break;
case 4:
losslsc->predict_difference[ci] = jpeg_difference4;
break;
case 5:
losslsc->predict_difference[ci] = jpeg_difference5;
break;
case 6:
losslsc->predict_difference[ci] = jpeg_difference6;
break;
case 7:
losslsc->predict_difference[ci] = jpeg_difference7;
break;
}
}
}
/*
* Reset predictor at the start of a pass or restart interval.
*/
LOCAL(void)
reset_predictor (j_compress_ptr cinfo, int ci)
{
j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec;
c_pred_ptr pred = (c_pred_ptr) losslsc->pred_private;
/* Initialize restart counter */
pred->restart_rows_to_go[ci] =
cinfo->restart_interval / cinfo->MCUs_per_row;
/* Set difference function to first row function */
losslsc->predict_difference[ci] = jpeg_difference_first_row;
}
/*
* Initialize for an input processing pass.
*/
METHODDEF(void)
start_pass (j_compress_ptr cinfo)
{
j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec;
c_pred_ptr pred = (c_pred_ptr) losslsc->pred_private;
int ci;
/* Check that the restart interval is an integer multiple of the number
* of MCU in an MCU-row.
*/
if (cinfo->restart_interval % cinfo->MCUs_per_row != 0)
ERREXIT2(cinfo, JERR_BAD_RESTART,
cinfo->restart_interval, cinfo->MCUs_per_row);
/* Set predictors for start of pass */
for (ci = 0; ci < cinfo->num_components; ci++)
reset_predictor(cinfo, ci);
}
/*
* Module initialization routine for the differencer.
*/
GLOBAL(void)
jinit_differencer (j_compress_ptr cinfo)
{
j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec;
c_pred_ptr pred;
pred = (c_pred_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(c_predictor));
losslsc->pred_private = (void *) pred;
losslsc->predict_start_pass = start_pass;
}
#endif /* C_LOSSLESS_SUPPORTED */

View File

@@ -2,9 +2,10 @@
* jcprepct.c * jcprepct.c
* *
* This file was part of the Independent JPEG Group's software: * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1998, Thomas G. Lane. * Copyright (C) 1994-1996, Thomas G. Lane.
* Lossless JPEG Modifications: * Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison. * Copyright (C) 1999, Ken Murchison.
* Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains the compression preprocessing controller. * This file contains the compression preprocessing controller.
@@ -137,6 +138,7 @@ pre_process_data (j_compress_ptr cinfo,
int numrows, ci; int numrows, ci;
JDIMENSION inrows; JDIMENSION inrows;
jpeg_component_info * compptr; jpeg_component_info * compptr;
int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
while (*in_row_ctr < in_rows_avail && while (*in_row_ctr < in_rows_avail &&
*out_row_group_ctr < out_row_groups_avail) { *out_row_group_ctr < out_row_groups_avail) {
@@ -176,7 +178,7 @@ pre_process_data (j_compress_ptr cinfo,
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) { ci++, compptr++) {
expand_bottom_edge(output_buf[ci], expand_bottom_edge(output_buf[ci],
compptr->width_in_data_units * cinfo->data_unit, compptr->width_in_blocks * data_unit,
(int) (*out_row_group_ctr * compptr->v_samp_factor), (int) (*out_row_group_ctr * compptr->v_samp_factor),
(int) (out_row_groups_avail * compptr->v_samp_factor)); (int) (out_row_groups_avail * compptr->v_samp_factor));
} }
@@ -273,6 +275,7 @@ create_context_buffer (j_compress_ptr cinfo)
int ci, i; int ci, i;
jpeg_component_info * compptr; jpeg_component_info * compptr;
JSAMPARRAY true_buffer, fake_buffer; JSAMPARRAY true_buffer, fake_buffer;
int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
/* Grab enough space for fake row pointers for all the components; /* Grab enough space for fake row pointers for all the components;
* we need five row groups' worth of pointers for each component. * we need five row groups' worth of pointers for each component.
@@ -290,7 +293,7 @@ create_context_buffer (j_compress_ptr cinfo)
*/ */
true_buffer = (*cinfo->mem->alloc_sarray) true_buffer = (*cinfo->mem->alloc_sarray)
((j_common_ptr) cinfo, JPOOL_IMAGE, ((j_common_ptr) cinfo, JPOOL_IMAGE,
(JDIMENSION) (((long) compptr->width_in_data_units * cinfo->data_unit * (JDIMENSION) (((long) compptr->width_in_blocks * data_unit *
cinfo->max_h_samp_factor) / compptr->h_samp_factor), cinfo->max_h_samp_factor) / compptr->h_samp_factor),
(JDIMENSION) (3 * rgroup_height)); (JDIMENSION) (3 * rgroup_height));
/* Copy true buffer row pointers into the middle of the fake row array */ /* Copy true buffer row pointers into the middle of the fake row array */
@@ -319,6 +322,7 @@ jinit_c_prep_controller (j_compress_ptr cinfo, boolean need_full_buffer)
my_prep_ptr prep; my_prep_ptr prep;
int ci; int ci;
jpeg_component_info * compptr; jpeg_component_info * compptr;
int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
if (need_full_buffer) /* safety check */ if (need_full_buffer) /* safety check */
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
@@ -348,7 +352,7 @@ jinit_c_prep_controller (j_compress_ptr cinfo, boolean need_full_buffer)
ci++, compptr++) { ci++, compptr++) {
prep->color_buf[ci] = (*cinfo->mem->alloc_sarray) prep->color_buf[ci] = (*cinfo->mem->alloc_sarray)
((j_common_ptr) cinfo, JPOOL_IMAGE, ((j_common_ptr) cinfo, JPOOL_IMAGE,
(JDIMENSION) (((long) compptr->width_in_data_units * cinfo->data_unit * (JDIMENSION) (((long) compptr->width_in_blocks * data_unit *
cinfo->max_h_samp_factor) / compptr->h_samp_factor), cinfo->max_h_samp_factor) / compptr->h_samp_factor),
(JDIMENSION) cinfo->max_v_samp_factor); (JDIMENSION) cinfo->max_v_samp_factor);
} }

View File

@@ -2,9 +2,10 @@
* jcsample.c * jcsample.c
* *
* This file was part of the Independent JPEG Group's software: * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1998, Thomas G. Lane. * Copyright (C) 1991-1996, Thomas G. Lane.
* Lossless JPEG Modifications: * Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison. * Copyright (C) 1999, Ken Murchison.
* Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains downsampling routines. * This file contains downsampling routines.
@@ -144,7 +145,8 @@ int_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
{ {
int inrow, outrow, h_expand, v_expand, numpix, numpix2, h, v; int inrow, outrow, h_expand, v_expand, numpix, numpix2, h, v;
JDIMENSION outcol, outcol_h; /* outcol_h == outcol*h_expand */ JDIMENSION outcol, outcol_h; /* outcol_h == outcol*h_expand */
JDIMENSION output_cols = compptr->width_in_data_units * cinfo->data_unit; int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
JDIMENSION output_cols = compptr->width_in_blocks * data_unit;
JSAMPROW inptr, outptr; JSAMPROW inptr, outptr;
INT32 outvalue; INT32 outvalue;
@@ -189,12 +191,14 @@ METHODDEF(void)
fullsize_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, fullsize_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
JSAMPARRAY input_data, JSAMPARRAY output_data) JSAMPARRAY input_data, JSAMPARRAY output_data)
{ {
int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
/* Copy the data */ /* Copy the data */
jcopy_sample_rows(input_data, 0, output_data, 0, jcopy_sample_rows(input_data, 0, output_data, 0,
cinfo->max_v_samp_factor, cinfo->image_width); cinfo->max_v_samp_factor, cinfo->image_width);
/* Edge-expand */ /* Edge-expand */
expand_right_edge(output_data, cinfo->max_v_samp_factor, expand_right_edge(output_data, cinfo->max_v_samp_factor,
cinfo->image_width, compptr->width_in_data_units * cinfo->data_unit); cinfo->image_width, compptr->width_in_blocks * data_unit);
} }
@@ -216,7 +220,8 @@ h2v1_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
{ {
int outrow; int outrow;
JDIMENSION outcol; JDIMENSION outcol;
JDIMENSION output_cols = compptr->width_in_data_units * cinfo->data_unit; int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
JDIMENSION output_cols = compptr->width_in_blocks * data_unit;
register JSAMPROW inptr, outptr; register JSAMPROW inptr, outptr;
register int bias; register int bias;
@@ -253,7 +258,8 @@ h2v2_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
{ {
int inrow, outrow; int inrow, outrow;
JDIMENSION outcol; JDIMENSION outcol;
JDIMENSION output_cols = compptr->width_in_data_units * cinfo->data_unit; int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
JDIMENSION output_cols = compptr->width_in_blocks * data_unit;
register JSAMPROW inptr0, inptr1, outptr; register JSAMPROW inptr0, inptr1, outptr;
register int bias; register int bias;
@@ -296,7 +302,8 @@ h2v2_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
{ {
int inrow, outrow; int inrow, outrow;
JDIMENSION colctr; JDIMENSION colctr;
JDIMENSION output_cols = compptr->width_in_data_units * cinfo->data_unit; int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
JDIMENSION output_cols = compptr->width_in_blocks * data_unit;
register JSAMPROW inptr0, inptr1, above_ptr, below_ptr, outptr; register JSAMPROW inptr0, inptr1, above_ptr, below_ptr, outptr;
INT32 membersum, neighsum, memberscale, neighscale; INT32 membersum, neighsum, memberscale, neighscale;
@@ -396,7 +403,8 @@ fullsize_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr,
{ {
int outrow; int outrow;
JDIMENSION colctr; JDIMENSION colctr;
JDIMENSION output_cols = compptr->width_in_data_units * cinfo->data_unit; int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
JDIMENSION output_cols = compptr->width_in_blocks * data_unit;
register JSAMPROW inptr, above_ptr, below_ptr, outptr; register JSAMPROW inptr, above_ptr, below_ptr, outptr;
INT32 membersum, neighsum, memberscale, neighscale; INT32 membersum, neighsum, memberscale, neighscale;
int colsum, lastcolsum, nextcolsum; int colsum, lastcolsum, nextcolsum;

View File

@@ -1,64 +0,0 @@
/*
* jcscale.c
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1998, Thomas G. Lane.
* Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains sample downscaling by 2^Pt for lossless JPEG.
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
#include "jlossls.h" /* Private declarations for lossless codec */
#ifdef C_LOSSLESS_SUPPORTED
METHODDEF(void)
simple_downscale(j_compress_ptr cinfo,
JSAMPROW input_buf, JSAMPROW output_buf, JDIMENSION width)
{
j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec;
int xindex;
for (xindex = 0; xindex < width; xindex++)
output_buf[xindex] = (JSAMPLE) RIGHT_SHIFT(GETJSAMPLE(input_buf[xindex]),
cinfo->Al);
}
METHODDEF(void)
noscale(j_compress_ptr cinfo,
JSAMPROW input_buf, JSAMPROW output_buf, JDIMENSION width)
{
MEMCOPY(output_buf, input_buf, width * SIZEOF(JSAMPLE));
return;
}
METHODDEF(void)
scaler_start_pass (j_compress_ptr cinfo)
{
j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec;
/* Set scaler function based on Pt */
if (cinfo->Al)
losslsc->scaler_scale = simple_downscale;
else
losslsc->scaler_scale = noscale;
}
GLOBAL(void)
jinit_c_scaler (j_compress_ptr cinfo)
{
j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec;
losslsc->scaler_start_pass = scaler_start_pass;
}
#endif /* C_LOSSLESS_SUPPORTED */

663
jcshuff.c
View File

@@ -1,663 +0,0 @@
/*
* jcshuff.c
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1998, Thomas G. Lane.
* Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains Huffman entropy encoding routines for sequential JPEG.
*
* Much of the complexity here has to do with supporting output suspension.
* If the data destination module demands suspension, we want to be able to
* back up to the start of the current MCU. To do this, we copy state
* variables into local working storage, and update them back to the
* permanent JPEG objects only upon successful completion of an MCU.
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
#include "jlossy.h" /* Private declarations for lossy codec */
#include "jchuff.h" /* Declarations shared with jc*huff.c */
/* Expanded entropy encoder object for Huffman encoding.
*
* The savable_state subrecord contains fields that change within an MCU,
* but must not be updated permanently until we complete the MCU.
*/
typedef struct {
INT32 put_buffer; /* current bit-accumulation buffer */
int put_bits; /* # of bits now in it */
int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */
} savable_state;
/* This macro is to work around compilers with missing or broken
* structure assignment. You'll need to fix this code if you have
* such a compiler and you change MAX_COMPS_IN_SCAN.
*/
#ifndef NO_STRUCT_ASSIGN
#define ASSIGN_STATE(dest,src) ((dest) = (src))
#else
#if MAX_COMPS_IN_SCAN == 4
#define ASSIGN_STATE(dest,src) \
((dest).put_buffer = (src).put_buffer, \
(dest).put_bits = (src).put_bits, \
(dest).last_dc_val[0] = (src).last_dc_val[0], \
(dest).last_dc_val[1] = (src).last_dc_val[1], \
(dest).last_dc_val[2] = (src).last_dc_val[2], \
(dest).last_dc_val[3] = (src).last_dc_val[3])
#endif
#endif
typedef struct {
savable_state saved; /* Bit buffer & DC state at start of MCU */
/* These fields are NOT loaded into local working state. */
unsigned int restarts_to_go; /* MCUs left in this restart interval */
int next_restart_num; /* next restart number to write (0-7) */
/* Pointers to derived tables (these workspaces have image lifespan) */
c_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS];
c_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS];
#ifdef ENTROPY_OPT_SUPPORTED /* Statistics tables for optimization */
long * dc_count_ptrs[NUM_HUFF_TBLS];
long * ac_count_ptrs[NUM_HUFF_TBLS];
#endif
} shuff_entropy_encoder;
typedef shuff_entropy_encoder * shuff_entropy_ptr;
/* Working state while writing an MCU.
* This struct contains all the fields that are needed by subroutines.
*/
typedef struct {
JOCTET * next_output_byte; /* => next byte to write in buffer */
size_t free_in_buffer; /* # of byte spaces remaining in buffer */
savable_state cur; /* Current bit buffer & DC state */
j_compress_ptr cinfo; /* dump_buffer needs access to this */
} working_state;
/* Forward declarations */
METHODDEF(boolean) encode_mcu_huff JPP((j_compress_ptr cinfo,
JBLOCKROW *MCU_data));
METHODDEF(void) finish_pass_huff JPP((j_compress_ptr cinfo));
#ifdef ENTROPY_OPT_SUPPORTED
METHODDEF(boolean) encode_mcu_gather JPP((j_compress_ptr cinfo,
JBLOCKROW *MCU_data));
METHODDEF(void) finish_pass_gather JPP((j_compress_ptr cinfo));
#endif
/*
* Initialize for a Huffman-compressed scan.
* If gather_statistics is TRUE, we do not output anything during the scan,
* just count the Huffman symbols used and generate Huffman code tables.
*/
METHODDEF(void)
start_pass_huff (j_compress_ptr cinfo, boolean gather_statistics)
{
j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec;
shuff_entropy_ptr entropy = (shuff_entropy_ptr) lossyc->entropy_private;
int ci, dctbl, actbl;
jpeg_component_info * compptr;
if (gather_statistics) {
#ifdef ENTROPY_OPT_SUPPORTED
lossyc->entropy_encode_mcu = encode_mcu_gather;
lossyc->pub.entropy_finish_pass = finish_pass_gather;
#else
ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif
} else {
lossyc->entropy_encode_mcu = encode_mcu_huff;
lossyc->pub.entropy_finish_pass = finish_pass_huff;
}
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
dctbl = compptr->dc_tbl_no;
actbl = compptr->ac_tbl_no;
if (gather_statistics) {
#ifdef ENTROPY_OPT_SUPPORTED
/* Check for invalid table indexes */
/* (make_c_derived_tbl does this in the other path) */
if (dctbl < 0 || dctbl >= NUM_HUFF_TBLS)
ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, dctbl);
if (actbl < 0 || actbl >= NUM_HUFF_TBLS)
ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, actbl);
/* Allocate and zero the statistics tables */
/* Note that jpeg_gen_optimal_table expects 257 entries in each table! */
if (entropy->dc_count_ptrs[dctbl] == NULL)
entropy->dc_count_ptrs[dctbl] = (long *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
257 * SIZEOF(long));
MEMZERO(entropy->dc_count_ptrs[dctbl], 257 * SIZEOF(long));
if (entropy->ac_count_ptrs[actbl] == NULL)
entropy->ac_count_ptrs[actbl] = (long *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
257 * SIZEOF(long));
MEMZERO(entropy->ac_count_ptrs[actbl], 257 * SIZEOF(long));
#endif
} else {
/* Compute derived values for Huffman tables */
/* We may do this more than once for a table, but it's not expensive */
jpeg_make_c_derived_tbl(cinfo, TRUE, dctbl,
& entropy->dc_derived_tbls[dctbl]);
jpeg_make_c_derived_tbl(cinfo, FALSE, actbl,
& entropy->ac_derived_tbls[actbl]);
}
/* Initialize DC predictions to 0 */
entropy->saved.last_dc_val[ci] = 0;
}
/* Initialize bit buffer to empty */
entropy->saved.put_buffer = 0;
entropy->saved.put_bits = 0;
/* Initialize restart stuff */
entropy->restarts_to_go = cinfo->restart_interval;
entropy->next_restart_num = 0;
}
/* Outputting bytes to the file */
/* Emit a byte, taking 'action' if must suspend. */
#define emit_byte(state,val,action) \
{ *(state)->next_output_byte++ = (JOCTET) (val); \
if (--(state)->free_in_buffer == 0) \
if (! dump_buffer(state)) \
{ action; } }
LOCAL(boolean)
dump_buffer (working_state * state)
/* Empty the output buffer; return TRUE if successful, FALSE if must suspend */
{
struct jpeg_destination_mgr * dest = state->cinfo->dest;
if (! (*dest->empty_output_buffer) (state->cinfo))
return FALSE;
/* After a successful buffer dump, must reset buffer pointers */
state->next_output_byte = dest->next_output_byte;
state->free_in_buffer = dest->free_in_buffer;
return TRUE;
}
/* Outputting bits to the file */
/* Only the right 24 bits of put_buffer are used; the valid bits are
* left-justified in this part. At most 16 bits can be passed to emit_bits
* in one call, and we never retain more than 7 bits in put_buffer
* between calls, so 24 bits are sufficient.
*/
INLINE
LOCAL(boolean)
emit_bits (working_state * state, unsigned int code, int size)
/* Emit some bits; return TRUE if successful, FALSE if must suspend */
{
/* This routine is heavily used, so it's worth coding tightly. */
register INT32 put_buffer = (INT32) code;
register int put_bits = state->cur.put_bits;
/* if size is 0, caller used an invalid Huffman table entry */
if (size == 0)
ERREXIT(state->cinfo, JERR_HUFF_MISSING_CODE);
put_buffer &= (((INT32) 1)<<size) - 1; /* mask off any extra bits in code */
put_bits += size; /* new number of bits in buffer */
put_buffer <<= 24 - put_bits; /* align incoming bits */
put_buffer |= state->cur.put_buffer; /* and merge with old buffer contents */
while (put_bits >= 8) {
int c = (int) ((put_buffer >> 16) & 0xFF);
emit_byte(state, c, return FALSE);
if (c == 0xFF) { /* need to stuff a zero byte? */
emit_byte(state, 0, return FALSE);
}
put_buffer <<= 8;
put_bits -= 8;
}
state->cur.put_buffer = put_buffer; /* update state variables */
state->cur.put_bits = put_bits;
return TRUE;
}
LOCAL(boolean)
flush_bits (working_state * state)
{
if (! emit_bits(state, 0x7F, 7)) /* fill any partial byte with ones */
return FALSE;
state->cur.put_buffer = 0; /* and reset bit-buffer to empty */
state->cur.put_bits = 0;
return TRUE;
}
/* Encode a single block's worth of coefficients */
LOCAL(boolean)
encode_one_block (working_state * state, JCOEFPTR block, int last_dc_val,
c_derived_tbl *dctbl, c_derived_tbl *actbl)
{
register int temp, temp2;
register int nbits;
register int k, r, i;
/* Encode the DC coefficient difference per section F.1.2.1 */
temp = temp2 = block[0] - last_dc_val;
if (temp < 0) {
temp = -temp; /* temp is abs value of input */
/* For a negative input, want temp2 = bitwise complement of abs(input) */
/* This code assumes we are on a two's complement machine */
temp2--;
}
/* Find the number of bits needed for the magnitude of the coefficient */
nbits = 0;
while (temp) {
nbits++;
temp >>= 1;
}
/* Check for out-of-range coefficient values.
* Since we're encoding a difference, the range limit is twice as much.
*/
if (nbits > MAX_COEF_BITS+1)
ERREXIT(state->cinfo, JERR_BAD_DCT_COEF);
/* Emit the Huffman-coded symbol for the number of bits */
if (! emit_bits(state, dctbl->ehufco[nbits], dctbl->ehufsi[nbits]))
return FALSE;
/* Emit that number of bits of the value, if positive, */
/* or the complement of its magnitude, if negative. */
if (nbits) /* emit_bits rejects calls with size 0 */
if (! emit_bits(state, (unsigned int) temp2, nbits))
return FALSE;
/* Encode the AC coefficients per section F.1.2.2 */
r = 0; /* r = run length of zeros */
for (k = 1; k < DCTSIZE2; k++) {
if ((temp = block[jpeg_natural_order[k]]) == 0) {
r++;
} else {
/* if run length > 15, must emit special run-length-16 codes (0xF0) */
while (r > 15) {
if (! emit_bits(state, actbl->ehufco[0xF0], actbl->ehufsi[0xF0]))
return FALSE;
r -= 16;
}
temp2 = temp;
if (temp < 0) {
temp = -temp; /* temp is abs value of input */
/* This code assumes we are on a two's complement machine */
temp2--;
}
/* Find the number of bits needed for the magnitude of the coefficient */
nbits = 1; /* there must be at least one 1 bit */
while ((temp >>= 1))
nbits++;
/* Check for out-of-range coefficient values */
if (nbits > MAX_COEF_BITS)
ERREXIT(state->cinfo, JERR_BAD_DCT_COEF);
/* Emit Huffman symbol for run length / number of bits */
i = (r << 4) + nbits;
if (! emit_bits(state, actbl->ehufco[i], actbl->ehufsi[i]))
return FALSE;
/* Emit that number of bits of the value, if positive, */
/* or the complement of its magnitude, if negative. */
if (! emit_bits(state, (unsigned int) temp2, nbits))
return FALSE;
r = 0;
}
}
/* If the last coef(s) were zero, emit an end-of-block code */
if (r > 0)
if (! emit_bits(state, actbl->ehufco[0], actbl->ehufsi[0]))
return FALSE;
return TRUE;
}
/*
* Emit a restart marker & resynchronize predictions.
*/
LOCAL(boolean)
emit_restart (working_state * state, int restart_num)
{
int ci;
if (! flush_bits(state))
return FALSE;
emit_byte(state, 0xFF, return FALSE);
emit_byte(state, JPEG_RST0 + restart_num, return FALSE);
/* Re-initialize DC predictions to 0 */
for (ci = 0; ci < state->cinfo->comps_in_scan; ci++)
state->cur.last_dc_val[ci] = 0;
/* The restart counter is not updated until we successfully write the MCU. */
return TRUE;
}
/*
* Encode and output one MCU's worth of Huffman-compressed coefficients.
*/
METHODDEF(boolean)
encode_mcu_huff (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
{
j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec;
shuff_entropy_ptr entropy = (shuff_entropy_ptr) lossyc->entropy_private;
working_state state;
int blkn, ci;
jpeg_component_info * compptr;
/* Load up working state */
state.next_output_byte = cinfo->dest->next_output_byte;
state.free_in_buffer = cinfo->dest->free_in_buffer;
ASSIGN_STATE(state.cur, entropy->saved);
state.cinfo = cinfo;
/* Emit restart marker if needed */
if (cinfo->restart_interval) {
if (entropy->restarts_to_go == 0)
if (! emit_restart(&state, entropy->next_restart_num))
return FALSE;
}
/* Encode the MCU data blocks */
for (blkn = 0; blkn < cinfo->data_units_in_MCU; blkn++) {
ci = cinfo->MCU_membership[blkn];
compptr = cinfo->cur_comp_info[ci];
if (! encode_one_block(&state,
MCU_data[blkn][0], state.cur.last_dc_val[ci],
entropy->dc_derived_tbls[compptr->dc_tbl_no],
entropy->ac_derived_tbls[compptr->ac_tbl_no]))
return FALSE;
/* Update last_dc_val */
state.cur.last_dc_val[ci] = MCU_data[blkn][0][0];
}
/* Completed MCU, so update state */
cinfo->dest->next_output_byte = state.next_output_byte;
cinfo->dest->free_in_buffer = state.free_in_buffer;
ASSIGN_STATE(entropy->saved, state.cur);
/* Update restart-interval state too */
if (cinfo->restart_interval) {
if (entropy->restarts_to_go == 0) {
entropy->restarts_to_go = cinfo->restart_interval;
entropy->next_restart_num++;
entropy->next_restart_num &= 7;
}
entropy->restarts_to_go--;
}
return TRUE;
}
/*
* Finish up at the end of a Huffman-compressed scan.
*/
METHODDEF(void)
finish_pass_huff (j_compress_ptr cinfo)
{
j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec;
shuff_entropy_ptr entropy = (shuff_entropy_ptr) lossyc->entropy_private;
working_state state;
/* Load up working state ... flush_bits needs it */
state.next_output_byte = cinfo->dest->next_output_byte;
state.free_in_buffer = cinfo->dest->free_in_buffer;
ASSIGN_STATE(state.cur, entropy->saved);
state.cinfo = cinfo;
/* Flush out the last data */
if (! flush_bits(&state))
ERREXIT(cinfo, JERR_CANT_SUSPEND);
/* Update state */
cinfo->dest->next_output_byte = state.next_output_byte;
cinfo->dest->free_in_buffer = state.free_in_buffer;
ASSIGN_STATE(entropy->saved, state.cur);
}
/*
* Huffman coding optimization.
*
* We first scan the supplied data and count the number of uses of each symbol
* that is to be Huffman-coded. (This process MUST agree with the code above.)
* Then we build a Huffman coding tree for the observed counts.
* Symbols which are not needed at all for the particular image are not
* assigned any code, which saves space in the DHT marker as well as in
* the compressed data.
*/
#ifdef ENTROPY_OPT_SUPPORTED
/* Process a single block's worth of coefficients */
LOCAL(void)
htest_one_block (j_compress_ptr cinfo, JCOEFPTR block, int last_dc_val,
long dc_counts[], long ac_counts[])
{
register int temp;
register int nbits;
register int k, r;
/* Encode the DC coefficient difference per section F.1.2.1 */
temp = block[0] - last_dc_val;
if (temp < 0)
temp = -temp;
/* Find the number of bits needed for the magnitude of the coefficient */
nbits = 0;
while (temp) {
nbits++;
temp >>= 1;
}
/* Check for out-of-range coefficient values.
* Since we're encoding a difference, the range limit is twice as much.
*/
if (nbits > MAX_COEF_BITS+1)
ERREXIT(cinfo, JERR_BAD_DCT_COEF);
/* Count the Huffman symbol for the number of bits */
dc_counts[nbits]++;
/* Encode the AC coefficients per section F.1.2.2 */
r = 0; /* r = run length of zeros */
for (k = 1; k < DCTSIZE2; k++) {
if ((temp = block[jpeg_natural_order[k]]) == 0) {
r++;
} else {
/* if run length > 15, must emit special run-length-16 codes (0xF0) */
while (r > 15) {
ac_counts[0xF0]++;
r -= 16;
}
/* Find the number of bits needed for the magnitude of the coefficient */
if (temp < 0)
temp = -temp;
/* Find the number of bits needed for the magnitude of the coefficient */
nbits = 1; /* there must be at least one 1 bit */
while ((temp >>= 1))
nbits++;
/* Check for out-of-range coefficient values */
if (nbits > MAX_COEF_BITS)
ERREXIT(cinfo, JERR_BAD_DCT_COEF);
/* Count Huffman symbol for run length / number of bits */
ac_counts[(r << 4) + nbits]++;
r = 0;
}
}
/* If the last coef(s) were zero, emit an end-of-block code */
if (r > 0)
ac_counts[0]++;
}
/*
* Trial-encode one MCU's worth of Huffman-compressed coefficients.
* No data is actually output, so no suspension return is possible.
*/
METHODDEF(boolean)
encode_mcu_gather (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
{
j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec;
shuff_entropy_ptr entropy = (shuff_entropy_ptr) lossyc->entropy_private;
int blkn, ci;
jpeg_component_info * compptr;
/* Take care of restart intervals if needed */
if (cinfo->restart_interval) {
if (entropy->restarts_to_go == 0) {
/* Re-initialize DC predictions to 0 */
for (ci = 0; ci < cinfo->comps_in_scan; ci++)
entropy->saved.last_dc_val[ci] = 0;
/* Update restart state */
entropy->restarts_to_go = cinfo->restart_interval;
}
entropy->restarts_to_go--;
}
for (blkn = 0; blkn < cinfo->data_units_in_MCU; blkn++) {
ci = cinfo->MCU_membership[blkn];
compptr = cinfo->cur_comp_info[ci];
htest_one_block(cinfo, MCU_data[blkn][0], entropy->saved.last_dc_val[ci],
entropy->dc_count_ptrs[compptr->dc_tbl_no],
entropy->ac_count_ptrs[compptr->ac_tbl_no]);
entropy->saved.last_dc_val[ci] = MCU_data[blkn][0][0];
}
return TRUE;
}
/*
* Finish up a statistics-gathering pass and create the new Huffman tables.
*/
METHODDEF(void)
finish_pass_gather (j_compress_ptr cinfo)
{
j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec;
shuff_entropy_ptr entropy = (shuff_entropy_ptr) lossyc->entropy_private;
int ci, dctbl, actbl;
jpeg_component_info * compptr;
JHUFF_TBL **htblptr;
boolean did_dc[NUM_HUFF_TBLS];
boolean did_ac[NUM_HUFF_TBLS];
/* It's important not to apply jpeg_gen_optimal_table more than once
* per table, because it clobbers the input frequency counts!
*/
MEMZERO(did_dc, SIZEOF(did_dc));
MEMZERO(did_ac, SIZEOF(did_ac));
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
dctbl = compptr->dc_tbl_no;
actbl = compptr->ac_tbl_no;
if (! did_dc[dctbl]) {
htblptr = & cinfo->dc_huff_tbl_ptrs[dctbl];
if (*htblptr == NULL)
*htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo);
jpeg_gen_optimal_table(cinfo, *htblptr, entropy->dc_count_ptrs[dctbl]);
did_dc[dctbl] = TRUE;
}
if (! did_ac[actbl]) {
htblptr = & cinfo->ac_huff_tbl_ptrs[actbl];
if (*htblptr == NULL)
*htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo);
jpeg_gen_optimal_table(cinfo, *htblptr, entropy->ac_count_ptrs[actbl]);
did_ac[actbl] = TRUE;
}
}
}
#endif /* ENTROPY_OPT_SUPPORTED */
METHODDEF(boolean)
need_optimization_pass (j_compress_ptr cinfo)
{
return TRUE;
}
/*
* Module initialization routine for Huffman entropy encoding.
*/
GLOBAL(void)
jinit_shuff_encoder (j_compress_ptr cinfo)
{
j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec;
shuff_entropy_ptr entropy;
int i;
entropy = (shuff_entropy_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(shuff_entropy_encoder));
lossyc->entropy_private = (struct jpeg_entropy_encoder *) entropy;
lossyc->pub.entropy_start_pass = start_pass_huff;
lossyc->pub.need_optimization_pass = need_optimization_pass;
/* Mark tables unallocated */
for (i = 0; i < NUM_HUFF_TBLS; i++) {
entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL;
#ifdef ENTROPY_OPT_SUPPORTED
entropy->dc_count_ptrs[i] = entropy->ac_count_ptrs[i] = NULL;
#endif
}
}

112
jctrans.c
View File

@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software: * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1995-1998, Thomas G. Lane. * Copyright (C) 1995-1998, Thomas G. Lane.
* Lossless JPEG Modifications: * Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison. * Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains library routines for transcoding compression, * This file contains library routines for transcoding compression,
@@ -15,14 +15,11 @@
#define JPEG_INTERNALS #define JPEG_INTERNALS
#include "jinclude.h" #include "jinclude.h"
#include "jpeglib.h" #include "jpeglib.h"
#include "jlossy.h" /* Private declarations for lossy codec */
/* Forward declarations */ /* Forward declarations */
LOCAL(void) transencode_master_selection LOCAL(void) transencode_master_selection
JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays)); JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays));
LOCAL(void) transencode_codec
JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays));
LOCAL(void) transencode_coef_controller LOCAL(void) transencode_coef_controller
JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays)); JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays));
@@ -42,6 +39,9 @@ LOCAL(void) transencode_coef_controller
GLOBAL(void) GLOBAL(void)
jpeg_write_coefficients (j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays) jpeg_write_coefficients (j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays)
{ {
if (cinfo->master->lossless)
ERREXIT(cinfo, JERR_NOTIMPL);
if (cinfo->global_state != CSTATE_START) if (cinfo->global_state != CSTATE_START)
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
/* Mark all tables to be written */ /* Mark all tables to be written */
@@ -73,6 +73,9 @@ jpeg_copy_critical_parameters (j_decompress_ptr srcinfo,
JQUANT_TBL *c_quant, *slot_quant; JQUANT_TBL *c_quant, *slot_quant;
int tblno, ci, coefi; int tblno, ci, coefi;
if (srcinfo->master->lossless)
ERREXIT(dstinfo, JERR_NOTIMPL);
/* Safety check to ensure start_compress not called yet. */ /* Safety check to ensure start_compress not called yet. */
if (dstinfo->global_state != CSTATE_START) if (dstinfo->global_state != CSTATE_START)
ERREXIT1(dstinfo, JERR_BAD_STATE, dstinfo->global_state); ERREXIT1(dstinfo, JERR_BAD_STATE, dstinfo->global_state);
@@ -163,7 +166,6 @@ LOCAL(void)
transencode_master_selection (j_compress_ptr cinfo, transencode_master_selection (j_compress_ptr cinfo,
jvirt_barray_ptr * coef_arrays) jvirt_barray_ptr * coef_arrays)
{ {
cinfo->data_unit = DCTSIZE;
/* Although we don't actually use input_components for transcoding, /* Although we don't actually use input_components for transcoding,
* jcmaster.c's initial_setup will complain if input_components is 0. * jcmaster.c's initial_setup will complain if input_components is 0.
*/ */
@@ -171,8 +173,22 @@ transencode_master_selection (j_compress_ptr cinfo,
/* Initialize master control (includes parameter checking/processing) */ /* Initialize master control (includes parameter checking/processing) */
jinit_c_master_control(cinfo, TRUE /* transcode only */); jinit_c_master_control(cinfo, TRUE /* transcode only */);
/* We need a special compression codec. */ /* Entropy encoding: either Huffman or arithmetic coding. */
transencode_codec(cinfo, coef_arrays); if (cinfo->arith_code) {
ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
} else {
if (cinfo->progressive_mode) {
#ifdef C_PROGRESSIVE_SUPPORTED
jinit_phuff_encoder(cinfo);
#else
ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif
} else
jinit_huff_encoder(cinfo);
}
/* We need a special coefficient buffer controller. */
transencode_coef_controller(cinfo, coef_arrays);
jinit_marker_writer(cinfo); jinit_marker_writer(cinfo);
@@ -198,6 +214,8 @@ transencode_master_selection (j_compress_ptr cinfo,
/* Private buffer controller object */ /* Private buffer controller object */
typedef struct { typedef struct {
struct jpeg_c_coef_controller pub; /* public fields */
JDIMENSION iMCU_row_num; /* iMCU row # within image */ JDIMENSION iMCU_row_num; /* iMCU row # within image */
JDIMENSION mcu_ctr; /* counts MCUs processed in current row */ JDIMENSION mcu_ctr; /* counts MCUs processed in current row */
int MCU_vert_offset; /* counts MCU rows within iMCU row */ int MCU_vert_offset; /* counts MCU rows within iMCU row */
@@ -207,18 +225,17 @@ typedef struct {
jvirt_barray_ptr * whole_image; jvirt_barray_ptr * whole_image;
/* Workspace for constructing dummy blocks at right/bottom edges. */ /* Workspace for constructing dummy blocks at right/bottom edges. */
JBLOCKROW dummy_buffer[C_MAX_DATA_UNITS_IN_MCU]; JBLOCKROW dummy_buffer[C_MAX_BLOCKS_IN_MCU];
} c_coef_controller; } my_coef_controller;
typedef c_coef_controller * c_coef_ptr; typedef my_coef_controller * my_coef_ptr;
LOCAL(void) LOCAL(void)
start_iMCU_row (j_compress_ptr cinfo) start_iMCU_row (j_compress_ptr cinfo)
/* Reset within-iMCU-row counters for a new row */ /* Reset within-iMCU-row counters for a new row */
{ {
j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
c_coef_ptr coef = (c_coef_ptr) lossyc->coef_private;
/* In an interleaved scan, an MCU row is the same as an iMCU row. /* In an interleaved scan, an MCU row is the same as an iMCU row.
* In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
@@ -245,8 +262,7 @@ start_iMCU_row (j_compress_ptr cinfo)
METHODDEF(void) METHODDEF(void)
start_pass_coef (j_compress_ptr cinfo, J_BUF_MODE pass_mode) start_pass_coef (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
{ {
j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
c_coef_ptr coef = (c_coef_ptr) lossyc->coef_private;
if (pass_mode != JBUF_CRANK_DEST) if (pass_mode != JBUF_CRANK_DEST)
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
@@ -269,15 +285,14 @@ start_pass_coef (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
METHODDEF(boolean) METHODDEF(boolean)
compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf) compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
{ {
j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
c_coef_ptr coef = (c_coef_ptr) lossyc->coef_private;
JDIMENSION MCU_col_num; /* index of current MCU within row */ JDIMENSION MCU_col_num; /* index of current MCU within row */
JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1; JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1;
JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
int blkn, ci, xindex, yindex, yoffset, blockcnt; int blkn, ci, xindex, yindex, yoffset, blockcnt;
JDIMENSION start_col; JDIMENSION start_col;
JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN]; JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN];
JBLOCKROW MCU_buffer[C_MAX_DATA_UNITS_IN_MCU]; JBLOCKROW MCU_buffer[C_MAX_BLOCKS_IN_MCU];
JBLOCKROW buffer_ptr; JBLOCKROW buffer_ptr;
jpeg_component_info *compptr; jpeg_component_info *compptr;
@@ -327,7 +342,7 @@ compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
} }
} }
/* Try to write the MCU. */ /* Try to write the MCU. */
if (! (*lossyc->entropy_encode_mcu) (cinfo, MCU_buffer)) { if (! (*cinfo->entropy->encode_mcu) (cinfo, MCU_buffer)) {
/* Suspension forced; update state counters and exit */ /* Suspension forced; update state counters and exit */
coef->MCU_vert_offset = yoffset; coef->MCU_vert_offset = yoffset;
coef->mcu_ctr = MCU_col_num; coef->mcu_ctr = MCU_col_num;
@@ -348,7 +363,7 @@ compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
* Initialize coefficient buffer controller. * Initialize coefficient buffer controller.
* *
* Each passed coefficient array must be the right size for that * Each passed coefficient array must be the right size for that
* coefficient: width_in_data_units wide and height_in_data_units high, * coefficient: width_in_blocks wide and height_in_blocks high,
* with unitheight at least v_samp_factor. * with unitheight at least v_samp_factor.
*/ */
@@ -356,15 +371,16 @@ LOCAL(void)
transencode_coef_controller (j_compress_ptr cinfo, transencode_coef_controller (j_compress_ptr cinfo,
jvirt_barray_ptr * coef_arrays) jvirt_barray_ptr * coef_arrays)
{ {
j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; my_coef_ptr coef;
c_coef_ptr coef;
JBLOCKROW buffer; JBLOCKROW buffer;
int i; int i;
coef = (c_coef_ptr) coef = (my_coef_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(c_coef_controller)); SIZEOF(my_coef_controller));
lossyc->coef_private = (struct jpeg_c_coef_controller *) coef; cinfo->coef = (struct jpeg_c_coef_controller *) coef;
coef->pub.start_pass = start_pass_coef;
coef->pub.compress_data = compress_output;
/* Save pointer to virtual arrays */ /* Save pointer to virtual arrays */
coef->whole_image = coef_arrays; coef->whole_image = coef_arrays;
@@ -372,51 +388,9 @@ transencode_coef_controller (j_compress_ptr cinfo,
/* Allocate and pre-zero space for dummy DCT blocks. */ /* Allocate and pre-zero space for dummy DCT blocks. */
buffer = (JBLOCKROW) buffer = (JBLOCKROW)
(*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
C_MAX_DATA_UNITS_IN_MCU * SIZEOF(JBLOCK)); C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK));
jzero_far((void FAR *) buffer, C_MAX_DATA_UNITS_IN_MCU * SIZEOF(JBLOCK)); jzero_far((void FAR *) buffer, C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK));
for (i = 0; i < C_MAX_DATA_UNITS_IN_MCU; i++) { for (i = 0; i < C_MAX_BLOCKS_IN_MCU; i++) {
coef->dummy_buffer[i] = buffer + i; coef->dummy_buffer[i] = buffer + i;
} }
} }
/*
* Initialize the transencoer codec.
* This is called only once, during master selection.
*/
LOCAL(void)
transencode_codec (j_compress_ptr cinfo,
jvirt_barray_ptr * coef_arrays)
{
j_lossy_c_ptr lossyc;
/* Create subobject in permanent pool */
lossyc = (j_lossy_c_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
SIZEOF(jpeg_lossy_c_codec));
cinfo->codec = (struct jpeg_c_codec *) lossyc;
/* Initialize sub-modules */
/* Entropy encoding: either Huffman or arithmetic coding. */
if (cinfo->arith_code) {
ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
} else {
if (cinfo->process == JPROC_PROGRESSIVE) {
#ifdef C_PROGRESSIVE_SUPPORTED
jinit_phuff_encoder(cinfo);
#else
ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif
} else
jinit_shuff_encoder(cinfo);
}
/* We need a special coefficient buffer controller. */
transencode_coef_controller(cinfo, coef_arrays);
/* Initialize method pointers */
lossyc->pub.start_pass = start_pass_coef;
lossyc->pub.compress_data = compress_output;
}

View File

@@ -5,6 +5,7 @@
* Copyright (C) 1994-1998, Thomas G. Lane. * Copyright (C) 1994-1998, Thomas G. Lane.
* Lossless JPEG Modifications: * Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison. * Copyright (C) 1999, Ken Murchison.
* Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains application interface code for the decompression half * This file contains application interface code for the decompression half
@@ -21,6 +22,7 @@
#define JPEG_INTERNALS #define JPEG_INTERNALS
#include "jinclude.h" #include "jinclude.h"
#include "jpeglib.h" #include "jpeglib.h"
#include "jdmaster.h"
/* /*
@@ -82,6 +84,14 @@ jpeg_CreateDecompress (j_decompress_ptr cinfo, int version, size_t structsize)
/* OK, I'm ready */ /* OK, I'm ready */
cinfo->global_state = DSTATE_START; cinfo->global_state = DSTATE_START;
/* The master struct is used to store extension parameters, so we allocate it
* here.
*/
cinfo->master = (struct jpeg_decomp_master *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
SIZEOF(my_decomp_master));
MEMZERO(cinfo->master, SIZEOF(my_decomp_master));
} }
@@ -151,16 +161,13 @@ default_decompress_parms (j_decompress_ptr cinfo)
else if (cid0 == 82 && cid1 == 71 && cid2 == 66) else if (cid0 == 82 && cid1 == 71 && cid2 == 66)
cinfo->jpeg_color_space = JCS_RGB; /* ASCII 'R', 'G', 'B' */ cinfo->jpeg_color_space = JCS_RGB; /* ASCII 'R', 'G', 'B' */
else { else {
if (cinfo->process == JPROC_LOSSLESS) { TRACEMS3(cinfo, 1, JTRC_UNKNOWN_IDS, cid0, cid1, cid2);
TRACEMS3(cinfo, 1, JTRC_UNKNOWN_LOSSLESS_IDS, cid0, cid1, cid2); if (cinfo->master->lossless)
cinfo->jpeg_color_space = JCS_RGB; /* assume it's RGB */ cinfo->jpeg_color_space = JCS_RGB; /* assume it's RGB */
} else
else { /* Lossy processes */
TRACEMS3(cinfo, 1, JTRC_UNKNOWN_LOSSY_IDS, cid0, cid1, cid2);
cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */ cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */
} }
} }
}
/* Always guess RGB is proper output colorspace. */ /* Always guess RGB is proper output colorspace. */
cinfo->out_color_space = JCS_RGB; cinfo->out_color_space = JCS_RGB;
break; break;

View File

@@ -2,9 +2,9 @@
* jdapistd.c * jdapistd.c
* *
* This file was part of the Independent JPEG Group's software: * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1998, Thomas G. Lane. * Copyright (C) 1994-1996, Thomas G. Lane.
* Lossless JPEG Modifications: * Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison. * Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains application interface code for the decompression half * This file contains application interface code for the decompression half
@@ -189,6 +189,9 @@ jpeg_read_raw_data (j_decompress_ptr cinfo, JSAMPIMAGE data,
{ {
JDIMENSION lines_per_iMCU_row; JDIMENSION lines_per_iMCU_row;
if (cinfo->master->lossless)
ERREXIT(cinfo, JERR_NOTIMPL);
if (cinfo->global_state != DSTATE_RAW_OK) if (cinfo->global_state != DSTATE_RAW_OK)
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
if (cinfo->output_scanline >= cinfo->output_height) { if (cinfo->output_scanline >= cinfo->output_height) {
@@ -204,12 +207,12 @@ jpeg_read_raw_data (j_decompress_ptr cinfo, JSAMPIMAGE data,
} }
/* Verify that at least one iMCU row can be returned. */ /* Verify that at least one iMCU row can be returned. */
lines_per_iMCU_row = cinfo->max_v_samp_factor * cinfo->min_codec_data_unit; lines_per_iMCU_row = cinfo->max_v_samp_factor * cinfo->min_DCT_scaled_size;
if (max_lines < lines_per_iMCU_row) if (max_lines < lines_per_iMCU_row)
ERREXIT(cinfo, JERR_BUFFER_SIZE); ERREXIT(cinfo, JERR_BUFFER_SIZE);
/* Decompress directly into user's buffer. */ /* Decompress directly into user's buffer. */
if (! (*cinfo->codec->decompress_data) (cinfo, data)) if (! (*cinfo->coef->decompress_data) (cinfo, data))
return 0; /* suspension forced, can do nothing more */ return 0; /* suspension forced, can do nothing more */
/* OK, we processed one iMCU row. */ /* OK, we processed one iMCU row. */

View File

@@ -2,9 +2,9 @@
* jdcoefct.c * jdcoefct.c
* *
* This file was part of the Independent JPEG Group's software: * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1998, Thomas G. Lane. * Copyright (C) 1994-1997, Thomas G. Lane.
* Lossless JPEG Modifications: * Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison. * Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains the coefficient buffer controller for decompression. * This file contains the coefficient buffer controller for decompression.
@@ -19,7 +19,6 @@
#define JPEG_INTERNALS #define JPEG_INTERNALS
#include "jinclude.h" #include "jinclude.h"
#include "jpeglib.h" #include "jpeglib.h"
#include "jlossy.h"
/* Block smoothing is only applicable for progressive JPEG, so: */ /* Block smoothing is only applicable for progressive JPEG, so: */
#ifndef D_PROGRESSIVE_SUPPORTED #ifndef D_PROGRESSIVE_SUPPORTED
@@ -29,6 +28,8 @@
/* Private buffer controller object */ /* Private buffer controller object */
typedef struct { typedef struct {
struct jpeg_d_coef_controller pub; /* public fields */
/* These variables keep track of the current location of the input side. */ /* These variables keep track of the current location of the input side. */
/* cinfo->input_iMCU_row is also used for this. */ /* cinfo->input_iMCU_row is also used for this. */
JDIMENSION MCU_ctr; /* counts MCUs processed in current row */ JDIMENSION MCU_ctr; /* counts MCUs processed in current row */
@@ -38,7 +39,7 @@ typedef struct {
/* The output side's location is represented by cinfo->output_iMCU_row. */ /* The output side's location is represented by cinfo->output_iMCU_row. */
/* In single-pass modes, it's sufficient to buffer just one MCU. /* In single-pass modes, it's sufficient to buffer just one MCU.
* We allocate a workspace of D_MAX_DATA_UNITS_IN_MCU coefficient blocks, * We allocate a workspace of D_MAX_BLOCKS_IN_MCU coefficient blocks,
* and let the entropy decoder write into that workspace each time. * and let the entropy decoder write into that workspace each time.
* (On 80x86, the workspace is FAR even though it's not really very big; * (On 80x86, the workspace is FAR even though it's not really very big;
* this is to keep the module interfaces unchanged when a large coefficient * this is to keep the module interfaces unchanged when a large coefficient
@@ -46,7 +47,7 @@ typedef struct {
* In multi-pass modes, this array points to the current MCU's blocks * In multi-pass modes, this array points to the current MCU's blocks
* within the virtual arrays; it is used only by the input side. * within the virtual arrays; it is used only by the input side.
*/ */
JBLOCKROW MCU_buffer[D_MAX_DATA_UNITS_IN_MCU]; JBLOCKROW MCU_buffer[D_MAX_BLOCKS_IN_MCU];
#ifdef D_MULTISCAN_FILES_SUPPORTED #ifdef D_MULTISCAN_FILES_SUPPORTED
/* In multi-pass modes, we need a virtual block array for each component. */ /* In multi-pass modes, we need a virtual block array for each component. */
@@ -58,9 +59,9 @@ typedef struct {
int * coef_bits_latch; int * coef_bits_latch;
#define SAVED_COEFS 6 /* we save coef_bits[0..5] */ #define SAVED_COEFS 6 /* we save coef_bits[0..5] */
#endif #endif
} d_coef_controller; } my_coef_controller;
typedef d_coef_controller * d_coef_ptr; typedef my_coef_controller * my_coef_ptr;
/* Forward declarations */ /* Forward declarations */
METHODDEF(int) decompress_onepass METHODDEF(int) decompress_onepass
@@ -80,8 +81,7 @@ LOCAL(void)
start_iMCU_row (j_decompress_ptr cinfo) start_iMCU_row (j_decompress_ptr cinfo)
/* Reset within-iMCU-row counters for a new row (input side) */ /* Reset within-iMCU-row counters for a new row (input side) */
{ {
j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
d_coef_ptr coef = (d_coef_ptr) lossyd->coef_private;
/* In an interleaved scan, an MCU row is the same as an iMCU row. /* In an interleaved scan, an MCU row is the same as an iMCU row.
* In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
@@ -121,15 +121,14 @@ METHODDEF(void)
start_output_pass (j_decompress_ptr cinfo) start_output_pass (j_decompress_ptr cinfo)
{ {
#ifdef BLOCK_SMOOTHING_SUPPORTED #ifdef BLOCK_SMOOTHING_SUPPORTED
j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
d_coef_ptr coef = (d_coef_ptr) lossyd->coef_private;
/* If multipass, check to see whether to use block smoothing on this pass */ /* If multipass, check to see whether to use block smoothing on this pass */
if (lossyd->coef_arrays != NULL) { if (coef->pub.coef_arrays != NULL) {
if (cinfo->do_block_smoothing && smoothing_ok(cinfo)) if (cinfo->do_block_smoothing && smoothing_ok(cinfo))
lossyd->pub.decompress_data = decompress_smooth_data; coef->pub.decompress_data = decompress_smooth_data;
else else
lossyd->pub.decompress_data = decompress_data; coef->pub.decompress_data = decompress_data;
} }
#endif #endif
cinfo->output_iMCU_row = 0; cinfo->output_iMCU_row = 0;
@@ -149,8 +148,7 @@ start_output_pass (j_decompress_ptr cinfo)
METHODDEF(int) METHODDEF(int)
decompress_onepass (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) decompress_onepass (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
{ {
j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
d_coef_ptr coef = (d_coef_ptr) lossyd->coef_private;
JDIMENSION MCU_col_num; /* index of current MCU within row */ JDIMENSION MCU_col_num; /* index of current MCU within row */
JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1; JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1;
JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
@@ -167,8 +165,8 @@ decompress_onepass (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
MCU_col_num++) { MCU_col_num++) {
/* Try to fetch an MCU. Entropy decoder expects buffer to be zeroed. */ /* Try to fetch an MCU. Entropy decoder expects buffer to be zeroed. */
jzero_far((void FAR *) coef->MCU_buffer[0], jzero_far((void FAR *) coef->MCU_buffer[0],
(size_t) (cinfo->data_units_in_MCU * SIZEOF(JBLOCK))); (size_t) (cinfo->blocks_in_MCU * SIZEOF(JBLOCK)));
if (! (*lossyd->entropy_decode_mcu) (cinfo, coef->MCU_buffer)) { if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) {
/* Suspension forced; update state counters and exit */ /* Suspension forced; update state counters and exit */
coef->MCU_vert_offset = yoffset; coef->MCU_vert_offset = yoffset;
coef->MCU_ctr = MCU_col_num; coef->MCU_ctr = MCU_col_num;
@@ -184,14 +182,14 @@ decompress_onepass (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
compptr = cinfo->cur_comp_info[ci]; compptr = cinfo->cur_comp_info[ci];
/* Don't bother to IDCT an uninteresting component. */ /* Don't bother to IDCT an uninteresting component. */
if (! compptr->component_needed) { if (! compptr->component_needed) {
blkn += compptr->MCU_data_units; blkn += compptr->MCU_blocks;
continue; continue;
} }
inverse_DCT = lossyd->inverse_DCT[compptr->component_index]; inverse_DCT = cinfo->idct->inverse_DCT[compptr->component_index];
useful_width = (MCU_col_num < last_MCU_col) ? compptr->MCU_width useful_width = (MCU_col_num < last_MCU_col) ? compptr->MCU_width
: compptr->last_col_width; : compptr->last_col_width;
output_ptr = output_buf[compptr->component_index] + output_ptr = output_buf[compptr->component_index] +
yoffset * compptr->codec_data_unit; yoffset * compptr->DCT_scaled_size;
start_col = MCU_col_num * compptr->MCU_sample_width; start_col = MCU_col_num * compptr->MCU_sample_width;
for (yindex = 0; yindex < compptr->MCU_height; yindex++) { for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
if (cinfo->input_iMCU_row < last_iMCU_row || if (cinfo->input_iMCU_row < last_iMCU_row ||
@@ -201,11 +199,11 @@ decompress_onepass (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
(*inverse_DCT) (cinfo, compptr, (*inverse_DCT) (cinfo, compptr,
(JCOEFPTR) coef->MCU_buffer[blkn+xindex], (JCOEFPTR) coef->MCU_buffer[blkn+xindex],
output_ptr, output_col); output_ptr, output_col);
output_col += compptr->codec_data_unit; output_col += compptr->DCT_scaled_size;
} }
} }
blkn += compptr->MCU_width; blkn += compptr->MCU_width;
output_ptr += compptr->codec_data_unit; output_ptr += compptr->DCT_scaled_size;
} }
} }
} }
@@ -247,8 +245,7 @@ dummy_consume_data (j_decompress_ptr cinfo)
METHODDEF(int) METHODDEF(int)
consume_data (j_decompress_ptr cinfo) consume_data (j_decompress_ptr cinfo)
{ {
j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
d_coef_ptr coef = (d_coef_ptr) lossyd->coef_private;
JDIMENSION MCU_col_num; /* index of current MCU within row */ JDIMENSION MCU_col_num; /* index of current MCU within row */
int blkn, ci, xindex, yindex, yoffset; int blkn, ci, xindex, yindex, yoffset;
JDIMENSION start_col; JDIMENSION start_col;
@@ -287,7 +284,7 @@ consume_data (j_decompress_ptr cinfo)
} }
} }
/* Try to fetch the MCU. */ /* Try to fetch the MCU. */
if (! (*lossyd->entropy_decode_mcu) (cinfo, coef->MCU_buffer)) { if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) {
/* Suspension forced; update state counters and exit */ /* Suspension forced; update state counters and exit */
coef->MCU_vert_offset = yoffset; coef->MCU_vert_offset = yoffset;
coef->MCU_ctr = MCU_col_num; coef->MCU_ctr = MCU_col_num;
@@ -319,8 +316,7 @@ consume_data (j_decompress_ptr cinfo)
METHODDEF(int) METHODDEF(int)
decompress_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) decompress_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
{ {
j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
d_coef_ptr coef = (d_coef_ptr) lossyd->coef_private;
JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
JDIMENSION block_num; JDIMENSION block_num;
int ci, block_row, block_rows; int ci, block_row, block_rows;
@@ -355,22 +351,22 @@ decompress_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
block_rows = compptr->v_samp_factor; block_rows = compptr->v_samp_factor;
else { else {
/* NB: can't use last_row_height here; it is input-side-dependent! */ /* NB: can't use last_row_height here; it is input-side-dependent! */
block_rows = (int) (compptr->height_in_data_units % compptr->v_samp_factor); block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
if (block_rows == 0) block_rows = compptr->v_samp_factor; if (block_rows == 0) block_rows = compptr->v_samp_factor;
} }
inverse_DCT = lossyd->inverse_DCT[ci]; inverse_DCT = cinfo->idct->inverse_DCT[ci];
output_ptr = output_buf[ci]; output_ptr = output_buf[ci];
/* Loop over all DCT blocks to be processed. */ /* Loop over all DCT blocks to be processed. */
for (block_row = 0; block_row < block_rows; block_row++) { for (block_row = 0; block_row < block_rows; block_row++) {
buffer_ptr = buffer[block_row]; buffer_ptr = buffer[block_row];
output_col = 0; output_col = 0;
for (block_num = 0; block_num < compptr->width_in_data_units; block_num++) { for (block_num = 0; block_num < compptr->width_in_blocks; block_num++) {
(*inverse_DCT) (cinfo, compptr, (JCOEFPTR) buffer_ptr, (*inverse_DCT) (cinfo, compptr, (JCOEFPTR) buffer_ptr,
output_ptr, output_col); output_ptr, output_col);
buffer_ptr++; buffer_ptr++;
output_col += compptr->codec_data_unit; output_col += compptr->DCT_scaled_size;
} }
output_ptr += compptr->codec_data_unit; output_ptr += compptr->DCT_scaled_size;
} }
} }
@@ -410,8 +406,7 @@ decompress_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
LOCAL(boolean) LOCAL(boolean)
smoothing_ok (j_decompress_ptr cinfo) smoothing_ok (j_decompress_ptr cinfo)
{ {
j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
d_coef_ptr coef = (d_coef_ptr) lossyd->coef_private;
boolean smoothing_useful = FALSE; boolean smoothing_useful = FALSE;
int ci, coefi; int ci, coefi;
jpeg_component_info *compptr; jpeg_component_info *compptr;
@@ -419,7 +414,7 @@ smoothing_ok (j_decompress_ptr cinfo)
int * coef_bits; int * coef_bits;
int * coef_bits_latch; int * coef_bits_latch;
if (! cinfo->process == JPROC_PROGRESSIVE || cinfo->coef_bits == NULL) if (! cinfo->progressive_mode || cinfo->coef_bits == NULL)
return FALSE; return FALSE;
/* Allocate latch area if not already done */ /* Allocate latch area if not already done */
@@ -467,8 +462,7 @@ smoothing_ok (j_decompress_ptr cinfo)
METHODDEF(int) METHODDEF(int)
decompress_smooth_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) decompress_smooth_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
{ {
j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
d_coef_ptr coef = (d_coef_ptr) lossyd->coef_private;
JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
JDIMENSION block_num, last_block_column; JDIMENSION block_num, last_block_column;
int ci, block_row, block_rows, access_rows; int ci, block_row, block_rows, access_rows;
@@ -516,7 +510,7 @@ decompress_smooth_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
last_row = FALSE; last_row = FALSE;
} else { } else {
/* NB: can't use last_row_height here; it is input-side-dependent! */ /* NB: can't use last_row_height here; it is input-side-dependent! */
block_rows = (int) (compptr->height_in_data_units % compptr->v_samp_factor); block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
if (block_rows == 0) block_rows = compptr->v_samp_factor; if (block_rows == 0) block_rows = compptr->v_samp_factor;
access_rows = block_rows; /* this iMCU row only */ access_rows = block_rows; /* this iMCU row only */
last_row = TRUE; last_row = TRUE;
@@ -545,7 +539,7 @@ decompress_smooth_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
Q20 = quanttbl->quantval[Q20_POS]; Q20 = quanttbl->quantval[Q20_POS];
Q11 = quanttbl->quantval[Q11_POS]; Q11 = quanttbl->quantval[Q11_POS];
Q02 = quanttbl->quantval[Q02_POS]; Q02 = quanttbl->quantval[Q02_POS];
inverse_DCT = lossyd->inverse_DCT[ci]; inverse_DCT = cinfo->idct->inverse_DCT[ci];
output_ptr = output_buf[ci]; output_ptr = output_buf[ci];
/* Loop over all DCT blocks to be processed. */ /* Loop over all DCT blocks to be processed. */
for (block_row = 0; block_row < block_rows; block_row++) { for (block_row = 0; block_row < block_rows; block_row++) {
@@ -565,7 +559,7 @@ decompress_smooth_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
DC4 = DC5 = DC6 = (int) buffer_ptr[0][0]; DC4 = DC5 = DC6 = (int) buffer_ptr[0][0];
DC7 = DC8 = DC9 = (int) next_block_row[0][0]; DC7 = DC8 = DC9 = (int) next_block_row[0][0];
output_col = 0; output_col = 0;
last_block_column = compptr->width_in_data_units - 1; last_block_column = compptr->width_in_blocks - 1;
for (block_num = 0; block_num <= last_block_column; block_num++) { for (block_num = 0; block_num <= last_block_column; block_num++) {
/* Fetch current DCT block into workspace so we can modify it. */ /* Fetch current DCT block into workspace so we can modify it. */
jcopy_block_row(buffer_ptr, (JBLOCKROW) workspace, (JDIMENSION) 1); jcopy_block_row(buffer_ptr, (JBLOCKROW) workspace, (JDIMENSION) 1);
@@ -662,9 +656,9 @@ decompress_smooth_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
DC4 = DC5; DC5 = DC6; DC4 = DC5; DC5 = DC6;
DC7 = DC8; DC8 = DC9; DC7 = DC8; DC8 = DC9;
buffer_ptr++, prev_block_row++, next_block_row++; buffer_ptr++, prev_block_row++, next_block_row++;
output_col += compptr->codec_data_unit; output_col += compptr->DCT_scaled_size;
} }
output_ptr += compptr->codec_data_unit; output_ptr += compptr->DCT_scaled_size;
} }
} }
@@ -683,15 +677,14 @@ decompress_smooth_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
GLOBAL(void) GLOBAL(void)
jinit_d_coef_controller (j_decompress_ptr cinfo, boolean need_full_buffer) jinit_d_coef_controller (j_decompress_ptr cinfo, boolean need_full_buffer)
{ {
j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; my_coef_ptr coef;
d_coef_ptr coef;
coef = (d_coef_ptr) coef = (my_coef_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(d_coef_controller)); SIZEOF(my_coef_controller));
lossyd->coef_private = (void *) coef; cinfo->coef = (struct jpeg_d_coef_controller *) coef;
lossyd->coef_start_input_pass = start_input_pass; coef->pub.start_input_pass = start_input_pass;
lossyd->coef_start_output_pass = start_output_pass; coef->pub.start_output_pass = start_output_pass;
#ifdef BLOCK_SMOOTHING_SUPPORTED #ifdef BLOCK_SMOOTHING_SUPPORTED
coef->coef_bits_latch = NULL; coef->coef_bits_latch = NULL;
#endif #endif
@@ -710,20 +703,20 @@ jinit_d_coef_controller (j_decompress_ptr cinfo, boolean need_full_buffer)
access_rows = compptr->v_samp_factor; access_rows = compptr->v_samp_factor;
#ifdef BLOCK_SMOOTHING_SUPPORTED #ifdef BLOCK_SMOOTHING_SUPPORTED
/* If block smoothing could be used, need a bigger window */ /* If block smoothing could be used, need a bigger window */
if (cinfo->process == JPROC_PROGRESSIVE) if (cinfo->progressive_mode)
access_rows *= 3; access_rows *= 3;
#endif #endif
coef->whole_image[ci] = (*cinfo->mem->request_virt_barray) coef->whole_image[ci] = (*cinfo->mem->request_virt_barray)
((j_common_ptr) cinfo, JPOOL_IMAGE, TRUE, ((j_common_ptr) cinfo, JPOOL_IMAGE, TRUE,
(JDIMENSION) jround_up((long) compptr->width_in_data_units, (JDIMENSION) jround_up((long) compptr->width_in_blocks,
(long) compptr->h_samp_factor), (long) compptr->h_samp_factor),
(JDIMENSION) jround_up((long) compptr->height_in_data_units, (JDIMENSION) jround_up((long) compptr->height_in_blocks,
(long) compptr->v_samp_factor), (long) compptr->v_samp_factor),
(JDIMENSION) access_rows); (JDIMENSION) access_rows);
} }
lossyd->pub.consume_data = consume_data; coef->pub.consume_data = consume_data;
lossyd->pub.decompress_data = decompress_data; coef->pub.decompress_data = decompress_data;
lossyd->coef_arrays = coef->whole_image; /* link to virtual arrays */ coef->pub.coef_arrays = coef->whole_image; /* link to virtual arrays */
#else #else
ERREXIT(cinfo, JERR_NOT_COMPILED); ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif #endif
@@ -734,12 +727,12 @@ jinit_d_coef_controller (j_decompress_ptr cinfo, boolean need_full_buffer)
buffer = (JBLOCKROW) buffer = (JBLOCKROW)
(*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
D_MAX_DATA_UNITS_IN_MCU * SIZEOF(JBLOCK)); D_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK));
for (i = 0; i < D_MAX_DATA_UNITS_IN_MCU; i++) { for (i = 0; i < D_MAX_BLOCKS_IN_MCU; i++) {
coef->MCU_buffer[i] = buffer + i; coef->MCU_buffer[i] = buffer + i;
} }
lossyd->pub.consume_data = dummy_consume_data; coef->pub.consume_data = dummy_consume_data;
lossyd->pub.decompress_data = decompress_onepass; coef->pub.decompress_data = decompress_onepass;
lossyd->coef_arrays = NULL; /* flag for no virtual arrays */ coef->pub.coef_arrays = NULL; /* flag for no virtual arrays */
} }
} }

View File

@@ -1,8 +1,10 @@
/* /*
* jdcolor.c * jdcolor.c
* *
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1997, Thomas G. Lane. * Copyright (C) 1991-1997, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software. * Lossless JPEG Modifications:
* Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains output colorspace conversion routines. * This file contains output colorspace conversion routines.
@@ -389,6 +391,15 @@ jinit_color_deconverter (j_decompress_ptr cinfo)
break; break;
} }
/* Prevent lossy color conversion in lossless mode */
if (cinfo->master->lossless) {
if ((cinfo->out_color_space == JCS_GRAYSCALE &&
cinfo->jpeg_color_space != JCS_GRAYSCALE) ||
(cinfo->out_color_space != JCS_GRAYSCALE &&
cconvert->pub.color_convert != null_convert))
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
}
if (cinfo->quantize_colors) if (cinfo->quantize_colors)
cinfo->output_components = 1; /* single colormapped output component */ cinfo->output_components = 1; /* single colormapped output component */
else else

View File

@@ -1,10 +1,8 @@
/* /*
* jddctmgr.c * jddctmgr.c
* *
* This file was part of the Independent JPEG Group's software: * Copyright (C) 1994-1996, Thomas G. Lane.
* Copyright (C) 1994-1998, Thomas G. Lane. * This file is part of the Independent JPEG Group's software.
* Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains the inverse-DCT management logic. * This file contains the inverse-DCT management logic.
@@ -20,7 +18,6 @@
#define JPEG_INTERNALS #define JPEG_INTERNALS
#include "jinclude.h" #include "jinclude.h"
#include "jpeglib.h" #include "jpeglib.h"
#include "jlossy.h" /* Private declarations for lossy subsystem */
#include "jdct.h" /* Private declarations for DCT subsystem */ #include "jdct.h" /* Private declarations for DCT subsystem */
@@ -44,15 +41,17 @@
/* Private subobject for this module */ /* Private subobject for this module */
typedef struct { typedef struct {
struct jpeg_inverse_dct pub; /* public fields */
/* This array contains the IDCT method code that each multiplier table /* This array contains the IDCT method code that each multiplier table
* is currently set up for, or -1 if it's not yet set up. * is currently set up for, or -1 if it's not yet set up.
* The actual multiplier tables are pointed to by dct_table in the * The actual multiplier tables are pointed to by dct_table in the
* per-component comp_info structures. * per-component comp_info structures.
*/ */
int cur_method[MAX_COMPONENTS]; int cur_method[MAX_COMPONENTS];
} idct_controller; } my_idct_controller;
typedef idct_controller * idct_ptr; typedef my_idct_controller * my_idct_ptr;
/* Allocated multiplier tables: big enough for any supported variant */ /* Allocated multiplier tables: big enough for any supported variant */
@@ -89,8 +88,7 @@ typedef union {
METHODDEF(void) METHODDEF(void)
start_pass (j_decompress_ptr cinfo) start_pass (j_decompress_ptr cinfo)
{ {
j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; my_idct_ptr idct = (my_idct_ptr) cinfo->idct;
idct_ptr idct = (idct_ptr) lossyd->idct_private;
int ci, i; int ci, i;
jpeg_component_info *compptr; jpeg_component_info *compptr;
int method = 0; int method = 0;
@@ -100,7 +98,7 @@ start_pass (j_decompress_ptr cinfo)
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) { ci++, compptr++) {
/* Select the proper IDCT routine for this component's scaling */ /* Select the proper IDCT routine for this component's scaling */
switch (compptr->codec_data_unit) { switch (compptr->DCT_scaled_size) {
#ifdef IDCT_SCALING_SUPPORTED #ifdef IDCT_SCALING_SUPPORTED
case 1: case 1:
method_ptr = jpeg_idct_1x1; method_ptr = jpeg_idct_1x1;
@@ -141,10 +139,10 @@ start_pass (j_decompress_ptr cinfo)
} }
break; break;
default: default:
ERREXIT1(cinfo, JERR_BAD_DCTSIZE, compptr->codec_data_unit); ERREXIT1(cinfo, JERR_BAD_DCTSIZE, compptr->DCT_scaled_size);
break; break;
} }
lossyd->inverse_DCT[ci] = method_ptr; idct->pub.inverse_DCT[ci] = method_ptr;
/* Create multiplier table from quant table. /* Create multiplier table from quant table.
* However, we can skip this if the component is uninteresting * However, we can skip this if the component is uninteresting
* or if we already built the table. Also, if no quant table * or if we already built the table. Also, if no quant table
@@ -248,16 +246,15 @@ start_pass (j_decompress_ptr cinfo)
GLOBAL(void) GLOBAL(void)
jinit_inverse_dct (j_decompress_ptr cinfo) jinit_inverse_dct (j_decompress_ptr cinfo)
{ {
j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; my_idct_ptr idct;
idct_ptr idct;
int ci; int ci;
jpeg_component_info *compptr; jpeg_component_info *compptr;
idct = (idct_ptr) idct = (my_idct_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(idct_controller)); SIZEOF(my_idct_controller));
lossyd->idct_private = (void *) idct; cinfo->idct = (struct jpeg_inverse_dct *) idct;
lossyd->idct_start_pass = start_pass; idct->pub.start_pass = start_pass;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) { ci++, compptr++) {

View File

@@ -2,9 +2,10 @@
* jddiffct.c * jddiffct.c
* *
* This file was part of the Independent JPEG Group's software: * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1998, Thomas G. Lane. * Copyright (C) 1994-1997, Thomas G. Lane.
* Lossless JPEG Modifications: * Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison. * Copyright (C) 1999, Ken Murchison.
* Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains the [un]difference buffer controller for decompression. * This file contains the [un]difference buffer controller for decompression.
@@ -20,7 +21,7 @@
#define JPEG_INTERNALS #define JPEG_INTERNALS
#include "jinclude.h" #include "jinclude.h"
#include "jpeglib.h" #include "jpeglib.h"
#include "jlossls.h" #include "jlossls.h" /* Private declarations for lossless codec */
#ifdef D_LOSSLESS_SUPPORTED #ifdef D_LOSSLESS_SUPPORTED
@@ -28,10 +29,13 @@
/* Private buffer controller object */ /* Private buffer controller object */
typedef struct { typedef struct {
struct jpeg_d_coef_controller pub; /* public fields */
/* These variables keep track of the current location of the input side. */ /* These variables keep track of the current location of the input side. */
/* cinfo->input_iMCU_row is also used for this. */ /* cinfo->input_iMCU_row is also used for this. */
JDIMENSION MCU_ctr; /* counts MCUs processed in current row */ JDIMENSION MCU_ctr; /* counts MCUs processed in current row */
unsigned int restart_rows_to_go; /* MCU-rows left in this restart interval */ unsigned int restart_rows_to_go; /* MCU rows left in this restart
interval */
unsigned int MCU_vert_offset; /* counts MCU rows within iMCU row */ unsigned int MCU_vert_offset; /* counts MCU rows within iMCU row */
unsigned int MCU_rows_per_iMCU_row; /* number of such rows needed */ unsigned int MCU_rows_per_iMCU_row; /* number of such rows needed */
@@ -44,9 +48,9 @@ typedef struct {
/* In multi-pass modes, we need a virtual sample array for each component. */ /* In multi-pass modes, we need a virtual sample array for each component. */
jvirt_sarray_ptr whole_image[MAX_COMPONENTS]; jvirt_sarray_ptr whole_image[MAX_COMPONENTS];
#endif #endif
} d_diff_controller; } my_diff_controller;
typedef d_diff_controller * d_diff_ptr; typedef my_diff_controller * my_diff_ptr;
/* Forward declarations */ /* Forward declarations */
METHODDEF(int) decompress_data METHODDEF(int) decompress_data
@@ -61,8 +65,7 @@ LOCAL(void)
start_iMCU_row (j_decompress_ptr cinfo) start_iMCU_row (j_decompress_ptr cinfo)
/* Reset within-iMCU-row counters for a new row (input side) */ /* Reset within-iMCU-row counters for a new row (input side) */
{ {
j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; my_diff_ptr diff = (my_diff_ptr) cinfo->coef;
d_diff_ptr diff = (d_diff_ptr) losslsd->diff_private;
/* In an interleaved scan, an MCU row is the same as an iMCU row. /* In an interleaved scan, an MCU row is the same as an iMCU row.
* In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
@@ -89,11 +92,17 @@ start_iMCU_row (j_decompress_ptr cinfo)
METHODDEF(void) METHODDEF(void)
start_input_pass (j_decompress_ptr cinfo) start_input_pass (j_decompress_ptr cinfo)
{ {
j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; my_diff_ptr diff = (my_diff_ptr) cinfo->coef;
d_diff_ptr diff = (d_diff_ptr) losslsd->diff_private;
/* Because it is hitching a ride on the jpeg_inverse_dct struct,
* start_pass_lossless() will be called at the start of the output pass.
* This ensures that it will be called at the start of the input pass as
* well.
*/
(*cinfo->idct->start_pass) (cinfo);
/* Check that the restart interval is an integer multiple of the number /* Check that the restart interval is an integer multiple of the number
* of MCU in an MCU-row. * of MCUs in an MCU row.
*/ */
if (cinfo->restart_interval % cinfo->MCUs_per_row != 0) if (cinfo->restart_interval % cinfo->MCUs_per_row != 0)
ERREXIT2(cinfo, JERR_BAD_RESTART, ERREXIT2(cinfo, JERR_BAD_RESTART,
@@ -115,13 +124,13 @@ start_input_pass (j_decompress_ptr cinfo)
METHODDEF(boolean) METHODDEF(boolean)
process_restart (j_decompress_ptr cinfo) process_restart (j_decompress_ptr cinfo)
{ {
j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; my_diff_ptr diff = (my_diff_ptr) cinfo->coef;
d_diff_ptr diff = (d_diff_ptr) losslsd->diff_private; lossless_decomp_ptr losslessd = (lossless_decomp_ptr) cinfo->idct;
if (! (*losslsd->entropy_process_restart) (cinfo)) if (! (*cinfo->entropy->process_restart) (cinfo))
return FALSE; return FALSE;
(*losslsd->predict_process_restart) (cinfo); (*losslessd->predict_process_restart) (cinfo);
/* Reset restart counter */ /* Reset restart counter */
diff->restart_rows_to_go = cinfo->restart_interval / cinfo->MCUs_per_row; diff->restart_rows_to_go = cinfo->restart_interval / cinfo->MCUs_per_row;
@@ -154,12 +163,12 @@ start_output_pass (j_decompress_ptr cinfo)
METHODDEF(int) METHODDEF(int)
decompress_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) decompress_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
{ {
j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; my_diff_ptr diff = (my_diff_ptr) cinfo->coef;
d_diff_ptr diff = (d_diff_ptr) losslsd->diff_private; lossless_decomp_ptr losslessd = (lossless_decomp_ptr) cinfo->idct;
JDIMENSION MCU_col_num; /* index of current MCU within row */ JDIMENSION MCU_col_num; /* index of current MCU within row */
JDIMENSION MCU_count; /* number of MCUs decoded */ JDIMENSION MCU_count; /* number of MCUs decoded */
JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
int comp, ci, yoffset, row, prev_row; int ci, compi, yoffset, row, prev_row;
jpeg_component_info *compptr; jpeg_component_info *compptr;
/* Loop to process as much as one whole iMCU row */ /* Loop to process as much as one whole iMCU row */
@@ -174,9 +183,9 @@ decompress_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
} }
MCU_col_num = diff->MCU_ctr; MCU_col_num = diff->MCU_ctr;
/* Try to fetch an MCU-row (or remaining portion of suspended MCU-row). */ /* Try to fetch an MCU row (or remaining portion of suspended MCU row). */
MCU_count = MCU_count =
(*losslsd->entropy_decode_mcus) (cinfo, (*cinfo->entropy->decode_mcus) (cinfo,
diff->diff_buf, yoffset, MCU_col_num, diff->diff_buf, yoffset, MCU_col_num,
cinfo->MCUs_per_row - MCU_col_num); cinfo->MCUs_per_row - MCU_col_num);
if (MCU_count != cinfo->MCUs_per_row - MCU_col_num) { if (MCU_count != cinfo->MCUs_per_row - MCU_col_num) {
@@ -194,25 +203,24 @@ decompress_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
} }
/* /*
* Undifference and scale each scanline of the disassembled MCU-row * Undifference and scale each scanline of the disassembled MCU row
* separately. We do not process dummy samples at the end of a scanline * separately. We do not process dummy samples at the end of a scanline
* or dummy rows at the end of the image. * or dummy rows at the end of the image.
*/ */
for (comp = 0; comp < cinfo->comps_in_scan; comp++) { for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[comp]; compptr = cinfo->cur_comp_info[ci];
ci = compptr->component_index; compi = compptr->component_index;
for (row = 0, prev_row = compptr->v_samp_factor - 1; for (row = 0, prev_row = compptr->v_samp_factor - 1;
row < (cinfo->input_iMCU_row == last_iMCU_row ? row < (cinfo->input_iMCU_row == last_iMCU_row ?
compptr->last_row_height : compptr->v_samp_factor); compptr->last_row_height : compptr->v_samp_factor);
prev_row = row, row++) { prev_row = row, row++) {
(*losslsd->predict_undifference[ci]) (cinfo, ci, (*losslessd->predict_undifference[compi])
diff->diff_buf[ci][row], (cinfo, compi, diff->diff_buf[compi][row],
diff->undiff_buf[ci][prev_row], diff->undiff_buf[compi][prev_row], diff->undiff_buf[compi][row],
diff->undiff_buf[ci][row], compptr->width_in_blocks);
compptr->width_in_data_units); (*losslessd->scaler_scale) (cinfo, diff->undiff_buf[compi][row],
(*losslsd->scaler_scale) (cinfo, diff->undiff_buf[ci][row], output_buf[compi][row],
output_buf[ci][row], compptr->width_in_blocks);
compptr->width_in_data_units);
} }
} }
@@ -255,21 +263,16 @@ dummy_consume_data (j_decompress_ptr cinfo)
METHODDEF(int) METHODDEF(int)
consume_data (j_decompress_ptr cinfo) consume_data (j_decompress_ptr cinfo)
{ {
j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; my_diff_ptr diff = (my_diff_ptr) cinfo->coef;
d_diff_ptr diff = (d_diff_ptr) losslsd->diff_private; int ci;
JDIMENSION MCU_col_num; /* index of current MCU within row */
JDIMENSION MCU_count; /* number of MCUs decoded */
JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
int comp, ci, yoffset, row, prev_row;
JSAMPARRAY buffer[MAX_COMPS_IN_SCAN]; JSAMPARRAY buffer[MAX_COMPS_IN_SCAN];
jpeg_component_info *compptr; jpeg_component_info *compptr;
/* Align the virtual buffers for the components used in this scan. */ /* Align the virtual buffers for the components used in this scan. */
for (comp = 0; comp < cinfo->comps_in_scan; comp++) { for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[comp]; compptr = cinfo->cur_comp_info[ci];
ci = compptr->component_index; buffer[compptr->component_index] = (*cinfo->mem->access_virt_sarray)
buffer[ci] = (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo, diff->whole_image[compptr->component_index],
((j_common_ptr) cinfo, diff->whole_image[ci],
cinfo->input_iMCU_row * compptr->v_samp_factor, cinfo->input_iMCU_row * compptr->v_samp_factor,
(JDIMENSION) compptr->v_samp_factor, TRUE); (JDIMENSION) compptr->v_samp_factor, TRUE);
} }
@@ -279,7 +282,7 @@ consume_data (j_decompress_ptr cinfo)
/* /*
* Output some data from the full-image buffer sample in the multi-pass case. * Output some data from the full-image sample buffer in the multi-pass case.
* Always attempts to emit one fully interleaved MCU row ("iMCU" row). * Always attempts to emit one fully interleaved MCU row ("iMCU" row).
* Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED.
* *
@@ -289,8 +292,7 @@ consume_data (j_decompress_ptr cinfo)
METHODDEF(int) METHODDEF(int)
output_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) output_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
{ {
j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; my_diff_ptr diff = (my_diff_ptr) cinfo->coef;
d_diff_ptr diff = (d_diff_ptr) losslsd->diff_private;
JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
int ci, samp_rows, row; int ci, samp_rows, row;
JSAMPARRAY buffer; JSAMPARRAY buffer;
@@ -317,13 +319,13 @@ output_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
samp_rows = compptr->v_samp_factor; samp_rows = compptr->v_samp_factor;
else { else {
/* NB: can't use last_row_height here; it is input-side-dependent! */ /* NB: can't use last_row_height here; it is input-side-dependent! */
samp_rows = (int) (compptr->height_in_data_units % compptr->v_samp_factor); samp_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
if (samp_rows == 0) samp_rows = compptr->v_samp_factor; if (samp_rows == 0) samp_rows = compptr->v_samp_factor;
} }
for (row = 0; row < samp_rows; row++) { for (row = 0; row < samp_rows; row++) {
MEMCOPY(output_buf[ci][row], buffer[row], MEMCOPY(output_buf[ci][row], buffer[row],
compptr->width_in_data_units * SIZEOF(JSAMPLE)); compptr->width_in_blocks * SIZEOF(JSAMPLE));
} }
} }
@@ -342,29 +344,28 @@ output_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
GLOBAL(void) GLOBAL(void)
jinit_d_diff_controller (j_decompress_ptr cinfo, boolean need_full_buffer) jinit_d_diff_controller (j_decompress_ptr cinfo, boolean need_full_buffer)
{ {
j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; my_diff_ptr diff;
d_diff_ptr diff;
int ci; int ci;
jpeg_component_info *compptr; jpeg_component_info *compptr;
diff = (d_diff_ptr) diff = (my_diff_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(d_diff_controller)); SIZEOF(my_diff_controller));
losslsd->diff_private = (void *) diff; cinfo->coef = (struct jpeg_d_coef_controller *) diff;
losslsd->diff_start_input_pass = start_input_pass; diff->pub.start_input_pass = start_input_pass;
losslsd->pub.start_output_pass = start_output_pass; diff->pub.start_output_pass = start_output_pass;
/* Create the [un]difference buffers. */ /* Create the [un]difference buffers. */
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) { ci++, compptr++) {
diff->diff_buf[ci] = (*cinfo->mem->alloc_darray) diff->diff_buf[ci] =
((j_common_ptr) cinfo, JPOOL_IMAGE, ALLOC_DARRAY(JPOOL_IMAGE,
(JDIMENSION) jround_up((long) compptr->width_in_data_units, (JDIMENSION) jround_up((long) compptr->width_in_blocks,
(long) compptr->h_samp_factor), (long) compptr->h_samp_factor),
(JDIMENSION) compptr->v_samp_factor); (JDIMENSION) compptr->v_samp_factor);
diff->undiff_buf[ci] = (*cinfo->mem->alloc_darray) diff->undiff_buf[ci] =
((j_common_ptr) cinfo, JPOOL_IMAGE, ALLOC_DARRAY(JPOOL_IMAGE,
(JDIMENSION) jround_up((long) compptr->width_in_data_units, (JDIMENSION) jround_up((long) compptr->width_in_blocks,
(long) compptr->h_samp_factor), (long) compptr->h_samp_factor),
(JDIMENSION) compptr->v_samp_factor); (JDIMENSION) compptr->v_samp_factor);
} }
@@ -379,20 +380,20 @@ jinit_d_diff_controller (j_decompress_ptr cinfo, boolean need_full_buffer)
access_rows = compptr->v_samp_factor; access_rows = compptr->v_samp_factor;
diff->whole_image[ci] = (*cinfo->mem->request_virt_sarray) diff->whole_image[ci] = (*cinfo->mem->request_virt_sarray)
((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
(JDIMENSION) jround_up((long) compptr->width_in_data_units, (JDIMENSION) jround_up((long) compptr->width_in_blocks,
(long) compptr->h_samp_factor), (long) compptr->h_samp_factor),
(JDIMENSION) jround_up((long) compptr->height_in_data_units, (JDIMENSION) jround_up((long) compptr->height_in_blocks,
(long) compptr->v_samp_factor), (long) compptr->v_samp_factor),
(JDIMENSION) access_rows); (JDIMENSION) access_rows);
} }
losslsd->pub.consume_data = consume_data; diff->pub.consume_data = consume_data;
losslsd->pub.decompress_data = output_data; diff->pub.decompress_data = output_data;
#else #else
ERREXIT(cinfo, JERR_NOT_COMPILED); ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif #endif
} else { } else {
losslsd->pub.consume_data = dummy_consume_data; diff->pub.consume_data = dummy_consume_data;
losslsd->pub.decompress_data = decompress_data; diff->pub.decompress_data = decompress_data;
diff->whole_image[0] = NULL; /* flag for no virtual arrays */ diff->whole_image[0] = NULL; /* flag for no virtual arrays */
} }
} }

371
jdhuff.c
View File

@@ -2,26 +2,150 @@
* jdhuff.c * jdhuff.c
* *
* This file was part of the Independent JPEG Group's software: * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1998, Thomas G. Lane. * Copyright (C) 1991-1997, Thomas G. Lane.
* Lossless JPEG Modifications: * Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison. * Copyright (C) 1999, Ken Murchison.
* Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains Huffman entropy decoding routines which are shared * This file contains Huffman entropy decoding routines.
* by the sequential, progressive and lossless decoders. *
* Much of the complexity here has to do with supporting input suspension.
* If the data source module demands suspension, we want to be able to back
* up to the start of the current MCU. To do this, we copy state variables
* into local working storage, and update them back to the permanent
* storage only upon successful completion of an MCU.
*/ */
#define JPEG_INTERNALS #define JPEG_INTERNALS
#include "jinclude.h" #include "jinclude.h"
#include "jpeglib.h" #include "jpeglib.h"
#include "jlossy.h" /* Private declarations for lossy codec */
#include "jlossls.h" /* Private declarations for lossless codec */
#include "jdhuff.h" /* Declarations shared with jd*huff.c */ #include "jdhuff.h" /* Declarations shared with jd*huff.c */
/*
* Expanded entropy decoder object for Huffman decoding.
*
* The savable_state subrecord contains fields that change within an MCU,
* but must not be updated permanently until we complete the MCU.
*/
typedef struct {
int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */
} savable_state;
/* This macro is to work around compilers with missing or broken
* structure assignment. You'll need to fix this code if you have
* such a compiler and you change MAX_COMPS_IN_SCAN.
*/
#ifndef NO_STRUCT_ASSIGN
#define ASSIGN_STATE(dest,src) ((dest) = (src))
#else
#if MAX_COMPS_IN_SCAN == 4
#define ASSIGN_STATE(dest,src) \
((dest).last_dc_val[0] = (src).last_dc_val[0], \
(dest).last_dc_val[1] = (src).last_dc_val[1], \
(dest).last_dc_val[2] = (src).last_dc_val[2], \
(dest).last_dc_val[3] = (src).last_dc_val[3])
#endif
#endif
typedef struct {
struct jpeg_entropy_decoder pub; /* public fields */
/* These fields are loaded into local variables at start of each MCU.
* In case of suspension, we exit WITHOUT updating them.
*/
bitread_perm_state bitstate; /* Bit buffer at start of MCU */
savable_state saved; /* Other state at start of MCU */
/* These fields are NOT loaded into local working state. */
unsigned int restarts_to_go; /* MCUs left in this restart interval */
/* Pointers to derived tables (these workspaces have image lifespan) */
d_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS];
d_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS];
/* Precalculated info set up by start_pass for use in decode_mcu: */
/* Pointers to derived tables to be used for each block within an MCU */
d_derived_tbl * dc_cur_tbls[D_MAX_BLOCKS_IN_MCU];
d_derived_tbl * ac_cur_tbls[D_MAX_BLOCKS_IN_MCU];
/* Whether we care about the DC and AC coefficient values for each block */
boolean dc_needed[D_MAX_BLOCKS_IN_MCU];
boolean ac_needed[D_MAX_BLOCKS_IN_MCU];
} huff_entropy_decoder;
typedef huff_entropy_decoder * huff_entropy_ptr;
/*
* Initialize for a Huffman-compressed scan.
*/
METHODDEF(void)
start_pass_huff_decoder (j_decompress_ptr cinfo)
{
huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
int ci, blkn, dctbl, actbl;
jpeg_component_info * compptr;
/* Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG.
* This ought to be an error condition, but we make it a warning because
* there are some baseline files out there with all zeroes in these bytes.
*/
if (cinfo->Ss != 0 || cinfo->Se != DCTSIZE2-1 ||
cinfo->Ah != 0 || cinfo->Al != 0)
WARNMS(cinfo, JWRN_NOT_SEQUENTIAL);
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
dctbl = compptr->dc_tbl_no;
actbl = compptr->ac_tbl_no;
/* Compute derived values for Huffman tables */
/* We may do this more than once for a table, but it's not expensive */
jpeg_make_d_derived_tbl(cinfo, TRUE, dctbl,
& entropy->dc_derived_tbls[dctbl]);
jpeg_make_d_derived_tbl(cinfo, FALSE, actbl,
& entropy->ac_derived_tbls[actbl]);
/* Initialize DC predictions to 0 */
entropy->saved.last_dc_val[ci] = 0;
}
/* Precalculate decoding info for each block in an MCU of this scan */
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
ci = cinfo->MCU_membership[blkn];
compptr = cinfo->cur_comp_info[ci];
/* Precalculate which table to use for each block */
entropy->dc_cur_tbls[blkn] = entropy->dc_derived_tbls[compptr->dc_tbl_no];
entropy->ac_cur_tbls[blkn] = entropy->ac_derived_tbls[compptr->ac_tbl_no];
/* Decide whether we really care about the coefficient values */
if (compptr->component_needed) {
entropy->dc_needed[blkn] = TRUE;
/* we don't need the ACs if producing a 1/8th-size image */
entropy->ac_needed[blkn] = (compptr->DCT_scaled_size > 1);
} else {
entropy->dc_needed[blkn] = entropy->ac_needed[blkn] = FALSE;
}
}
/* Initialize bitread state variables */
entropy->bitstate.bits_left = 0;
entropy->bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */
entropy->pub.insufficient_data = FALSE;
/* Initialize restart counter */
entropy->restarts_to_go = cinfo->restart_interval;
}
/* /*
* Compute the derived values for a Huffman table. * Compute the derived values for a Huffman table.
* This routine also performs some validation checks on the table. * This routine also performs some validation checks on the table.
*
* Note this is also used by jdphuff.c and jdlhuff.c.
*/ */
GLOBAL(void) GLOBAL(void)
@@ -131,14 +255,14 @@ jpeg_make_d_derived_tbl (j_decompress_ptr cinfo, boolean isDC, int tblno,
/* Validate symbols as being reasonable. /* Validate symbols as being reasonable.
* For AC tables, we make no check, but accept all byte values 0..255. * For AC tables, we make no check, but accept all byte values 0..255.
* For DC tables, we require the symbols to be in range 0..16. * For DC tables, we require the symbols to be in range 0..15 in lossy mode
* (Tighter bounds could be applied depending on the data depth and mode, * and 0..16 in lossless mode. (Tighter bounds could be applied depending on
* but this is sufficient to ensure safe decoding.) * the data depth and mode, but this is sufficient to ensure safe decoding.)
*/ */
if (isDC) { if (isDC) {
for (i = 0; i < numsymbols; i++) { for (i = 0; i < numsymbols; i++) {
int sym = htbl->huffval[i]; int sym = htbl->huffval[i];
if (sym < 0 || sym > 16) if (sym < 0 || sym > (cinfo->master->lossless ? 16 : 15))
ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
} }
} }
@@ -146,7 +270,7 @@ jpeg_make_d_derived_tbl (j_decompress_ptr cinfo, boolean isDC, int tblno,
/* /*
* Out-of-line code for bit fetching. * Out-of-line code for bit fetching (shared with jdphuff.c and jdlhuff.c).
* See jdhuff.h for info about usage. * See jdhuff.h for info about usage.
* Note: current values of get_buffer and bits_left are passed as parameters, * Note: current values of get_buffer and bits_left are passed as parameters,
* but are returned in the corresponding fields of the state struct. * but are returned in the corresponding fields of the state struct.
@@ -248,14 +372,9 @@ jpeg_fill_bit_buffer (bitread_working_state * state,
* We use a nonvolatile flag to ensure that only one warning message * We use a nonvolatile flag to ensure that only one warning message
* appears per data segment. * appears per data segment.
*/ */
huffd_common_ptr huffd; if (! cinfo->entropy->insufficient_data) {
if (cinfo->process == JPROC_LOSSLESS)
huffd = (huffd_common_ptr) ((j_lossless_d_ptr) cinfo->codec)->entropy_private;
else
huffd = (huffd_common_ptr) ((j_lossy_d_ptr) cinfo->codec)->entropy_private;
if (! huffd->insufficient_data) {
WARNMS(cinfo, JWRN_HIT_MARKER); WARNMS(cinfo, JWRN_HIT_MARKER);
huffd->insufficient_data = TRUE; cinfo->entropy->insufficient_data = TRUE;
} }
/* Fill the buffer with zero bits */ /* Fill the buffer with zero bits */
get_buffer <<= MIN_GET_BITS - bits_left; get_buffer <<= MIN_GET_BITS - bits_left;
@@ -315,3 +434,221 @@ jpeg_huff_decode (bitread_working_state * state,
return htbl->pub->huffval[ (int) (code + htbl->valoffset[l]) ]; return htbl->pub->huffval[ (int) (code + htbl->valoffset[l]) ];
} }
/*
* Figure F.12: extend sign bit.
* On some machines, a shift and add will be faster than a table lookup.
*/
#ifdef AVOID_TABLES
#define HUFF_EXTEND(x,s) ((x) < (1<<((s)-1)) ? (x) + (((-1)<<(s)) + 1) : (x))
#else
#define HUFF_EXTEND(x,s) ((x) < extend_test[s] ? (x) + extend_offset[s] : (x))
static const int extend_test[16] = /* entry n is 2**(n-1) */
{ 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000 };
static const int extend_offset[16] = /* entry n is (-1 << n) + 1 */
{ 0, ((-1)<<1) + 1, ((-1)<<2) + 1, ((-1)<<3) + 1, ((-1)<<4) + 1,
((-1)<<5) + 1, ((-1)<<6) + 1, ((-1)<<7) + 1, ((-1)<<8) + 1,
((-1)<<9) + 1, ((-1)<<10) + 1, ((-1)<<11) + 1, ((-1)<<12) + 1,
((-1)<<13) + 1, ((-1)<<14) + 1, ((-1)<<15) + 1 };
#endif /* AVOID_TABLES */
/*
* Check for a restart marker & resynchronize decoder.
* Returns FALSE if must suspend.
*/
LOCAL(boolean)
process_restart (j_decompress_ptr cinfo)
{
huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
int ci;
/* Throw away any unused bits remaining in bit buffer; */
/* include any full bytes in next_marker's count of discarded bytes */
cinfo->marker->discarded_bytes += entropy->bitstate.bits_left / 8;
entropy->bitstate.bits_left = 0;
/* Advance past the RSTn marker */
if (! (*cinfo->marker->read_restart_marker) (cinfo))
return FALSE;
/* Re-initialize DC predictions to 0 */
for (ci = 0; ci < cinfo->comps_in_scan; ci++)
entropy->saved.last_dc_val[ci] = 0;
/* Reset restart counter */
entropy->restarts_to_go = cinfo->restart_interval;
/* Reset out-of-data flag, unless read_restart_marker left us smack up
* against a marker. In that case we will end up treating the next data
* segment as empty, and we can avoid producing bogus output pixels by
* leaving the flag set.
*/
if (cinfo->unread_marker == 0)
entropy->pub.insufficient_data = FALSE;
return TRUE;
}
/*
* Decode and return one MCU's worth of Huffman-compressed coefficients.
* The coefficients are reordered from zigzag order into natural array order,
* but are not dequantized.
*
* The i'th block of the MCU is stored into the block pointed to by
* MCU_data[i]. WE ASSUME THIS AREA HAS BEEN ZEROED BY THE CALLER.
* (Wholesale zeroing is usually a little faster than retail...)
*
* Returns FALSE if data source requested suspension. In that case no
* changes have been made to permanent state. (Exception: some output
* coefficients may already have been assigned. This is harmless for
* this module, since we'll just re-assign them on the next call.)
*/
METHODDEF(boolean)
decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
{
huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
int blkn;
BITREAD_STATE_VARS;
savable_state state;
/* Process restart marker if needed; may have to suspend */
if (cinfo->restart_interval) {
if (entropy->restarts_to_go == 0)
if (! process_restart(cinfo))
return FALSE;
}
/* If we've run out of data, just leave the MCU set to zeroes.
* This way, we return uniform gray for the remainder of the segment.
*/
if (! entropy->pub.insufficient_data) {
/* Load up working state */
BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
ASSIGN_STATE(state, entropy->saved);
/* Outer loop handles each block in the MCU */
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
JBLOCKROW block = MCU_data[blkn];
d_derived_tbl * dctbl = entropy->dc_cur_tbls[blkn];
d_derived_tbl * actbl = entropy->ac_cur_tbls[blkn];
register int s, k, r;
/* Decode a single block's worth of coefficients */
/* Section F.2.2.1: decode the DC coefficient difference */
HUFF_DECODE(s, br_state, dctbl, return FALSE, label1);
if (s) {
CHECK_BIT_BUFFER(br_state, s, return FALSE);
r = GET_BITS(s);
s = HUFF_EXTEND(r, s);
}
if (entropy->dc_needed[blkn]) {
/* Convert DC difference to actual value, update last_dc_val */
int ci = cinfo->MCU_membership[blkn];
s += state.last_dc_val[ci];
state.last_dc_val[ci] = s;
/* Output the DC coefficient (assumes jpeg_natural_order[0] = 0) */
(*block)[0] = (JCOEF) s;
}
if (entropy->ac_needed[blkn]) {
/* Section F.2.2.2: decode the AC coefficients */
/* Since zeroes are skipped, output area must be cleared beforehand */
for (k = 1; k < DCTSIZE2; k++) {
HUFF_DECODE(s, br_state, actbl, return FALSE, label2);
r = s >> 4;
s &= 15;
if (s) {
k += r;
CHECK_BIT_BUFFER(br_state, s, return FALSE);
r = GET_BITS(s);
s = HUFF_EXTEND(r, s);
/* Output coefficient in natural (dezigzagged) order.
* Note: the extra entries in jpeg_natural_order[] will save us
* if k >= DCTSIZE2, which could happen if the data is corrupted.
*/
(*block)[jpeg_natural_order[k]] = (JCOEF) s;
} else {
if (r != 15)
break;
k += 15;
}
}
} else {
/* Section F.2.2.2: decode the AC coefficients */
/* In this path we just discard the values */
for (k = 1; k < DCTSIZE2; k++) {
HUFF_DECODE(s, br_state, actbl, return FALSE, label3);
r = s >> 4;
s &= 15;
if (s) {
k += r;
CHECK_BIT_BUFFER(br_state, s, return FALSE);
DROP_BITS(s);
} else {
if (r != 15)
break;
k += 15;
}
}
}
}
/* Completed MCU, so update state */
BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
ASSIGN_STATE(entropy->saved, state);
}
/* Account for restart interval (no-op if not using restarts) */
entropy->restarts_to_go--;
return TRUE;
}
/*
* Module initialization routine for Huffman entropy decoding.
*/
GLOBAL(void)
jinit_huff_decoder (j_decompress_ptr cinfo)
{
huff_entropy_ptr entropy;
int i;
entropy = (huff_entropy_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(huff_entropy_decoder));
cinfo->entropy = (struct jpeg_entropy_decoder *) entropy;
entropy->pub.start_pass = start_pass_huff_decoder;
entropy->pub.decode_mcu = decode_mcu;
/* Mark tables unallocated */
for (i = 0; i < NUM_HUFF_TBLS; i++) {
entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL;
}
}

View File

@@ -2,15 +2,15 @@
* jdhuff.h * jdhuff.h
* *
* This file was part of the Independent JPEG Group's software: * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1998, Thomas G. Lane. * Copyright (C) 1991-1997, Thomas G. Lane.
* Lossless JPEG Modifications: * Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison. * Copyright (C) 1999, Ken Murchison.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains declarations for Huffman entropy decoding routines * This file contains declarations for Huffman entropy decoding routines
* that are shared between the sequential decoder (jdhuff.c), the * that are shared between the sequential decoder (jdhuff.c), the progressive
* progressive decoder (jdphuff.c) and the lossless decoder (jdlhuff.c). * decoder (jdphuff.c), and the lossless decoder (jdlhuff.c). No other modules
* No other modules need to see these. * need to see these.
*/ */
/* Short forms of external names for systems with brain-damaged linkers. */ /* Short forms of external names for systems with brain-damaged linkers. */
@@ -202,30 +202,3 @@ slowlabel: \
EXTERN(int) jpeg_huff_decode EXTERN(int) jpeg_huff_decode
JPP((bitread_working_state * state, register bit_buf_type get_buffer, JPP((bitread_working_state * state, register bit_buf_type get_buffer,
register int bits_left, d_derived_tbl * htbl, int min_bits)); register int bits_left, d_derived_tbl * htbl, int min_bits));
/* Common fields between sequential, progressive and lossless Huffman entropy
* decoder master structs.
*/
#define huffd_common_fields \
boolean insufficient_data; /* set TRUE after emmitting warning */ \
/* These fields are loaded into local variables at start of each MCU. \
* In case of suspension, we exit WITHOUT updating them. \
*/ \
bitread_perm_state bitstate /* Bit buffer at start of MCU */
/* Routines that are to be used by any or all of the entropy decoders are
* declared to receive a pointer to this structure. There are no actual
* instances of huffd_common_struct, only of shuff_entropy_decoder,
* phuff_entropy_decoder and lhuff_entropy_decoder.
*/
struct huffd_common_struct {
huffd_common_fields; /* Fields common to all decoder struct types */
/* Additional fields follow in an actual shuff_entropy_decoder,
* phuff_entropy_decoder or lhuff_entropy_decoder struct. All four structs
* must agree on these initial fields! (This would be a lot cleaner in C++.)
*/
};
typedef struct huffd_common_struct * huffd_common_ptr;

132
jdinput.c
View File

@@ -2,9 +2,10 @@
* jdinput.c * jdinput.c
* *
* This file was part of the Independent JPEG Group's software: * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1998, Thomas G. Lane. * Copyright (C) 1991-1997, Thomas G. Lane.
* Lossless JPEG Modifications: * Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison. * Copyright (C) 1999, Ken Murchison.
* Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains input control logic for the JPEG decompressor. * This file contains input control logic for the JPEG decompressor.
@@ -44,19 +45,19 @@ initial_setup (j_decompress_ptr cinfo)
{ {
int ci; int ci;
jpeg_component_info *compptr; jpeg_component_info *compptr;
int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
/* Make sure image isn't bigger than I can handle */ /* Make sure image isn't bigger than I can handle */
if ((long) cinfo->image_height > (long) JPEG_MAX_DIMENSION || if ((long) cinfo->image_height > (long) JPEG_MAX_DIMENSION ||
(long) cinfo->image_width > (long) JPEG_MAX_DIMENSION) (long) cinfo->image_width > (long) JPEG_MAX_DIMENSION)
ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION); ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION);
if (cinfo->process == JPROC_LOSSLESS) { if (cinfo->master->lossless) {
/* If precision > compiled-in value, we must downscale */ /* If precision > compiled-in value, we must downscale */
if (cinfo->data_precision > BITS_IN_JSAMPLE) if (cinfo->data_precision > BITS_IN_JSAMPLE)
WARNMS2(cinfo, JWRN_MUST_DOWNSCALE, WARNMS2(cinfo, JWRN_MUST_DOWNSCALE,
cinfo->data_precision, BITS_IN_JSAMPLE); cinfo->data_precision, BITS_IN_JSAMPLE);
} } else {
else { /* Lossy processes */
/* For now, precision must match compiled-in value... */ /* For now, precision must match compiled-in value... */
if (cinfo->data_precision != BITS_IN_JSAMPLE) if (cinfo->data_precision != BITS_IN_JSAMPLE)
ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision); ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
@@ -81,23 +82,23 @@ initial_setup (j_decompress_ptr cinfo)
compptr->v_samp_factor); compptr->v_samp_factor);
} }
/* We initialize codec_data_unit and min_codec_data_unit to data_unit. /* We initialize DCT_scaled_size and min_DCT_scaled_size to DCTSIZE in lossy
* In the full decompressor, this will be overridden by jdmaster.c; * mode. In the full decompressor, this will be overridden by jdmaster.c;
* but in the transcoder, jdmaster.c is not used, so we must do it here. * but in the transcoder, jdmaster.c is not used, so we must do it here.
*/ */
cinfo->min_codec_data_unit = cinfo->data_unit; cinfo->min_DCT_scaled_size = data_unit;
/* Compute dimensions of components */ /* Compute dimensions of components */
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) { ci++, compptr++) {
compptr->codec_data_unit = cinfo->data_unit; compptr->DCT_scaled_size = data_unit;
/* Size in data units */ /* Size in data units */
compptr->width_in_data_units = (JDIMENSION) compptr->width_in_blocks = (JDIMENSION)
jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor, jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor,
(long) (cinfo->max_h_samp_factor * cinfo->data_unit)); (long) (cinfo->max_h_samp_factor * data_unit));
compptr->height_in_data_units = (JDIMENSION) compptr->height_in_blocks = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor, jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor,
(long) (cinfo->max_v_samp_factor * cinfo->data_unit)); (long) (cinfo->max_v_samp_factor * data_unit));
/* downsampled_width and downsampled_height will also be overridden by /* downsampled_width and downsampled_height will also be overridden by
* jdmaster.c if we are doing full decompression. The transcoder library * jdmaster.c if we are doing full decompression. The transcoder library
* doesn't use these values, but the calling application might. * doesn't use these values, but the calling application might.
@@ -118,11 +119,10 @@ initial_setup (j_decompress_ptr cinfo)
/* Compute number of fully interleaved MCU rows. */ /* Compute number of fully interleaved MCU rows. */
cinfo->total_iMCU_rows = (JDIMENSION) cinfo->total_iMCU_rows = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height, jdiv_round_up((long) cinfo->image_height,
(long) (cinfo->max_v_samp_factor*cinfo->data_unit)); (long) (cinfo->max_v_samp_factor*data_unit));
/* Decide whether file contains multiple scans */ /* Decide whether file contains multiple scans */
if (cinfo->comps_in_scan < cinfo->num_components || if (cinfo->comps_in_scan < cinfo->num_components || cinfo->progressive_mode)
cinfo->process == JPROC_PROGRESSIVE)
cinfo->inputctl->has_multiple_scans = TRUE; cinfo->inputctl->has_multiple_scans = TRUE;
else else
cinfo->inputctl->has_multiple_scans = FALSE; cinfo->inputctl->has_multiple_scans = FALSE;
@@ -136,6 +136,7 @@ per_scan_setup (j_decompress_ptr cinfo)
{ {
int ci, mcublks, tmp; int ci, mcublks, tmp;
jpeg_component_info *compptr; jpeg_component_info *compptr;
int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
if (cinfo->comps_in_scan == 1) { if (cinfo->comps_in_scan == 1) {
@@ -143,24 +144,24 @@ per_scan_setup (j_decompress_ptr cinfo)
compptr = cinfo->cur_comp_info[0]; compptr = cinfo->cur_comp_info[0];
/* Overall image size in MCUs */ /* Overall image size in MCUs */
cinfo->MCUs_per_row = compptr->width_in_data_units; cinfo->MCUs_per_row = compptr->width_in_blocks;
cinfo->MCU_rows_in_scan = compptr->height_in_data_units; cinfo->MCU_rows_in_scan = compptr->height_in_blocks;
/* For noninterleaved scan, always one data unit per MCU */ /* For noninterleaved scan, always one data unit per MCU */
compptr->MCU_width = 1; compptr->MCU_width = 1;
compptr->MCU_height = 1; compptr->MCU_height = 1;
compptr->MCU_data_units = 1; compptr->MCU_blocks = 1;
compptr->MCU_sample_width = compptr->codec_data_unit; compptr->MCU_sample_width = compptr->DCT_scaled_size;
compptr->last_col_width = 1; compptr->last_col_width = 1;
/* For noninterleaved scans, it is convenient to define last_row_height /* For noninterleaved scans, it is convenient to define last_row_height
* as the number of data unit rows present in the last iMCU row. * as the number of data unit rows present in the last iMCU row.
*/ */
tmp = (int) (compptr->height_in_data_units % compptr->v_samp_factor); tmp = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
if (tmp == 0) tmp = compptr->v_samp_factor; if (tmp == 0) tmp = compptr->v_samp_factor;
compptr->last_row_height = tmp; compptr->last_row_height = tmp;
/* Prepare array describing MCU composition */ /* Prepare array describing MCU composition */
cinfo->data_units_in_MCU = 1; cinfo->blocks_in_MCU = 1;
cinfo->MCU_membership[0] = 0; cinfo->MCU_membership[0] = 0;
} else { } else {
@@ -173,33 +174,33 @@ per_scan_setup (j_decompress_ptr cinfo)
/* Overall image size in MCUs */ /* Overall image size in MCUs */
cinfo->MCUs_per_row = (JDIMENSION) cinfo->MCUs_per_row = (JDIMENSION)
jdiv_round_up((long) cinfo->image_width, jdiv_round_up((long) cinfo->image_width,
(long) (cinfo->max_h_samp_factor*cinfo->data_unit)); (long) (cinfo->max_h_samp_factor*data_unit));
cinfo->MCU_rows_in_scan = (JDIMENSION) cinfo->MCU_rows_in_scan = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height, jdiv_round_up((long) cinfo->image_height,
(long) (cinfo->max_v_samp_factor*cinfo->data_unit)); (long) (cinfo->max_v_samp_factor*data_unit));
cinfo->data_units_in_MCU = 0; cinfo->blocks_in_MCU = 0;
for (ci = 0; ci < cinfo->comps_in_scan; ci++) { for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci]; compptr = cinfo->cur_comp_info[ci];
/* Sampling factors give # of data units of component in each MCU */ /* Sampling factors give # of data units of component in each MCU */
compptr->MCU_width = compptr->h_samp_factor; compptr->MCU_width = compptr->h_samp_factor;
compptr->MCU_height = compptr->v_samp_factor; compptr->MCU_height = compptr->v_samp_factor;
compptr->MCU_data_units = compptr->MCU_width * compptr->MCU_height; compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height;
compptr->MCU_sample_width = compptr->MCU_width * compptr->codec_data_unit; compptr->MCU_sample_width = compptr->MCU_width * compptr->DCT_scaled_size;
/* Figure number of non-dummy data units in last MCU column & row */ /* Figure number of non-dummy data units in last MCU column & row */
tmp = (int) (compptr->width_in_data_units % compptr->MCU_width); tmp = (int) (compptr->width_in_blocks % compptr->MCU_width);
if (tmp == 0) tmp = compptr->MCU_width; if (tmp == 0) tmp = compptr->MCU_width;
compptr->last_col_width = tmp; compptr->last_col_width = tmp;
tmp = (int) (compptr->height_in_data_units % compptr->MCU_height); tmp = (int) (compptr->height_in_blocks % compptr->MCU_height);
if (tmp == 0) tmp = compptr->MCU_height; if (tmp == 0) tmp = compptr->MCU_height;
compptr->last_row_height = tmp; compptr->last_row_height = tmp;
/* Prepare array describing MCU composition */ /* Prepare array describing MCU composition */
mcublks = compptr->MCU_data_units; mcublks = compptr->MCU_blocks;
if (cinfo->data_units_in_MCU + mcublks > D_MAX_DATA_UNITS_IN_MCU) if (cinfo->blocks_in_MCU + mcublks > D_MAX_BLOCKS_IN_MCU)
ERREXIT(cinfo, JERR_BAD_MCU_SIZE); ERREXIT(cinfo, JERR_BAD_MCU_SIZE);
while (mcublks-- > 0) { while (mcublks-- > 0) {
cinfo->MCU_membership[cinfo->data_units_in_MCU++] = ci; cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci;
} }
} }
@@ -207,6 +208,54 @@ per_scan_setup (j_decompress_ptr cinfo)
} }
/*
* Save away a copy of the Q-table referenced by each component present
* in the current scan, unless already saved during a prior scan.
*
* In a multiple-scan JPEG file, the encoder could assign different components
* the same Q-table slot number, but change table definitions between scans
* so that each component uses a different Q-table. (The IJG encoder is not
* currently capable of doing this, but other encoders might.) Since we want
* to be able to dequantize all the components at the end of the file, this
* means that we have to save away the table actually used for each component.
* We do this by copying the table at the start of the first scan containing
* the component.
* The JPEG spec prohibits the encoder from changing the contents of a Q-table
* slot between scans of a component using that slot. If the encoder does so
* anyway, this decoder will simply use the Q-table values that were current
* at the start of the first scan for the component.
*
* The decompressor output side looks only at the saved quant tables,
* not at the current Q-table slots.
*/
LOCAL(void)
latch_quant_tables (j_decompress_ptr cinfo)
{
int ci, qtblno;
jpeg_component_info *compptr;
JQUANT_TBL * qtbl;
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
/* No work if we already saved Q-table for this component */
if (compptr->quant_table != NULL)
continue;
/* Make sure specified quantization table is present */
qtblno = compptr->quant_tbl_no;
if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS ||
cinfo->quant_tbl_ptrs[qtblno] == NULL)
ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, qtblno);
/* OK, save away the quantization table */
qtbl = (JQUANT_TBL *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(JQUANT_TBL));
MEMCOPY(qtbl, cinfo->quant_tbl_ptrs[qtblno], SIZEOF(JQUANT_TBL));
compptr->quant_table = qtbl;
}
}
/* /*
* Initialize the input modules to read a scan of compressed data. * Initialize the input modules to read a scan of compressed data.
* The first call to this is done by jdmaster.c after initializing * The first call to this is done by jdmaster.c after initializing
@@ -218,15 +267,18 @@ METHODDEF(void)
start_input_pass (j_decompress_ptr cinfo) start_input_pass (j_decompress_ptr cinfo)
{ {
per_scan_setup(cinfo); per_scan_setup(cinfo);
(*cinfo->codec->start_input_pass) (cinfo); if (! cinfo->master->lossless)
cinfo->inputctl->consume_input = cinfo->codec->consume_data; latch_quant_tables(cinfo);
(*cinfo->entropy->start_pass) (cinfo);
(*cinfo->coef->start_input_pass) (cinfo);
cinfo->inputctl->consume_input = cinfo->coef->consume_data;
} }
/* /*
* Finish up after inputting a compressed-data scan. * Finish up after inputting a compressed-data scan.
* This is called by the coefficient controller after it's read all * This is called by the coefficient or difference controller after it's read
* the expected data of the scan. * all the expected data of the scan.
*/ */
METHODDEF(void) METHODDEF(void)
@@ -242,8 +294,8 @@ finish_input_pass (j_decompress_ptr cinfo)
* Return value is JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. * Return value is JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI.
* *
* The consume_input method pointer points either here or to the * The consume_input method pointer points either here or to the
* coefficient controller's consume_data routine, depending on whether * coefficient or difference controller's consume_data routine, depending on
* we are reading a compressed data segment or inter-segment markers. * whether we are reading a compressed data segment or inter-segment markers.
*/ */
METHODDEF(int) METHODDEF(int)
@@ -261,12 +313,6 @@ consume_markers (j_decompress_ptr cinfo)
case JPEG_REACHED_SOS: /* Found SOS */ case JPEG_REACHED_SOS: /* Found SOS */
if (inputctl->inheaders) { /* 1st SOS */ if (inputctl->inheaders) { /* 1st SOS */
initial_setup(cinfo); initial_setup(cinfo);
/*
* Initialize the decompression codec. We need to do this here so that
* any codec-specific fields and function pointers are available to
* the rest of the library.
*/
jinit_d_codec(cinfo);
inputctl->inheaders = FALSE; inputctl->inheaders = FALSE;
/* Note: start_input_pass must be called by jdmaster.c /* Note: start_input_pass must be called by jdmaster.c
* before any more input can be consumed. jdapimin.c is * before any more input can be consumed. jdapimin.c is

View File

@@ -2,9 +2,10 @@
* jdlhuff.c * jdlhuff.c
* *
* This file was part of the Independent JPEG Group's software: * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1998, Thomas G. Lane. * Copyright (C) 1991-1997, Thomas G. Lane.
* Lossless JPEG Modifications: * Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison. * Copyright (C) 1999, Ken Murchison.
* Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains Huffman entropy decoding routines for lossless JPEG. * This file contains Huffman entropy decoding routines for lossless JPEG.
@@ -30,11 +31,16 @@ typedef struct {
} lhd_output_ptr_info; } lhd_output_ptr_info;
/* /*
* Private entropy decoder object for lossless Huffman decoding. * Expanded entropy decoder object for Huffman decoding in lossless mode.
*/ */
typedef struct { typedef struct {
huffd_common_fields; /* Fields shared with other entropy decoders */ struct jpeg_entropy_decoder pub; /* public fields */
/* These fields are loaded into local variables at start of each MCU.
* In case of suspension, we exit WITHOUT updating them.
*/
bitread_perm_state bitstate; /* Bit buffer at start of MCU */
/* Pointers to derived tables (these workspaces have image lifespan) */ /* Pointers to derived tables (these workspaces have image lifespan) */
d_derived_tbl * derived_tbls[NUM_HUFF_TBLS]; d_derived_tbl * derived_tbls[NUM_HUFF_TBLS];
@@ -42,12 +48,12 @@ typedef struct {
/* Precalculated info set up by start_pass for use in decode_mcus: */ /* Precalculated info set up by start_pass for use in decode_mcus: */
/* Pointers to derived tables to be used for each data unit within an MCU */ /* Pointers to derived tables to be used for each data unit within an MCU */
d_derived_tbl * cur_tbls[D_MAX_DATA_UNITS_IN_MCU]; d_derived_tbl * cur_tbls[D_MAX_BLOCKS_IN_MCU];
/* Pointers to the proper output difference row for each group of data units /* Pointers to the proper output difference row for each group of data units
* within an MCU. For each component, there are Vi groups of Hi data units. * within an MCU. For each component, there are Vi groups of Hi data units.
*/ */
JDIFFROW output_ptr[D_MAX_DATA_UNITS_IN_MCU]; JDIFFROW output_ptr[D_MAX_BLOCKS_IN_MCU];
/* Number of output pointers in use for the current MCU. This is the sum /* Number of output pointers in use for the current MCU. This is the sum
* of all Vi in the MCU. * of all Vi in the MCU.
@@ -57,10 +63,10 @@ typedef struct {
/* Information used for positioning the output pointers within the output /* Information used for positioning the output pointers within the output
* difference rows. * difference rows.
*/ */
lhd_output_ptr_info output_ptr_info[D_MAX_DATA_UNITS_IN_MCU]; lhd_output_ptr_info output_ptr_info[D_MAX_BLOCKS_IN_MCU];
/* Index of the proper output pointer for each data unit within an MCU */ /* Index of the proper output pointer for each data unit within an MCU */
int output_ptr_index[D_MAX_DATA_UNITS_IN_MCU]; int output_ptr_index[D_MAX_BLOCKS_IN_MCU];
} lhuff_entropy_decoder; } lhuff_entropy_decoder;
@@ -74,8 +80,7 @@ typedef lhuff_entropy_decoder * lhuff_entropy_ptr;
METHODDEF(void) METHODDEF(void)
start_pass_lhuff_decoder (j_decompress_ptr cinfo) start_pass_lhuff_decoder (j_decompress_ptr cinfo)
{ {
j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; lhuff_entropy_ptr entropy = (lhuff_entropy_ptr) cinfo->entropy;
lhuff_entropy_ptr entropy = (lhuff_entropy_ptr) losslsd->entropy_private;
int ci, dctbl, sampn, ptrn, yoffset, xoffset; int ci, dctbl, sampn, ptrn, yoffset, xoffset;
jpeg_component_info * compptr; jpeg_component_info * compptr;
@@ -93,7 +98,7 @@ start_pass_lhuff_decoder (j_decompress_ptr cinfo)
} }
/* Precalculate decoding info for each sample in an MCU of this scan */ /* Precalculate decoding info for each sample in an MCU of this scan */
for (sampn = 0, ptrn = 0; sampn < cinfo->data_units_in_MCU;) { for (sampn = 0, ptrn = 0; sampn < cinfo->blocks_in_MCU;) {
compptr = cinfo->cur_comp_info[cinfo->MCU_membership[sampn]]; compptr = cinfo->cur_comp_info[cinfo->MCU_membership[sampn]];
ci = compptr->component_index; ci = compptr->component_index;
for (yoffset = 0; yoffset < compptr->MCU_height; yoffset++, ptrn++) { for (yoffset = 0; yoffset < compptr->MCU_height; yoffset++, ptrn++) {
@@ -114,7 +119,7 @@ start_pass_lhuff_decoder (j_decompress_ptr cinfo)
/* Initialize bitread state variables */ /* Initialize bitread state variables */
entropy->bitstate.bits_left = 0; entropy->bitstate.bits_left = 0;
entropy->bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */ entropy->bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */
entropy->insufficient_data = FALSE; entropy->pub.insufficient_data = FALSE;
} }
@@ -149,12 +154,10 @@ static const int extend_offset[16] = /* entry n is (-1 << n) + 1 */
* Returns FALSE if must suspend. * Returns FALSE if must suspend.
*/ */
METHODDEF(boolean) LOCAL(boolean)
process_restart (j_decompress_ptr cinfo) process_restart (j_decompress_ptr cinfo)
{ {
j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; lhuff_entropy_ptr entropy = (lhuff_entropy_ptr) cinfo->entropy;
lhuff_entropy_ptr entropy = (lhuff_entropy_ptr) losslsd->entropy_private;
int ci;
/* Throw away any unused bits remaining in bit buffer; */ /* Throw away any unused bits remaining in bit buffer; */
/* include any full bytes in next_marker's count of discarded bytes */ /* include any full bytes in next_marker's count of discarded bytes */
@@ -171,23 +174,23 @@ process_restart (j_decompress_ptr cinfo)
* leaving the flag set. * leaving the flag set.
*/ */
if (cinfo->unread_marker == 0) if (cinfo->unread_marker == 0)
entropy->insufficient_data = FALSE; entropy->pub.insufficient_data = FALSE;
return TRUE; return TRUE;
} }
/* /*
* Decode and return nMCU's worth of Huffman-compressed differences. * Decode and return nMCU MCUs' worth of Huffman-compressed differences.
* Each MCU is also disassembled and placed accordingly in diff_buf. * Each MCU is also disassembled and placed accordingly in diff_buf.
* *
* MCU_col_num specifies the column of the first MCU being requested within * MCU_col_num specifies the column of the first MCU being requested within
* the MCU-row. This tells us where to position the output row pointers in * the MCU row. This tells us where to position the output row pointers in
* diff_buf. * diff_buf.
* *
* Returns the number of MCUs decoded. This may be less than nMCU if data * Returns the number of MCUs decoded. This may be less than nMCU MCUs if
* source requested suspension. In that case no changes have been made to * data source requested suspension. In that case no changes have been made
* permanent state. (Exception: some output differences may already have * to permanent state. (Exception: some output differences may already have
* been assigned. This is harmless for this module, since we'll just * been assigned. This is harmless for this module, since we'll just
* re-assign them on the next call.) * re-assign them on the next call.)
*/ */
@@ -196,8 +199,8 @@ METHODDEF(JDIMENSION)
decode_mcus (j_decompress_ptr cinfo, JDIFFIMAGE diff_buf, decode_mcus (j_decompress_ptr cinfo, JDIFFIMAGE diff_buf,
JDIMENSION MCU_row_num, JDIMENSION MCU_col_num, JDIMENSION nMCU) JDIMENSION MCU_row_num, JDIMENSION MCU_col_num, JDIMENSION nMCU)
{ {
j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; lossless_decomp_ptr losslessd = (lossless_decomp_ptr) cinfo->idct;
lhuff_entropy_ptr entropy = (lhuff_entropy_ptr) losslsd->entropy_private; lhuff_entropy_ptr entropy = (lhuff_entropy_ptr) cinfo->entropy;
int mcu_num, sampn, ci, yoffset, MCU_width, ptrn; int mcu_num, sampn, ci, yoffset, MCU_width, ptrn;
BITREAD_STATE_VARS; BITREAD_STATE_VARS;
@@ -217,12 +220,12 @@ decode_mcus (j_decompress_ptr cinfo, JDIFFIMAGE diff_buf,
* NB: We should find a way to do this without interacting with the * NB: We should find a way to do this without interacting with the
* undifferencer module directly. * undifferencer module directly.
*/ */
if (entropy->insufficient_data) { if (entropy->pub.insufficient_data) {
for (ptrn = 0; ptrn < entropy->num_output_ptrs; ptrn++) for (ptrn = 0; ptrn < entropy->num_output_ptrs; ptrn++)
jzero_far((void FAR *) entropy->output_ptr[ptrn], jzero_far((void FAR *) entropy->output_ptr[ptrn],
nMCU * entropy->output_ptr_info[ptrn].MCU_width * SIZEOF(JDIFF)); nMCU * entropy->output_ptr_info[ptrn].MCU_width * SIZEOF(JDIFF));
(*losslsd->predict_process_restart) (cinfo); (*losslessd->predict_process_restart) (cinfo);
} }
else { else {
@@ -230,12 +233,12 @@ decode_mcus (j_decompress_ptr cinfo, JDIFFIMAGE diff_buf,
/* Load up working state */ /* Load up working state */
BITREAD_LOAD_STATE(cinfo,entropy->bitstate); BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
/* Outer loop handles the number of MCU requested */ /* Outer loop handles the number of MCUs requested */
for (mcu_num = 0; mcu_num < nMCU; mcu_num++) { for (mcu_num = 0; mcu_num < nMCU; mcu_num++) {
/* Inner loop handles the samples in the MCU */ /* Inner loop handles the samples in the MCU */
for (sampn = 0; sampn < cinfo->data_units_in_MCU; sampn++) { for (sampn = 0; sampn < cinfo->blocks_in_MCU; sampn++) {
d_derived_tbl * dctbl = entropy->cur_tbls[sampn]; d_derived_tbl * dctbl = entropy->cur_tbls[sampn];
register int s, r; register int s, r;
@@ -265,23 +268,22 @@ decode_mcus (j_decompress_ptr cinfo, JDIFFIMAGE diff_buf,
/* /*
* Module initialization routine for lossless Huffman entropy decoding. * Module initialization routine for lossless mode Huffman entropy decoding.
*/ */
GLOBAL(void) GLOBAL(void)
jinit_lhuff_decoder (j_decompress_ptr cinfo) jinit_lhuff_decoder (j_decompress_ptr cinfo)
{ {
j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec;
lhuff_entropy_ptr entropy; lhuff_entropy_ptr entropy;
int i; int i;
entropy = (lhuff_entropy_ptr) entropy = (lhuff_entropy_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(lhuff_entropy_decoder)); SIZEOF(lhuff_entropy_decoder));
losslsd->entropy_private = (void *) entropy; cinfo->entropy = (struct jpeg_entropy_decoder *) entropy;
losslsd->entropy_start_pass = start_pass_lhuff_decoder; entropy->pub.start_pass = start_pass_lhuff_decoder;
losslsd->entropy_process_restart = process_restart; entropy->pub.decode_mcus = decode_mcus;
losslsd->entropy_decode_mcus = decode_mcus; entropy->pub.process_restart = process_restart;
/* Mark tables unallocated */ /* Mark tables unallocated */
for (i = 0; i < NUM_HUFF_TBLS; i++) { for (i = 0; i < NUM_HUFF_TBLS; i++) {

View File

@@ -5,9 +5,11 @@
* Copyright (C) 1998, Thomas G. Lane. * Copyright (C) 1998, Thomas G. Lane.
* Lossless JPEG Modifications: * Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison. * Copyright (C) 1999, Ken Murchison.
* Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains the control logic for the lossless JPEG decompressor. * This file contains prediction, sample undifferencing, point transform, and
* sample scaling routines for the lossless JPEG decompressor.
*/ */
#define JPEG_INTERNALS #define JPEG_INTERNALS
@@ -15,22 +17,234 @@
#include "jpeglib.h" #include "jpeglib.h"
#include "jlossls.h" #include "jlossls.h"
#ifdef D_LOSSLESS_SUPPORTED #ifdef D_LOSSLESS_SUPPORTED
/**************** Sample undifferencing (reconstruction) *****************/
/* /*
* Compute output image dimensions and related values. * In order to avoid a performance penalty for checking which predictor is
* being used and which row is being processed for each call of the
* undifferencer, and to promote optimization, we have separate undifferencing
* functions for each predictor selection value.
*
* We are able to avoid duplicating source code by implementing the predictors
* and undifferencers as macros. Each of the undifferencing functions is
* simply a wrapper around an UNDIFFERENCE macro with the appropriate PREDICTOR
* macro passed as an argument.
*/
/* Predictor for the first column of the first row: 2^(P-Pt-1) */
#define INITIAL_PREDICTORx (1 << (cinfo->data_precision - cinfo->Al - 1))
/* Predictor for the first column of the remaining rows: Rb */
#define INITIAL_PREDICTOR2 GETJSAMPLE(prev_row[0])
/*
* 1-Dimensional undifferencer routine.
*
* This macro implements the 1-D horizontal predictor (1). INITIAL_PREDICTOR
* is used as the special case predictor for the first column, which must be
* either INITIAL_PREDICTOR2 or INITIAL_PREDICTORx. The remaining samples
* use PREDICTOR1.
*
* The reconstructed sample is supposed to be calculated modulo 2^16, so we
* logically AND the result with 0xFFFF.
*/
#define UNDIFFERENCE_1D(INITIAL_PREDICTOR) \
int Ra; \
\
Ra = (*diff_buf++ + INITIAL_PREDICTOR) & 0xFFFF; \
*undiff_buf++ = Ra; \
\
while (--width) { \
Ra = (*diff_buf++ + PREDICTOR1) & 0xFFFF; \
*undiff_buf++ = Ra; \
}
/*
* 2-Dimensional undifferencer routine.
*
* This macro implements the 2-D horizontal predictors (#2-7). PREDICTOR2 is
* used as the special case predictor for the first column. The remaining
* samples use PREDICTOR, which is a function of Ra, Rb, and Rc.
*
* Because prev_row and output_buf may point to the same storage area (in an
* interleaved image with Vi=1, for example), we must take care to buffer Rb/Rc
* before writing the current reconstructed sample value into output_buf.
*
* The reconstructed sample is supposed to be calculated modulo 2^16, so we
* logically AND the result with 0xFFFF.
*/
#define UNDIFFERENCE_2D(PREDICTOR) \
int Ra, Rb, Rc; \
\
Rb = GETJSAMPLE(*prev_row++); \
Ra = (*diff_buf++ + PREDICTOR2) & 0xFFFF; \
*undiff_buf++ = Ra; \
\
while (--width) { \
Rc = Rb; \
Rb = GETJSAMPLE(*prev_row++); \
Ra = (*diff_buf++ + PREDICTOR) & 0xFFFF; \
*undiff_buf++ = Ra; \
}
/*
* Undifferencers for the second and subsequent rows in a scan or restart
* interval. The first sample in the row is undifferenced using the vertical
* predictor (2). The rest of the samples are undifferenced using the
* predictor specified in the scan header.
*/ */
METHODDEF(void) METHODDEF(void)
calc_output_dimensions (j_decompress_ptr cinfo) jpeg_undifference1(j_decompress_ptr cinfo, int comp_index,
JDIFFROW diff_buf, JDIFFROW prev_row,
JDIFFROW undiff_buf, JDIMENSION width)
{ {
/* Hardwire it to "no scaling" */ UNDIFFERENCE_1D(INITIAL_PREDICTOR2);
cinfo->output_width = cinfo->image_width; }
cinfo->output_height = cinfo->image_height;
/* jdinput.c has already initialized codec_data_unit to 1, METHODDEF(void)
* and has computed unscaled downsampled_width and downsampled_height. jpeg_undifference2(j_decompress_ptr cinfo, int comp_index,
JDIFFROW diff_buf, JDIFFROW prev_row,
JDIFFROW undiff_buf, JDIMENSION width)
{
UNDIFFERENCE_2D(PREDICTOR2);
(void)(Rc);
}
METHODDEF(void)
jpeg_undifference3(j_decompress_ptr cinfo, int comp_index,
JDIFFROW diff_buf, JDIFFROW prev_row,
JDIFFROW undiff_buf, JDIMENSION width)
{
UNDIFFERENCE_2D(PREDICTOR3);
}
METHODDEF(void)
jpeg_undifference4(j_decompress_ptr cinfo, int comp_index,
JDIFFROW diff_buf, JDIFFROW prev_row,
JDIFFROW undiff_buf, JDIMENSION width)
{
UNDIFFERENCE_2D(PREDICTOR4);
}
METHODDEF(void)
jpeg_undifference5(j_decompress_ptr cinfo, int comp_index,
JDIFFROW diff_buf, JDIFFROW prev_row,
JDIFFROW undiff_buf, JDIMENSION width)
{
UNDIFFERENCE_2D(PREDICTOR5);
}
METHODDEF(void)
jpeg_undifference6(j_decompress_ptr cinfo, int comp_index,
JDIFFROW diff_buf, JDIFFROW prev_row,
JDIFFROW undiff_buf, JDIMENSION width)
{
UNDIFFERENCE_2D(PREDICTOR6);
}
METHODDEF(void)
jpeg_undifference7(j_decompress_ptr cinfo, int comp_index,
JDIFFROW diff_buf, JDIFFROW prev_row,
JDIFFROW undiff_buf, JDIMENSION width)
{
UNDIFFERENCE_2D(PREDICTOR7);
(void)(Rc);
}
/*
* Undifferencer for the first row in a scan or restart interval. The first
* sample in the row is undifferenced using the special predictor constant
* x=2^(P-Pt-1). The rest of the samples are undifferenced using the
* 1-D horizontal predictor (1).
*/ */
METHODDEF(void)
jpeg_undifference_first_row(j_decompress_ptr cinfo, int comp_index,
JDIFFROW diff_buf, JDIFFROW prev_row,
JDIFFROW undiff_buf, JDIMENSION width)
{
lossless_decomp_ptr losslessd = (lossless_decomp_ptr) cinfo->idct;
UNDIFFERENCE_1D(INITIAL_PREDICTORx);
/*
* Now that we have undifferenced the first row, we want to use the
* undifferencer that corresponds to the predictor specified in the
* scan header.
*/
switch (cinfo->Ss) {
case 1:
losslessd->predict_undifference[comp_index] = jpeg_undifference1;
break;
case 2:
losslessd->predict_undifference[comp_index] = jpeg_undifference2;
break;
case 3:
losslessd->predict_undifference[comp_index] = jpeg_undifference3;
break;
case 4:
losslessd->predict_undifference[comp_index] = jpeg_undifference4;
break;
case 5:
losslessd->predict_undifference[comp_index] = jpeg_undifference5;
break;
case 6:
losslessd->predict_undifference[comp_index] = jpeg_undifference6;
break;
case 7:
losslessd->predict_undifference[comp_index] = jpeg_undifference7;
break;
}
}
/**************************** Sample scaling *****************************/
/*
* This is a combination of upscaling the undifferenced sample by 2^Pt and
* downscaling the sample to fit into JSAMPLE.
*/
METHODDEF(void)
simple_upscale(j_decompress_ptr cinfo,
JDIFFROW diff_buf, JSAMPROW output_buf,
JDIMENSION width)
{
lossless_decomp_ptr losslessd = (lossless_decomp_ptr) cinfo->idct;
while (width--)
*output_buf++ = (JSAMPLE) (*diff_buf++ << losslessd->scale_factor);
}
METHODDEF(void)
simple_downscale(j_decompress_ptr cinfo,
JDIFFROW diff_buf, JSAMPROW output_buf,
JDIMENSION width)
{
lossless_decomp_ptr losslessd = (lossless_decomp_ptr) cinfo->idct;
while (width--)
*output_buf++ = (JSAMPLE) RIGHT_SHIFT(*diff_buf++,
losslessd->scale_factor);
}
METHODDEF(void)
noscale(j_decompress_ptr cinfo,
JDIFFROW diff_buf, JSAMPROW output_buf,
JDIMENSION width)
{
while (width--)
*output_buf++ = (JSAMPLE) *diff_buf++;
} }
@@ -39,58 +253,67 @@ calc_output_dimensions (j_decompress_ptr cinfo)
*/ */
METHODDEF(void) METHODDEF(void)
start_input_pass (j_decompress_ptr cinfo) start_pass_lossless (j_decompress_ptr cinfo)
{ {
j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; lossless_decomp_ptr losslessd = (lossless_decomp_ptr) cinfo->idct;
int ci, downscale;
(*losslsd->entropy_start_pass) (cinfo); /* Check that the scan parameters Ss, Se, Ah, Al are OK for lossless JPEG.
(*losslsd->predict_start_pass) (cinfo); *
(*losslsd->scaler_start_pass) (cinfo); * Ss is the predictor selection value (psv). Legal values for sequential
(*losslsd->diff_start_input_pass) (cinfo); * lossless JPEG are: 1 <= psv <= 7.
*
* Se and Ah are not used and should be zero.
*
* Al specifies the point transform (Pt).
* Legal values are: 0 <= Pt <= (data precision - 1).
*/
if (cinfo->Ss < 1 || cinfo->Ss > 7 ||
cinfo->Se != 0 || cinfo->Ah != 0 ||
cinfo->Al < 0 || cinfo->Al >= cinfo->data_precision)
ERREXIT4(cinfo, JERR_BAD_PROGRESSION,
cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al);
/* Set undifference functions to first row function */
for (ci = 0; ci < cinfo->num_components; ci++)
losslessd->predict_undifference[ci] = jpeg_undifference_first_row;
/*
* Downscale by the difference in the input vs. output precision. If the
* output precision >= input precision, then do not downscale.
*/
downscale = BITS_IN_JSAMPLE < cinfo->data_precision ?
cinfo->data_precision - BITS_IN_JSAMPLE : 0;
losslessd->scale_factor = cinfo->Al - downscale;
/* Set scaler functions based on scale_factor (positive = left shift) */
if (losslessd->scale_factor > 0)
losslessd->scaler_scale = simple_upscale;
else if (losslessd->scale_factor < 0) {
losslessd->scale_factor = -losslessd->scale_factor;
losslessd->scaler_scale = simple_downscale;
}
else
losslessd->scaler_scale = noscale;
} }
/* /*
* Initialize the lossless decompression codec. * Initialize the lossless decompressor.
* This is called only once, during master selection.
*/ */
GLOBAL(void) GLOBAL(void)
jinit_lossless_d_codec(j_decompress_ptr cinfo) jinit_lossless_decompressor(j_decompress_ptr cinfo)
{ {
j_lossless_d_ptr losslsd; lossless_decomp_ptr losslessd;
boolean use_c_buffer;
/* Create subobject in permanent pool */ /* Create subobject in permanent pool */
losslsd = (j_lossless_d_ptr) losslessd = (lossless_decomp_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
SIZEOF(jpeg_lossless_d_codec)); SIZEOF(jpeg_lossless_decompressor));
cinfo->codec = (struct jpeg_d_codec *) losslsd; cinfo->idct = (struct jpeg_inverse_dct *) losslessd;
losslessd->pub.start_pass = start_pass_lossless;
/* Initialize sub-modules */
/* Entropy decoding: either Huffman or arithmetic coding. */
if (cinfo->arith_code) {
ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
} else {
jinit_lhuff_decoder(cinfo);
}
/* Undifferencer */
jinit_undifferencer(cinfo);
/* Scaler */
jinit_d_scaler(cinfo);
use_c_buffer = cinfo->inputctl->has_multiple_scans || cinfo->buffered_image;
jinit_d_diff_controller(cinfo, use_c_buffer);
/* Initialize method pointers.
*
* Note: consume_data, start_output_pass and decompress_data are
* assigned in jddiffct.c.
*/
losslsd->pub.calc_output_dimensions = calc_output_dimensions;
losslsd->pub.start_input_pass = start_input_pass;
} }
#endif /* D_LOSSLESS_SUPPORTED */ #endif /* D_LOSSLESS_SUPPORTED */

230
jdlossy.c
View File

@@ -1,230 +0,0 @@
/*
* jdlossy.c
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1998, Thomas G. Lane.
* Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains the control logic for the lossy JPEG decompressor.
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
#include "jlossy.h"
/*
* Compute output image dimensions and related values.
*/
METHODDEF(void)
calc_output_dimensions (j_decompress_ptr cinfo)
{
#ifdef IDCT_SCALING_SUPPORTED
int ci;
jpeg_component_info *compptr;
/* Compute actual output image dimensions and DCT scaling choices. */
if (cinfo->scale_num * 8 <= cinfo->scale_denom) {
/* Provide 1/8 scaling */
cinfo->output_width = (JDIMENSION)
jdiv_round_up((long) cinfo->image_width, 8L);
cinfo->output_height = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height, 8L);
cinfo->min_codec_data_unit = 1;
} else if (cinfo->scale_num * 4 <= cinfo->scale_denom) {
/* Provide 1/4 scaling */
cinfo->output_width = (JDIMENSION)
jdiv_round_up((long) cinfo->image_width, 4L);
cinfo->output_height = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height, 4L);
cinfo->min_codec_data_unit = 2;
} else if (cinfo->scale_num * 2 <= cinfo->scale_denom) {
/* Provide 1/2 scaling */
cinfo->output_width = (JDIMENSION)
jdiv_round_up((long) cinfo->image_width, 2L);
cinfo->output_height = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height, 2L);
cinfo->min_codec_data_unit = 4;
} else {
/* Provide 1/1 scaling */
cinfo->output_width = cinfo->image_width;
cinfo->output_height = cinfo->image_height;
cinfo->min_codec_data_unit = DCTSIZE;
}
/* In selecting the actual DCT scaling for each component, we try to
* scale up the chroma components via IDCT scaling rather than upsampling.
* This saves time if the upsampler gets to use 1:1 scaling.
* Note this code assumes that the supported DCT scalings are powers of 2.
*/
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
int ssize = cinfo->min_codec_data_unit;
while (ssize < DCTSIZE &&
(compptr->h_samp_factor * ssize * 2 <=
cinfo->max_h_samp_factor * cinfo->min_codec_data_unit) &&
(compptr->v_samp_factor * ssize * 2 <=
cinfo->max_v_samp_factor * cinfo->min_codec_data_unit)) {
ssize = ssize * 2;
}
compptr->codec_data_unit = ssize;
}
/* Recompute downsampled dimensions of components;
* application needs to know these if using raw downsampled data.
*/
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
/* Size in samples, after IDCT scaling */
compptr->downsampled_width = (JDIMENSION)
jdiv_round_up((long) cinfo->image_width *
(long) (compptr->h_samp_factor * compptr->codec_data_unit),
(long) (cinfo->max_h_samp_factor * DCTSIZE));
compptr->downsampled_height = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height *
(long) (compptr->v_samp_factor * compptr->codec_data_unit),
(long) (cinfo->max_v_samp_factor * DCTSIZE));
}
#else /* !IDCT_SCALING_SUPPORTED */
/* Hardwire it to "no scaling" */
cinfo->output_width = cinfo->image_width;
cinfo->output_height = cinfo->image_height;
/* jdinput.c has already initialized codec_data_unit to DCTSIZE,
* and has computed unscaled downsampled_width and downsampled_height.
*/
#endif /* IDCT_SCALING_SUPPORTED */
}
/*
* Save away a copy of the Q-table referenced by each component present
* in the current scan, unless already saved during a prior scan.
*
* In a multiple-scan JPEG file, the encoder could assign different components
* the same Q-table slot number, but change table definitions between scans
* so that each component uses a different Q-table. (The IJG encoder is not
* currently capable of doing this, but other encoders might.) Since we want
* to be able to dequantize all the components at the end of the file, this
* means that we have to save away the table actually used for each component.
* We do this by copying the table at the start of the first scan containing
* the component.
* The JPEG spec prohibits the encoder from changing the contents of a Q-table
* slot between scans of a component using that slot. If the encoder does so
* anyway, this decoder will simply use the Q-table values that were current
* at the start of the first scan for the component.
*
* The decompressor output side looks only at the saved quant tables,
* not at the current Q-table slots.
*/
LOCAL(void)
latch_quant_tables (j_decompress_ptr cinfo)
{
int ci, qtblno;
jpeg_component_info *compptr;
JQUANT_TBL * qtbl;
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
/* No work if we already saved Q-table for this component */
if (compptr->quant_table != NULL)
continue;
/* Make sure specified quantization table is present */
qtblno = compptr->quant_tbl_no;
if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS ||
cinfo->quant_tbl_ptrs[qtblno] == NULL)
ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, qtblno);
/* OK, save away the quantization table */
qtbl = (JQUANT_TBL *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(JQUANT_TBL));
MEMCOPY(qtbl, cinfo->quant_tbl_ptrs[qtblno], SIZEOF(JQUANT_TBL));
compptr->quant_table = qtbl;
}
}
/*
* Initialize for an input processing pass.
*/
METHODDEF(void)
start_input_pass (j_decompress_ptr cinfo)
{
j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec;
latch_quant_tables(cinfo);
(*lossyd->entropy_start_pass) (cinfo);
(*lossyd->coef_start_input_pass) (cinfo);
}
/*
* Initialize for an output processing pass.
*/
METHODDEF(void)
start_output_pass (j_decompress_ptr cinfo)
{
j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec;
(*lossyd->idct_start_pass) (cinfo);
(*lossyd->coef_start_output_pass) (cinfo);
}
/*
* Initialize the lossy decompression codec.
* This is called only once, during master selection.
*/
GLOBAL(void)
jinit_lossy_d_codec (j_decompress_ptr cinfo)
{
j_lossy_d_ptr lossyd;
boolean use_c_buffer;
/* Create subobject in permanent pool */
lossyd = (j_lossy_d_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
SIZEOF(jpeg_lossy_d_codec));
cinfo->codec = (struct jpeg_d_codec *) lossyd;
/* Initialize sub-modules */
/* Inverse DCT */
jinit_inverse_dct(cinfo);
/* Entropy decoding: either Huffman or arithmetic coding. */
if (cinfo->arith_code) {
ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
} else {
if (cinfo->process == JPROC_PROGRESSIVE) {
#ifdef D_PROGRESSIVE_SUPPORTED
jinit_phuff_decoder(cinfo);
#else
ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif
} else
jinit_shuff_decoder(cinfo);
}
use_c_buffer = cinfo->inputctl->has_multiple_scans || cinfo->buffered_image;
jinit_d_coef_controller(cinfo, use_c_buffer);
/* Initialize method pointers.
*
* Note: consume_data and decompress_data are assigned in jdcoefct.c.
*/
lossyd->pub.calc_output_dimensions = calc_output_dimensions;
lossyd->pub.start_input_pass = start_input_pass;
lossyd->pub.start_output_pass = start_output_pass;
}

View File

@@ -2,9 +2,9 @@
* jdmainct.c * jdmainct.c
* *
* This file was part of the Independent JPEG Group's software: * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1998, Thomas G. Lane. * Copyright (C) 1994-1996, Thomas G. Lane.
* Lossless JPEG Modifications: * Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison. * Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains the main buffer controller for decompression. * This file contains the main buffer controller for decompression.
@@ -22,35 +22,36 @@
/* /*
* In the current system design, the main buffer need never be a full-image * In the current system design, the main buffer need never be a full-image
* buffer; any full-height buffers will be found inside the coefficient or * buffer; any full-height buffers will be found inside the coefficient,
* postprocessing controllers. Nonetheless, the main controller is not * difference, or postprocessing controllers. Nonetheless, the main controller
* trivial. Its responsibility is to provide context rows for upsampling/ * is not trivial. Its responsibility is to provide context rows for
* rescaling, and doing this in an efficient fashion is a bit tricky. * upsampling/rescaling, and doing this in an efficient fashion is a bit
* tricky.
* *
* Postprocessor input data is counted in "row groups". A row group * Postprocessor input data is counted in "row groups". A row group
* is defined to be (v_samp_factor * codec_data_unit / min_codec_data_unit) * is defined to be (v_samp_factor * DCT_scaled_size / min_DCT_scaled_size)
* sample rows of each component. (We require codec_data_unit values to be * sample rows of each component. (We require DCT_scaled_size values to be
* chosen such that these numbers are integers. In practice codec_data_unit * chosen such that these numbers are integers. In practice DCT_scaled_size
* values will likely be powers of two, so we actually have the stronger * values will likely be powers of two, so we actually have the stronger
* condition that codec_data_unit / min_codec_data_unit is an integer.) * condition that DCT_scaled_size / min_DCT_scaled_size is an integer.)
* Upsampling will typically produce max_v_samp_factor pixel rows from each * Upsampling will typically produce max_v_samp_factor pixel rows from each
* row group (times any additional scale factor that the upsampler is * row group (times any additional scale factor that the upsampler is
* applying). * applying).
* *
* The decompression codec will deliver data to us one iMCU row at a time; * The coefficient or difference controller will deliver data to us one iMCU
* each iMCU row contains v_samp_factor * codec_data_unit sample rows, or * row at a time; each iMCU row contains v_samp_factor * DCT_scaled_size sample
* exactly min_codec_data_unit row groups. (This amount of data corresponds * rows, or exactly min_DCT_scaled_size row groups. (This amount of data
* to one row of MCUs when the image is fully interleaved.) Note that the * corresponds to one row of MCUs when the image is fully interleaved.) Note
* number of sample rows varies across components, but the number of row * that the number of sample rows varies across components, but the number of
* groups does not. Some garbage sample rows may be included in the last iMCU * row groups does not. Some garbage sample rows may be included in the last
* row at the bottom of the image. * iMCU row at the bottom of the image.
* *
* Depending on the vertical scaling algorithm used, the upsampler may need * Depending on the vertical scaling algorithm used, the upsampler may need
* access to the sample row(s) above and below its current input row group. * access to the sample row(s) above and below its current input row group.
* The upsampler is required to set need_context_rows TRUE at global selection * The upsampler is required to set need_context_rows TRUE at global selection
* time if so. When need_context_rows is FALSE, this controller can simply * time if so. When need_context_rows is FALSE, this controller can simply
* obtain one iMCU row at a time from the coefficient controller and dole it * obtain one iMCU row at a time from the coefficient or difference controller
* out as row groups to the postprocessor. * and dole it out as row groups to the postprocessor.
* *
* When need_context_rows is TRUE, this controller guarantees that the buffer * When need_context_rows is TRUE, this controller guarantees that the buffer
* passed to postprocessing contains at least one row group's worth of samples * passed to postprocessing contains at least one row group's worth of samples
@@ -66,7 +67,7 @@
* supporting arbitrary output rescaling might wish for more than one row * supporting arbitrary output rescaling might wish for more than one row
* group of context when shrinking the image; tough, we don't handle that. * group of context when shrinking the image; tough, we don't handle that.
* (This is justified by the assumption that downsizing will be handled mostly * (This is justified by the assumption that downsizing will be handled mostly
* by adjusting the codec_data_unit values, so that the actual scale factor at * by adjusting the DCT_scaled_size values, so that the actual scale factor at
* the upsample step needn't be much less than one.) * the upsample step needn't be much less than one.)
* *
* To provide the desired context, we have to retain the last two row groups * To provide the desired context, we have to retain the last two row groups
@@ -76,7 +77,7 @@
* We could do this most simply by copying data around in our buffer, but * We could do this most simply by copying data around in our buffer, but
* that'd be very slow. We can avoid copying any data by creating a rather * that'd be very slow. We can avoid copying any data by creating a rather
* strange pointer structure. Here's how it works. We allocate a workspace * strange pointer structure. Here's how it works. We allocate a workspace
* consisting of M+2 row groups (where M = min_codec_data_unit is the number * consisting of M+2 row groups (where M = min_DCT_scaled_size is the number
* of row groups per iMCU row). We create two sets of redundant pointers to * of row groups per iMCU row). We create two sets of redundant pointers to
* the workspace. Labeling the physical row groups 0 to M+1, the synthesized * the workspace. Labeling the physical row groups 0 to M+1, the synthesized
* pointer lists look like this: * pointer lists look like this:
@@ -101,11 +102,11 @@
* the first or last sample row as necessary (this is cheaper than copying * the first or last sample row as necessary (this is cheaper than copying
* sample rows around). * sample rows around).
* *
* This scheme breaks down if M < 2, ie, min_codec_data_unit is 1. In that * This scheme breaks down if M < 2, ie, min_DCT_scaled_size is 1. In that
* situation each iMCU row provides only one row group so the buffering logic * situation each iMCU row provides only one row group so the buffering logic
* must be different (eg, we must read two iMCU rows before we can emit the * must be different (eg, we must read two iMCU rows before we can emit the
* first row group). For now, we simply do not support providing context * first row group). For now, we simply do not support providing context
* rows when min_codec_data_unit is 1. That combination seems unlikely to * rows when min_DCT_scaled_size is 1. That combination seems unlikely to
* be worth providing --- if someone wants a 1/8th-size preview, they probably * be worth providing --- if someone wants a 1/8th-size preview, they probably
* want it quick and dirty, so a context-free upsampler is sufficient. * want it quick and dirty, so a context-free upsampler is sufficient.
*/ */
@@ -163,7 +164,7 @@ alloc_funny_pointers (j_decompress_ptr cinfo)
{ {
my_main_ptr main = (my_main_ptr) cinfo->main; my_main_ptr main = (my_main_ptr) cinfo->main;
int ci, rgroup; int ci, rgroup;
int M = cinfo->min_codec_data_unit; int M = cinfo->min_DCT_scaled_size;
jpeg_component_info *compptr; jpeg_component_info *compptr;
JSAMPARRAY xbuf; JSAMPARRAY xbuf;
@@ -177,8 +178,8 @@ alloc_funny_pointers (j_decompress_ptr cinfo)
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) { ci++, compptr++) {
rgroup = (compptr->v_samp_factor * compptr->codec_data_unit) / rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) /
cinfo->min_codec_data_unit; /* height of a row group of component */ cinfo->min_DCT_scaled_size; /* height of a row group of component */
/* Get space for pointer lists --- M+4 row groups in each list. /* Get space for pointer lists --- M+4 row groups in each list.
* We alloc both pointer lists with one call to save a few cycles. * We alloc both pointer lists with one call to save a few cycles.
*/ */
@@ -204,14 +205,14 @@ make_funny_pointers (j_decompress_ptr cinfo)
{ {
my_main_ptr main = (my_main_ptr) cinfo->main; my_main_ptr main = (my_main_ptr) cinfo->main;
int ci, i, rgroup; int ci, i, rgroup;
int M = cinfo->min_codec_data_unit; int M = cinfo->min_DCT_scaled_size;
jpeg_component_info *compptr; jpeg_component_info *compptr;
JSAMPARRAY buf, xbuf0, xbuf1; JSAMPARRAY buf, xbuf0, xbuf1;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) { ci++, compptr++) {
rgroup = (compptr->v_samp_factor * compptr->codec_data_unit) / rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) /
cinfo->min_codec_data_unit; /* height of a row group of component */ cinfo->min_DCT_scaled_size; /* height of a row group of component */
xbuf0 = main->xbuffer[0][ci]; xbuf0 = main->xbuffer[0][ci];
xbuf1 = main->xbuffer[1][ci]; xbuf1 = main->xbuffer[1][ci];
/* First copy the workspace pointers as-is */ /* First copy the workspace pointers as-is */
@@ -244,14 +245,14 @@ set_wraparound_pointers (j_decompress_ptr cinfo)
{ {
my_main_ptr main = (my_main_ptr) cinfo->main; my_main_ptr main = (my_main_ptr) cinfo->main;
int ci, i, rgroup; int ci, i, rgroup;
int M = cinfo->min_codec_data_unit; int M = cinfo->min_DCT_scaled_size;
jpeg_component_info *compptr; jpeg_component_info *compptr;
JSAMPARRAY xbuf0, xbuf1; JSAMPARRAY xbuf0, xbuf1;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) { ci++, compptr++) {
rgroup = (compptr->v_samp_factor * compptr->codec_data_unit) / rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) /
cinfo->min_codec_data_unit; /* height of a row group of component */ cinfo->min_DCT_scaled_size; /* height of a row group of component */
xbuf0 = main->xbuffer[0][ci]; xbuf0 = main->xbuffer[0][ci];
xbuf1 = main->xbuffer[1][ci]; xbuf1 = main->xbuffer[1][ci];
for (i = 0; i < rgroup; i++) { for (i = 0; i < rgroup; i++) {
@@ -279,8 +280,8 @@ set_bottom_pointers (j_decompress_ptr cinfo)
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) { ci++, compptr++) {
/* Count sample rows in one iMCU row and in one row group */ /* Count sample rows in one iMCU row and in one row group */
iMCUheight = compptr->v_samp_factor * compptr->codec_data_unit; iMCUheight = compptr->v_samp_factor * compptr->DCT_scaled_size;
rgroup = iMCUheight / cinfo->min_codec_data_unit; rgroup = iMCUheight / cinfo->min_DCT_scaled_size;
/* Count nondummy sample rows remaining for this component */ /* Count nondummy sample rows remaining for this component */
rows_left = (int) (compptr->downsampled_height % (JDIMENSION) iMCUheight); rows_left = (int) (compptr->downsampled_height % (JDIMENSION) iMCUheight);
if (rows_left == 0) rows_left = iMCUheight; if (rows_left == 0) rows_left = iMCUheight;
@@ -353,13 +354,13 @@ process_data_simple_main (j_decompress_ptr cinfo,
/* Read input data if we haven't filled the main buffer yet */ /* Read input data if we haven't filled the main buffer yet */
if (! main->buffer_full) { if (! main->buffer_full) {
if (! (*cinfo->codec->decompress_data) (cinfo, main->buffer)) if (! (*cinfo->coef->decompress_data) (cinfo, main->buffer))
return; /* suspension forced, can do nothing more */ return; /* suspension forced, can do nothing more */
main->buffer_full = TRUE; /* OK, we have an iMCU row to work with */ main->buffer_full = TRUE; /* OK, we have an iMCU row to work with */
} }
/* There are always min_codec_data_unit row groups in an iMCU row. */ /* There are always min_DCT_scaled_size row groups in an iMCU row. */
rowgroups_avail = (JDIMENSION) cinfo->min_codec_data_unit; rowgroups_avail = (JDIMENSION) cinfo->min_DCT_scaled_size;
/* Note: at the bottom of the image, we may pass extra garbage row groups /* Note: at the bottom of the image, we may pass extra garbage row groups
* to the postprocessor. The postprocessor has to check for bottom * to the postprocessor. The postprocessor has to check for bottom
* of image anyway (at row resolution), so no point in us doing it too. * of image anyway (at row resolution), so no point in us doing it too.
@@ -392,7 +393,7 @@ process_data_context_main (j_decompress_ptr cinfo,
/* Read input data if we haven't filled the main buffer yet */ /* Read input data if we haven't filled the main buffer yet */
if (! main->buffer_full) { if (! main->buffer_full) {
if (! (*cinfo->codec->decompress_data) (cinfo, if (! (*cinfo->coef->decompress_data) (cinfo,
main->xbuffer[main->whichptr])) main->xbuffer[main->whichptr]))
return; /* suspension forced, can do nothing more */ return; /* suspension forced, can do nothing more */
main->buffer_full = TRUE; /* OK, we have an iMCU row to work with */ main->buffer_full = TRUE; /* OK, we have an iMCU row to work with */
@@ -419,7 +420,7 @@ process_data_context_main (j_decompress_ptr cinfo,
case CTX_PREPARE_FOR_IMCU: case CTX_PREPARE_FOR_IMCU:
/* Prepare to process first M-1 row groups of this iMCU row */ /* Prepare to process first M-1 row groups of this iMCU row */
main->rowgroup_ctr = 0; main->rowgroup_ctr = 0;
main->rowgroups_avail = (JDIMENSION) (cinfo->min_codec_data_unit - 1); main->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_scaled_size - 1);
/* Check for bottom of image: if so, tweak pointers to "duplicate" /* Check for bottom of image: if so, tweak pointers to "duplicate"
* the last sample row, and adjust rowgroups_avail to ignore padding rows. * the last sample row, and adjust rowgroups_avail to ignore padding rows.
*/ */
@@ -442,8 +443,8 @@ process_data_context_main (j_decompress_ptr cinfo,
main->buffer_full = FALSE; main->buffer_full = FALSE;
/* Still need to process last row group of this iMCU row, */ /* Still need to process last row group of this iMCU row, */
/* which is saved at index M+1 of the other xbuffer */ /* which is saved at index M+1 of the other xbuffer */
main->rowgroup_ctr = (JDIMENSION) (cinfo->min_codec_data_unit + 1); main->rowgroup_ctr = (JDIMENSION) (cinfo->min_DCT_scaled_size + 1);
main->rowgroups_avail = (JDIMENSION) (cinfo->min_codec_data_unit + 2); main->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_scaled_size + 2);
main->context_state = CTX_POSTPONED_ROW; main->context_state = CTX_POSTPONED_ROW;
} }
} }
@@ -494,21 +495,21 @@ jinit_d_main_controller (j_decompress_ptr cinfo, boolean need_full_buffer)
* ngroups is the number of row groups we need. * ngroups is the number of row groups we need.
*/ */
if (cinfo->upsample->need_context_rows) { if (cinfo->upsample->need_context_rows) {
if (cinfo->min_codec_data_unit < 2) /* unsupported, see comments above */ if (cinfo->min_DCT_scaled_size < 2) /* unsupported, see comments above */
ERREXIT(cinfo, JERR_NOTIMPL); ERREXIT(cinfo, JERR_NOTIMPL);
alloc_funny_pointers(cinfo); /* Alloc space for xbuffer[] lists */ alloc_funny_pointers(cinfo); /* Alloc space for xbuffer[] lists */
ngroups = cinfo->min_codec_data_unit + 2; ngroups = cinfo->min_DCT_scaled_size + 2;
} else { } else {
ngroups = cinfo->min_codec_data_unit; ngroups = cinfo->min_DCT_scaled_size;
} }
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) { ci++, compptr++) {
rgroup = (compptr->v_samp_factor * compptr->codec_data_unit) / rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) /
cinfo->min_codec_data_unit; /* height of a row group of component */ cinfo->min_DCT_scaled_size; /* height of a row group of component */
main->buffer[ci] = (*cinfo->mem->alloc_sarray) main->buffer[ci] = (*cinfo->mem->alloc_sarray)
((j_common_ptr) cinfo, JPOOL_IMAGE, ((j_common_ptr) cinfo, JPOOL_IMAGE,
compptr->width_in_data_units * compptr->codec_data_unit, compptr->width_in_blocks * compptr->DCT_scaled_size,
(JDIMENSION) (rgroup * ngroups)); (JDIMENSION) (rgroup * ngroups));
} }
} }

View File

@@ -5,6 +5,7 @@
* Copyright (C) 1991-1998, Thomas G. Lane. * Copyright (C) 1991-1998, Thomas G. Lane.
* Lossless JPEG Modifications: * Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison. * Copyright (C) 1999, Ken Murchison.
* Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains routines to decode JPEG datastream markers. * This file contains routines to decode JPEG datastream markers.
@@ -236,8 +237,8 @@ get_soi (j_decompress_ptr cinfo)
LOCAL(boolean) LOCAL(boolean)
get_sof (j_decompress_ptr cinfo, J_CODEC_PROCESS process, boolean is_arith, get_sof (j_decompress_ptr cinfo, boolean is_prog, boolean is_lossless,
int data_unit) boolean is_arith)
/* Process a SOFn marker */ /* Process a SOFn marker */
{ {
INT32 length; INT32 length;
@@ -245,8 +246,8 @@ get_sof (j_decompress_ptr cinfo, J_CODEC_PROCESS process, boolean is_arith,
jpeg_component_info * compptr; jpeg_component_info * compptr;
INPUT_VARS(cinfo); INPUT_VARS(cinfo);
cinfo->data_unit = data_unit; cinfo->progressive_mode = is_prog;
cinfo->process = process; cinfo->master->lossless = is_lossless;
cinfo->arith_code = is_arith; cinfo->arith_code = is_arith;
INPUT_2BYTES(cinfo, length, return FALSE); INPUT_2BYTES(cinfo, length, return FALSE);
@@ -980,32 +981,32 @@ read_markers (j_decompress_ptr cinfo)
case M_SOF0: /* Baseline */ case M_SOF0: /* Baseline */
case M_SOF1: /* Extended sequential, Huffman */ case M_SOF1: /* Extended sequential, Huffman */
if (! get_sof(cinfo, JPROC_SEQUENTIAL, FALSE, DCTSIZE)) if (! get_sof(cinfo, FALSE, FALSE, FALSE))
return JPEG_SUSPENDED; return JPEG_SUSPENDED;
break; break;
case M_SOF2: /* Progressive, Huffman */ case M_SOF2: /* Progressive, Huffman */
if (! get_sof(cinfo, JPROC_PROGRESSIVE, FALSE, DCTSIZE)) if (! get_sof(cinfo, TRUE, FALSE, FALSE))
return JPEG_SUSPENDED; return JPEG_SUSPENDED;
break; break;
case M_SOF3: /* Lossless, Huffman */ case M_SOF3: /* Lossless, Huffman */
if (! get_sof(cinfo, JPROC_LOSSLESS, FALSE, 1)) if (! get_sof(cinfo, FALSE, TRUE, FALSE))
return JPEG_SUSPENDED; return JPEG_SUSPENDED;
break; break;
case M_SOF9: /* Extended sequential, arithmetic */ case M_SOF9: /* Extended sequential, arithmetic */
if (! get_sof(cinfo, JPROC_SEQUENTIAL, TRUE, DCTSIZE)) if (! get_sof(cinfo, FALSE, FALSE, TRUE))
return JPEG_SUSPENDED; return JPEG_SUSPENDED;
break; break;
case M_SOF10: /* Progressive, arithmetic */ case M_SOF10: /* Progressive, arithmetic */
if (! get_sof(cinfo, JPROC_PROGRESSIVE, TRUE, DCTSIZE)) if (! get_sof(cinfo, TRUE, FALSE, TRUE))
return JPEG_SUSPENDED; return JPEG_SUSPENDED;
break; break;
case M_SOF11: /* Lossless, arithmetic */ case M_SOF11: /* Lossless, arithmetic */
if (! get_sof(cinfo, JPROC_LOSSLESS, TRUE, 1)) if (! get_sof(cinfo, FALSE, TRUE, TRUE))
return JPEG_SUSPENDED; return JPEG_SUSPENDED;
break; break;

View File

@@ -2,9 +2,10 @@
* jdmaster.c * jdmaster.c
* *
* This file was part of the Independent JPEG Group's software: * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1998, Thomas G. Lane. * Copyright (C) 1991-1997, Thomas G. Lane.
* Lossless JPEG Modifications: * Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison. * Copyright (C) 1999, Ken Murchison.
* Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains master control logic for the JPEG decompressor. * This file contains master control logic for the JPEG decompressor.
@@ -16,25 +17,7 @@
#define JPEG_INTERNALS #define JPEG_INTERNALS
#include "jinclude.h" #include "jinclude.h"
#include "jpeglib.h" #include "jpeglib.h"
#include "jdmaster.h"
/* Private state */
typedef struct {
struct jpeg_decomp_master pub; /* public fields */
int pass_number; /* # of passes completed */
boolean using_merged_upsample; /* TRUE if using merged upsample/cconvert */
/* Saved references to initialized quantizer modules,
* in case we need to switch modes.
*/
struct jpeg_color_quantizer * quantizer_1pass;
struct jpeg_color_quantizer * quantizer_2pass;
} my_decomp_master;
typedef my_decomp_master * my_master_ptr;
/* /*
@@ -62,11 +45,10 @@ use_merged_upsample (j_decompress_ptr cinfo)
cinfo->comp_info[1].v_samp_factor != 1 || cinfo->comp_info[1].v_samp_factor != 1 ||
cinfo->comp_info[2].v_samp_factor != 1) cinfo->comp_info[2].v_samp_factor != 1)
return FALSE; return FALSE;
/* furthermore, it doesn't work if each component has been /* furthermore, it doesn't work if we've scaled the IDCTs differently */
processed differently */ if (cinfo->comp_info[0].DCT_scaled_size != cinfo->min_DCT_scaled_size ||
if (cinfo->comp_info[0].codec_data_unit != cinfo->min_codec_data_unit || cinfo->comp_info[1].DCT_scaled_size != cinfo->min_DCT_scaled_size ||
cinfo->comp_info[1].codec_data_unit != cinfo->min_codec_data_unit || cinfo->comp_info[2].DCT_scaled_size != cinfo->min_DCT_scaled_size)
cinfo->comp_info[2].codec_data_unit != cinfo->min_codec_data_unit)
return FALSE; return FALSE;
/* ??? also need to test for upsample-time rescaling, when & if supported */ /* ??? also need to test for upsample-time rescaling, when & if supported */
return TRUE; /* by golly, it'll work... */ return TRUE; /* by golly, it'll work... */
@@ -87,11 +69,89 @@ GLOBAL(void)
jpeg_calc_output_dimensions (j_decompress_ptr cinfo) jpeg_calc_output_dimensions (j_decompress_ptr cinfo)
/* Do computations that are needed before master selection phase */ /* Do computations that are needed before master selection phase */
{ {
#ifdef IDCT_SCALING_SUPPORTED
int ci;
jpeg_component_info *compptr;
#endif
/* Prevent application from calling me at wrong times */ /* Prevent application from calling me at wrong times */
if (cinfo->global_state != DSTATE_READY) if (cinfo->global_state != DSTATE_READY)
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
(*cinfo->codec->calc_output_dimensions) (cinfo); #ifdef IDCT_SCALING_SUPPORTED
if (! cinfo->master->lossless) {
/* Compute actual output image dimensions and DCT scaling choices. */
if (cinfo->scale_num * 8 <= cinfo->scale_denom) {
/* Provide 1/8 scaling */
cinfo->output_width = (JDIMENSION)
jdiv_round_up((long) cinfo->image_width, 8L);
cinfo->output_height = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height, 8L);
cinfo->min_DCT_scaled_size = 1;
} else if (cinfo->scale_num * 4 <= cinfo->scale_denom) {
/* Provide 1/4 scaling */
cinfo->output_width = (JDIMENSION)
jdiv_round_up((long) cinfo->image_width, 4L);
cinfo->output_height = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height, 4L);
cinfo->min_DCT_scaled_size = 2;
} else if (cinfo->scale_num * 2 <= cinfo->scale_denom) {
/* Provide 1/2 scaling */
cinfo->output_width = (JDIMENSION)
jdiv_round_up((long) cinfo->image_width, 2L);
cinfo->output_height = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height, 2L);
cinfo->min_DCT_scaled_size = 4;
} else {
/* Provide 1/1 scaling */
cinfo->output_width = cinfo->image_width;
cinfo->output_height = cinfo->image_height;
cinfo->min_DCT_scaled_size = DCTSIZE;
}
/* In selecting the actual DCT scaling for each component, we try to
* scale up the chroma components via IDCT scaling rather than upsampling.
* This saves time if the upsampler gets to use 1:1 scaling.
* Note this code assumes that the supported DCT scalings are powers of 2.
*/
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
int ssize = cinfo->min_DCT_scaled_size;
while (ssize < DCTSIZE &&
(compptr->h_samp_factor * ssize * 2 <=
cinfo->max_h_samp_factor * cinfo->min_DCT_scaled_size) &&
(compptr->v_samp_factor * ssize * 2 <=
cinfo->max_v_samp_factor * cinfo->min_DCT_scaled_size)) {
ssize = ssize * 2;
}
compptr->DCT_scaled_size = ssize;
}
/* Recompute downsampled dimensions of components;
* application needs to know these if using raw downsampled data.
*/
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
/* Size in samples, after IDCT scaling */
compptr->downsampled_width = (JDIMENSION)
jdiv_round_up((long) cinfo->image_width *
(long) (compptr->h_samp_factor * compptr->DCT_scaled_size),
(long) (cinfo->max_h_samp_factor * DCTSIZE));
compptr->downsampled_height = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height *
(long) (compptr->v_samp_factor * compptr->DCT_scaled_size),
(long) (cinfo->max_v_samp_factor * DCTSIZE));
}
} else
#endif /* !IDCT_SCALING_SUPPORTED */
{
/* Hardwire it to "no scaling" */
cinfo->output_width = cinfo->image_width;
cinfo->output_height = cinfo->image_height;
/* jdinput.c has already initialized DCT_scaled_size to DCTSIZE,
* and has computed unscaled downsampled_width and downsampled_height.
*/
}
/* Report number of components in selected colorspace. */ /* Report number of components in selected colorspace. */
/* Probably this should be in the color conversion module... */ /* Probably this should be in the color conversion module... */
@@ -213,9 +273,21 @@ LOCAL(void)
master_selection (j_decompress_ptr cinfo) master_selection (j_decompress_ptr cinfo)
{ {
my_master_ptr master = (my_master_ptr) cinfo->master; my_master_ptr master = (my_master_ptr) cinfo->master;
boolean use_c_buffer;
long samplesperrow; long samplesperrow;
JDIMENSION jd_samplesperrow; JDIMENSION jd_samplesperrow;
/* Disable IDCT scaling and raw (downsampled) data output in lossless mode.
* IDCT scaling is not useful in lossless mode, and it must be disabled in
* order to properly calculate the output dimensions. Raw data output isn't
* particularly useful without subsampling and has not been tested in
* lossless mode.
*/
if (cinfo->master->lossless) {
cinfo->raw_data_out = FALSE;
cinfo->scale_num = cinfo->scale_denom = 1;
}
/* Initialize dimensions and other stuff */ /* Initialize dimensions and other stuff */
jpeg_calc_output_dimensions(cinfo); jpeg_calc_output_dimensions(cinfo);
prepare_range_limit_table(cinfo); prepare_range_limit_table(cinfo);
@@ -294,7 +366,49 @@ master_selection (j_decompress_ptr cinfo)
jinit_d_post_controller(cinfo, cinfo->enable_2pass_quant); jinit_d_post_controller(cinfo, cinfo->enable_2pass_quant);
} }
if (cinfo->master->lossless) {
#ifdef D_LOSSLESS_SUPPORTED
/* Prediction, sample undifferencing, point transform, and sample size
* scaling
*/
jinit_lossless_decompressor(cinfo);
/* Entropy decoding: either Huffman or arithmetic coding. */
if (cinfo->arith_code) {
ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
} else {
jinit_lhuff_decoder(cinfo);
}
/* Initialize principal buffer controllers. */ /* Initialize principal buffer controllers. */
use_c_buffer = cinfo->inputctl->has_multiple_scans ||
cinfo->buffered_image;
jinit_d_diff_controller(cinfo, use_c_buffer);
#else
ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif
} else {
/* Inverse DCT */
jinit_inverse_dct(cinfo);
/* Entropy decoding: either Huffman or arithmetic coding. */
if (cinfo->arith_code) {
ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
} else {
if (cinfo->progressive_mode) {
#ifdef D_PROGRESSIVE_SUPPORTED
jinit_phuff_decoder(cinfo);
#else
ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif
} else
jinit_huff_decoder(cinfo);
}
/* Initialize principal buffer controllers. */
use_c_buffer = cinfo->inputctl->has_multiple_scans ||
cinfo->buffered_image;
jinit_d_coef_controller(cinfo, use_c_buffer);
}
if (! cinfo->raw_data_out) if (! cinfo->raw_data_out)
jinit_d_main_controller(cinfo, FALSE /* never need full buffer here */); jinit_d_main_controller(cinfo, FALSE /* never need full buffer here */);
@@ -313,7 +427,7 @@ master_selection (j_decompress_ptr cinfo)
cinfo->inputctl->has_multiple_scans) { cinfo->inputctl->has_multiple_scans) {
int nscans; int nscans;
/* Estimate number of scans to set pass_limit. */ /* Estimate number of scans to set pass_limit. */
if (cinfo->process == JPROC_PROGRESSIVE) { if (cinfo->progressive_mode) {
/* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */ /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */
nscans = 2 + 3 * cinfo->num_components; nscans = 2 + 3 * cinfo->num_components;
} else { } else {
@@ -367,7 +481,8 @@ prepare_for_output_pass (j_decompress_ptr cinfo)
ERREXIT(cinfo, JERR_MODE_CHANGE); ERREXIT(cinfo, JERR_MODE_CHANGE);
} }
} }
(*cinfo->codec->start_output_pass) (cinfo); (*cinfo->idct->start_pass) (cinfo);
(*cinfo->coef->start_output_pass) (cinfo);
if (! cinfo->raw_data_out) { if (! cinfo->raw_data_out) {
if (! master->using_merged_upsample) if (! master->using_merged_upsample)
(*cinfo->cconvert->start_pass) (cinfo); (*cinfo->cconvert->start_pass) (cinfo);
@@ -447,12 +562,8 @@ jpeg_new_colormap (j_decompress_ptr cinfo)
GLOBAL(void) GLOBAL(void)
jinit_master_decompress (j_decompress_ptr cinfo) jinit_master_decompress (j_decompress_ptr cinfo)
{ {
my_master_ptr master; my_master_ptr master = (my_master_ptr) cinfo->master;
master = (my_master_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(my_decomp_master));
cinfo->master = (struct jpeg_decomp_master *) master;
master->pub.prepare_for_output_pass = prepare_for_output_pass; master->pub.prepare_for_output_pass = prepare_for_output_pass;
master->pub.finish_output_pass = finish_output_pass; master->pub.finish_output_pass = finish_output_pass;

27
jdmaster.h Normal file
View File

@@ -0,0 +1,27 @@
/*
* jdmaster.h
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1995, Thomas G. Lane.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains the master control structure for the JPEG decompressor.
*/
/* Private state */
typedef struct {
struct jpeg_decomp_master pub; /* public fields */
int pass_number; /* # of passes completed */
boolean using_merged_upsample; /* TRUE if using merged upsample/cconvert */
/* Saved references to initialized quantizer modules,
* in case we need to switch modes.
*/
struct jpeg_color_quantizer * quantizer_1pass;
struct jpeg_color_quantizer * quantizer_2pass;
} my_decomp_master;
typedef my_decomp_master * my_master_ptr;

View File

@@ -2,7 +2,7 @@
* jdphuff.c * jdphuff.c
* *
* This file was part of the Independent JPEG Group's software: * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1995-1998, Thomas G. Lane. * Copyright (C) 1995-1997, Thomas G. Lane.
* Lossless JPEG Modifications: * Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison. * Copyright (C) 1999, Ken Murchison.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
@@ -19,14 +19,13 @@
#define JPEG_INTERNALS #define JPEG_INTERNALS
#include "jinclude.h" #include "jinclude.h"
#include "jpeglib.h" #include "jpeglib.h"
#include "jlossy.h" /* Private declarations for lossy subsystem */
#include "jdhuff.h" /* Declarations shared with jd*huff.c */ #include "jdhuff.h" /* Declarations shared with jd*huff.c */
#ifdef D_PROGRESSIVE_SUPPORTED #ifdef D_PROGRESSIVE_SUPPORTED
/* /*
* Private entropy decoder object for progressive Huffman decoding. * Expanded entropy decoder object for progressive Huffman decoding.
* *
* The savable_state subrecord contains fields that change within an MCU, * The savable_state subrecord contains fields that change within an MCU,
* but must not be updated permanently until we complete the MCU. * but must not be updated permanently until we complete the MCU.
@@ -57,11 +56,12 @@ typedef struct {
typedef struct { typedef struct {
huffd_common_fields; /* Fields shared with other entropy decoders */ struct jpeg_entropy_decoder pub; /* public fields */
/* These fields are loaded into local variables at start of each MCU. /* These fields are loaded into local variables at start of each MCU.
* In case of suspension, we exit WITHOUT updating them. * In case of suspension, we exit WITHOUT updating them.
*/ */
bitread_perm_state bitstate; /* Bit buffer at start of MCU */
savable_state saved; /* Other state at start of MCU */ savable_state saved; /* Other state at start of MCU */
/* These fields are NOT loaded into local working state. */ /* These fields are NOT loaded into local working state. */
@@ -93,8 +93,7 @@ METHODDEF(boolean) decode_mcu_AC_refine JPP((j_decompress_ptr cinfo,
METHODDEF(void) METHODDEF(void)
start_pass_phuff_decoder (j_decompress_ptr cinfo) start_pass_phuff_decoder (j_decompress_ptr cinfo)
{ {
j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyd->entropy_private;
boolean is_DC_band, bad; boolean is_DC_band, bad;
int ci, coefi, tbl; int ci, coefi, tbl;
int *coef_bit_ptr; int *coef_bit_ptr;
@@ -151,14 +150,14 @@ start_pass_phuff_decoder (j_decompress_ptr cinfo)
/* Select MCU decoding routine */ /* Select MCU decoding routine */
if (cinfo->Ah == 0) { if (cinfo->Ah == 0) {
if (is_DC_band) if (is_DC_band)
lossyd->entropy_decode_mcu = decode_mcu_DC_first; entropy->pub.decode_mcu = decode_mcu_DC_first;
else else
lossyd->entropy_decode_mcu = decode_mcu_AC_first; entropy->pub.decode_mcu = decode_mcu_AC_first;
} else { } else {
if (is_DC_band) if (is_DC_band)
lossyd->entropy_decode_mcu = decode_mcu_DC_refine; entropy->pub.decode_mcu = decode_mcu_DC_refine;
else else
lossyd->entropy_decode_mcu = decode_mcu_AC_refine; entropy->pub.decode_mcu = decode_mcu_AC_refine;
} }
for (ci = 0; ci < cinfo->comps_in_scan; ci++) { for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
@@ -186,7 +185,7 @@ start_pass_phuff_decoder (j_decompress_ptr cinfo)
/* Initialize bitread state variables */ /* Initialize bitread state variables */
entropy->bitstate.bits_left = 0; entropy->bitstate.bits_left = 0;
entropy->bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */ entropy->bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */
entropy->insufficient_data = FALSE; entropy->pub.insufficient_data = FALSE;
/* Initialize private state variables */ /* Initialize private state variables */
entropy->saved.EOBRUN = 0; entropy->saved.EOBRUN = 0;
@@ -230,8 +229,7 @@ static const int extend_offset[16] = /* entry n is (-1 << n) + 1 */
LOCAL(boolean) LOCAL(boolean)
process_restart (j_decompress_ptr cinfo) process_restart (j_decompress_ptr cinfo)
{ {
j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyd->entropy_private;
int ci; int ci;
/* Throw away any unused bits remaining in bit buffer; */ /* Throw away any unused bits remaining in bit buffer; */
@@ -258,7 +256,7 @@ process_restart (j_decompress_ptr cinfo)
* leaving the flag set. * leaving the flag set.
*/ */
if (cinfo->unread_marker == 0) if (cinfo->unread_marker == 0)
entropy->insufficient_data = FALSE; entropy->pub.insufficient_data = FALSE;
return TRUE; return TRUE;
} }
@@ -289,8 +287,7 @@ process_restart (j_decompress_ptr cinfo)
METHODDEF(boolean) METHODDEF(boolean)
decode_mcu_DC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) decode_mcu_DC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
{ {
j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyd->entropy_private;
int Al = cinfo->Al; int Al = cinfo->Al;
register int s, r; register int s, r;
int blkn, ci; int blkn, ci;
@@ -310,7 +307,7 @@ decode_mcu_DC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
/* If we've run out of data, just leave the MCU set to zeroes. /* If we've run out of data, just leave the MCU set to zeroes.
* This way, we return uniform gray for the remainder of the segment. * This way, we return uniform gray for the remainder of the segment.
*/ */
if (! entropy->insufficient_data) { if (! entropy->pub.insufficient_data) {
/* Load up working state */ /* Load up working state */
BITREAD_LOAD_STATE(cinfo,entropy->bitstate); BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
@@ -318,7 +315,7 @@ decode_mcu_DC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
/* Outer loop handles each block in the MCU */ /* Outer loop handles each block in the MCU */
for (blkn = 0; blkn < cinfo->data_units_in_MCU; blkn++) { for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
block = MCU_data[blkn]; block = MCU_data[blkn];
ci = cinfo->MCU_membership[blkn]; ci = cinfo->MCU_membership[blkn];
compptr = cinfo->cur_comp_info[ci]; compptr = cinfo->cur_comp_info[ci];
@@ -361,8 +358,7 @@ decode_mcu_DC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
METHODDEF(boolean) METHODDEF(boolean)
decode_mcu_AC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) decode_mcu_AC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
{ {
j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyd->entropy_private;
int Se = cinfo->Se; int Se = cinfo->Se;
int Al = cinfo->Al; int Al = cinfo->Al;
register int s, k, r; register int s, k, r;
@@ -381,7 +377,7 @@ decode_mcu_AC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
/* If we've run out of data, just leave the MCU set to zeroes. /* If we've run out of data, just leave the MCU set to zeroes.
* This way, we return uniform gray for the remainder of the segment. * This way, we return uniform gray for the remainder of the segment.
*/ */
if (! entropy->insufficient_data) { if (! entropy->pub.insufficient_data) {
/* Load up working state. /* Load up working state.
* We can avoid loading/saving bitread state if in an EOB run. * We can avoid loading/saving bitread state if in an EOB run.
@@ -447,8 +443,7 @@ decode_mcu_AC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
METHODDEF(boolean) METHODDEF(boolean)
decode_mcu_DC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) decode_mcu_DC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
{ {
j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyd->entropy_private;
int p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */ int p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */
int blkn; int blkn;
JBLOCKROW block; JBLOCKROW block;
@@ -470,7 +465,7 @@ decode_mcu_DC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
/* Outer loop handles each block in the MCU */ /* Outer loop handles each block in the MCU */
for (blkn = 0; blkn < cinfo->data_units_in_MCU; blkn++) { for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
block = MCU_data[blkn]; block = MCU_data[blkn];
/* Encoded data is simply the next bit of the two's-complement DC value */ /* Encoded data is simply the next bit of the two's-complement DC value */
@@ -497,8 +492,7 @@ decode_mcu_DC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
METHODDEF(boolean) METHODDEF(boolean)
decode_mcu_AC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) decode_mcu_AC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
{ {
j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyd->entropy_private;
int Se = cinfo->Se; int Se = cinfo->Se;
int p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */ int p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */
int m1 = (-1) << cinfo->Al; /* -1 in the bit position being coded */ int m1 = (-1) << cinfo->Al; /* -1 in the bit position being coded */
@@ -520,7 +514,7 @@ decode_mcu_AC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
/* If we've run out of data, don't modify the MCU. /* If we've run out of data, don't modify the MCU.
*/ */
if (! entropy->insufficient_data) { if (! entropy->pub.insufficient_data) {
/* Load up working state */ /* Load up working state */
BITREAD_LOAD_STATE(cinfo,entropy->bitstate); BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
@@ -648,7 +642,6 @@ undoit:
GLOBAL(void) GLOBAL(void)
jinit_phuff_decoder (j_decompress_ptr cinfo) jinit_phuff_decoder (j_decompress_ptr cinfo)
{ {
j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec;
phuff_entropy_ptr entropy; phuff_entropy_ptr entropy;
int *coef_bit_ptr; int *coef_bit_ptr;
int ci, i; int ci, i;
@@ -656,8 +649,8 @@ jinit_phuff_decoder (j_decompress_ptr cinfo)
entropy = (phuff_entropy_ptr) entropy = (phuff_entropy_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(phuff_entropy_decoder)); SIZEOF(phuff_entropy_decoder));
lossyd->entropy_private = (void *) entropy; cinfo->entropy = (struct jpeg_entropy_decoder *) entropy;
lossyd->entropy_start_pass = start_pass_phuff_decoder; entropy->pub.start_pass = start_pass_phuff_decoder;
/* Mark derived tables unallocated */ /* Mark derived tables unallocated */
for (i = 0; i < NUM_HUFF_TBLS; i++) { for (i = 0; i < NUM_HUFF_TBLS; i++) {

249
jdpred.c
View File

@@ -1,249 +0,0 @@
/*
* jdpred.c
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1998, Thomas G. Lane.
* Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains sample undifferencing (reconstruction) for lossless JPEG.
*
* In order to avoid paying the performance penalty of having to check the
* predictor being used and the row being processed for each call of the
* undifferencer, and to promote optimization, we have separate undifferencing
* functions for each case.
*
* We are able to avoid duplicating source code by implementing the predictors
* and undifferencers as macros. Each of the undifferencing functions are
* simply wrappers around an UNDIFFERENCE macro with the appropriate PREDICTOR
* macro passed as an argument.
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
#include "jlossls.h" /* Private declarations for lossless codec */
#ifdef D_LOSSLESS_SUPPORTED
/* Predictor for the first column of the first row: 2^(P-Pt-1) */
#define INITIAL_PREDICTORx (1 << (cinfo->data_precision - cinfo->Al - 1))
/* Predictor for the first column of the remaining rows: Rb */
#define INITIAL_PREDICTOR2 GETJSAMPLE(prev_row[0])
/*
* 1-Dimensional undifferencer routine.
*
* This macro implements the 1-D horizontal predictor (1). INITIAL_PREDICTOR
* is used as the special case predictor for the first column, which must be
* either INITIAL_PREDICTOR2 or INITIAL_PREDICTORx. The remaining samples
* use PREDICTOR1.
*
* The reconstructed sample is supposed to be calculated modulo 2^16, so we
* logically AND the result with 0xFFFF.
*/
#define UNDIFFERENCE_1D(INITIAL_PREDICTOR) \
int xindex; \
int Ra; \
\
Ra = (diff_buf[0] + INITIAL_PREDICTOR) & 0xFFFF; \
undiff_buf[0] = Ra; \
\
for (xindex = 1; xindex < width; xindex++) { \
Ra = (diff_buf[xindex] + PREDICTOR1) & 0xFFFF; \
undiff_buf[xindex] = Ra; \
}
/*
* 2-Dimensional undifferencer routine.
*
* This macro implements the 2-D horizontal predictors (#2-7). PREDICTOR2 is
* used as the special case predictor for the first column. The remaining
* samples use PREDICTOR, which is a function of Ra, Rb, Rc.
*
* Because prev_row and output_buf may point to the same storage area (in an
* interleaved image with Vi=1, for example), we must take care to buffer Rb/Rc
* before writing the current reconstructed sample value into output_buf.
*
* The reconstructed sample is supposed to be calculated modulo 2^16, so we
* logically AND the result with 0xFFFF.
*/
#define UNDIFFERENCE_2D(PREDICTOR) \
int xindex; \
int Ra, Rb, Rc; \
\
Rb = GETJSAMPLE(prev_row[0]); \
Ra = (diff_buf[0] + PREDICTOR2) & 0xFFFF; \
undiff_buf[0] = Ra; \
\
for (xindex = 1; xindex < width; xindex++) { \
Rc = Rb; \
Rb = GETJSAMPLE(prev_row[xindex]); \
Ra = (diff_buf[xindex] + PREDICTOR) & 0xFFFF; \
undiff_buf[xindex] = Ra; \
}
/*
* Undifferencers for the all rows but the first in a scan or restart interval.
* The first sample in the row is undifferenced using the vertical
* predictor (2). The rest of the samples are undifferenced using the
* predictor specified in the scan header.
*/
METHODDEF(void)
jpeg_undifference1(j_decompress_ptr cinfo, int comp_index,
JDIFFROW diff_buf, JDIFFROW prev_row,
JDIFFROW undiff_buf, JDIMENSION width)
{
UNDIFFERENCE_1D(INITIAL_PREDICTOR2);
}
METHODDEF(void)
jpeg_undifference2(j_decompress_ptr cinfo, int comp_index,
JDIFFROW diff_buf, JDIFFROW prev_row,
JDIFFROW undiff_buf, JDIMENSION width)
{
UNDIFFERENCE_2D(PREDICTOR2);
}
METHODDEF(void)
jpeg_undifference3(j_decompress_ptr cinfo, int comp_index,
JDIFFROW diff_buf, JDIFFROW prev_row,
JDIFFROW undiff_buf, JDIMENSION width)
{
UNDIFFERENCE_2D(PREDICTOR3);
}
METHODDEF(void)
jpeg_undifference4(j_decompress_ptr cinfo, int comp_index,
JDIFFROW diff_buf, JDIFFROW prev_row,
JDIFFROW undiff_buf, JDIMENSION width)
{
UNDIFFERENCE_2D(PREDICTOR4);
}
METHODDEF(void)
jpeg_undifference5(j_decompress_ptr cinfo, int comp_index,
JDIFFROW diff_buf, JDIFFROW prev_row,
JDIFFROW undiff_buf, JDIMENSION width)
{
UNDIFFERENCE_2D(PREDICTOR5);
}
METHODDEF(void)
jpeg_undifference6(j_decompress_ptr cinfo, int comp_index,
JDIFFROW diff_buf, JDIFFROW prev_row,
JDIFFROW undiff_buf, JDIMENSION width)
{
UNDIFFERENCE_2D(PREDICTOR6);
}
METHODDEF(void)
jpeg_undifference7(j_decompress_ptr cinfo, int comp_index,
JDIFFROW diff_buf, JDIFFROW prev_row,
JDIFFROW undiff_buf, JDIMENSION width)
{
UNDIFFERENCE_2D(PREDICTOR7);
}
/*
* Undifferencer for the first row in a scan or restart interval. The first
* sample in the row is undifferenced using the special predictor constant
* x=2^(P-Pt-1). The rest of the samples are undifferenced using the
* 1-D horizontal predictor (1).
*/
METHODDEF(void)
jpeg_undifference_first_row(j_decompress_ptr cinfo, int comp_index,
JDIFFROW diff_buf, JDIFFROW prev_row,
JDIFFROW undiff_buf, JDIMENSION width)
{
j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec;
UNDIFFERENCE_1D(INITIAL_PREDICTORx);
/*
* Now that we have undifferenced the first row, we want to use the
* undifferencer which corresponds to the predictor specified in the
* scan header.
*/
switch (cinfo->Ss) {
case 1:
losslsd->predict_undifference[comp_index] = jpeg_undifference1;
break;
case 2:
losslsd->predict_undifference[comp_index] = jpeg_undifference2;
break;
case 3:
losslsd->predict_undifference[comp_index] = jpeg_undifference3;
break;
case 4:
losslsd->predict_undifference[comp_index] = jpeg_undifference4;
break;
case 5:
losslsd->predict_undifference[comp_index] = jpeg_undifference5;
break;
case 6:
losslsd->predict_undifference[comp_index] = jpeg_undifference6;
break;
case 7:
losslsd->predict_undifference[comp_index] = jpeg_undifference7;
break;
}
}
/*
* Initialize for an input processing pass.
*/
METHODDEF(void)
predict_start_pass (j_decompress_ptr cinfo)
{
j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec;
int ci;
/* Check that the scan parameters Ss, Se, Ah, Al are OK for lossless JPEG.
*
* Ss is the predictor selection value (psv). Legal values for sequential
* lossless JPEG are: 1 <= psv <= 7.
*
* Se and Ah are not used and should be zero.
*
* Al specifies the point transform (Pt). Legal values are: 0 <= Pt <= 15.
*/
if (cinfo->Ss < 1 || cinfo->Ss > 7 ||
cinfo->Se != 0 || cinfo->Ah != 0 ||
cinfo->Al > 15) /* need not check for < 0 */
ERREXIT4(cinfo, JERR_BAD_LOSSLESS,
cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al);
/* Set undifference functions to first row function */
for (ci = 0; ci < cinfo->num_components; ci++)
losslsd->predict_undifference[ci] = jpeg_undifference_first_row;
}
/*
* Module initialization routine for the undifferencer.
*/
GLOBAL(void)
jinit_undifferencer (j_decompress_ptr cinfo)
{
j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec;
losslsd->predict_start_pass = predict_start_pass;
losslsd->predict_process_restart = predict_start_pass;
}
#endif /* D_LOSSLESS_SUPPORTED */

View File

@@ -1,16 +1,14 @@
/* /*
* jdsample.c * jdsample.c
* *
* This file was part of the Independent JPEG Group's software: * Copyright (C) 1991-1996, Thomas G. Lane.
* Copyright (C) 1991-1998, Thomas G. Lane. * This file is part of the Independent JPEG Group's software.
* Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains upsampling routines. * This file contains upsampling routines.
* *
* Upsampling input data is counted in "row groups". A row group * Upsampling input data is counted in "row groups". A row group
* is defined to be (v_samp_factor * codec_data_unit / min_codec_data_unit) * is defined to be (v_samp_factor * DCT_scaled_size / min_DCT_scaled_size)
* sample rows of each component. Upsampling will normally produce * sample rows of each component. Upsampling will normally produce
* max_v_samp_factor pixel rows from each row group (but this could vary * max_v_samp_factor pixel rows from each row group (but this could vary
* if the upsampler is applying a scale factor of its own). * if the upsampler is applying a scale factor of its own).
@@ -417,10 +415,10 @@ jinit_upsampler (j_decompress_ptr cinfo)
if (cinfo->CCIR601_sampling) /* this isn't supported */ if (cinfo->CCIR601_sampling) /* this isn't supported */
ERREXIT(cinfo, JERR_CCIR601_NOTIMPL); ERREXIT(cinfo, JERR_CCIR601_NOTIMPL);
/* jdmainct.c doesn't support context rows when min_codec_data_unit = 1, /* jdmainct.c doesn't support context rows when min_DCT_scaled_size = 1,
* so don't ask for it. * so don't ask for it.
*/ */
do_fancy = cinfo->do_fancy_upsampling && cinfo->min_codec_data_unit > 1; do_fancy = cinfo->do_fancy_upsampling && cinfo->min_DCT_scaled_size > 1;
/* Verify we can handle the sampling factors, select per-component methods, /* Verify we can handle the sampling factors, select per-component methods,
* and create storage as needed. * and create storage as needed.
@@ -430,10 +428,10 @@ jinit_upsampler (j_decompress_ptr cinfo)
/* Compute size of an "input group" after IDCT scaling. This many samples /* Compute size of an "input group" after IDCT scaling. This many samples
* are to be converted to max_h_samp_factor * max_v_samp_factor pixels. * are to be converted to max_h_samp_factor * max_v_samp_factor pixels.
*/ */
h_in_group = (compptr->h_samp_factor * compptr->codec_data_unit) / h_in_group = (compptr->h_samp_factor * compptr->DCT_scaled_size) /
cinfo->min_codec_data_unit; cinfo->min_DCT_scaled_size;
v_in_group = (compptr->v_samp_factor * compptr->codec_data_unit) / v_in_group = (compptr->v_samp_factor * compptr->DCT_scaled_size) /
cinfo->min_codec_data_unit; cinfo->min_DCT_scaled_size;
h_out_group = cinfo->max_h_samp_factor; h_out_group = cinfo->max_h_samp_factor;
v_out_group = cinfo->max_v_samp_factor; v_out_group = cinfo->max_v_samp_factor;
upsample->rowgroup_height[ci] = v_in_group; /* save for use later */ upsample->rowgroup_height[ci] = v_in_group; /* save for use later */

120
jdscale.c
View File

@@ -1,120 +0,0 @@
/*
* jdscale.c
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1998, Thomas G. Lane.
* Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains sample scaling for lossless JPEG. This is a
* combination of upscaling the undifferenced sample by 2^Pt and downscaling
* the sample to fit into JSAMPLE.
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
#include "jlossls.h" /* Private declarations for lossless codec */
#ifdef D_LOSSLESS_SUPPORTED
/*
* Private scaler object for lossless decoding.
*/
typedef struct {
int scale_factor;
} scaler;
typedef scaler * scaler_ptr;
/*
* Scalers for packing sample differences into JSAMPLEs.
*/
METHODDEF(void)
simple_upscale(j_decompress_ptr cinfo,
JDIFFROW diff_buf, JSAMPROW output_buf,
JDIMENSION width)
{
j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec;
scaler_ptr scaler = (scaler_ptr) losslsd->scaler_private;
int scale_factor = scaler->scale_factor;
int xindex;
for (xindex = 0; xindex < width; xindex++)
output_buf[xindex] = (JSAMPLE) (diff_buf[xindex] << scale_factor);
}
METHODDEF(void)
simple_downscale(j_decompress_ptr cinfo,
JDIFFROW diff_buf, JSAMPROW output_buf,
JDIMENSION width)
{
j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec;
scaler_ptr scaler = (scaler_ptr) losslsd->scaler_private;
int scale_factor = scaler->scale_factor;
int xindex;
for (xindex = 0; xindex < width; xindex++)
output_buf[xindex] = (JSAMPLE) RIGHT_SHIFT(diff_buf[xindex], scale_factor);
}
METHODDEF(void)
noscale(j_decompress_ptr cinfo,
JDIFFROW diff_buf, JSAMPROW output_buf,
JDIMENSION width)
{
int xindex;
for (xindex = 0; xindex < width; xindex++)
output_buf[xindex] = (JSAMPLE) diff_buf[xindex];
}
METHODDEF(void)
scaler_start_pass (j_decompress_ptr cinfo)
{
j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec;
scaler_ptr scaler = (scaler_ptr) losslsd->scaler_private;
int downscale;
/*
* Downscale by the difference in the input vs. output precision. If the
* output precision >= input precision, then do not downscale.
*/
downscale = BITS_IN_JSAMPLE < cinfo->data_precision ?
cinfo->data_precision - BITS_IN_JSAMPLE : 0;
scaler->scale_factor = cinfo->Al - downscale;
/* Set scaler functions based on scale_factor (positive = left shift) */
if (scaler->scale_factor > 0)
losslsd->scaler_scale = simple_upscale;
else if (scaler->scale_factor < 0) {
scaler->scale_factor = -scaler->scale_factor;
losslsd->scaler_scale = simple_downscale;
}
else
losslsd->scaler_scale = noscale;
}
GLOBAL(void)
jinit_d_scaler (j_decompress_ptr cinfo)
{
j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec;
scaler_ptr scaler;
scaler = (scaler_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(scaler));
losslsd->scaler_private = (void *) scaler;
losslsd->scaler_start_pass = scaler_start_pass;
}
#endif /* D_LOSSLESS_SUPPORTED */

362
jdshuff.c
View File

@@ -1,362 +0,0 @@
/*
* jdshuff.c
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1998, Thomas G. Lane.
* Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains Huffman entropy decoding routines for sequential JPEG.
*
* Much of the complexity here has to do with supporting input suspension.
* If the data source module demands suspension, we want to be able to back
* up to the start of the current MCU. To do this, we copy state variables
* into local working storage, and update them back to the permanent
* storage only upon successful completion of an MCU.
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
#include "jlossy.h" /* Private declarations for lossy codec */
#include "jdhuff.h" /* Declarations shared with jd*huff.c */
/*
* Private entropy decoder object for Huffman decoding.
*
* The savable_state subrecord contains fields that change within an MCU,
* but must not be updated permanently until we complete the MCU.
*/
typedef struct {
int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */
} savable_state;
/* This macro is to work around compilers with missing or broken
* structure assignment. You'll need to fix this code if you have
* such a compiler and you change MAX_COMPS_IN_SCAN.
*/
#ifndef NO_STRUCT_ASSIGN
#define ASSIGN_STATE(dest,src) ((dest) = (src))
#else
#if MAX_COMPS_IN_SCAN == 4
#define ASSIGN_STATE(dest,src) \
((dest).last_dc_val[0] = (src).last_dc_val[0], \
(dest).last_dc_val[1] = (src).last_dc_val[1], \
(dest).last_dc_val[2] = (src).last_dc_val[2], \
(dest).last_dc_val[3] = (src).last_dc_val[3])
#endif
#endif
typedef struct {
huffd_common_fields; /* Fields shared with other entropy decoders */
/* These fields are loaded into local variables at start of each MCU.
* In case of suspension, we exit WITHOUT updating them.
*/
savable_state saved; /* Other state at start of MCU */
/* These fields are NOT loaded into local working state. */
unsigned int restarts_to_go; /* MCUs left in this restart interval */
/* Pointers to derived tables (these workspaces have image lifespan) */
d_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS];
d_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS];
/* Precalculated info set up by start_pass for use in decode_mcu: */
/* Pointers to derived tables to be used for each block within an MCU */
d_derived_tbl * dc_cur_tbls[D_MAX_DATA_UNITS_IN_MCU];
d_derived_tbl * ac_cur_tbls[D_MAX_DATA_UNITS_IN_MCU];
/* Whether we care about the DC and AC coefficient values for each block */
boolean dc_needed[D_MAX_DATA_UNITS_IN_MCU];
boolean ac_needed[D_MAX_DATA_UNITS_IN_MCU];
} shuff_entropy_decoder;
typedef shuff_entropy_decoder * shuff_entropy_ptr;
/*
* Initialize for a Huffman-compressed scan.
*/
METHODDEF(void)
start_pass_huff_decoder (j_decompress_ptr cinfo)
{
j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec;
shuff_entropy_ptr entropy = (shuff_entropy_ptr) lossyd->entropy_private;
int ci, blkn, dctbl, actbl;
jpeg_component_info * compptr;
/* Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG.
* This ought to be an error condition, but we make it a warning because
* there are some baseline files out there with all zeroes in these bytes.
*/
if (cinfo->Ss != 0 || cinfo->Se != DCTSIZE2-1 ||
cinfo->Ah != 0 || cinfo->Al != 0)
WARNMS(cinfo, JWRN_NOT_SEQUENTIAL);
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
dctbl = compptr->dc_tbl_no;
actbl = compptr->ac_tbl_no;
/* Compute derived values for Huffman tables */
/* We may do this more than once for a table, but it's not expensive */
jpeg_make_d_derived_tbl(cinfo, TRUE, dctbl,
& entropy->dc_derived_tbls[dctbl]);
jpeg_make_d_derived_tbl(cinfo, FALSE, actbl,
& entropy->ac_derived_tbls[actbl]);
/* Initialize DC predictions to 0 */
entropy->saved.last_dc_val[ci] = 0;
}
/* Precalculate decoding info for each block in an MCU of this scan */
for (blkn = 0; blkn < cinfo->data_units_in_MCU; blkn++) {
ci = cinfo->MCU_membership[blkn];
compptr = cinfo->cur_comp_info[ci];
/* Precalculate which table to use for each block */
entropy->dc_cur_tbls[blkn] = entropy->dc_derived_tbls[compptr->dc_tbl_no];
entropy->ac_cur_tbls[blkn] = entropy->ac_derived_tbls[compptr->ac_tbl_no];
/* Decide whether we really care about the coefficient values */
if (compptr->component_needed) {
entropy->dc_needed[blkn] = TRUE;
/* we don't need the ACs if producing a 1/8th-size image */
entropy->ac_needed[blkn] = (compptr->codec_data_unit > 1);
} else {
entropy->dc_needed[blkn] = entropy->ac_needed[blkn] = FALSE;
}
}
/* Initialize bitread state variables */
entropy->bitstate.bits_left = 0;
entropy->bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */
entropy->insufficient_data = FALSE;
/* Initialize restart counter */
entropy->restarts_to_go = cinfo->restart_interval;
}
/*
* Figure F.12: extend sign bit.
* On some machines, a shift and add will be faster than a table lookup.
*/
#ifdef AVOID_TABLES
#define HUFF_EXTEND(x,s) ((x) < (1<<((s)-1)) ? (x) + (((-1)<<(s)) + 1) : (x))
#else
#define HUFF_EXTEND(x,s) ((x) < extend_test[s] ? (x) + extend_offset[s] : (x))
static const int extend_test[16] = /* entry n is 2**(n-1) */
{ 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000 };
static const int extend_offset[16] = /* entry n is (-1 << n) + 1 */
{ 0, ((-1)<<1) + 1, ((-1)<<2) + 1, ((-1)<<3) + 1, ((-1)<<4) + 1,
((-1)<<5) + 1, ((-1)<<6) + 1, ((-1)<<7) + 1, ((-1)<<8) + 1,
((-1)<<9) + 1, ((-1)<<10) + 1, ((-1)<<11) + 1, ((-1)<<12) + 1,
((-1)<<13) + 1, ((-1)<<14) + 1, ((-1)<<15) + 1 };
#endif /* AVOID_TABLES */
/*
* Check for a restart marker & resynchronize decoder.
* Returns FALSE if must suspend.
*/
LOCAL(boolean)
process_restart (j_decompress_ptr cinfo)
{
j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec;
shuff_entropy_ptr entropy = (shuff_entropy_ptr) lossyd->entropy_private;
int ci;
/* Throw away any unused bits remaining in bit buffer; */
/* include any full bytes in next_marker's count of discarded bytes */
cinfo->marker->discarded_bytes += entropy->bitstate.bits_left / 8;
entropy->bitstate.bits_left = 0;
/* Advance past the RSTn marker */
if (! (*cinfo->marker->read_restart_marker) (cinfo))
return FALSE;
/* Re-initialize DC predictions to 0 */
for (ci = 0; ci < cinfo->comps_in_scan; ci++)
entropy->saved.last_dc_val[ci] = 0;
/* Reset restart counter */
entropy->restarts_to_go = cinfo->restart_interval;
/* Reset out-of-data flag, unless read_restart_marker left us smack up
* against a marker. In that case we will end up treating the next data
* segment as empty, and we can avoid producing bogus output pixels by
* leaving the flag set.
*/
if (cinfo->unread_marker == 0)
entropy->insufficient_data = FALSE;
return TRUE;
}
/*
* Decode and return one MCU's worth of Huffman-compressed coefficients.
* The coefficients are reordered from zigzag order into natural array order,
* but are not dequantized.
*
* The i'th block of the MCU is stored into the block pointed to by
* MCU_data[i]. WE ASSUME THIS AREA HAS BEEN ZEROED BY THE CALLER.
* (Wholesale zeroing is usually a little faster than retail...)
*
* Returns FALSE if data source requested suspension. In that case no
* changes have been made to permanent state. (Exception: some output
* coefficients may already have been assigned. This is harmless for
* this module, since we'll just re-assign them on the next call.)
*/
METHODDEF(boolean)
decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
{
j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec;
shuff_entropy_ptr entropy = (shuff_entropy_ptr) lossyd->entropy_private;
int blkn;
BITREAD_STATE_VARS;
savable_state state;
/* Process restart marker if needed; may have to suspend */
if (cinfo->restart_interval) {
if (entropy->restarts_to_go == 0)
if (! process_restart(cinfo))
return FALSE;
}
/* If we've run out of data, just leave the MCU set to zeroes.
* This way, we return uniform gray for the remainder of the segment.
*/
if (! entropy->insufficient_data) {
/* Load up working state */
BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
ASSIGN_STATE(state, entropy->saved);
/* Outer loop handles each block in the MCU */
for (blkn = 0; blkn < cinfo->data_units_in_MCU; blkn++) {
JBLOCKROW block = MCU_data[blkn];
d_derived_tbl * dctbl = entropy->dc_cur_tbls[blkn];
d_derived_tbl * actbl = entropy->ac_cur_tbls[blkn];
register int s, k, r;
/* Decode a single block's worth of coefficients */
/* Section F.2.2.1: decode the DC coefficient difference */
HUFF_DECODE(s, br_state, dctbl, return FALSE, label1);
if (s) {
CHECK_BIT_BUFFER(br_state, s, return FALSE);
r = GET_BITS(s);
s = HUFF_EXTEND(r, s);
}
if (entropy->dc_needed[blkn]) {
/* Convert DC difference to actual value, update last_dc_val */
int ci = cinfo->MCU_membership[blkn];
s += state.last_dc_val[ci];
state.last_dc_val[ci] = s;
/* Output the DC coefficient (assumes jpeg_natural_order[0] = 0) */
(*block)[0] = (JCOEF) s;
}
if (entropy->ac_needed[blkn]) {
/* Section F.2.2.2: decode the AC coefficients */
/* Since zeroes are skipped, output area must be cleared beforehand */
for (k = 1; k < DCTSIZE2; k++) {
HUFF_DECODE(s, br_state, actbl, return FALSE, label2);
r = s >> 4;
s &= 15;
if (s) {
k += r;
CHECK_BIT_BUFFER(br_state, s, return FALSE);
r = GET_BITS(s);
s = HUFF_EXTEND(r, s);
/* Output coefficient in natural (dezigzagged) order.
* Note: the extra entries in jpeg_natural_order[] will save us
* if k >= DCTSIZE2, which could happen if the data is corrupted.
*/
(*block)[jpeg_natural_order[k]] = (JCOEF) s;
} else {
if (r != 15)
break;
k += 15;
}
}
} else {
/* Section F.2.2.2: decode the AC coefficients */
/* In this path we just discard the values */
for (k = 1; k < DCTSIZE2; k++) {
HUFF_DECODE(s, br_state, actbl, return FALSE, label3);
r = s >> 4;
s &= 15;
if (s) {
k += r;
CHECK_BIT_BUFFER(br_state, s, return FALSE);
DROP_BITS(s);
} else {
if (r != 15)
break;
k += 15;
}
}
}
}
/* Completed MCU, so update state */
BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
ASSIGN_STATE(entropy->saved, state);
}
/* Account for restart interval (no-op if not using restarts) */
entropy->restarts_to_go--;
return TRUE;
}
/*
* Module initialization routine for Huffman entropy decoding.
*/
GLOBAL(void)
jinit_shuff_decoder (j_decompress_ptr cinfo)
{
j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec;
shuff_entropy_ptr entropy;
int i;
entropy = (shuff_entropy_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(shuff_entropy_decoder));
lossyd->entropy_private = (void *) entropy;
lossyd->entropy_start_pass = start_pass_huff_decoder;
lossyd->entropy_decode_mcu = decode_mcu;
/* Mark tables unallocated */
for (i = 0; i < NUM_HUFF_TBLS; i++) {
entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL;
}
}

View File

@@ -2,9 +2,9 @@
* jdtrans.c * jdtrans.c
* *
* This file was part of the Independent JPEG Group's software: * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1995-1998, Thomas G. Lane. * Copyright (C) 1995-1997, Thomas G. Lane.
* Lossless JPEG Modifications: * Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison. * Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains library routines for transcoding decompression, * This file contains library routines for transcoding decompression,
@@ -15,7 +15,6 @@
#define JPEG_INTERNALS #define JPEG_INTERNALS
#include "jinclude.h" #include "jinclude.h"
#include "jpeglib.h" #include "jpeglib.h"
#include "jlossy.h"
/* Forward declarations */ /* Forward declarations */
@@ -47,13 +46,8 @@ LOCAL(void) transdecode_master_selection JPP((j_decompress_ptr cinfo));
GLOBAL(jvirt_barray_ptr *) GLOBAL(jvirt_barray_ptr *)
jpeg_read_coefficients (j_decompress_ptr cinfo) jpeg_read_coefficients (j_decompress_ptr cinfo)
{ {
j_lossy_d_ptr decomp; if (cinfo->master->lossless)
ERREXIT(cinfo, JERR_NOTIMPL);
/* Can't read coefficients from lossless streams */
if (cinfo->process == JPROC_LOSSLESS) {
ERREXIT(cinfo, JERR_CANT_TRANSCODE);
return NULL;
}
if (cinfo->global_state == DSTATE_READY) { if (cinfo->global_state == DSTATE_READY) {
/* First call: initialize active modules */ /* First call: initialize active modules */
@@ -91,7 +85,7 @@ jpeg_read_coefficients (j_decompress_ptr cinfo)
*/ */
if ((cinfo->global_state == DSTATE_STOPPING || if ((cinfo->global_state == DSTATE_STOPPING ||
cinfo->global_state == DSTATE_BUFIMAGE) && cinfo->buffered_image) { cinfo->global_state == DSTATE_BUFIMAGE) && cinfo->buffered_image) {
return ((j_lossy_d_ptr) cinfo->codec)->coef_arrays; return cinfo->coef->coef_arrays;
} }
/* Oops, improper usage */ /* Oops, improper usage */
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
@@ -110,8 +104,22 @@ transdecode_master_selection (j_decompress_ptr cinfo)
/* This is effectively a buffered-image operation. */ /* This is effectively a buffered-image operation. */
cinfo->buffered_image = TRUE; cinfo->buffered_image = TRUE;
/* Initialize decompression codec */ /* Entropy decoding: either Huffman or arithmetic coding. */
jinit_d_codec(cinfo); if (cinfo->arith_code) {
ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
} else {
if (cinfo->progressive_mode) {
#ifdef D_PROGRESSIVE_SUPPORTED
jinit_phuff_decoder(cinfo);
#else
ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif
} else
jinit_huff_decoder(cinfo);
}
/* Always get a full-image coefficient buffer. */
jinit_d_coef_controller(cinfo, TRUE);
/* We can now tell the memory manager to allocate virtual arrays. */ /* We can now tell the memory manager to allocate virtual arrays. */
(*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo);
@@ -123,7 +131,7 @@ transdecode_master_selection (j_decompress_ptr cinfo)
if (cinfo->progress != NULL) { if (cinfo->progress != NULL) {
int nscans; int nscans;
/* Estimate number of scans to set pass_limit. */ /* Estimate number of scans to set pass_limit. */
if (cinfo->process == JPROC_PROGRESSIVE) { if (cinfo->progressive_mode) {
/* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */ /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */
nscans = 2 + 3 * cinfo->num_components; nscans = 2 + 3 * cinfo->num_components;
} else if (cinfo->inputctl->has_multiple_scans) { } else if (cinfo->inputctl->has_multiple_scans) {

View File

@@ -2,9 +2,10 @@
* jerror.h * jerror.h
* *
* This file was part of the Independent JPEG Group's software: * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1998, Thomas G. Lane. * Copyright (C) 1994-1997, Thomas G. Lane.
* Lossless JPEG Modifications: * Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison. * Copyright (C) 1999, Ken Murchison.
* Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file defines the error and message codes for the JPEG library. * This file defines the error and message codes for the JPEG library.
@@ -47,27 +48,22 @@ JMESSAGE(JERR_BAD_ALIGN_TYPE, "ALIGN_TYPE is wrong, please fix")
JMESSAGE(JERR_BAD_ALLOC_CHUNK, "MAX_ALLOC_CHUNK is wrong, please fix") JMESSAGE(JERR_BAD_ALLOC_CHUNK, "MAX_ALLOC_CHUNK is wrong, please fix")
JMESSAGE(JERR_BAD_BUFFER_MODE, "Bogus buffer control mode") JMESSAGE(JERR_BAD_BUFFER_MODE, "Bogus buffer control mode")
JMESSAGE(JERR_BAD_COMPONENT_ID, "Invalid component ID %d in SOS") JMESSAGE(JERR_BAD_COMPONENT_ID, "Invalid component ID %d in SOS")
JMESSAGE(JERR_BAD_DCT_COEF, "DCT coefficient out of range") JMESSAGE(JERR_BAD_DCT_COEF,
"DCT coefficient (lossy) or spatial difference (lossless) out of range")
JMESSAGE(JERR_BAD_DCTSIZE, "IDCT output block size %d not supported") JMESSAGE(JERR_BAD_DCTSIZE, "IDCT output block size %d not supported")
JMESSAGE(JERR_BAD_DIFF, "spatial difference out of range")
JMESSAGE(JERR_BAD_HUFF_TABLE, "Bogus Huffman table definition") JMESSAGE(JERR_BAD_HUFF_TABLE, "Bogus Huffman table definition")
JMESSAGE(JERR_BAD_IN_COLORSPACE, "Bogus input colorspace") JMESSAGE(JERR_BAD_IN_COLORSPACE, "Bogus input colorspace")
JMESSAGE(JERR_BAD_J_COLORSPACE, "Bogus JPEG colorspace") JMESSAGE(JERR_BAD_J_COLORSPACE, "Bogus JPEG colorspace")
JMESSAGE(JERR_BAD_LENGTH, "Bogus marker length") JMESSAGE(JERR_BAD_LENGTH, "Bogus marker length")
JMESSAGE(JERR_BAD_LIB_VERSION, JMESSAGE(JERR_BAD_LIB_VERSION,
"Wrong JPEG library version: library is %d, caller expects %d") "Wrong JPEG library version: library is %d, caller expects %d")
JMESSAGE(JERR_BAD_LOSSLESS,
"Invalid lossless parameters Ss=%d Se=%d Ah=%d Al=%d")
JMESSAGE(JERR_BAD_LOSSLESS_SCRIPT,
"Invalid lossless parameters at scan script entry %d")
JMESSAGE(JERR_BAD_MCU_SIZE, "Sampling factors too large for interleaved scan") JMESSAGE(JERR_BAD_MCU_SIZE, "Sampling factors too large for interleaved scan")
JMESSAGE(JERR_BAD_POOL_ID, "Invalid memory pool code %d") JMESSAGE(JERR_BAD_POOL_ID, "Invalid memory pool code %d")
JMESSAGE(JERR_BAD_PRECISION, "Unsupported JPEG data precision %d") JMESSAGE(JERR_BAD_PRECISION, "Unsupported JPEG data precision %d")
JMESSAGE(JERR_BAD_PROGRESSION, JMESSAGE(JERR_BAD_PROGRESSION,
"Invalid progressive parameters Ss=%d Se=%d Ah=%d Al=%d") "Invalid progressive/lossless parameters Ss=%d Se=%d Ah=%d Al=%d")
JMESSAGE(JERR_BAD_PROG_SCRIPT, JMESSAGE(JERR_BAD_PROG_SCRIPT,
"Invalid progressive parameters at scan script entry %d") "Invalid progressive/lossless parameters at scan script entry %d")
JMESSAGE(JERR_BAD_RESTART, "Invalid restart interval: %d, must be an integer multiple of the number of MCUs in an MCU_row (%d)")
JMESSAGE(JERR_BAD_SAMPLING, "Bogus sampling factors") JMESSAGE(JERR_BAD_SAMPLING, "Bogus sampling factors")
JMESSAGE(JERR_BAD_SCAN_SCRIPT, "Invalid scan script at entry %d") JMESSAGE(JERR_BAD_SCAN_SCRIPT, "Invalid scan script at entry %d")
JMESSAGE(JERR_BAD_STATE, "Improper call to JPEG library in state %d") JMESSAGE(JERR_BAD_STATE, "Improper call to JPEG library in state %d")
@@ -76,8 +72,6 @@ JMESSAGE(JERR_BAD_STRUCT_SIZE,
JMESSAGE(JERR_BAD_VIRTUAL_ACCESS, "Bogus virtual array access") JMESSAGE(JERR_BAD_VIRTUAL_ACCESS, "Bogus virtual array access")
JMESSAGE(JERR_BUFFER_SIZE, "Buffer passed to JPEG library is too small") JMESSAGE(JERR_BUFFER_SIZE, "Buffer passed to JPEG library is too small")
JMESSAGE(JERR_CANT_SUSPEND, "Suspension not allowed here") JMESSAGE(JERR_CANT_SUSPEND, "Suspension not allowed here")
JMESSAGE(JERR_CANT_TRANSCODE,
"Cannot transcode to/from lossless JPEG datastreams")
JMESSAGE(JERR_CCIR601_NOTIMPL, "CCIR601 sampling not implemented yet") JMESSAGE(JERR_CCIR601_NOTIMPL, "CCIR601 sampling not implemented yet")
JMESSAGE(JERR_COMPONENT_COUNT, "Too many color components: %d, max %d") JMESSAGE(JERR_COMPONENT_COUNT, "Too many color components: %d, max %d")
JMESSAGE(JERR_CONVERSION_NOTIMPL, "Unsupported color conversion request") JMESSAGE(JERR_CONVERSION_NOTIMPL, "Unsupported color conversion request")
@@ -106,7 +100,6 @@ JMESSAGE(JERR_NOT_COMPILED, "Requested feature was omitted at compile time")
JMESSAGE(JERR_NO_BACKING_STORE, "Backing store not supported") JMESSAGE(JERR_NO_BACKING_STORE, "Backing store not supported")
JMESSAGE(JERR_NO_HUFF_TABLE, "Huffman table 0x%02x was not defined") JMESSAGE(JERR_NO_HUFF_TABLE, "Huffman table 0x%02x was not defined")
JMESSAGE(JERR_NO_IMAGE, "JPEG datastream contains no image") JMESSAGE(JERR_NO_IMAGE, "JPEG datastream contains no image")
JMESSAGE(JERR_NO_LOSSLESS_SCRIPT, "Lossless encoding was requested but no scan script was supplied")
JMESSAGE(JERR_NO_QUANT_TABLE, "Quantization table 0x%02x was not defined") JMESSAGE(JERR_NO_QUANT_TABLE, "Quantization table 0x%02x was not defined")
JMESSAGE(JERR_NO_SOI, "Not a JPEG file: starts with 0x%02x 0x%02x") JMESSAGE(JERR_NO_SOI, "Not a JPEG file: starts with 0x%02x 0x%02x")
JMESSAGE(JERR_OUT_OF_MEMORY, "Insufficient memory (case %d)") JMESSAGE(JERR_OUT_OF_MEMORY, "Insufficient memory (case %d)")
@@ -176,10 +169,8 @@ JMESSAGE(JTRC_THUMB_PALETTE,
"JFIF extension marker: palette thumbnail image, length %u") "JFIF extension marker: palette thumbnail image, length %u")
JMESSAGE(JTRC_THUMB_RGB, JMESSAGE(JTRC_THUMB_RGB,
"JFIF extension marker: RGB thumbnail image, length %u") "JFIF extension marker: RGB thumbnail image, length %u")
JMESSAGE(JTRC_UNKNOWN_LOSSLESS_IDS, JMESSAGE(JTRC_UNKNOWN_IDS,
"Unrecognized component IDs %d %d %d, assuming RGB") "Unrecognized component IDs %d %d %d, assuming YCbCr (lossy) or RGB (lossless)")
JMESSAGE(JTRC_UNKNOWN_LOSSY_IDS,
"Unrecognized component IDs %d %d %d, assuming YCbCr")
JMESSAGE(JTRC_XMS_CLOSE, "Freed XMS handle %u") JMESSAGE(JTRC_XMS_CLOSE, "Freed XMS handle %u")
JMESSAGE(JTRC_XMS_OPEN, "Obtained XMS handle %u") JMESSAGE(JTRC_XMS_OPEN, "Obtained XMS handle %u")
JMESSAGE(JWRN_ADOBE_XFORM, "Unknown Adobe color transform code %d") JMESSAGE(JWRN_ADOBE_XFORM, "Unknown Adobe color transform code %d")
@@ -191,12 +182,13 @@ JMESSAGE(JWRN_HIT_MARKER, "Corrupt JPEG data: premature end of data segment")
JMESSAGE(JWRN_HUFF_BAD_CODE, "Corrupt JPEG data: bad Huffman code") JMESSAGE(JWRN_HUFF_BAD_CODE, "Corrupt JPEG data: bad Huffman code")
JMESSAGE(JWRN_JFIF_MAJOR, "Warning: unknown JFIF revision number %d.%02d") JMESSAGE(JWRN_JFIF_MAJOR, "Warning: unknown JFIF revision number %d.%02d")
JMESSAGE(JWRN_JPEG_EOF, "Premature end of JPEG file") JMESSAGE(JWRN_JPEG_EOF, "Premature end of JPEG file")
JMESSAGE(JWRN_MUST_DOWNSCALE,
"Must downscale data from %d bits to %d")
JMESSAGE(JWRN_MUST_RESYNC, JMESSAGE(JWRN_MUST_RESYNC,
"Corrupt JPEG data: found marker 0x%02x instead of RST%d") "Corrupt JPEG data: found marker 0x%02x instead of RST%d")
JMESSAGE(JWRN_NOT_SEQUENTIAL, "Invalid SOS parameters for sequential JPEG") JMESSAGE(JWRN_NOT_SEQUENTIAL, "Invalid SOS parameters for sequential JPEG")
JMESSAGE(JWRN_TOO_MUCH_DATA, "Application transferred too many scanlines") JMESSAGE(JWRN_TOO_MUCH_DATA, "Application transferred too many scanlines")
JMESSAGE(JERR_BAD_RESTART, "Invalid restart interval %d; must be an integer multiple of the number of MCUs in an MCU row (%d)")
JMESSAGE(JWRN_MUST_DOWNSCALE,
"Must downscale data from %d bits to %d")
#ifdef JMAKE_ENUM_LIST #ifdef JMAKE_ENUM_LIST

108
jlossls.h
View File

@@ -5,6 +5,7 @@
* Copyright (C) 1998, Thomas G. Lane. * Copyright (C) 1998, Thomas G. Lane.
* Lossless JPEG Modifications: * Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison. * Copyright (C) 1999, Ken Murchison.
* Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This include file contains common declarations for the lossless JPEG * This include file contains common declarations for the lossless JPEG
@@ -14,6 +15,17 @@
#ifndef JLOSSLS_H #ifndef JLOSSLS_H
#define JLOSSLS_H #define JLOSSLS_H
#if defined(C_LOSSLESS_SUPPORTED) || defined(D_LOSSLESS_SUPPORTED)
#define JPEG_INTERNALS
#include "jpeglib.h"
#define ALLOC_DARRAY(pool_id, diffsperrow, numrows) \
(JDIFFARRAY)(*cinfo->mem->alloc_sarray) \
((j_common_ptr) cinfo, pool_id, \
(diffsperrow) * sizeof(JDIFF) / sizeof(JSAMPLE), numrows)
/* /*
* Table H.1: Predictors for lossless coding. * Table H.1: Predictors for lossless coding.
@@ -27,125 +39,65 @@
#define PREDICTOR6 (int) ((INT32) Rb + RIGHT_SHIFT((INT32) Ra - (INT32) Rc, 1)) #define PREDICTOR6 (int) ((INT32) Rb + RIGHT_SHIFT((INT32) Ra - (INT32) Rc, 1))
#define PREDICTOR7 (int) RIGHT_SHIFT((INT32) Ra + (INT32) Rb, 1) #define PREDICTOR7 (int) RIGHT_SHIFT((INT32) Ra + (INT32) Rb, 1)
#endif
#ifdef C_LOSSLESS_SUPPORTED
typedef JMETHOD(void, predict_difference_method_ptr, typedef JMETHOD(void, predict_difference_method_ptr,
(j_compress_ptr cinfo, int ci, (j_compress_ptr cinfo, int ci,
JSAMPROW input_buf, JSAMPROW prev_row, JSAMPROW input_buf, JSAMPROW prev_row,
JDIFFROW diff_buf, JDIMENSION width)); JDIFFROW diff_buf, JDIMENSION width));
typedef JMETHOD(void, scaler_method_ptr, /* Lossless compressor */
(j_compress_ptr cinfo, int ci,
JSAMPROW input_buf, JSAMPROW output_buf,
JDIMENSION width));
/* Lossless-specific compression codec (compressor proper) */
typedef struct { typedef struct {
struct jpeg_c_codec pub; /* public fields */ struct jpeg_forward_dct pub; /* public fields */
/* Difference buffer control */
JMETHOD(void, diff_start_pass, (j_compress_ptr cinfo,
J_BUF_MODE pass_mode));
/* Pointer to data which is private to diff controller */
void *diff_private;
/* Entropy encoding */
JMETHOD(JDIMENSION, entropy_encode_mcus, (j_compress_ptr cinfo,
JDIFFIMAGE diff_buf,
JDIMENSION MCU_row_num,
JDIMENSION MCU_col_num,
JDIMENSION nMCU));
/* Pointer to data which is private to entropy module */
void *entropy_private;
/* Prediction, differencing */
JMETHOD(void, predict_start_pass, (j_compress_ptr cinfo));
/* It is useful to allow each component to have a separate diff method. */ /* It is useful to allow each component to have a separate diff method. */
predict_difference_method_ptr predict_difference[MAX_COMPONENTS]; predict_difference_method_ptr predict_difference[MAX_COMPONENTS];
/* Pointer to data which is private to predictor module */ /* MCU rows left in the restart interval for each component */
void *pred_private; unsigned int restart_rows_to_go[MAX_COMPONENTS];
/* Sample scaling */ /* Sample scaling */
JMETHOD(void, scaler_start_pass, (j_compress_ptr cinfo));
JMETHOD(void, scaler_scale, (j_compress_ptr cinfo, JMETHOD(void, scaler_scale, (j_compress_ptr cinfo,
JSAMPROW input_buf, JSAMPROW output_buf, JSAMPROW input_buf, JSAMPROW output_buf,
JDIMENSION width)); JDIMENSION width));
} jpeg_lossless_compressor;
/* Pointer to data which is private to scaler module */ typedef jpeg_lossless_compressor * lossless_comp_ptr;
void *scaler_private;
} jpeg_lossless_c_codec; #endif /* C_LOSSLESS_SUPPORTED */
typedef jpeg_lossless_c_codec * j_lossless_c_ptr;
#ifdef D_LOSSLESS_SUPPORTED
typedef JMETHOD(void, predict_undifference_method_ptr, typedef JMETHOD(void, predict_undifference_method_ptr,
(j_decompress_ptr cinfo, int comp_index, (j_decompress_ptr cinfo, int comp_index,
JDIFFROW diff_buf, JDIFFROW prev_row, JDIFFROW diff_buf, JDIFFROW prev_row,
JDIFFROW undiff_buf, JDIMENSION width)); JDIFFROW undiff_buf, JDIMENSION width));
/* Lossless-specific decompression codec (decompressor proper) */ /* Lossless decompressor */
typedef struct { typedef struct {
struct jpeg_d_codec pub; /* public fields */ struct jpeg_inverse_dct pub; /* public fields */
/* Difference buffer control */
JMETHOD(void, diff_start_input_pass, (j_decompress_ptr cinfo));
/* Pointer to data which is private to diff controller */
void *diff_private;
/* Entropy decoding */
JMETHOD(void, entropy_start_pass, (j_decompress_ptr cinfo));
JMETHOD(boolean, entropy_process_restart, (j_decompress_ptr cinfo));
JMETHOD(JDIMENSION, entropy_decode_mcus, (j_decompress_ptr cinfo,
JDIFFIMAGE diff_buf,
JDIMENSION MCU_row_num,
JDIMENSION MCU_col_num,
JDIMENSION nMCU));
/* Pointer to data which is private to entropy module */
void *entropy_private;
/* Prediction, undifferencing */ /* Prediction, undifferencing */
JMETHOD(void, predict_start_pass, (j_decompress_ptr cinfo));
JMETHOD(void, predict_process_restart, (j_decompress_ptr cinfo)); JMETHOD(void, predict_process_restart, (j_decompress_ptr cinfo));
/* It is useful to allow each component to have a separate undiff method. */ /* It is useful to allow each component to have a separate undiff method. */
predict_undifference_method_ptr predict_undifference[MAX_COMPONENTS]; predict_undifference_method_ptr predict_undifference[MAX_COMPONENTS];
/* Pointer to data which is private to predictor module */
void *pred_private;
/* Sample scaling */ /* Sample scaling */
JMETHOD(void, scaler_start_pass, (j_decompress_ptr cinfo));
JMETHOD(void, scaler_scale, (j_decompress_ptr cinfo, JMETHOD(void, scaler_scale, (j_decompress_ptr cinfo,
JDIFFROW diff_buf, JSAMPROW output_buf, JDIFFROW diff_buf, JSAMPROW output_buf,
JDIMENSION width)); JDIMENSION width));
/* Pointer to data which is private to scaler module */ int scale_factor;
void *scaler_private;
} jpeg_lossless_d_codec; } jpeg_lossless_decompressor;
typedef jpeg_lossless_d_codec * j_lossless_d_ptr; typedef jpeg_lossless_decompressor * lossless_decomp_ptr;
#endif /* D_LOSSLESS_SUPPORTED */
/* Compression module initialization routines */
EXTERN(void) jinit_lhuff_encoder JPP((j_compress_ptr cinfo));
EXTERN(void) jinit_differencer JPP((j_compress_ptr cinfo));
EXTERN(void) jinit_c_scaler JPP((j_compress_ptr cinfo));
/* Decompression module initialization routines */
EXTERN(void) jinit_lhuff_decoder JPP((j_decompress_ptr cinfo));
EXTERN(void) jinit_undifferencer JPP((j_decompress_ptr cinfo));
EXTERN(void) jinit_d_scaler JPP((j_decompress_ptr cinfo));
#endif /* JLOSSLS_H */ #endif /* JLOSSLS_H */

122
jlossy.h
View File

@@ -1,122 +0,0 @@
/*
* jlossy.h
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1998, Thomas G. Lane.
* Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison.
* For conditions of distribution and use, see the accompanying README file.
*
* This include file contains common declarations for the lossy (DCT-based)
* JPEG codec modules.
*/
#ifndef JLOSSY_H
#define JLOSSY_H
/* Lossy-specific compression codec (compressor proper) */
typedef struct {
struct jpeg_c_codec pub; /* public fields */
/* Coefficient buffer control */
JMETHOD(void, coef_start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode));
/* JMETHOD(boolean, coef_compress_data, (j_compress_ptr cinfo,
JSAMPIMAGE input_buf));*/
/* Pointer to data which is private to coef module */
void *coef_private;
/* Forward DCT (also controls coefficient quantization) */
JMETHOD(void, fdct_start_pass, (j_compress_ptr cinfo));
/* perhaps this should be an array??? */
JMETHOD(void, fdct_forward_DCT, (j_compress_ptr cinfo,
jpeg_component_info * compptr,
JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
JDIMENSION start_row, JDIMENSION start_col,
JDIMENSION num_blocks));
/* Pointer to data which is private to fdct module */
void *fdct_private;
/* Entropy encoding */
JMETHOD(boolean, entropy_encode_mcu, (j_compress_ptr cinfo,
JBLOCKROW *MCU_data));
/* Pointer to data which is private to entropy module */
void *entropy_private;
} jpeg_lossy_c_codec;
typedef jpeg_lossy_c_codec * j_lossy_c_ptr;
typedef JMETHOD(void, inverse_DCT_method_ptr,
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
JCOEFPTR coef_block,
JSAMPARRAY output_buf, JDIMENSION output_col));
/* Lossy-specific decompression codec (decompressor proper) */
typedef struct {
struct jpeg_d_codec pub; /* public fields */
/* Coefficient buffer control */
JMETHOD(void, coef_start_input_pass, (j_decompress_ptr cinfo));
JMETHOD(void, coef_start_output_pass, (j_decompress_ptr cinfo));
/* Pointer to array of coefficient virtual arrays, or NULL if none */
jvirt_barray_ptr *coef_arrays;
/* Pointer to data which is private to coef module */
void *coef_private;
/* Entropy decoding */
JMETHOD(void, entropy_start_pass, (j_decompress_ptr cinfo));
JMETHOD(boolean, entropy_decode_mcu, (j_decompress_ptr cinfo,
JBLOCKROW *MCU_data));
/* This is here to share code between baseline and progressive decoders; */
/* other modules probably should not use it */
boolean entropy_insufficient_data; /* set TRUE after emitting warning */
/* Pointer to data which is private to entropy module */
void *entropy_private;
/* Inverse DCT (also performs dequantization) */
JMETHOD(void, idct_start_pass, (j_decompress_ptr cinfo));
/* It is useful to allow each component to have a separate IDCT method. */
inverse_DCT_method_ptr inverse_DCT[MAX_COMPONENTS];
/* Pointer to data which is private to idct module */
void *idct_private;
} jpeg_lossy_d_codec;
typedef jpeg_lossy_d_codec * j_lossy_d_ptr;
/* Compression module initialization routines */
EXTERN(void) jinit_lossy_c_codec JPP((j_compress_ptr cinfo));
EXTERN(void) jinit_c_coef_controller JPP((j_compress_ptr cinfo,
boolean need_full_buffer));
EXTERN(void) jinit_forward_dct JPP((j_compress_ptr cinfo));
EXTERN(void) jinit_shuff_encoder JPP((j_compress_ptr cinfo));
EXTERN(void) jinit_phuff_encoder JPP((j_compress_ptr cinfo));
/* Decompression module initialization routines */
EXTERN(void) jinit_lossy_d_codec JPP((j_decompress_ptr cinfo));
EXTERN(void) jinit_d_coef_controller JPP((j_decompress_ptr cinfo,
boolean need_full_buffer));
EXTERN(void) jinit_shuff_decoder JPP((j_decompress_ptr cinfo));
EXTERN(void) jinit_phuff_decoder JPP((j_decompress_ptr cinfo));
EXTERN(void) jinit_inverse_dct JPP((j_decompress_ptr cinfo));
#endif /* JLOSSY_H */

View File

@@ -1,10 +1,8 @@
/* /*
* jmemmgr.c * jmemmgr.c
* *
* This file was part of the Independent JPEG Group's software: * Copyright (C) 1991-1997, Thomas G. Lane.
* Copyright (C) 1991-1998, Thomas G. Lane. * This file is part of the Independent JPEG Group's software.
* Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains the JPEG system-independent memory management * This file contains the JPEG system-independent memory management
@@ -44,12 +42,11 @@ extern char * getenv JPP((const char * name));
* The allocation routines provided here must never return NULL. * The allocation routines provided here must never return NULL.
* They should exit to error_exit if unsuccessful. * They should exit to error_exit if unsuccessful.
* *
* It's not a good idea to try to merge the sarray, barray and darray * It's not a good idea to try to merge the sarray and barray routines,
* routines, even though they are textually almost the same, because * even though they are textually almost the same, because samples are
* samples are usually stored as bytes while coefficients and differenced * usually stored as bytes while coefficients are shorts or ints. Thus,
* are shorts or ints. Thus, in machines where byte pointers have a * in machines where byte pointers have a different representation from
* different representation from word pointers, the resulting machine * word pointers, the resulting machine code could not be the same.
* code could not be the same.
*/ */
@@ -485,58 +482,6 @@ alloc_barray (j_common_ptr cinfo, int pool_id,
} }
#ifdef NEED_DARRAY
/*
* Creation of 2-D difference arrays.
* This is essentially the same as the code for sample arrays, above.
*/
METHODDEF(JDIFFARRAY)
alloc_darray (j_common_ptr cinfo, int pool_id,
JDIMENSION diffsperrow, JDIMENSION numrows)
/* Allocate a 2-D difference array */
{
my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
JDIFFARRAY result;
JDIFFROW workspace;
JDIMENSION rowsperchunk, currow, i;
long ltemp;
/* Calculate max # of rows allowed in one allocation chunk */
ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) /
((long) diffsperrow * SIZEOF(JDIFF));
if (ltemp <= 0)
ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
if (ltemp < (long) numrows)
rowsperchunk = (JDIMENSION) ltemp;
else
rowsperchunk = numrows;
mem->last_rowsperchunk = rowsperchunk;
/* Get space for row pointers (small object) */
result = (JDIFFARRAY) alloc_small(cinfo, pool_id,
(size_t) (numrows * SIZEOF(JDIFFROW)));
/* Get the rows themselves (large objects) */
currow = 0;
while (currow < numrows) {
rowsperchunk = MIN(rowsperchunk, numrows - currow);
workspace = (JDIFFROW) alloc_large(cinfo, pool_id,
(size_t) ((size_t) rowsperchunk * (size_t) diffsperrow
* SIZEOF(JDIFF)));
for (i = rowsperchunk; i > 0; i--) {
result[currow++] = workspace;
workspace += diffsperrow;
}
}
return result;
}
#endif
/* /*
* About virtual array management: * About virtual array management:
* *
@@ -1123,9 +1068,6 @@ jinit_memory_mgr (j_common_ptr cinfo)
mem->pub.alloc_large = alloc_large; mem->pub.alloc_large = alloc_large;
mem->pub.alloc_sarray = alloc_sarray; mem->pub.alloc_sarray = alloc_sarray;
mem->pub.alloc_barray = alloc_barray; mem->pub.alloc_barray = alloc_barray;
#ifdef NEED_DARRAY
mem->pub.alloc_darray = alloc_darray;
#endif
mem->pub.request_virt_sarray = request_virt_sarray; mem->pub.request_virt_sarray = request_virt_sarray;
mem->pub.request_virt_barray = request_virt_barray; mem->pub.request_virt_barray = request_virt_barray;
mem->pub.realize_virt_arrays = realize_virt_arrays; mem->pub.realize_virt_arrays = realize_virt_arrays;

View File

@@ -2,7 +2,7 @@
* jmorecfg.h * jmorecfg.h
* *
* This file was part of the Independent JPEG Group's software: * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1998, Thomas G. Lane. * Copyright (C) 1991-1997, Thomas G. Lane.
* Lossless JPEG Modifications: * Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison. * Copyright (C) 1999, Ken Murchison.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
@@ -128,13 +128,6 @@ typedef short JSAMPLE;
typedef short JCOEF; typedef short JCOEF;
/* Representation of a spatial difference value.
* This should be a signed value of at least 16 bits; int is usually OK.
*/
typedef int JDIFF;
/* Compressed datastreams are represented as arrays of JOCTET. /* Compressed datastreams are represented as arrays of JOCTET.
* These must be EXACTLY 8 bits wide, at least once they are written to * These must be EXACTLY 8 bits wide, at least once they are written to
* external storage. Note that when using the stdio data source/destination * external storage. Note that when using the stdio data source/destination
@@ -309,7 +302,7 @@ typedef int boolean;
#define ENTROPY_OPT_SUPPORTED /* Optimization of entropy coding parms? */ #define ENTROPY_OPT_SUPPORTED /* Optimization of entropy coding parms? */
/* Note: if you selected 12-bit data precision, it is dangerous to turn off /* Note: if you selected 12-bit data precision, it is dangerous to turn off
* ENTROPY_OPT_SUPPORTED. The standard Huffman tables are only good for 8-bit * ENTROPY_OPT_SUPPORTED. The standard Huffman tables are only good for 8-bit
* precision, so jcshuff.c normally uses entropy optimization to compute * precision, so jchuff.c normally uses entropy optimization to compute
* usable tables for higher precision. If you don't want to do optimization, * usable tables for higher precision. If you don't want to do optimization,
* you'll have to supply different default Huffman tables. * you'll have to supply different default Huffman tables.
* The exact same statements apply for progressive and lossless JPEG: * The exact same statements apply for progressive and lossless JPEG:

148
jpegint.h
View File

@@ -2,9 +2,10 @@
* jpegint.h * jpegint.h
* *
* This file was part of the Independent JPEG Group's software: * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1998, Thomas G. Lane. * Copyright (C) 1991-1997, Thomas G. Lane.
* Lossless JPEG Modifications: * Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison. * Copyright (C) 1999, Ken Murchison.
* Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file provides common declarations for the various JPEG modules. * This file provides common declarations for the various JPEG modules.
@@ -13,6 +14,17 @@
*/ */
/* Representation of a spatial difference value.
* This should be a signed value of at least 16 bits; int is usually OK.
*/
typedef int JDIFF;
typedef JDIFF FAR *JDIFFROW; /* pointer to one row of difference values */
typedef JDIFFROW *JDIFFARRAY; /* ptr to some rows (a 2-D diff array) */
typedef JDIFFARRAY *JDIFFIMAGE; /* a 3-D diff array: top index is color */
/* Declarations for both compression & decompression */ /* Declarations for both compression & decompression */
typedef enum { /* Operating modes for buffer controllers */ typedef enum { /* Operating modes for buffer controllers */
@@ -52,6 +64,7 @@ struct jpeg_comp_master {
/* State variables made visible to other modules */ /* State variables made visible to other modules */
boolean call_pass_startup; /* True if pass_startup must be called */ boolean call_pass_startup; /* True if pass_startup must be called */
boolean is_last_pass; /* True during last pass */ boolean is_last_pass; /* True during last pass */
boolean lossless; /* True if lossless mode is enabled */
}; };
/* Main buffer control (downsampled-data buffer) */ /* Main buffer control (downsampled-data buffer) */
@@ -74,12 +87,10 @@ struct jpeg_c_prep_controller {
JDIMENSION out_row_groups_avail)); JDIMENSION out_row_groups_avail));
}; };
/* Compression codec (compressor proper) */ /* Lossy mode: Coefficient buffer control
struct jpeg_c_codec { * Lossless mode: Difference buffer control
JMETHOD(void, entropy_start_pass, (j_compress_ptr cinfo, */
boolean gather_statistics)); struct jpeg_c_coef_controller {
JMETHOD(void, entropy_finish_pass, (j_compress_ptr cinfo));
JMETHOD(boolean, need_optimization_pass, (j_compress_ptr cinfo));
JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode));
JMETHOD(boolean, compress_data, (j_compress_ptr cinfo, JMETHOD(boolean, compress_data, (j_compress_ptr cinfo,
JSAMPIMAGE input_buf)); JSAMPIMAGE input_buf));
@@ -104,6 +115,36 @@ struct jpeg_downsampler {
boolean need_context_rows; /* TRUE if need rows above & below */ boolean need_context_rows; /* TRUE if need rows above & below */
}; };
/* Lossy mode: Forward DCT (also controls coefficient quantization)
* Lossless mode: Prediction, sample differencing, and point transform
*/
struct jpeg_forward_dct {
JMETHOD(void, start_pass, (j_compress_ptr cinfo));
/* Lossy mode */
/* perhaps this should be an array??? */
JMETHOD(void, forward_DCT, (j_compress_ptr cinfo,
jpeg_component_info * compptr,
JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
JDIMENSION start_row, JDIMENSION start_col,
JDIMENSION num_blocks));
};
/* Entropy encoding */
struct jpeg_entropy_encoder {
JMETHOD(void, start_pass, (j_compress_ptr cinfo, boolean gather_statistics));
/* Lossy mode */
JMETHOD(boolean, encode_mcu, (j_compress_ptr cinfo, JBLOCKROW *MCU_data));
/* Lossless mode */
JMETHOD(JDIMENSION, encode_mcus, (j_compress_ptr cinfo,
JDIFFIMAGE diff_buf,
JDIMENSION MCU_row_num,
JDIMENSION MCU_col_num, JDIMENSION nMCU));
JMETHOD(void, finish_pass, (j_compress_ptr cinfo));
};
/* Marker writing */ /* Marker writing */
struct jpeg_marker_writer { struct jpeg_marker_writer {
JMETHOD(void, write_file_header, (j_compress_ptr cinfo)); JMETHOD(void, write_file_header, (j_compress_ptr cinfo));
@@ -128,6 +169,7 @@ struct jpeg_decomp_master {
/* State variables made visible to other modules */ /* State variables made visible to other modules */
boolean is_dummy_pass; /* True during 1st pass for 2-pass quant */ boolean is_dummy_pass; /* True during 1st pass for 2-pass quant */
boolean lossless; /* True if decompressing a lossless image */
}; };
/* Input control module */ /* Input control module */
@@ -150,14 +192,19 @@ struct jpeg_d_main_controller {
JDIMENSION out_rows_avail)); JDIMENSION out_rows_avail));
}; };
/* Decompression codec (decompressor proper) */ /* Lossy mode: Coefficient buffer control
struct jpeg_d_codec { * Lossless mode: Difference buffer control
JMETHOD(void, calc_output_dimensions, (j_decompress_ptr cinfo)); */
struct jpeg_d_coef_controller {
JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo));
JMETHOD(int, consume_data, (j_decompress_ptr cinfo)); JMETHOD(int, consume_data, (j_decompress_ptr cinfo));
JMETHOD(void, start_output_pass, (j_decompress_ptr cinfo)); JMETHOD(void, start_output_pass, (j_decompress_ptr cinfo));
JMETHOD(int, decompress_data, (j_decompress_ptr cinfo, JMETHOD(int, decompress_data, (j_decompress_ptr cinfo,
JSAMPIMAGE output_buf)); JSAMPIMAGE output_buf));
/* Lossy mode */
/* Pointer to array of coefficient virtual arrays, or NULL if none */
jvirt_barray_ptr *coef_arrays;
}; };
/* Decompression postprocessing (color quantization buffer control) */ /* Decompression postprocessing (color quantization buffer control) */
@@ -192,6 +239,42 @@ struct jpeg_marker_reader {
unsigned int discarded_bytes; /* # of bytes skipped looking for a marker */ unsigned int discarded_bytes; /* # of bytes skipped looking for a marker */
}; };
/* Entropy decoding */
struct jpeg_entropy_decoder {
JMETHOD(void, start_pass, (j_decompress_ptr cinfo));
/* Lossy mode */
JMETHOD(boolean, decode_mcu, (j_decompress_ptr cinfo,
JBLOCKROW *MCU_data));
/* Lossless mode */
JMETHOD(JDIMENSION, decode_mcus, (j_decompress_ptr cinfo,
JDIFFIMAGE diff_buf,
JDIMENSION MCU_row_num,
JDIMENSION MCU_col_num, JDIMENSION nMCU));
JMETHOD(boolean, process_restart, (j_decompress_ptr cinfo));
/* This is here to share code between baseline and progressive decoders; */
/* other modules probably should not use it */
boolean insufficient_data; /* set TRUE after emitting warning */
};
/* Lossy mode: Inverse DCT (also performs dequantization)
* Lossless mode: Prediction, sample undifferencing, point transform, and
* sample size scaling
*/
typedef JMETHOD(void, inverse_DCT_method_ptr,
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
JCOEFPTR coef_block,
JSAMPARRAY output_buf, JDIMENSION output_col));
struct jpeg_inverse_dct {
JMETHOD(void, start_pass, (j_decompress_ptr cinfo));
/* Lossy mode */
/* It is useful to allow each component to have a separate IDCT method. */
inverse_DCT_method_ptr inverse_DCT[MAX_COMPONENTS];
};
/* Upsampling (note that upsampler must also call color converter) */ /* Upsampling (note that upsampler must also call color converter) */
struct jpeg_upsampler { struct jpeg_upsampler {
JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); JMETHOD(void, start_pass, (j_decompress_ptr cinfo));
@@ -258,8 +341,6 @@ struct jpeg_color_quantizer {
/* Short forms of external names for systems with brain-damaged linkers. */ /* Short forms of external names for systems with brain-damaged linkers. */
#ifdef NEED_SHORT_EXTERNAL_NAMES #ifdef NEED_SHORT_EXTERNAL_NAMES
#define jinit_c_codec jICCodec
#define jinit_lossy_c_codec jILossyC
#define jinit_compress_master jICompress #define jinit_compress_master jICompress
#define jinit_c_master_control jICMaster #define jinit_c_master_control jICMaster
#define jinit_c_main_controller jICMainC #define jinit_c_main_controller jICMainC
@@ -268,24 +349,17 @@ struct jpeg_color_quantizer {
#define jinit_color_converter jICColor #define jinit_color_converter jICColor
#define jinit_downsampler jIDownsampler #define jinit_downsampler jIDownsampler
#define jinit_forward_dct jIFDCT #define jinit_forward_dct jIFDCT
#define jinit_shuff_encoder jISHEncoder #define jinit_huff_encoder jIHEncoder
#define jinit_phuff_encoder jIPHEncoder #define jinit_phuff_encoder jIPHEncoder
#define jinit_marker_writer jIMWriter #define jinit_marker_writer jIMWriter
#define jinit_d_codec jIDCodec
#define jinit_lossy_d_codec jILossyD
#define jinit_lossless_d_codec jILosslsD
#define jinit_master_decompress jIDMaster #define jinit_master_decompress jIDMaster
#define jinit_d_main_controller jIDMainC #define jinit_d_main_controller jIDMainC
#define jinit_d_coef_controller jIDCoefC #define jinit_d_coef_controller jIDCoefC
#define jinit_d_diff_controller jIDDiffC
#define jinit_d_post_controller jIDPostC #define jinit_d_post_controller jIDPostC
#define jinit_input_controller jIInCtlr #define jinit_input_controller jIInCtlr
#define jinit_marker_reader jIMReader #define jinit_marker_reader jIMReader
#define jinit_shuff_decoder jISHDecoder #define jinit_huff_decoder jIHDecoder
#define jinit_phuff_decoder jIPHDecoder #define jinit_phuff_decoder jIPHDecoder
#define jinit_lhuff_decoder jILHDecoder
#define jinit_undifferencer jIUndiff
#define jinit_d_scaler jIDScaler
#define jinit_inverse_dct jIIDCT #define jinit_inverse_dct jIIDCT
#define jinit_upsampler jIUpsampler #define jinit_upsampler jIUpsampler
#define jinit_color_deconverter jIDColor #define jinit_color_deconverter jIDColor
@@ -305,38 +379,50 @@ struct jpeg_color_quantizer {
/* Compression module initialization routines */ /* Compression module initialization routines */
EXTERN(void) jinit_compress_master JPP((j_compress_ptr cinfo)); EXTERN(void) jinit_compress_master JPP((j_compress_ptr cinfo));
EXTERN(void) jinit_c_codec JPP((j_compress_ptr cinfo));
EXTERN(void) jinit_c_diff_controller JPP((j_compress_ptr cinfo,
boolean need_full_buffer));
EXTERN(void) jinit_c_master_control JPP((j_compress_ptr cinfo, EXTERN(void) jinit_c_master_control JPP((j_compress_ptr cinfo,
boolean transcode_only)); boolean transcode_only));
EXTERN(void) jinit_c_main_controller JPP((j_compress_ptr cinfo, EXTERN(void) jinit_c_main_controller JPP((j_compress_ptr cinfo,
boolean need_full_buffer)); boolean need_full_buffer));
EXTERN(void) jinit_c_prep_controller JPP((j_compress_ptr cinfo, EXTERN(void) jinit_c_prep_controller JPP((j_compress_ptr cinfo,
boolean need_full_buffer)); boolean need_full_buffer));
EXTERN(void) jinit_compressor JPP((j_compress_ptr cinfo)); EXTERN(void) jinit_c_coef_controller JPP((j_compress_ptr cinfo,
boolean need_full_buffer));
EXTERN(void) jinit_color_converter JPP((j_compress_ptr cinfo)); EXTERN(void) jinit_color_converter JPP((j_compress_ptr cinfo));
EXTERN(void) jinit_downsampler JPP((j_compress_ptr cinfo)); EXTERN(void) jinit_downsampler JPP((j_compress_ptr cinfo));
EXTERN(void) jinit_lossless_c_codec JPP((j_compress_ptr cinfo)); EXTERN(void) jinit_forward_dct JPP((j_compress_ptr cinfo));
EXTERN(void) jinit_huff_encoder JPP((j_compress_ptr cinfo));
EXTERN(void) jinit_phuff_encoder JPP((j_compress_ptr cinfo));
EXTERN(void) jinit_marker_writer JPP((j_compress_ptr cinfo)); EXTERN(void) jinit_marker_writer JPP((j_compress_ptr cinfo));
#ifdef C_LOSSLESS_SUPPORTED
EXTERN(void) jinit_c_diff_controller JPP((j_compress_ptr cinfo,
boolean need_full_buffer));
EXTERN(void) jinit_lhuff_encoder JPP((j_compress_ptr cinfo));
EXTERN(void) jinit_lossless_compressor JPP((j_compress_ptr cinfo));
#endif
/* Decompression module initialization routines */ /* Decompression module initialization routines */
EXTERN(void) jinit_master_decompress JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_master_decompress JPP((j_decompress_ptr cinfo));
EXTERN(void) jinit_d_codec JPP((j_decompress_ptr cinfo));
EXTERN(void) jinit_d_diff_controller JPP((j_decompress_ptr cinfo,
boolean need_full_buffer));
EXTERN(void) jinit_d_main_controller JPP((j_decompress_ptr cinfo, EXTERN(void) jinit_d_main_controller JPP((j_decompress_ptr cinfo,
boolean need_full_buffer)); boolean need_full_buffer));
EXTERN(void) jinit_decompressor JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_d_coef_controller JPP((j_decompress_ptr cinfo,
boolean need_full_buffer));
EXTERN(void) jinit_d_post_controller JPP((j_decompress_ptr cinfo, EXTERN(void) jinit_d_post_controller JPP((j_decompress_ptr cinfo,
boolean need_full_buffer)); boolean need_full_buffer));
EXTERN(void) jinit_input_controller JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_input_controller JPP((j_decompress_ptr cinfo));
EXTERN(void) jinit_lossless_d_codec JPP((j_decompress_ptr cinfo));
EXTERN(void) jinit_marker_reader JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_marker_reader JPP((j_decompress_ptr cinfo));
EXTERN(void) jinit_huff_decoder JPP((j_decompress_ptr cinfo));
EXTERN(void) jinit_phuff_decoder JPP((j_decompress_ptr cinfo));
EXTERN(void) jinit_inverse_dct JPP((j_decompress_ptr cinfo));
EXTERN(void) jinit_upsampler JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_upsampler JPP((j_decompress_ptr cinfo));
EXTERN(void) jinit_color_deconverter JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_color_deconverter JPP((j_decompress_ptr cinfo));
EXTERN(void) jinit_1pass_quantizer JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_1pass_quantizer JPP((j_decompress_ptr cinfo));
EXTERN(void) jinit_2pass_quantizer JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_2pass_quantizer JPP((j_decompress_ptr cinfo));
EXTERN(void) jinit_merged_upsampler JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_merged_upsampler JPP((j_decompress_ptr cinfo));
#ifdef D_LOSSLESS_SUPPORTED
EXTERN(void) jinit_d_diff_controller JPP((j_decompress_ptr cinfo,
boolean need_full_buffer));
EXTERN(void) jinit_lhuff_decoder JPP((j_decompress_ptr cinfo));
EXTERN(void) jinit_lossless_decompressor JPP((j_decompress_ptr cinfo));
#endif
/* Memory manager initialization */ /* Memory manager initialization */
EXTERN(void) jinit_memory_mgr JPP((j_common_ptr cinfo)); EXTERN(void) jinit_memory_mgr JPP((j_common_ptr cinfo));

158
jpeglib.h
View File

@@ -5,6 +5,7 @@
* Copyright (C) 1991-1998, Thomas G. Lane. * Copyright (C) 1991-1998, Thomas G. Lane.
* Lossless JPEG Modifications: * Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison. * Copyright (C) 1999, Ken Murchison.
* Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file defines the application interface for the JPEG library. * This file defines the application interface for the JPEG library.
@@ -40,6 +41,13 @@
* if you want to be compatible. * if you want to be compatible.
*/ */
/* NOTE: In lossless mode, an MCU contains one or more samples rather than one
* or more 8x8 DCT blocks, so the term "data unit" is used to generically
* describe a sample in lossless mode or an 8x8 DCT block in lossy mode. To
* preserve backward API/ABI compatibility, the field and macro names retain
* the "block" terminology.
*/
#define DCTSIZE 8 /* The basic DCT block is 8x8 samples */ #define DCTSIZE 8 /* The basic DCT block is 8x8 samples */
#define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */ #define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */
#define NUM_QUANT_TBLS 4 /* Quantization tables are numbered 0..3 */ #define NUM_QUANT_TBLS 4 /* Quantization tables are numbered 0..3 */
@@ -48,16 +56,15 @@
#define MAX_COMPS_IN_SCAN 4 /* JPEG limit on # of components in one scan */ #define MAX_COMPS_IN_SCAN 4 /* JPEG limit on # of components in one scan */
#define MAX_SAMP_FACTOR 4 /* JPEG limit on sampling factors */ #define MAX_SAMP_FACTOR 4 /* JPEG limit on sampling factors */
/* Unfortunately, some bozo at Adobe saw no reason to be bound by the standard; /* Unfortunately, some bozo at Adobe saw no reason to be bound by the standard;
* the PostScript DCT filter can emit files with many more than 10 data units * the PostScript DCT filter can emit files with many more than 10 blocks/MCU.
* per MCU. * If you happen to run across such a file, you can up D_MAX_BLOCKS_IN_MCU
* If you happen to run across such a file, you can up D_MAX_DATA_UNITS_IN_MCU
* to handle it. We even let you do this from the jconfig.h file. However, * to handle it. We even let you do this from the jconfig.h file. However,
* we strongly discourage changing C_MAX_DATA_UNITS_IN_MCU; just because Adobe * we strongly discourage changing C_MAX_BLOCKS_IN_MCU; just because Adobe
* sometimes emits noncompliant files doesn't mean you should too. * sometimes emits noncompliant files doesn't mean you should too.
*/ */
#define C_MAX_DATA_UNITS_IN_MCU 10 /* compressor's limit on data units/MCU */ #define C_MAX_BLOCKS_IN_MCU 10 /* compressor's limit on data units/MCU */
#ifndef D_MAX_DATA_UNITS_IN_MCU #ifndef D_MAX_BLOCKS_IN_MCU
#define D_MAX_DATA_UNITS_IN_MCU 10 /* decompressor's limit on data units/MCU */ #define D_MAX_BLOCKS_IN_MCU 10 /* decompressor's limit on data units/MCU */
#endif #endif
@@ -77,10 +84,6 @@ typedef JBLOCKARRAY *JBLOCKIMAGE; /* a 3-D array of coefficient blocks */
typedef JCOEF FAR *JCOEFPTR; /* useful in a couple of places */ typedef JCOEF FAR *JCOEFPTR; /* useful in a couple of places */
typedef JDIFF FAR *JDIFFROW; /* pointer to one row of difference values */
typedef JDIFFROW *JDIFFARRAY; /* ptr to some rows (a 2-D diff array) */
typedef JDIFFARRAY *JDIFFIMAGE; /* a 3-D diff array: top index is color */
/* Types for JPEG compression parameters and working tables. */ /* Types for JPEG compression parameters and working tables. */
@@ -140,25 +143,28 @@ typedef struct {
/* These values are computed during compression or decompression startup: */ /* These values are computed during compression or decompression startup: */
/* Component's size in data units. /* Component's size in data units.
* Any dummy data units added to complete an MCU are not counted; therefore * In lossy mode, any dummy blocks added to complete an MCU are not counted;
* these values do not depend on whether a scan is interleaved or not. * therefore these values do not depend on whether a scan is interleaved or
* not. In lossless mode, these are always equal to the image width and
* height.
*/ */
JDIMENSION width_in_data_units; JDIMENSION width_in_blocks;
JDIMENSION height_in_data_units; JDIMENSION height_in_blocks;
/* Size of a data unit in/output by the codec (in samples). Always /* Size of a data unit in samples. Always DCTSIZE for lossy compression.
* data_unit for compression. For decompression this is the size of the * For lossy decompression this is the size of the output from one DCT block,
* output from one data_unit, reflecting any processing performed by the * reflecting any scaling we choose to apply during the IDCT step.
* codec. For example, in the DCT-based codec, scaling may be applied * Values of 1,2,4,8 are likely to be supported. Note that different
* during the IDCT step. Values of 1,2,4,8 are likely to be supported. * components may receive different IDCT scalings. In lossless mode, this is
* Note that different components may have different codec_data_unit sizes. * always equal to 1.
*/ */
int codec_data_unit; int DCT_scaled_size;
/* The downsampled dimensions are the component's actual, unpadded number /* The downsampled dimensions are the component's actual, unpadded number
* of samples at the main buffer (preprocessing/compression interface), thus * of samples at the main buffer (preprocessing/compression interface), thus
* downsampled_width = ceil(image_width * Hi/Hmax) * downsampled_width = ceil(image_width * Hi/Hmax)
* and similarly for height. For decompression, codec-based processing is * and similarly for height. For lossy decompression, IDCT scaling is
* included (ie, IDCT scaling), so * included, so
* downsampled_width = ceil(image_width * Hi/Hmax * codec_data_unit/data_unit) * downsampled_width = ceil(image_width * Hi/Hmax * DCT_scaled_size/DCTSIZE)
* In lossless mode, these are always equal to the image width and height.
*/ */
JDIMENSION downsampled_width; /* actual width in samples */ JDIMENSION downsampled_width; /* actual width in samples */
JDIMENSION downsampled_height; /* actual height in samples */ JDIMENSION downsampled_height; /* actual height in samples */
@@ -172,10 +178,10 @@ typedef struct {
/* The decompressor output side may not use these variables. */ /* The decompressor output side may not use these variables. */
int MCU_width; /* number of data units per MCU, horizontally */ int MCU_width; /* number of data units per MCU, horizontally */
int MCU_height; /* number of data units per MCU, vertically */ int MCU_height; /* number of data units per MCU, vertically */
int MCU_data_units; /* MCU_width * MCU_height */ int MCU_blocks; /* MCU_width * MCU_height */
int MCU_sample_width; /* MCU width in samples, MCU_width*codec_data_unit */ int MCU_sample_width; /* MCU width in samples, MCU_width*DCT_scaled_size */
int last_col_width; /* # of non-dummy data_units across in last MCU */ int last_col_width; /* # of non-dummy data units across in last MCU */
int last_row_height; /* # of non-dummy data_units down in last MCU */ int last_row_height; /* # of non-dummy data units down in last MCU */
/* Saved quantization table for component; NULL if none yet saved. /* Saved quantization table for component; NULL if none yet saved.
* See jdinput.c comments about the need for this information. * See jdinput.c comments about the need for this information.
@@ -194,9 +200,11 @@ typedef struct {
int comps_in_scan; /* number of components encoded in this scan */ int comps_in_scan; /* number of components encoded in this scan */
int component_index[MAX_COMPS_IN_SCAN]; /* their SOF/comp_info[] indexes */ int component_index[MAX_COMPS_IN_SCAN]; /* their SOF/comp_info[] indexes */
int Ss, Se; /* progressive JPEG spectral selection parms int Ss, Se; /* progressive JPEG spectral selection parms
lossless JPEG predictor select parm (Ss) */ (Ss is the predictor selection value in
lossless mode) */
int Ah, Al; /* progressive JPEG successive approx. parms int Ah, Al; /* progressive JPEG successive approx. parms
lossless JPEG point transform parm (Al) */ (Al is the point transform value in lossless
mode) */
} jpeg_scan_info; } jpeg_scan_info;
/* The decompressor can save APPn and COM markers in a list of these: */ /* The decompressor can save APPn and COM markers in a list of these: */
@@ -212,14 +220,6 @@ struct jpeg_marker_struct {
/* the marker length word is not counted in data_length or original_length */ /* the marker length word is not counted in data_length or original_length */
}; };
/* Known codec processes. */
typedef enum {
JPROC_SEQUENTIAL, /* baseline/extended sequential DCT */
JPROC_PROGRESSIVE, /* progressive DCT */
JPROC_LOSSLESS /* lossless (sequential) */
} J_CODEC_PROCESS;
/* Known color spaces. */ /* Known color spaces. */
typedef enum { typedef enum {
@@ -310,8 +310,6 @@ struct jpeg_compress_struct {
* helper routines to simplify changing parameters. * helper routines to simplify changing parameters.
*/ */
boolean lossless; /* TRUE=lossless encoding, FALSE=lossy */
int data_precision; /* bits of precision in image data */ int data_precision; /* bits of precision in image data */
int num_components; /* # of color components in JPEG image */ int num_components; /* # of color components in JPEG image */
@@ -381,17 +379,17 @@ struct jpeg_compress_struct {
/* /*
* These fields are computed during compression startup * These fields are computed during compression startup
*/ */
int data_unit; /* size of data unit in samples */ boolean progressive_mode; /* TRUE if scan script uses progressive mode */
J_CODEC_PROCESS process; /* encoding process of JPEG image */
int max_h_samp_factor; /* largest h_samp_factor */ int max_h_samp_factor; /* largest h_samp_factor */
int max_v_samp_factor; /* largest v_samp_factor */ int max_v_samp_factor; /* largest v_samp_factor */
JDIMENSION total_iMCU_rows; /* # of iMCU rows to be input to codec */ JDIMENSION total_iMCU_rows; /* # of iMCU rows to be input to coefficient or
/* The codec receives data in units of MCU rows as defined for fully difference controller */
* interleaved scans (whether the JPEG file is interleaved or not). /* The coefficient or difference controller receives data in units of MCU
* There are v_samp_factor * data_unit sample rows of each component in an * rows as defined for fully interleaved scans (whether the JPEG file is
* "iMCU" (interleaved MCU) row. * interleaved or not). In lossy mode, there are v_samp_factor * DCTSIZE
* sample rows of each component in an "iMCU" (interleaved MCU) row. In
* lossless mode, total_iMCU_rows is always equal to the image height.
*/ */
/* /*
@@ -405,12 +403,13 @@ struct jpeg_compress_struct {
JDIMENSION MCUs_per_row; /* # of MCUs across the image */ JDIMENSION MCUs_per_row; /* # of MCUs across the image */
JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */
int data_units_in_MCU; /* # of data units per MCU */ int blocks_in_MCU; /* # of data units per MCU */
int MCU_membership[C_MAX_DATA_UNITS_IN_MCU]; int MCU_membership[C_MAX_BLOCKS_IN_MCU];
/* MCU_membership[i] is index in cur_comp_info of component owning */ /* MCU_membership[i] is index in cur_comp_info of component owning */
/* i'th block in an MCU */ /* i'th data unit in an MCU */
int Ss, Se, Ah, Al; /* progressive/lossless JPEG parameters for scan */ int Ss, Se, Ah, Al; /* progressive/lossless JPEG parameters for
scan */
/* /*
* Links to compression subobjects (methods and private variables of modules) * Links to compression subobjects (methods and private variables of modules)
@@ -418,10 +417,12 @@ struct jpeg_compress_struct {
struct jpeg_comp_master * master; struct jpeg_comp_master * master;
struct jpeg_c_main_controller * main; struct jpeg_c_main_controller * main;
struct jpeg_c_prep_controller * prep; struct jpeg_c_prep_controller * prep;
struct jpeg_c_codec * codec; struct jpeg_c_coef_controller * coef;
struct jpeg_marker_writer * marker; struct jpeg_marker_writer * marker;
struct jpeg_color_converter * cconvert; struct jpeg_color_converter * cconvert;
struct jpeg_downsampler * downsample; struct jpeg_downsampler * downsample;
struct jpeg_forward_dct * fdct;
struct jpeg_entropy_encoder * entropy;
jpeg_scan_info * script_space; /* workspace for jpeg_simple_progression */ jpeg_scan_info * script_space; /* workspace for jpeg_simple_progression */
int script_space_size; int script_space_size;
}; };
@@ -556,6 +557,7 @@ struct jpeg_decompress_struct {
jpeg_component_info * comp_info; jpeg_component_info * comp_info;
/* comp_info[i] describes component that appears i'th in SOF */ /* comp_info[i] describes component that appears i'th in SOF */
boolean progressive_mode; /* TRUE if SOFn specifies progressive mode */
boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */
UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */
@@ -592,21 +594,19 @@ struct jpeg_decompress_struct {
/* /*
* These fields are computed during decompression startup * These fields are computed during decompression startup
*/ */
int data_unit; /* size of data unit in samples */
J_CODEC_PROCESS process; /* decoding process of JPEG image */
int max_h_samp_factor; /* largest h_samp_factor */ int max_h_samp_factor; /* largest h_samp_factor */
int max_v_samp_factor; /* largest v_samp_factor */ int max_v_samp_factor; /* largest v_samp_factor */
int min_codec_data_unit; /* smallest codec_data_unit of any component */ int min_DCT_scaled_size; /* smallest DCT_scaled_size of any component */
JDIMENSION total_iMCU_rows; /* # of iMCU rows in image */ JDIMENSION total_iMCU_rows; /* # of iMCU rows in image */
/* The codec's input and output progress is measured in units of "iMCU" /* The coefficient or difference controller's input and output progress is
* (interleaved MCU) rows. These are the same as MCU rows in fully * measured in units of "iMCU" (interleaved MCU) rows. These are the same as
* interleaved JPEG scans, but are used whether the scan is interleaved * MCU rows in fully interleaved JPEG scans, but are used whether the scan is
* or not. We define an iMCU row as v_samp_factor data_unit rows of each * interleaved or not. In lossy mode, we define an iMCU row as v_samp_factor
* component. Therefore, the codec output contains * DCT block rows of each component. Therefore, the IDCT output contains
* v_samp_factor*codec_data_unit sample rows of a component per iMCU row. * v_samp_factor*DCT_scaled_size sample rows of a component per iMCU row. In
* lossless mode, total_iMCU_rows is always equal to the image height.
*/ */
JSAMPLE * sample_range_limit; /* table for fast range-limiting */ JSAMPLE * sample_range_limit; /* table for fast range-limiting */
@@ -623,12 +623,13 @@ struct jpeg_decompress_struct {
JDIMENSION MCUs_per_row; /* # of MCUs across the image */ JDIMENSION MCUs_per_row; /* # of MCUs across the image */
JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */
int data_units_in_MCU; /* # of data _units per MCU */ int blocks_in_MCU; /* # of data units per MCU */
int MCU_membership[D_MAX_DATA_UNITS_IN_MCU]; int MCU_membership[D_MAX_BLOCKS_IN_MCU];
/* MCU_membership[i] is index in cur_comp_info of component owning */ /* MCU_membership[i] is index in cur_comp_info of component owning */
/* i'th data unit in an MCU */ /* i'th data unit in an MCU */
int Ss, Se, Ah, Al; /* progressive/lossless JPEG parms for scan */ int Ss, Se, Ah, Al; /* progressive/lossless JPEG parameters for
scan */
/* This field is shared between entropy decoder and marker parser. /* This field is shared between entropy decoder and marker parser.
* It is either zero or the code of a JPEG marker that has been * It is either zero or the code of a JPEG marker that has been
@@ -641,10 +642,12 @@ struct jpeg_decompress_struct {
*/ */
struct jpeg_decomp_master * master; struct jpeg_decomp_master * master;
struct jpeg_d_main_controller * main; struct jpeg_d_main_controller * main;
struct jpeg_d_codec * codec; struct jpeg_d_coef_controller * coef;
struct jpeg_d_post_controller * post; struct jpeg_d_post_controller * post;
struct jpeg_input_controller * inputctl; struct jpeg_input_controller * inputctl;
struct jpeg_marker_reader * marker; struct jpeg_marker_reader * marker;
struct jpeg_entropy_decoder * entropy;
struct jpeg_inverse_dct * idct;
struct jpeg_upsampler * upsample; struct jpeg_upsampler * upsample;
struct jpeg_color_deconverter * cconvert; struct jpeg_color_deconverter * cconvert;
struct jpeg_color_quantizer * cquantize; struct jpeg_color_quantizer * cquantize;
@@ -774,14 +777,6 @@ typedef struct jvirt_sarray_control * jvirt_sarray_ptr;
typedef struct jvirt_barray_control * jvirt_barray_ptr; typedef struct jvirt_barray_control * jvirt_barray_ptr;
#ifdef C_LOSSLESS_SUPPORTED
#define NEED_DARRAY
#else
#ifdef D_LOSSLESS_SUPPORTED
#define NEED_DARRAY
#endif
#endif
struct jpeg_memory_mgr { struct jpeg_memory_mgr {
/* Method pointers */ /* Method pointers */
JMETHOD(void *, alloc_small, (j_common_ptr cinfo, int pool_id, JMETHOD(void *, alloc_small, (j_common_ptr cinfo, int pool_id,
@@ -794,11 +789,6 @@ struct jpeg_memory_mgr {
JMETHOD(JBLOCKARRAY, alloc_barray, (j_common_ptr cinfo, int pool_id, JMETHOD(JBLOCKARRAY, alloc_barray, (j_common_ptr cinfo, int pool_id,
JDIMENSION blocksperrow, JDIMENSION blocksperrow,
JDIMENSION numrows)); JDIMENSION numrows));
#ifdef NEED_DARRAY
JMETHOD(JDIFFARRAY, alloc_darray, (j_common_ptr cinfo, int pool_id,
JDIMENSION diffsperrow,
JDIMENSION numrows));
#endif
JMETHOD(jvirt_sarray_ptr, request_virt_sarray, (j_common_ptr cinfo, JMETHOD(jvirt_sarray_ptr, request_virt_sarray, (j_common_ptr cinfo,
int pool_id, int pool_id,
boolean pre_zero, boolean pre_zero,
@@ -877,7 +867,6 @@ typedef JMETHOD(boolean, jpeg_marker_parser_method, (j_decompress_ptr cinfo));
#define jpeg_set_linear_quality jSetLQuality #define jpeg_set_linear_quality jSetLQuality
#define jpeg_add_quant_table jAddQuantTable #define jpeg_add_quant_table jAddQuantTable
#define jpeg_quality_scaling jQualityScaling #define jpeg_quality_scaling jQualityScaling
#define jpeg_simple_lossless jSimLossless
#define jpeg_simple_progression jSimProgress #define jpeg_simple_progression jSimProgress
#define jpeg_suppress_tables jSuppressTables #define jpeg_suppress_tables jSuppressTables
#define jpeg_alloc_quant_table jAlcQTable #define jpeg_alloc_quant_table jAlcQTable
@@ -961,8 +950,9 @@ EXTERN(void) jpeg_add_quant_table JPP((j_compress_ptr cinfo, int which_tbl,
int scale_factor, int scale_factor,
boolean force_baseline)); boolean force_baseline));
EXTERN(int) jpeg_quality_scaling JPP((int quality)); EXTERN(int) jpeg_quality_scaling JPP((int quality));
EXTERN(void) jpeg_simple_lossless JPP((j_compress_ptr cinfo, EXTERN(void) jpeg_enable_lossless JPP((j_compress_ptr cinfo,
int predictor, int point_transform)); int predictor_selection_value,
int point_transform));
EXTERN(void) jpeg_simple_progression JPP((j_compress_ptr cinfo)); EXTERN(void) jpeg_simple_progression JPP((j_compress_ptr cinfo));
EXTERN(void) jpeg_suppress_tables JPP((j_compress_ptr cinfo, EXTERN(void) jpeg_suppress_tables JPP((j_compress_ptr cinfo,
boolean suppress)); boolean suppress));

View File

@@ -4,6 +4,7 @@ This file was part of the Independent JPEG Group's software:
Copyright (C) 1994-1998, Thomas G. Lane. Copyright (C) 1994-1998, Thomas G. Lane.
Lossless JPEG Modifications: Lossless JPEG Modifications:
Copyright (C) 1999, Ken Murchison. Copyright (C) 1999, Ken Murchison.
Copyright (C) 2022, D. R. Commander.
For conditions of distribution and use, see the accompanying README file. For conditions of distribution and use, see the accompanying README file.
@@ -871,11 +872,27 @@ jpeg_simple_progression (j_compress_ptr cinfo)
unless you want to make a custom scan sequence. You must ensure that unless you want to make a custom scan sequence. You must ensure that
the JPEG color space is set correctly before calling this routine. the JPEG color space is set correctly before calling this routine.
jpeg_simple_lossless (j_compress_ptr cinfo, int predictor, int point_transform) jpeg_enable_lossless (j_compress_ptr cinfo, int predictor_selection_value,
Generates a default scan script for writing a lossless-JPEG file. int point_transform)
This is the recommended method of creating a lossless file, Enables lossless mode with the specified predictor selection value
unless you want to make a custom scan sequence. You must ensure that (1 - 7) and optional point transform (0 - {precision}-1, where
the JPEG color space is set correctly before calling this routine. {precision} is the JPEG data precision). A point transform value of 0
is necessary in order to create a fully lossless JPEG image. (A
non-zero point transform value right-shifts the input samples by the
specified number of bits, which is effectively a form of lossy color
quantization.) Note that the following features will be unavailable
when compressing or decompressing lossless JPEG images:
* Quality/quantization table selection
* DCT/IDCT algorithm selection
* Smoothing
* Downsampling/upsampling
* Color conversion (the JPEG image will use the same color space as
the input image)
* IDCT scaling
* Raw (downsampled) data input/output
* Transcoding of DCT coefficients
Any parameters used to enable or configure those features will be
ignored.
Compression parameters (cinfo fields) include: Compression parameters (cinfo fields) include:
@@ -915,15 +932,15 @@ boolean optimize_coding
unsigned int restart_interval unsigned int restart_interval
int restart_in_rows int restart_in_rows
To emit restart markers in the JPEG file, set one of these nonzero. To emit restart markers in the JPEG file, set one of these nonzero.
Set restart_interval to specify the exact interval in MCU blocks. Set restart_interval to specify the exact interval in MCU blocks
Set restart_in_rows to specify the interval in MCU rows. (If (samples in lossless mode). Set restart_in_rows to specify the
restart_in_rows is not 0, then restart_interval is set after the interval in MCU rows. (If restart_in_rows is not 0, then
image width in MCUs is computed.) Defaults are zero (no restarts). restart_interval is set after the image width in MCUs is computed.)
One restart marker per MCU row is often a good choice. Defaults are zero (no restarts). One restart marker per MCU row is
NOTE: the overhead of restart markers is higher in grayscale JPEG often a good choice. NOTE: the overhead of restart markers is higher
files than in color files, and MUCH higher in progressive JPEGs. in grayscale JPEG files than in color files, and MUCH higher in
If you use restarts, you may want to use larger intervals in those progressive JPEGs. If you use restarts, you may want to use larger
cases. intervals in those cases.
const jpeg_scan_info * scan_info const jpeg_scan_info * scan_info
int num_scans int num_scans

View File

@@ -74,15 +74,14 @@ INSTALL_DATA= @INSTALL_DATA@
# source files: JPEG library proper # source files: JPEG library proper
LIBSOURCES= jcapimin.c jcapistd.c jccoefct.c jccolor.c jcdctmgr.c jcdiffct.c \ LIBSOURCES= jcapimin.c jcapistd.c jccoefct.c jccolor.c jcdctmgr.c jcdiffct.c \
jchuff.c jcinit.c jclhuff.c jclossls.c jclossy.c jcmainct.c \ jchuff.c jcinit.c jclhuff.c jclossls.c jcmainct.c jcmarker.c \
jcmarker.c jcmaster.c jcodec.c jcomapi.c jcparam.c jcphuff.c jcpred.c \ jcmaster.c jcomapi.c jcparam.c jcphuff.c jcprepct.c jcsample.c \
jcprepct.c jcsample.c jcscale.c jcshuff.c jctrans.c jdapimin.c \ jctrans.c jdapimin.c jdapistd.c jdatadst.c jdatasrc.c jdcoefct.c \
jdapistd.c jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c jddctmgr.c \ jdcolor.c jddctmgr.c jddiffct.c jdhuff.c jdinput.c jdlhuff.c \
jddiffct.c jdhuff.c jdinput.c jdlhuff.c jdlossls.c jdlossy.c \ jdlossls.c jdmainct.c jdmarker.c jdmaster.c jdmerge.c jdphuff.c \
jdmainct.c jdmarker.c jdmaster.c jdmerge.c jdphuff.c jdpostct.c \ jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c jfdctfst.c \
jdpred.c jdsample.c jdscale.c jdshuff.c jdtrans.c jerror.c jfdctflt.c \ jfdctint.c jidctflt.c jidctfst.c jidctint.c jidctred.c jquant1.c \
jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c jidctred.c \ jquant2.c jutils.c jmemmgr.c
jquant1.c jquant2.c jutils.c jmemmgr.c
# memmgr back ends: compile only one of these into a working library # memmgr back ends: compile only one of these into a working library
SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c
# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom # source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom
@@ -91,9 +90,8 @@ APPSOURCES= cjpeg.c djpeg.c jpegtran.c rdjpgcom.c wrjpgcom.c cdjpeg.c \
rdtarga.c wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c rdtarga.c wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c
SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES) SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES)
# files included by source files # files included by source files
INCLUDES= jchuff.h jdhuff.h jdct.h jerror.h jinclude.h jlossls.h jlossy.h \ INCLUDES= jchuff.h jdhuff.h jdct.h jerror.h jinclude.h jlossls.h jmemsys.h \
jmemsys.h jmorecfg.h jpegint.h jpeglib.h jversion.h cdjpeg.h \ jmorecfg.h jpegint.h jpeglib.h jversion.h cdjpeg.h cderror.h transupp.h
cderror.h transupp.h
# documentation, test, and support files # documentation, test, and support files
DOCS= README install.doc usage.doc cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \ DOCS= README install.doc usage.doc cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \
wrjpgcom.1 wizard.doc example.c libjpeg.doc structure.doc \ wrjpgcom.1 wizard.doc example.c libjpeg.doc structure.doc \
@@ -113,22 +111,20 @@ TESTFILES= testorig.jpg testimg.ppm testimg.bmp testimg.jpg testprog.jpg \
DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \ DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \
$(CONFIGUREFILES) $(OTHERFILES) $(TESTFILES) $(CONFIGUREFILES) $(OTHERFILES) $(TESTFILES)
# library object files common to compression and decompression # library object files common to compression and decompression
COMOBJECTS= jcomapi.$(O) jcodec.$(O) jutils.$(O) jerror.$(O) jmemmgr.$(O) \ COMOBJECTS= jcomapi.$(O) jutils.$(O) jerror.$(O) jmemmgr.$(O) $(SYSDEPMEM)
$(SYSDEPMEM)
# compression library object files # compression library object files
CLIBOBJECTS= jcapimin.$(O) jcapistd.$(O) jctrans.$(O) jcparam.$(O) \ CLIBOBJECTS= jcapimin.$(O) jcapistd.$(O) jctrans.$(O) jcparam.$(O) \
jdatadst.$(O) jcinit.$(O) jcmaster.$(O) jcmarker.$(O) jcmainct.$(O) \ jdatadst.$(O) jcinit.$(O) jcmaster.$(O) jcmarker.$(O) jcmainct.$(O) \
jcprepct.$(O) jclossls.$(O) jclossy.o jccoefct.$(O) jccolor.$(O) \ jcprepct.$(O) jclossls.$(O) jccoefct.$(O) jccolor.$(O) jcsample.$(O) \
jcsample.$(O) jchuff.$(O) jcphuff.$(O) jcshuff.$(O) jclhuff.$(O) \ jchuff.$(O) jcphuff.$(O) jclhuff.$(O) jcdiffct.$(O) jcdctmgr.$(O) \
jcpred.$(O) jcscale.$(O) jcdiffct.$(O) jcdctmgr.$(O) jfdctfst.$(O) \ jfdctfst.$(O) jfdctflt.$(O) jfdctint.$(O)
jfdctflt.$(O) jfdctint.$(O)
# decompression library object files # decompression library object files
DLIBOBJECTS= jdapimin.$(O) jdapistd.$(O) jdtrans.$(O) jdatasrc.$(O) \ DLIBOBJECTS= jdapimin.$(O) jdapistd.$(O) jdtrans.$(O) jdatasrc.$(O) \
jdmaster.$(O) jdinput.$(O) jdmarker.$(O) jdlossls.$(O) jdlossy.$(O) \ jdmaster.$(O) jdinput.$(O) jdmarker.$(O) jdlossls.$(O) jdhuff.$(O) \
jdhuff.$(O) jdlhuff.$(O) jdphuff.$(O) jdshuff.$(O) jdpred.$(O) \ jdlhuff.$(O) jdphuff.$(O) jddiffct.$(O) jdmainct.$(O) jdcoefct.$(O) \
jdscale.$(O) jddiffct.$(O) jdmainct.$(O) jdcoefct.$(O) jdpostct.$(O) \ jdpostct.$(O) jddctmgr.$(O) jidctfst.$(O) jidctflt.$(O) jidctint.$(O) \
jddctmgr.$(O) jidctfst.$(O) jidctflt.$(O) jidctint.$(O) jidctred.$(O) \ jidctred.$(O) jdsample.$(O) jdcolor.$(O) jquant1.$(O) jquant2.$(O) \
jdsample.$(O) jdcolor.$(O) jquant1.$(O) jquant2.$(O) jdmerge.$(O) jdmerge.$(O)
# These objectfiles are included in libjpeg.a # These objectfiles are included in libjpeg.a
LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS) LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS)
# object files for sample applications (excluding library files) # object files for sample applications (excluding library files)
@@ -260,52 +256,44 @@ jconfig.h: jconfig.doc
jcapimin.$(O): jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jcapimin.$(O): jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
jcapistd.$(O): jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jcapistd.$(O): jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
jccoefct.$(O): jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jlossy.h jccoefct.$(O): jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
jcodec.$(O): jcodec.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jlossy.h jlossls.h
jccolor.$(O): jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jccolor.$(O): jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
jcdctmgr.$(O): jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jlossy.h jdct.h jcdctmgr.$(O): jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
jcdiffct.$(O): jcdiffct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jlossls.h jcdiffct.$(O): jcdiffct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jlossls.h
jchuff.$(O): jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jlossy.h jlossls.h jchuff.h jchuff.$(O): jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h
jcinit.$(O): jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jcinit.$(O): jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
jclhuff.$(O): jclhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jlossls.h jchuff.h jclhuff.$(O): jclhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jlossls.h jchuff.h
jclossls.$(O): jclossls.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jlossls.h jclossls.$(O): jclossls.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jlossls.h
jclossy.$(O): jclossy.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jlossy.h
jcmainct.$(O): jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jcmainct.$(O): jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
jcmarker.$(O): jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jcmarker.$(O): jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
jcmaster.$(O): jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jcmaster.$(O): jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
jcomapi.$(O): jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jcomapi.$(O): jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
jcparam.$(O): jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jcparam.$(O): jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
jcphuff.$(O): jcphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jlossy.h jchuff.h jcphuff.$(O): jcphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h
jcpred.$(O): jcpred.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jlossls.h
jcprepct.$(O): jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jcprepct.$(O): jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
jcsample.$(O): jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jcsample.$(O): jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
jcscale.$(O): jcscale.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jlossls.h jctrans.$(O): jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
jcshuff.$(O): jcshuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jlossy.h jlossls.h jchuff.h
jctrans.$(O): jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jlossy.h
jdapimin.$(O): jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdapimin.$(O): jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
jdapistd.$(O): jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdapistd.$(O): jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
jdatadst.$(O): jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h jdatadst.$(O): jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
jdatasrc.$(O): jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h jdatasrc.$(O): jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
jdcoefct.$(O): jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jlossy.h jdcoefct.$(O): jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
jdcolor.$(O): jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdcolor.$(O): jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
jddctmgr.$(O): jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jlossy.h jdct.h jddctmgr.$(O): jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
jddiffct.$(O): jddiffct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jlossls.h jddiffct.$(O): jddiffct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jlossls.h
jdhuff.$(O): jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jlossy.h jlossls.h jdhuff.h jdhuff.$(O): jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h
jdinput.$(O): jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdinput.$(O): jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
jdlhuff.$(O): jdlhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jlossls.h jdhuff.h jdlhuff.$(O): jdlhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jlossls.h jdhuff.h
jdlossls.$(O): jdlossls.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jlossls.h jdlossls.$(O): jdlossls.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jlossls.h
jdlossy.$(O): jdlossy.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jlossy.h
jdmainct.$(O): jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdmainct.$(O): jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
jdmarker.$(O): jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdmarker.$(O): jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
jdmaster.$(O): jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdmaster.$(O): jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
jdmerge.$(O): jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdmerge.$(O): jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
jdphuff.$(O): jdphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jlossy.h jdhuff.h jdphuff.$(O): jdphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h
jdpostct.$(O): jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdpostct.$(O): jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
jdpred.$(O): jdpred.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jlossls.h
jdsample.$(O): jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdsample.$(O): jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
jdscale.$(O): jdscale.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jlossls.h jdtrans.$(O): jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
jdshuff.$(O): jdshuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jlossy.h jdhuff.h
jdtrans.$(O): jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jlossy.h
jerror.$(O): jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h jerror.$(O): jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h
jfdctflt.$(O): jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h jfdctflt.$(O): jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
jfdctfst.$(O): jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h jfdctfst.$(O): jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h

View File

@@ -1,10 +1,8 @@
/* /*
* rdswitch.c * rdswitch.c
* *
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1996, Thomas G. Lane. * Copyright (C) 1991-1996, Thomas G. Lane.
* Lossless JPEG Modifications: * This file is part of the Independent JPEG Group's software.
* Copyright (C) 1999, Ken Murchison.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains routines to process some of cjpeg's more complicated * This file contains routines to process some of cjpeg's more complicated
@@ -332,29 +330,3 @@ set_sample_factors (j_compress_ptr cinfo, char *arg)
} }
return TRUE; return TRUE;
} }
#ifdef C_LOSSLESS_SUPPORTED
GLOBAL(boolean)
set_simple_lossless (j_compress_ptr cinfo, char *arg)
{
int pred, pt = 0;
char ch;
ch = ','; /* if not set by sscanf, will be ',' */
if (sscanf(arg, "%d%c", &pred, &ch) < 1)
return FALSE;
if (ch != ',') /* syntax check */
return FALSE;
while (*arg && *arg++ != ',') /* advance to next segment of arg string */
;
if (*arg) {
if (sscanf(arg, "%d", &pt) != 1)
pt = 0;
}
jpeg_simple_lossless(cinfo, pred, pt);
return TRUE;
}
#endif /* C_LOSSLESS_SUPPORTED */

View File

@@ -4,6 +4,7 @@ This file was part of the Independent JPEG Group's software:
Copyright (C) 1991-1995, Thomas G. Lane. Copyright (C) 1991-1995, Thomas G. Lane.
Lossless JPEG Modifications: Lossless JPEG Modifications:
Copyright (C) 1999, Ken Murchison. Copyright (C) 1999, Ken Murchison.
Copyright (C) 2022, D. R. Commander.
For conditions of distribution and use, see the accompanying README file. For conditions of distribution and use, see the accompanying README file.
@@ -23,7 +24,7 @@ In this document, JPEG-specific terminology follows the JPEG standard:
A "sample" is a single component value (i.e., one number in the image data). A "sample" is a single component value (i.e., one number in the image data).
A "coefficient" is a frequency coefficient (a DCT transform output number). A "coefficient" is a frequency coefficient (a DCT transform output number).
A "block" is an 8x8 group of samples or coefficients. A "block" is an 8x8 group of samples or coefficients.
A "data unit" is an abstract data type which is either a block for lossy A "data unit" is an abstract data type that is either a block for lossy
(DCT-based) codecs or a sample for lossless (predictive) codecs. (DCT-based) codecs or a sample for lossless (predictive) codecs.
An "MCU" (minimum coded unit) is an interleaved set of data units of size An "MCU" (minimum coded unit) is an interleaved set of data units of size
determined by the sampling factors, or a single data unit in a determined by the sampling factors, or a single data unit in a
@@ -47,8 +48,8 @@ command-line user interface and I/O routines for several uncompressed image
formats. This document concentrates on the library itself. formats. This document concentrates on the library itself.
We desire the library to be capable of supporting all JPEG baseline, extended We desire the library to be capable of supporting all JPEG baseline, extended
sequential, and progressive DCT processes, as well as the lossless (spatial) sequential, progressive DCT, and lossless (spatial) processes. Hierarchical
process. Hierarchical processes are not supported. processes are not supported.
Within these limits, any set of compression parameters allowed by the JPEG Within these limits, any set of compression parameters allowed by the JPEG
spec should be readable for decompression. (We can be more restrictive about spec should be readable for decompression. (We can be more restrictive about
@@ -319,52 +320,31 @@ overall system structuring principle, not as a complete description of the
task performed by any one controller. task performed by any one controller.
*** Codec object structure ***
As noted above, this library supports both the lossy (DCT-based) and lossless
JPEG processes. Because these processes have little in common with one another
(and their implementations share very little code), we need to provide a way to
isloate the underlying JPEG process from the rest of the library. This is
accomplished by introducing an abstract "codec object" which acts a generic
interface to the JPEG (de)compressor proper.
Using the power of the object-oriented scheme described above, we build the
lossy and lossless modules as two separate implementations of the codec object.
Switching between lossy and lossless processes then becomes as trivial as
assigning the appropriate method pointers during initialization of the library.
*** Compression object structure *** *** Compression object structure ***
Here is a sketch of the logical structure of the JPEG compression library: Here is a sketch of the logical structure of the JPEG compression library in
lossy mode:
|-- Colorspace conversion |-- Colorspace conversion
|-- Preprocessing controller --| |-- Preprocessing controller --|
| |-- Downsampling | |-- Downsampling
|
Main controller --| Main controller --|
| /--> Lossy codec | |-- Forward DCT, quantize
| / |-- Coefficient controller --|
|-- Compression codec < *OR*
\
\--> Lossless codec
where the lossy codec looks like:
|-- Forward DCT, quantize
<-- Coefficient controller --|
|-- Entropy encoding |-- Entropy encoding
... and in lossless mode:
and the lossless codec looks like: |-- Colorspace conversion
|-- Preprocessing controller --|
|-- Point transformation | |-- Downsampling
Main controller --|
| |-- Point transform
| |
|-- Difference controller --|-- Prediction, differencing
| |
<-- Difference controller --|-- Prediction, differencing |-- Lossless mode entropy
| encoding
|-- Lossless entropy encoding
This sketch also describes the flow of control (subroutine calls) during This sketch also describes the flow of control (subroutine calls) during
typical image data processing. Each of the components shown in the diagram is typical image data processing. Each of the components shown in the diagram is
@@ -425,16 +405,15 @@ The objects shown above are:
of subsampled data is processed per call, even when the JPEG file is of subsampled data is processed per call, even when the JPEG file is
noninterleaved. noninterleaved.
* Point transformation: Scale the data down by the point transformation * Point transform: Downscale the data by the point transform value.
parameter.
* Prediction and differencing: Calculate the predictor and subtract it * Prediction and differencing: Calculate the predictor and subtract it
from the input. Works on one scanline per call. The difference from the input. Works on one scanline per call. The difference
controller supplies the prior scanline which is used for prediction. controller supplies the prior scanline, which is used for prediction.
* Lossless entropy encoding: Perform Huffman or arithmetic entropy coding and * Lossless mode entropy encoding: Perform Huffman or arithmetic entropy coding
emit the coded data to the data destination module. This module handles MCU and emit the coded data to the data destination module. This module handles
assembly. Works on one MCU-row per call. MCU assembly. Works on one MCU row per call.
In addition to the above objects, the compression library includes these In addition to the above objects, the compression library includes these
objects: objects:
@@ -475,36 +454,32 @@ decompression; the progress monitor, if used, may be shared as well.
*** Decompression object structure *** *** Decompression object structure ***
Here is a sketch of the logical structure of the JPEG decompression library: Here is a sketch of the logical structure of the JPEG decompression library in
lossy mode:
/--> Lossy codec |-- Entropy decoding
/ |-- Coefficient controller --|
|-- Decompression codec < *OR* | |-- Dequantize, Inverse DCT
| \
| \--> Lossless codec
Main controller --| Main controller --|
|
| |-- Upsampling | |-- Upsampling
|-- Postprocessing controller --| |-- Colorspace conversion |-- Postprocessing controller --| |-- Colorspace conversion
|-- Color quantization |-- Color quantization
|-- Color precision reduction |-- Color precision reduction
... and in lossless mode:
where the lossy codec looks like: |-- Lossless mode entropy
| decoding
|-- Entropy decoding
<-- Coefficient controller --|
|-- Dequantize, Inverse DCT
and the lossless codec looks like:
|-- Lossless entropy decoding
| |
<-- Difference controller --|-- Prediction, undifferencing |-- Difference controller --|-- Prediction, undifferencing
| | |
|-- Point transformation, sample size scaling | |-- Point transform, sample size
| scaling
Main controller --|
| |-- Upsampling
|-- Postprocessing controller --| |-- Colorspace conversion
|-- Color quantization
|-- Color precision reduction
As before, this diagram also represents typical control flow. The objects As before, this diagram also represents typical control flow. The objects
shown are: shown are:
@@ -544,17 +519,16 @@ shown are:
buffering the full image. The equivalent of one fully interleaved MCU row buffering the full image. The equivalent of one fully interleaved MCU row
is processed per call, even when the source JPEG file is noninterleaved. is processed per call, even when the source JPEG file is noninterleaved.
* Lossless entropy decoding: Read coded data from the data source module and * Lossless mode entropy decoding: Read coded data from the data source module
perform Huffman or arithmetic entropy decoding. Works on one MCU-row per and perform Huffman or arithmetic entropy decoding. Works on one MCU row per
call. call.
* Prediction and undifferencing: Calculate the predictor and add it to the * Prediction and undifferencing: Calculate the predictor and add it to the
decoded difference. Works on one scanline per call. The difference decoded difference. Works on one scanline per call. The difference
controller supplies the prior scanline which is used for prediction. controller supplies the prior scanline, which is used for prediction.
* Point transform and sample size scaling: Scale the data up by the point * Point transform and sample size scaling: Upscale the data by the point
transformation parameter and scale it down to fit into the compiled-in transform value and downscale it to fit into the compiled-in sample size.
sample size.
* Postprocessing controller: buffer controller for the color quantization * Postprocessing controller: buffer controller for the color quantization
input buffer, when quantization is in use. (Without quantization, this input buffer, when quantization is in use. (Without quantization, this

View File

@@ -1,10 +1,8 @@
/* /*
* transupp.c * transupp.c
* *
* This file was part of the Independent JPEG Group's software: * Copyright (C) 1997, Thomas G. Lane.
* Copyright (C) 1997-1998, Thomas G. Lane. * This file is part of the Independent JPEG Group's software.
* Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains image transformation routines and other utility code * This file contains image transformation routines and other utility code
@@ -86,7 +84,7 @@ do_flip_h (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
for (ci = 0; ci < dstinfo->num_components; ci++) { for (ci = 0; ci < dstinfo->num_components; ci++) {
compptr = dstinfo->comp_info + ci; compptr = dstinfo->comp_info + ci;
comp_width = MCU_cols * compptr->h_samp_factor; comp_width = MCU_cols * compptr->h_samp_factor;
for (blk_y = 0; blk_y < compptr->height_in_data_units; for (blk_y = 0; blk_y < compptr->height_in_blocks;
blk_y += compptr->v_samp_factor) { blk_y += compptr->v_samp_factor) {
buffer = (*srcinfo->mem->access_virt_barray) buffer = (*srcinfo->mem->access_virt_barray)
((j_common_ptr) srcinfo, src_coef_arrays[ci], blk_y, ((j_common_ptr) srcinfo, src_coef_arrays[ci], blk_y,
@@ -138,7 +136,7 @@ do_flip_v (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
for (ci = 0; ci < dstinfo->num_components; ci++) { for (ci = 0; ci < dstinfo->num_components; ci++) {
compptr = dstinfo->comp_info + ci; compptr = dstinfo->comp_info + ci;
comp_height = MCU_rows * compptr->v_samp_factor; comp_height = MCU_rows * compptr->v_samp_factor;
for (dst_blk_y = 0; dst_blk_y < compptr->height_in_data_units; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
dst_blk_y += compptr->v_samp_factor) { dst_blk_y += compptr->v_samp_factor) {
dst_buffer = (*srcinfo->mem->access_virt_barray) dst_buffer = (*srcinfo->mem->access_virt_barray)
((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
@@ -160,7 +158,7 @@ do_flip_v (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
/* Row is within the mirrorable area. */ /* Row is within the mirrorable area. */
dst_row_ptr = dst_buffer[offset_y]; dst_row_ptr = dst_buffer[offset_y];
src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1];
for (dst_blk_x = 0; dst_blk_x < compptr->width_in_data_units; for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
dst_blk_x++) { dst_blk_x++) {
dst_ptr = dst_row_ptr[dst_blk_x]; dst_ptr = dst_row_ptr[dst_blk_x];
src_ptr = src_row_ptr[dst_blk_x]; src_ptr = src_row_ptr[dst_blk_x];
@@ -176,7 +174,7 @@ do_flip_v (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
} else { } else {
/* Just copy row verbatim. */ /* Just copy row verbatim. */
jcopy_block_row(src_buffer[offset_y], dst_buffer[offset_y], jcopy_block_row(src_buffer[offset_y], dst_buffer[offset_y],
compptr->width_in_data_units); compptr->width_in_blocks);
} }
} }
} }
@@ -203,13 +201,13 @@ do_transpose (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
*/ */
for (ci = 0; ci < dstinfo->num_components; ci++) { for (ci = 0; ci < dstinfo->num_components; ci++) {
compptr = dstinfo->comp_info + ci; compptr = dstinfo->comp_info + ci;
for (dst_blk_y = 0; dst_blk_y < compptr->height_in_data_units; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
dst_blk_y += compptr->v_samp_factor) { dst_blk_y += compptr->v_samp_factor) {
dst_buffer = (*srcinfo->mem->access_virt_barray) dst_buffer = (*srcinfo->mem->access_virt_barray)
((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
(JDIMENSION) compptr->v_samp_factor, TRUE); (JDIMENSION) compptr->v_samp_factor, TRUE);
for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
for (dst_blk_x = 0; dst_blk_x < compptr->width_in_data_units; for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
dst_blk_x += compptr->h_samp_factor) { dst_blk_x += compptr->h_samp_factor) {
src_buffer = (*srcinfo->mem->access_virt_barray) src_buffer = (*srcinfo->mem->access_virt_barray)
((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x,
@@ -253,13 +251,13 @@ do_rot_90 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
for (ci = 0; ci < dstinfo->num_components; ci++) { for (ci = 0; ci < dstinfo->num_components; ci++) {
compptr = dstinfo->comp_info + ci; compptr = dstinfo->comp_info + ci;
comp_width = MCU_cols * compptr->h_samp_factor; comp_width = MCU_cols * compptr->h_samp_factor;
for (dst_blk_y = 0; dst_blk_y < compptr->height_in_data_units; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
dst_blk_y += compptr->v_samp_factor) { dst_blk_y += compptr->v_samp_factor) {
dst_buffer = (*srcinfo->mem->access_virt_barray) dst_buffer = (*srcinfo->mem->access_virt_barray)
((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
(JDIMENSION) compptr->v_samp_factor, TRUE); (JDIMENSION) compptr->v_samp_factor, TRUE);
for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
for (dst_blk_x = 0; dst_blk_x < compptr->width_in_data_units; for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
dst_blk_x += compptr->h_samp_factor) { dst_blk_x += compptr->h_samp_factor) {
src_buffer = (*srcinfo->mem->access_virt_barray) src_buffer = (*srcinfo->mem->access_virt_barray)
((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x,
@@ -317,13 +315,13 @@ do_rot_270 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
for (ci = 0; ci < dstinfo->num_components; ci++) { for (ci = 0; ci < dstinfo->num_components; ci++) {
compptr = dstinfo->comp_info + ci; compptr = dstinfo->comp_info + ci;
comp_height = MCU_rows * compptr->v_samp_factor; comp_height = MCU_rows * compptr->v_samp_factor;
for (dst_blk_y = 0; dst_blk_y < compptr->height_in_data_units; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
dst_blk_y += compptr->v_samp_factor) { dst_blk_y += compptr->v_samp_factor) {
dst_buffer = (*srcinfo->mem->access_virt_barray) dst_buffer = (*srcinfo->mem->access_virt_barray)
((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
(JDIMENSION) compptr->v_samp_factor, TRUE); (JDIMENSION) compptr->v_samp_factor, TRUE);
for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
for (dst_blk_x = 0; dst_blk_x < compptr->width_in_data_units; for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
dst_blk_x += compptr->h_samp_factor) { dst_blk_x += compptr->h_samp_factor) {
src_buffer = (*srcinfo->mem->access_virt_barray) src_buffer = (*srcinfo->mem->access_virt_barray)
((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x,
@@ -380,7 +378,7 @@ do_rot_180 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
compptr = dstinfo->comp_info + ci; compptr = dstinfo->comp_info + ci;
comp_width = MCU_cols * compptr->h_samp_factor; comp_width = MCU_cols * compptr->h_samp_factor;
comp_height = MCU_rows * compptr->v_samp_factor; comp_height = MCU_rows * compptr->v_samp_factor;
for (dst_blk_y = 0; dst_blk_y < compptr->height_in_data_units; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
dst_blk_y += compptr->v_samp_factor) { dst_blk_y += compptr->v_samp_factor) {
dst_buffer = (*srcinfo->mem->access_virt_barray) dst_buffer = (*srcinfo->mem->access_virt_barray)
((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
@@ -420,7 +418,7 @@ do_rot_180 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
} }
} }
/* Any remaining right-edge blocks are only mirrored vertically. */ /* Any remaining right-edge blocks are only mirrored vertically. */
for (; dst_blk_x < compptr->width_in_data_units; dst_blk_x++) { for (; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
dst_ptr = dst_row_ptr[dst_blk_x]; dst_ptr = dst_row_ptr[dst_blk_x];
src_ptr = src_row_ptr[dst_blk_x]; src_ptr = src_row_ptr[dst_blk_x];
for (i = 0; i < DCTSIZE; i += 2) { for (i = 0; i < DCTSIZE; i += 2) {
@@ -444,7 +442,7 @@ do_rot_180 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
} }
} }
/* Any remaining right-edge blocks are only copied. */ /* Any remaining right-edge blocks are only copied. */
for (; dst_blk_x < compptr->width_in_data_units; dst_blk_x++) { for (; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
dst_ptr = dst_row_ptr[dst_blk_x]; dst_ptr = dst_row_ptr[dst_blk_x];
src_ptr = src_row_ptr[dst_blk_x]; src_ptr = src_row_ptr[dst_blk_x];
for (i = 0; i < DCTSIZE2; i++) for (i = 0; i < DCTSIZE2; i++)
@@ -484,13 +482,13 @@ do_transverse (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
compptr = dstinfo->comp_info + ci; compptr = dstinfo->comp_info + ci;
comp_width = MCU_cols * compptr->h_samp_factor; comp_width = MCU_cols * compptr->h_samp_factor;
comp_height = MCU_rows * compptr->v_samp_factor; comp_height = MCU_rows * compptr->v_samp_factor;
for (dst_blk_y = 0; dst_blk_y < compptr->height_in_data_units; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
dst_blk_y += compptr->v_samp_factor) { dst_blk_y += compptr->v_samp_factor) {
dst_buffer = (*srcinfo->mem->access_virt_barray) dst_buffer = (*srcinfo->mem->access_virt_barray)
((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
(JDIMENSION) compptr->v_samp_factor, TRUE); (JDIMENSION) compptr->v_samp_factor, TRUE);
for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
for (dst_blk_x = 0; dst_blk_x < compptr->width_in_data_units; for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
dst_blk_x += compptr->h_samp_factor) { dst_blk_x += compptr->h_samp_factor) {
src_buffer = (*srcinfo->mem->access_virt_barray) src_buffer = (*srcinfo->mem->access_virt_barray)
((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x,
@@ -602,9 +600,9 @@ jtransform_request_workspace (j_decompress_ptr srcinfo,
compptr = srcinfo->comp_info + ci; compptr = srcinfo->comp_info + ci;
coef_arrays[ci] = (*srcinfo->mem->request_virt_barray) coef_arrays[ci] = (*srcinfo->mem->request_virt_barray)
((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE, ((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE,
(JDIMENSION) jround_up((long) compptr->width_in_data_units, (JDIMENSION) jround_up((long) compptr->width_in_blocks,
(long) compptr->h_samp_factor), (long) compptr->h_samp_factor),
(JDIMENSION) jround_up((long) compptr->height_in_data_units, (JDIMENSION) jround_up((long) compptr->height_in_blocks,
(long) compptr->v_samp_factor), (long) compptr->v_samp_factor),
(JDIMENSION) compptr->v_samp_factor); (JDIMENSION) compptr->v_samp_factor);
} }
@@ -624,9 +622,9 @@ jtransform_request_workspace (j_decompress_ptr srcinfo,
compptr = srcinfo->comp_info + ci; compptr = srcinfo->comp_info + ci;
coef_arrays[ci] = (*srcinfo->mem->request_virt_barray) coef_arrays[ci] = (*srcinfo->mem->request_virt_barray)
((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE, ((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE,
(JDIMENSION) jround_up((long) compptr->height_in_data_units, (JDIMENSION) jround_up((long) compptr->height_in_blocks,
(long) compptr->v_samp_factor), (long) compptr->v_samp_factor),
(JDIMENSION) jround_up((long) compptr->width_in_data_units, (JDIMENSION) jround_up((long) compptr->width_in_blocks,
(long) compptr->h_samp_factor), (long) compptr->h_samp_factor),
(JDIMENSION) compptr->h_samp_factor); (JDIMENSION) compptr->h_samp_factor);
} }

View File

@@ -140,6 +140,30 @@ progressive JPEG file at all.
Switches for advanced users: Switches for advanced users:
-lossless psv[,Pt] Create a lossless JPEG file using the specified
predictor selection value (1 - 7) and optional point
transform (0 - {precision}-1, where {precision} is the
JPEG data precision in bits). A point transform value
of 0 (the default) is necessary in order to create a
fully lossless JPEG file. (A non-zero point transform
value right-shifts the input samples by the specified
number of bits, which is effectively a form of lossy
color quantization.) CAUTION: lossless JPEG is not yet
widely implemented, so many decoders will be unable to
view a lossless JPEG file at all. Note that the
following features will be unavailable when compressing
or decompressing a lossless JPEG file:
* Quality/quantization table selection
* Color conversion (the JPEG image will use the same
color space as the input image)
* DCT/IDCT algorithm selection
* Smoothing
* Downsampling/upsampling
* IDCT scaling
* Transformations using jpegtran
Any switches used to enable or configure those features
will be ignored.
-dct int Use integer DCT method (default). -dct int Use integer DCT method (default).
-dct fast Use fast integer DCT (less accurate). -dct fast Use fast integer DCT (less accurate).
-dct float Use floating-point DCT method. -dct float Use floating-point DCT method.
@@ -152,8 +176,9 @@ Switches for advanced users:
is much less accurate than the other two. is much less accurate than the other two.
-restart N Emit a JPEG restart marker every N MCU rows, or every -restart N Emit a JPEG restart marker every N MCU rows, or every
N MCU blocks if "B" is attached to the number. N MCU blocks (samples in lossless mode) if "B" is
-restart 0 (the default) means no restart markers. attached to the number. -restart 0 (the default) means
no restart markers.
-smooth N Smooth the input image to eliminate dithering noise. -smooth N Smooth the input image to eliminate dithering noise.
N, ranging from 1 to 100, indicates the strength of N, ranging from 1 to 100, indicates the strength of

View File

@@ -115,23 +115,23 @@ Multiple Scan / Progression Control
By default, cjpeg emits a single-scan sequential JPEG file. The By default, cjpeg emits a single-scan sequential JPEG file. The
-progressive switch generates a progressive JPEG file using a default series -progressive switch generates a progressive JPEG file using a default series
of progression parameters. You can create multiple-scan sequential JPEG of progression parameters. You can create multiple-scan sequential or lossless
files or progressive JPEG files with custom progression parameters by using JPEG files or progressive JPEG files with custom progression parameters by
the -scans switch: using the -scans switch:
-scans file Use the scan sequence given in the named file. -scans file Use the scan sequence given in the named file.
The specified file should be a text file containing a "scan script". The specified file should be a text file containing a "scan script".
The script specifies the contents and ordering of the scans to be emitted. The script specifies the contents and ordering of the scans to be emitted.
Each entry in the script defines one scan. A scan definition specifies Each entry in the script defines one scan. A scan definition specifies
the components to be included in the scan, and for progressive JPEG it also the components to be included in the scan, and for progressive and lossless
specifies the progression parameters Ss,Se,Ah,Al for the scan. Scan JPEG it also specifies the progression/lossless parameters Ss,Se,Ah,Al for the
definitions are separated by semicolons (';'). A semicolon after the last scan. Scan definitions are separated by semicolons (';'). A semicolon after
scan definition is optional. the last scan definition is optional.
Each scan definition contains one to four component indexes, optionally Each scan definition contains one to four component indexes, optionally
followed by a colon (':') and the four progressive-JPEG parameters. The followed by a colon (':') and the four progressive/lossless-JPEG parameters.
component indexes denote which color component(s) are to be transmitted in The component indexes denote which color component(s) are to be transmitted in
the scan. Components are numbered in the order in which they appear in the the scan. Components are numbered in the order in which they appear in the
JPEG SOF marker, with the first component being numbered 0. (Note that these JPEG SOF marker, with the first component being numbered 0. (Note that these
indexes are not the "component ID" codes assigned to the components, just indexes are not the "component ID" codes assigned to the components, just
@@ -142,13 +142,23 @@ The progression parameters for each scan are:
Se Zigzag index of last coefficient included in scan Se Zigzag index of last coefficient included in scan
Ah Zero for first scan of a coefficient, else Al of prior scan Ah Zero for first scan of a coefficient, else Al of prior scan
Al Successive approximation low bit position for scan Al Successive approximation low bit position for scan
If the progression parameters are omitted, the values 0,63,0,0 are used,
producing a sequential JPEG file. cjpeg automatically determines whether The lossless parameters for each scan are:
Ss Predictor selection value
Se Must be zero
Ah Must be zero
Al Point transform value
If the progression/lossless parameters are omitted, the values 0,63,0,0 are
used, producing a sequential JPEG file. cjpeg automatically determines whether
the script represents a progressive or sequential file, by observing whether the script represents a progressive or sequential file, by observing whether
Ss and Se values other than 0 and 63 appear. (The -progressive switch is Ss and Se values other than 0 and 63 appear. cjpeg also automatically
not needed to specify this; in fact, it is ignored when -scans appears.) determines whether the script represents a lossless file, by observing whether
The scan script must meet the JPEG restrictions on progression sequences. Ss (the predictor selection value) is non-zero and Se is zero, which are
(cjpeg checks that the spec's requirements are obeyed.) illegal values for progressive and sequential files. (The -progressive and
-lossless switches are not needed to specify this; in fact, they are ignored
when -scans appears.) The scan script must meet the JPEG restrictions on
progression sequences. (cjpeg checks that the spec's requirements are obeyed.)
Scan script files are free format, in that arbitrary whitespace can appear Scan script files are free format, in that arbitrary whitespace can appear
between numbers and around punctuation. Also, comments can be included: a between numbers and around punctuation. Also, comments can be included: a