Further partial image decompression fixes

- Referring to 073b0e88a1 and #185, the
  reason why BMP and RLE didn't (and won't) work with partial image
  decompression is that the output engines for both formats maintain a
  whole-image buffer, which is used to reverse the order of scanlines.
  However, it was straightforward to add -crop support for GIF and
  Targa, which is useful for testing partial image decompression along
  with color quantization.
- Such testing reproduced a bug reported by Mozilla (refer to PR #182)
  whereby jpeg_skip_scanlines() would segfault if color quantization was
  enabled.  To fix this issue, read_and_discard_scanlines() now sets up
  a dummy quantize function in the same manner that it sets up a dummy
  color conversion function.

Closes #182
This commit is contained in:
DRC
2017-11-13 21:01:53 -06:00
parent f3ad13e3d8
commit 5bc43c7821
11 changed files with 110 additions and 52 deletions

View File

@@ -10,9 +10,16 @@ image planes and allocates memory for the image planes.
2. Fixed an issue whereby the Java version of TJUnitTest would fail when
testing BufferedImage encoding/decoding on big endian systems.
3. djpeg will now exit gracefully if an output image format other than PPM/PGM
is selected along with the `-crop` option. That option does not currently work
with other output image formats.
3. Fixed a segfault in djpeg that would occur if an output format other than
PPM/PGM was selected along with the `-crop` option. The `-crop` option now
works with the GIF and Targa formats as well (unfortunately, it cannot be made
to work with the BMP and RLE formats due to the fact that those output engines
write scanlines in bottom-up order.) djpeg will now exit gracefully if an
output format other than PPM/PGM, GIF, or Targa is selected along with the
`-crop` option.
4. Fixed an issue whereby `jpeg_skip_scanlines()` would segfault if color
quantization was enabled.
4. TJBench (both C and Java versions) will now display usage information if any
command-line argument is unrecognized. This prevents the program from silently

View File

@@ -3,8 +3,8 @@
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1997, Thomas G. Lane.
* It was modified by The libjpeg-turbo Project to include only code relevant
* to libjpeg-turbo.
* libjpeg-turbo Modifications:
* Copyright (C) 2017, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -54,6 +54,14 @@ struct djpeg_dest_struct {
JDIMENSION rows_supplied);
/* Finish up at the end of the image. */
void (*finish_output) (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo);
/* Re-calculate buffer dimensions based on output dimensions (for use with
partial image decompression.) If this is NULL, then the output format
does not support partial image decompression (BMP and RLE, in particular,
cannot support partial decompression because they use an inversion buffer
to write the image in bottom-up order.) */
void (*calc_buffer_dimensions) (j_decompress_ptr cinfo,
djpeg_dest_ptr dinfo);
/* Target file spec; filled in by djpeg.c after object is created. */
FILE *output_file;

View File

@@ -1,4 +1,4 @@
.TH DJPEG 1 "8 November 2017"
.TH DJPEG 1 "13 November 2017"
.SH NAME
djpeg \- decompress a JPEG file to an image file
.SH SYNOPSIS
@@ -205,7 +205,7 @@ with width W and height H. If necessary, X will be shifted left to the nearest
iMCU boundary, and the width will be increased accordingly. Note that if
decompression scaling is being used, then X, Y, W, and H are relative to the
scaled image dimensions. Currently this option only works with the
PBMPLUS (PPM/PGM) output format.
PBMPLUS (PPM/PGM), GIF, and Targa output formats.
.TP
.B \-verbose
Enable debug printout. More

10
djpeg.c
View File

@@ -31,7 +31,6 @@
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
#include "jversion.h" /* for version message */
#include "jconfigint.h"
#include "wrppm.h"
#include <ctype.h> /* to declare isprint() */
@@ -173,7 +172,7 @@ usage (void)
fprintf(stderr, " -skip Y0,Y1 Decompress all rows except those between Y0 and Y1 (inclusive)\n");
fprintf(stderr, " -crop WxH+X+Y Decompress only a rectangular subregion of the image\n");
fprintf(stderr, " [requires PBMPLUS (PPM/PGM) output format]\n");
fprintf(stderr, " [requires PBMPLUS (PPM/PGM), GIF, or Targa output format]\n");
fprintf(stderr, " -verbose or -debug Emit debug output\n");
fprintf(stderr, " -version Print version information and exit\n");
exit(EXIT_FAILURE);
@@ -714,11 +713,10 @@ main (int argc, char **argv)
}
jpeg_crop_scanline(&cinfo, &crop_x, &crop_width);
if (requested_fmt != FMT_PPM)
if (dest_mgr->calc_buffer_dimensions)
(*dest_mgr->calc_buffer_dimensions) (&cinfo, dest_mgr);
else
ERREXIT(&cinfo, JERR_UNSUPPORTED_FORMAT);
((ppm_dest_ptr) dest_mgr)->buffer_width = cinfo.output_width *
cinfo.out_color_components *
sizeof(JSAMPLE);
/* Write output file header. This is a hack to ensure that the destination
* manager creates an output image of the proper size.

View File

@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
* Copyright (C) 2010, 2015-2016, D. R. Commander.
* Copyright (C) 2010, 2015-2017, D. R. Commander.
* Copyright (C) 2015, Google, Inc.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
@@ -293,6 +293,14 @@ noop_convert (j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
}
/* Dummy quantize function used by jpeg_skip_scanlines() */
LOCAL(void)
noop_quantize (j_decompress_ptr cinfo, JSAMPARRAY input_buf,
JSAMPARRAY output_buf, int num_rows)
{
}
/*
* In some cases, it is best to call jpeg_read_scanlines() and discard the
* output, rather than skipping the scanlines, because this allows us to
@@ -308,14 +316,22 @@ read_and_discard_scanlines (j_decompress_ptr cinfo, JDIMENSION num_lines)
void (*color_convert) (j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
JDIMENSION input_row, JSAMPARRAY output_buf,
int num_rows);
void (*color_quantize) (j_decompress_ptr cinfo, JSAMPARRAY input_buf,
JSAMPARRAY output_buf, int num_rows) = NULL;
color_convert = cinfo->cconvert->color_convert;
cinfo->cconvert->color_convert = noop_convert;
if (cinfo->cquantize && cinfo->cquantize->color_quantize) {
color_quantize = cinfo->cquantize->color_quantize;
cinfo->cquantize->color_quantize = noop_quantize;
}
for (n = 0; n < num_lines; n++)
jpeg_read_scanlines(cinfo, NULL, 1);
cinfo->cconvert->color_convert = color_convert;
if (color_quantize)
cinfo->cquantize->color_quantize = color_quantize;
}

View File

@@ -5,7 +5,7 @@
* Copyright (C) 1994-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
* Copyright (C) 2013, Linaro Limited.
* Copyright (C) 2014-2015, D. R. Commander.
* Copyright (C) 2014-2015, 2017, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -437,6 +437,7 @@ jinit_write_bmp (j_decompress_ptr cinfo, boolean is_os2)
sizeof(bmp_dest_struct));
dest->pub.start_output = start_output_bmp;
dest->pub.finish_output = finish_output_bmp;
dest->pub.calc_buffer_dimensions = NULL;
dest->is_os2 = is_os2;
if (cinfo->out_color_space == JCS_GRAYSCALE) {

13
wrgif.c
View File

@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1997, Thomas G. Lane.
* libjpeg-turbo Modifications:
* Copyright (C) 2015, D. R. Commander.
* Copyright (C) 2015, 2017, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -355,6 +355,16 @@ finish_output_gif (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
}
/*
* Re-calculate buffer dimensions based on output dimensions.
*/
METHODDEF(void)
calc_buffer_dimensions_gif (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
{
}
/*
* The module selection routine for GIF format output.
*/
@@ -372,6 +382,7 @@ jinit_write_gif (j_decompress_ptr cinfo)
dest->pub.start_output = start_output_gif;
dest->pub.put_pixel_rows = put_pixel_rows;
dest->pub.finish_output = finish_output_gif;
dest->pub.calc_buffer_dimensions = calc_buffer_dimensions_gif;
if (cinfo->out_color_space != JCS_GRAYSCALE &&
cinfo->out_color_space != JCS_RGB)

38
wrppm.c
View File

@@ -4,8 +4,8 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1996, Thomas G. Lane.
* Modified 2009 by Guido Vollbeding.
* It was modified by The libjpeg-turbo Project to include only code and
* information relevant to libjpeg-turbo.
* libjpeg-turbo Modifications:
* Copyright (C) 2017, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -20,7 +20,6 @@
*/
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
#include "wrppm.h"
#ifdef PPM_SUPPORTED
@@ -63,6 +62,21 @@
*/
/* Private version of data destination object */
typedef struct {
struct djpeg_dest_struct pub; /* public fields */
/* Usually these two pointers point to the same place: */
char *iobuffer; /* fwrite's I/O buffer */
JSAMPROW pixrow; /* decompressor output buffer */
size_t buffer_width; /* width of I/O buffer */
JDIMENSION samples_per_row; /* JSAMPLEs per output row */
} ppm_dest_struct;
typedef ppm_dest_struct *ppm_dest_ptr;
/*
* Write some pixel data.
* In this module rows_supplied will always be 1.
@@ -196,6 +210,20 @@ finish_output_ppm (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
}
/*
* Re-calculate buffer dimensions based on output dimensions.
*/
METHODDEF(void)
calc_buffer_dimensions_ppm (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
{
ppm_dest_ptr dest = (ppm_dest_ptr) dinfo;
dest->samples_per_row = cinfo->output_width * cinfo->out_color_components;
dest->buffer_width = dest->samples_per_row * (BYTESPERSAMPLE * sizeof(char));
}
/*
* The module selection routine for PPM format output.
*/
@@ -211,13 +239,13 @@ jinit_write_ppm (j_decompress_ptr cinfo)
sizeof(ppm_dest_struct));
dest->pub.start_output = start_output_ppm;
dest->pub.finish_output = finish_output_ppm;
dest->pub.calc_buffer_dimensions = calc_buffer_dimensions_ppm;
/* Calculate output image dimensions so we can allocate space */
jpeg_calc_output_dimensions(cinfo);
/* Create physical I/O buffer */
dest->samples_per_row = cinfo->output_width * cinfo->out_color_components;
dest->buffer_width = dest->samples_per_row * (BYTESPERSAMPLE * sizeof(char));
dest->pub.calc_buffer_dimensions (cinfo, (djpeg_dest_ptr) dest);
dest->iobuffer = (char *) (*cinfo->mem->alloc_small)
((j_common_ptr) cinfo, JPOOL_IMAGE, dest->buffer_width);

26
wrppm.h
View File

@@ -1,26 +0,0 @@
/*
* wrppm.h
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994, Thomas G. Lane.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*/
#ifdef PPM_SUPPORTED
/* Private version of data destination object */
typedef struct {
struct djpeg_dest_struct pub; /* public fields */
/* Usually these two pointers point to the same place: */
char *iobuffer; /* fwrite's I/O buffer */
JSAMPROW pixrow; /* decompressor output buffer */
size_t buffer_width; /* width of I/O buffer */
JDIMENSION samples_per_row; /* JSAMPLEs per output row */
} ppm_dest_struct;
typedef ppm_dest_struct *ppm_dest_ptr;
#endif

View File

@@ -3,8 +3,8 @@
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1996, Thomas G. Lane.
* It was modified by The libjpeg-turbo Project to include only code and
* information relevant to libjpeg-turbo.
* libjpeg-turbo Modifications:
* Copyright (C) 2017, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -286,6 +286,7 @@ jinit_write_rle (j_decompress_ptr cinfo)
sizeof(rle_dest_struct));
dest->pub.start_output = start_output_rle;
dest->pub.finish_output = finish_output_rle;
dest->pub.calc_buffer_dimensions = NULL;
/* Calculate output image dimensions so we can allocate space */
jpeg_calc_output_dimensions(cinfo);

