Skip to content

Commit

Permalink
Clean up the lossless JPEG feature
Browse files Browse the repository at this point in the history
- 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.
  • Loading branch information
dcommander committed Nov 14, 2022
1 parent ec6e451 commit 217d1a7
Show file tree
Hide file tree
Showing 67 changed files with 3,168 additions and 3,868 deletions.
8 changes: 4 additions & 4 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,10 @@ remarkably high compression levels are possible if you can tolerate a
low-quality image. For more details, see the references, or just experiment
with various compression settings.

This software implements JPEG baseline, extended-sequential, progressive
and lossless compression processes. Provision is made for supporting all
variants of these processes, although some uncommon parameter settings aren't
implemented yet. For legal reasons, we are not distributing code for the
This software implements JPEG baseline, extended-sequential, progressive, and
lossless compression processes. Provision is made for supporting all variants
of these processes, although some uncommon parameter settings aren't
implemented yet. For legal reasons, we are not distributing code for the
arithmetic-coding variants of JPEG; see LEGAL ISSUES. We have made no
provision for supporting the hierarchical processes defined in the standard.

Expand Down
5 changes: 0 additions & 5 deletions TODO
Original file line number Diff line number Diff line change
Expand Up @@ -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)? -
see jdinput.c.

* Check comment blocks for errors/changes.

* Review new filenames. Try to avoid filename conflicts with possible JPEG-LS
codec.
5 changes: 1 addition & 4 deletions cdjpeg.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
/*
* cdjpeg.h
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1997, Thomas G. Lane.
* Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains common declarations for the sample applications
Expand Down Expand Up @@ -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) 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_simple_lossless JPP((j_compress_ptr cinfo, char *arg));

/* djpeg support routines (in rdcolmap.c) */

Expand Down
50 changes: 40 additions & 10 deletions cjpeg.1
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.TH CJPEG 1 "27 April 1999"
.TH CJPEG 1 "11 November 2022"
.SH NAME
cjpeg \- compress an image file to a JPEG file
.SH SYNOPSIS
Expand Down Expand Up @@ -62,13 +62,6 @@ decompression are unaffected by
.B \-progressive
Create progressive JPEG file (see below).
.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
Input file is Targa format. Targa files that contain an "identification"
field will not be automatically recognized by
Expand Down Expand Up @@ -130,6 +123,43 @@ unable to view a progressive JPEG file at all.
.PP
Switches for advanced users:
.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
Use integer DCT method (default).
.TP
Expand All @@ -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.
.TP
.BI \-restart " N"
Emit a JPEG restart marker every N MCU rows, or every N MCU blocks if "B" is
attached to the number.
Emit a JPEG restart marker every N MCU rows, or every N MCU blocks (samples in
lossless mode) if "B" is attached to the number.
.B \-restart 0
(the default) means no restart markers.
.TP
Expand Down
31 changes: 18 additions & 13 deletions cjpeg.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* Copyright (C) 1991-1998, Thomas G. Lane.
* 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.
*
* This file contains a command-line user interface for the JPEG compressor.
Expand Down Expand Up @@ -159,13 +160,13 @@ usage (void)
#ifdef C_PROGRESSIVE_SUPPORTED
fprintf(stderr, " -progressive Create progressive JPEG file\n");
#endif
#ifdef C_LOSSLESS_SUPPORTED
fprintf(stderr, " -lossless psv[,Pt] Create lossless JPEG file\n");
#endif
#ifdef TARGA_SUPPORTED
fprintf(stderr, " -targa Input file is Targa format (usually not needed)\n");
#endif
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
fprintf(stderr, " -dct int Use integer DCT method%s\n",
(JDCT_DEFAULT == JDCT_ISLOW ? " (default)" : ""));
Expand Down Expand Up @@ -214,6 +215,9 @@ parse_switches (j_compress_ptr cinfo, int argc, char **argv,
{
int argn;
char * arg;
#ifdef C_LOSSLESS_SUPPORTED
int psv, pt = 0;
#endif
int quality; /* -quality parameter */
int q_scale_factor; /* scaling percentage for -qtables */
boolean force_baseline;
Expand All @@ -222,7 +226,6 @@ parse_switches (j_compress_ptr cinfo, int argc, char **argv,
char * qslotsarg = NULL; /* saves -qslots parm if any */
char * samplearg = NULL; /* saves -sample parm if any */
char * scansarg = NULL; /* saves -scans parm if any */
char * losslsarg = NULL; /* saves -lossless parm if any */

/* Set up default JPEG parameters. */
/* Note that default -quality level need not, and does not,
Expand Down Expand Up @@ -294,12 +297,20 @@ parse_switches (j_compress_ptr cinfo, int argc, char **argv,
jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);

} else if (keymatch(arg, "lossless", 1)) {
/* Select simple lossless mode. */
/* Enable lossless mode. */
#ifdef C_LOSSLESS_SUPPORTED
char ch = ',', *ptr;

if (++argn >= argc) /* advance to next argument */
usage();
losslsarg = argv[argn];
/* We must postpone execution until num_components is known. */
if (sscanf(argv[argn], "%d%c", &psv, &ch) < 1 || ch != ',')
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
fprintf(stderr, "%s: sorry, lossless output was not compiled\n",
progname);
Expand Down Expand Up @@ -461,12 +472,6 @@ parse_switches (j_compress_ptr cinfo, int argc, char **argv,
jpeg_simple_progression(cinfo);
#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
if (scansarg != NULL) /* process -scans if it was present */
if (! read_scan_script(cinfo, scansarg))
Expand Down
26 changes: 10 additions & 16 deletions filelist.doc
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
IJG JPEG LIBRARY: FILE LIST

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:
Copyright (C) 1999, Ken Murchison.
Copyright (C) 2022, D. R. Commander.
For conditions of distribution and use, see the accompanying README file.


Expand Down Expand Up @@ -31,7 +32,6 @@ jinclude.h Central include file used by all IJG .c files to reference
system include files.
jpegint.h JPEG library's internal 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.
jdhuff.h Private declarations for Huffman decoder modules.
jdct.h Private declarations for forward & reverse DCT subsystems.
Expand Down Expand Up @@ -68,40 +68,37 @@ Compression side of the library:
jcinit.c Initialization: determines which other modules to use.
jcmaster.c Master control: setup and inter-pass sequencing logic.
jcmainct.c Main buffer controller (preprocessor => JPEG compressor).
jchuff.c Codec-independent Huffman entropy encoding routines.
jcprepct.c Preprocessor buffer controller.
jccolor.c Color space conversion.
jcsample.c Downsampling.
jchuff.c Shared Huffman entropy encoding routines.
jcmarker.c JPEG marker writing.
jdatadst.c Data destination manager for stdio output.

Lossy (DCT) codec:

jlossy.c Lossy compressor proper.
jccoefct.c Buffer controller for DCT coefficient buffer.
jcdctmgr.c DCT manager (DCT implementation selection & control).
jfdctint.c Forward DCT using slow-but-accurate integer method.
jfdctfst.c Forward DCT using faster, less accurate integer method.
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.

Lossless (spatial) codec:

jclossls.c Lossless compressor proper.
jcdiffct.c Buffer controller for difference buffer.
jcscale.c Point transformation.
jcpred.c Sample predictor and differencer.
jclossls.c Prediction, sample differencing, and point transform
jclhuff.c Huffman entropy encoding for lossless JPEG.

Decompression side of the library:

jdmaster.c Master control: determines which other modules to use.
jdinput.c Input controller: controls input processing modules.
jdmainct.c Main buffer controller (JPEG decompressor => postprocessor).
jdhuff.c Codec-independent Huffman entropy decoding routines.
jdpostct.c Postprocessor buffer controller.
jdmarker.c JPEG marker reading.
jdhuff.c Shared Huffman entropy decoding routines.
jdsample.c Upsampling.
jdcolor.c Color space conversion.
jdmerge.c Merged upsampling/color conversion (faster, lower quality).
Expand All @@ -112,9 +109,8 @@ jdatasrc.c Data source manager for stdio input.

Lossy (DCT) codec:

jdlossy.c Lossy decompressor proper.
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.
jddctmgr.c IDCT manager (IDCT implementation selection & control).
jidctint.c Inverse DCT using slow-but-accurate integer method.
Expand All @@ -124,17 +120,15 @@ jidctred.c Inverse DCTs with reduced-size outputs.

Lossless (spatial) codec:

jdlossls.c Lossless decompressor proper.
jddiffct.c Buffer controller for difference buffers.
jddiffct.c Buffer controller for difference buffer.
jdlossls.c Prediction, sample undifferencing, point transform, and sample
scaling
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:

jerror.c Standard error handling routines (application replaceable).
jmemmgr.c System-independent (more or less) memory management code.
jcodec.c Codec-independent utility routines.
jutils.c Miscellaneous utility routines.

jmemmgr.c relies on a system-dependent memory management module. The IJG
Expand Down
13 changes: 11 additions & 2 deletions jcapimin.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1998, Thomas G. Lane.
* 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.
*
* This file contains application interface code for the compression half
Expand All @@ -21,6 +21,7 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
#include "jcmaster.h"


/*
Expand Down Expand Up @@ -79,6 +80,14 @@ jpeg_CreateCompress (j_compress_ptr cinfo, int version, size_t structsize)

/* OK, I'm ready */
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));
}


Expand Down Expand Up @@ -170,7 +179,7 @@ jpeg_finish_compress (j_compress_ptr cinfo)
/* We bypass the main controller and invoke coef controller directly;
* 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);
}
(*cinfo->master->finish_pass) (cinfo);
Expand Down
9 changes: 6 additions & 3 deletions jcapistd.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1996, Thomas G. Lane.
* 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.
*
* This file contains application interface code for the compression half
Expand Down Expand Up @@ -124,6 +124,9 @@ jpeg_write_raw_data (j_compress_ptr cinfo, JSAMPIMAGE data,
{
JDIMENSION lines_per_iMCU_row;

if (cinfo->master->lossless)
ERREXIT(cinfo, JERR_NOTIMPL);

if (cinfo->global_state != CSTATE_RAW_OK)
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
if (cinfo->next_scanline >= cinfo->image_height) {
Expand All @@ -147,12 +150,12 @@ jpeg_write_raw_data (j_compress_ptr cinfo, JSAMPIMAGE data,
(*cinfo->master->pass_startup) (cinfo);

/* 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)
ERREXIT(cinfo, JERR_BUFFER_SIZE);

/* 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. */
return 0;
}
Expand Down
Loading

0 comments on commit 217d1a7

Please sign in to comment.