View File

@@ -3,8 +3,8 @@
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1996, Thomas G. Lane.
* It was modified by The libjpeg-turbo Project to include only code and
* information relevant to libjpeg-turbo.
* libjpeg-turbo Modifications:
* Copyright (C) 2017, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -211,6 +211,19 @@ finish_output_tga (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
}
/*
* Re-calculate buffer dimensions based on output dimensions.
*/
METHODDEF(void)
calc_buffer_dimensions_tga (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
{
tga_dest_ptr dest = (tga_dest_ptr) dinfo;
dest->buffer_width = cinfo->output_width * cinfo->output_components;
}
/*
* The module selection routine for Targa format output.
*/
@@ -226,12 +239,13 @@ jinit_write_targa (j_decompress_ptr cinfo)
sizeof(tga_dest_struct));
dest->pub.start_output = start_output_tga;
dest->pub.finish_output = finish_output_tga;
dest->pub.calc_buffer_dimensions = calc_buffer_dimensions_tga;
/* Calculate output image dimensions so we can allocate space */
jpeg_calc_output_dimensions(cinfo);
/* Create I/O buffer. */
dest->buffer_width = cinfo->output_width * cinfo->output_components;
dest->pub.calc_buffer_dimensions (cinfo, (djpeg_dest_ptr) dest);
dest->iobuffer = (char *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
(size_t) (dest->buffer_width * sizeof(char)));