1
0
mirror of https://github.com/libjpeg-turbo/libjpeg-turbo.git synced 2026-10-23 11:48:53 +03:00

djpeg: Opt. read multiple scanlines at a time

... when writing PBMPLUS files.  This exercises certain partial image
decompression and RGB565 conversion code paths that djpeg otherwise
wouldn't touch, which helps expose issues such as #915 and #929.
This commit is contained in:
DRC
2026-10-22 12:01:59 -04:00
parent e0f9164547
commit eb037b4fd7
4 changed files with 150 additions and 61 deletions

View File

@@ -13,8 +13,19 @@
* cjpeg and djpeg. It is NOT used by the core JPEG library.
*/
/* Uncomment this to make djpeg process more than one scanline at a time when
* writing PBMPLUS (PPM/PGM) files, which exercises esoteric code paths in the
* library that would otherwise be difficult to test.
*
#define DJPEG_MULTILINE
*/
#define JPEG_CJPEG_DJPEG /* define proper options in jconfig.h */
#ifdef DJPEG_MULTILINE
#define JPEG_INTERNALS
#else
#define JPEG_INTERNAL_OPTIONS /* cjpeg.c,djpeg.c need to see xxx_SUPPORTED */
#endif
#include "jinclude.h"
#include "jpeglib.h"
#include "jerror.h" /* get library error codes too */

View File

@@ -808,8 +808,12 @@ main(int argc, char **argv)
if (cinfo.data_precision == 8) {
/* Process data */
while (cinfo.output_scanline < skip_start) {
JDIMENSION max_lines = dest_mgr->buffer_height;
#ifdef DJPEG_MULTILINE
max_lines = MIN(max_lines, skip_start - cinfo.output_scanline);
#endif
num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer,
dest_mgr->buffer_height);
max_lines);
(*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
}
if ((tmp = jpeg_skip_scanlines(&cinfo, skip_end - skip_start + 1)) !=
@@ -826,8 +830,12 @@ main(int argc, char **argv)
} else if (cinfo.data_precision == 12) {
/* Process data */
while (cinfo.output_scanline < skip_start) {
JDIMENSION max_lines = dest_mgr->buffer_height;
#ifdef DJPEG_MULTILINE
max_lines = MIN(max_lines, skip_start - cinfo.output_scanline);
#endif
num_scanlines = jpeg12_read_scanlines(&cinfo, dest_mgr->buffer12,
dest_mgr->buffer_height);
max_lines);
(*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
}
if ((tmp = jpeg12_skip_scanlines(&cinfo, skip_end - skip_start + 1)) !=
@@ -885,8 +893,13 @@ main(int argc, char **argv)
exit(EXIT_FAILURE);
}
while (cinfo.output_scanline < crop_y + crop_height) {
JDIMENSION max_lines = dest_mgr->buffer_height;
#ifdef DJPEG_MULTILINE
max_lines = MIN(max_lines,
crop_y + crop_height - cinfo.output_scanline);
#endif
num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer,
dest_mgr->buffer_height);
max_lines);
(*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
}
if ((tmp =
@@ -905,8 +918,13 @@ main(int argc, char **argv)
exit(EXIT_FAILURE);
}
while (cinfo.output_scanline < crop_y + crop_height) {
JDIMENSION max_lines = dest_mgr->buffer_height;
#ifdef DJPEG_MULTILINE
max_lines = MIN(max_lines,
crop_y + crop_height - cinfo.output_scanline);
#endif
num_scanlines = jpeg12_read_scanlines(&cinfo, dest_mgr->buffer12,
dest_mgr->buffer_height);
max_lines);
(*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
}
if ((tmp =

View File

@@ -19,6 +19,7 @@
* an ordinary stdio stream.
*/
#include "cmyk.h"
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
@@ -99,6 +100,8 @@ static INLINE boolean is_big_endian(void)
* output buffer is physically the same as the fwrite buffer.
*/
#ifndef DJPEG_MULTILINE
METHODDEF(void)
put_pixel_rows(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
JDIMENSION rows_supplied)
@@ -110,6 +113,8 @@ put_pixel_rows(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
#endif
#endif
/*
* This code is used when we have to copy the data and apply a pixel
@@ -123,14 +128,20 @@ copy_pixel_rows(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
ppm_dest_ptr dest = (ppm_dest_ptr)dinfo;
register char *bufferptr;
register _JSAMPROW ptr;
register JDIMENSION col;
register JDIMENSION row = 0, col;
ptr = dest->pub._buffer[0];
bufferptr = dest->iobuffer;
for (col = dest->samples_per_row; col > 0; col--) {
PUTPPMSAMPLE(bufferptr, *ptr++);
#ifdef DJPEG_MULTILINE
for (row = 0; row < MIN(dest->pub.buffer_height, rows_supplied); row++) {
#endif
ptr = dest->pub._buffer[row];
bufferptr = dest->iobuffer;
for (col = dest->samples_per_row; col > 0; col--) {
PUTPPMSAMPLE(bufferptr, *ptr++);
}
fwrite(dest->iobuffer, 1, dest->buffer_width, dest->pub.output_file);
#ifdef DJPEG_MULTILINE
}
fwrite(dest->iobuffer, 1, dest->buffer_width, dest->pub.output_file);
#endif
}
@@ -144,21 +155,27 @@ put_rgb(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, JDIMENSION rows_supplied)
ppm_dest_ptr dest = (ppm_dest_ptr)dinfo;
register char *bufferptr;
register _JSAMPROW ptr;
register JDIMENSION col;
register JDIMENSION row = 0, col;
register int rindex = rgb_red[cinfo->out_color_space];
register int gindex = rgb_green[cinfo->out_color_space];
register int bindex = rgb_blue[cinfo->out_color_space];
register int ps = rgb_pixelsize[cinfo->out_color_space];
ptr = dest->pub._buffer[0];
bufferptr = dest->iobuffer;
for (col = cinfo->output_width; col > 0; col--) {
PUTPPMSAMPLE(bufferptr, ptr[rindex]);
PUTPPMSAMPLE(bufferptr, ptr[gindex]);
PUTPPMSAMPLE(bufferptr, ptr[bindex]);
ptr += ps;
#ifdef DJPEG_MULTILINE
for (row = 0; row < MIN(dest->pub.buffer_height, rows_supplied); row++) {
#endif
ptr = dest->pub._buffer[row];
bufferptr = dest->iobuffer;
for (col = cinfo->output_width; col > 0; col--) {
PUTPPMSAMPLE(bufferptr, ptr[rindex]);
PUTPPMSAMPLE(bufferptr, ptr[gindex]);
PUTPPMSAMPLE(bufferptr, ptr[bindex]);
ptr += ps;
}
fwrite(dest->iobuffer, 1, dest->buffer_width, dest->pub.output_file);
#ifdef DJPEG_MULTILINE
}
fwrite(dest->iobuffer, 1, dest->buffer_width, dest->pub.output_file);
#endif
}
@@ -175,25 +192,31 @@ put_rgb565(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
ppm_dest_ptr dest = (ppm_dest_ptr)dinfo;
register char *bufferptr;
register unsigned short *ptr;
register JDIMENSION col;
register JDIMENSION row = 0, col;
boolean big_endian = is_big_endian();
ptr = (unsigned short *)dest->pub._buffer[0];
bufferptr = dest->iobuffer;
for (col = cinfo->output_width; col > 0; col--) {
if (big_endian) {
bufferptr[0] = *ptr & 0xF8;
bufferptr[1] = ((*ptr << 5) & 0xE0) | ((*ptr >> 11) & 0x1C);
bufferptr[2] = (*ptr >> 5) & 0xF8;
} else {
bufferptr[0] = (*ptr >> 8) & 0xF8;
bufferptr[1] = (*ptr >> 3) & 0xFC;
bufferptr[2] = (*ptr << 3) & 0xF8;
#ifdef DJPEG_MULTILINE
for (row = 0; row < MIN(dest->pub.buffer_height, rows_supplied); row++) {
#endif
ptr = (unsigned short *)dest->pub._buffer[row];
bufferptr = dest->iobuffer;
for (col = cinfo->output_width; col > 0; col--) {
if (big_endian) {
bufferptr[0] = *ptr & 0xF8;
bufferptr[1] = ((*ptr << 5) & 0xE0) | ((*ptr >> 11) & 0x1C);
bufferptr[2] = (*ptr >> 5) & 0xF8;
} else {
bufferptr[0] = (*ptr >> 8) & 0xF8;
bufferptr[1] = (*ptr >> 3) & 0xFC;
bufferptr[2] = (*ptr << 3) & 0xF8;
}
bufferptr += 3;
ptr++;
}
bufferptr += 3;
ptr++;
fwrite(dest->iobuffer, 1, dest->buffer_width, dest->pub.output_file);
#ifdef DJPEG_MULTILINE
}
fwrite(dest->iobuffer, 1, dest->buffer_width, dest->pub.output_file);
#endif
}
#endif
@@ -210,18 +233,24 @@ put_cmyk(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
ppm_dest_ptr dest = (ppm_dest_ptr)dinfo;
register char *bufferptr;
register _JSAMPROW ptr;
register JDIMENSION col;
register JDIMENSION row = 0, col;
ptr = dest->pub._buffer[0];
bufferptr = dest->iobuffer;
for (col = cinfo->output_width; col > 0; col--) {
_JSAMPLE r, g, b, c = *ptr++, m = *ptr++, y = *ptr++, k = *ptr++;
cmyk_to_rgb(PPM_MAXVAL, c, m, y, k, &r, &g, &b);
PUTPPMSAMPLE(bufferptr, r);
PUTPPMSAMPLE(bufferptr, g);
PUTPPMSAMPLE(bufferptr, b);
#ifdef DJPEG_MULTILINE
for (row = 0; row < MIN(dest->pub.buffer_height, rows_supplied); row++) {
#endif
ptr = dest->pub._buffer[row];
bufferptr = dest->iobuffer;
for (col = cinfo->output_width; col > 0; col--) {
_JSAMPLE r, g, b, c = *ptr++, m = *ptr++, y = *ptr++, k = *ptr++;
cmyk_to_rgb(PPM_MAXVAL, c, m, y, k, &r, &g, &b);
PUTPPMSAMPLE(bufferptr, r);
PUTPPMSAMPLE(bufferptr, g);
PUTPPMSAMPLE(bufferptr, b);
}
fwrite(dest->iobuffer, 1, dest->buffer_width, dest->pub.output_file);
#ifdef DJPEG_MULTILINE
}
fwrite(dest->iobuffer, 1, dest->buffer_width, dest->pub.output_file);
#endif
}
@@ -244,17 +273,23 @@ put_demapped_rgb(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
((_JSAMPARRAY)cinfo->colormap)[rgb_green[cinfo->out_color_space]];
register _JSAMPROW color_map2 =
((_JSAMPARRAY)cinfo->colormap)[rgb_blue[cinfo->out_color_space]];
register JDIMENSION col;
register JDIMENSION row = 0, col;
ptr = dest->pub._buffer[0];
bufferptr = dest->iobuffer;
for (col = cinfo->output_width; col > 0; col--) {
pixval = *ptr++;
PUTPPMSAMPLE(bufferptr, color_map0[pixval]);
PUTPPMSAMPLE(bufferptr, color_map1[pixval]);
PUTPPMSAMPLE(bufferptr, color_map2[pixval]);
#ifdef DJPEG_MULTILINE
for (row = 0; row < MIN(dest->pub.buffer_height, rows_supplied); row++) {
#endif
ptr = dest->pub._buffer[row];
bufferptr = dest->iobuffer;
for (col = cinfo->output_width; col > 0; col--) {
pixval = *ptr++;
PUTPPMSAMPLE(bufferptr, color_map0[pixval]);
PUTPPMSAMPLE(bufferptr, color_map1[pixval]);
PUTPPMSAMPLE(bufferptr, color_map2[pixval]);
}
fwrite(dest->iobuffer, 1, dest->buffer_width, dest->pub.output_file);
#ifdef DJPEG_MULTILINE
}
fwrite(dest->iobuffer, 1, dest->buffer_width, dest->pub.output_file);
#endif
}
@@ -266,14 +301,20 @@ put_demapped_gray(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
register char *bufferptr;
register _JSAMPROW ptr;
register _JSAMPROW color_map = ((_JSAMPARRAY)cinfo->colormap)[0];
register JDIMENSION col;
register JDIMENSION row = 0, col;
ptr = dest->pub._buffer[0];
bufferptr = dest->iobuffer;
for (col = cinfo->output_width; col > 0; col--) {
PUTPPMSAMPLE(bufferptr, color_map[*ptr++]);
#ifdef DJPEG_MULTILINE
for (row = 0; row < MIN(dest->pub.buffer_height, rows_supplied); row++) {
#endif
ptr = dest->pub._buffer[row];
bufferptr = dest->iobuffer;
for (col = cinfo->output_width; col > 0; col--) {
PUTPPMSAMPLE(bufferptr, color_map[*ptr++]);
}
fwrite(dest->iobuffer, 1, dest->buffer_width, dest->pub.output_file);
#ifdef DJPEG_MULTILINE
}
fwrite(dest->iobuffer, 1, dest->buffer_width, dest->pub.output_file);
#endif
}
@@ -395,7 +436,7 @@ _jinit_write_ppm(j_decompress_ptr cinfo)
dest->iobuffer = (char *)(*cinfo->mem->alloc_small)
((j_common_ptr)cinfo, JPOOL_IMAGE, dest->buffer_width);
#if BITS_IN_JSAMPLE == 8
#if BITS_IN_JSAMPLE == 8 && !defined(DJPEG_MULTILINE)
if (cinfo->quantize_colors ||
(cinfo->out_color_space != JCS_EXT_RGB &&
#if RGB_RED == 0 && RGB_GREEN == 1 && RGB_BLUE == 2 && RGB_PIXELSIZE == 3
@@ -408,10 +449,26 @@ _jinit_write_ppm(j_decompress_ptr cinfo)
* that's separate from the physical I/O buffer. We also need a
* separate buffer if pixel format translation must take place.
*/
#if BITS_IN_JSAMPLE == 8 && defined(DJPEG_MULTILINE)
/* Allocate the sample array manually to ensure that the rows are
* contiguous in memory, which further exercises esoteric code paths in the
* library.
*/
JDIMENSION row_width = cinfo->output_width * cinfo->output_components;
dest->pub._buffer = (JSAMPARRAY)(*cinfo->mem->alloc_small)
((j_common_ptr)cinfo, JPOOL_IMAGE, 4 * sizeof(JSAMPROW));
dest->pub._buffer[0] = (JSAMPROW)(*cinfo->mem->alloc_small)
((j_common_ptr)cinfo, JPOOL_IMAGE, row_width * 4);
dest->pub._buffer[1] = dest->pub._buffer[0] + row_width;
dest->pub._buffer[2] = dest->pub._buffer[1] + row_width;
dest->pub._buffer[3] = dest->pub._buffer[2] + row_width;
dest->pub.buffer_height = 4;
#else
dest->pub._buffer = (_JSAMPARRAY)(*cinfo->mem->alloc_sarray)
((j_common_ptr)cinfo, JPOOL_IMAGE,
cinfo->output_width * cinfo->output_components, (JDIMENSION)1);
dest->pub.buffer_height = 1;
#endif
if (!cinfo->quantize_colors) {
if (IsExtRGB(cinfo->out_color_space))
dest->pub.put_pixel_rows = put_rgb;
@@ -428,7 +485,7 @@ _jinit_write_ppm(j_decompress_ptr cinfo)
else
dest->pub.put_pixel_rows = put_demapped_rgb;
}
#if BITS_IN_JSAMPLE == 8
#if BITS_IN_JSAMPLE == 8 && !defined(DJPEG_MULTILINE)
else {
/* We will fwrite() directly from decompressor output buffer. */
/* Synthesize a _JSAMPARRAY pointer structure */

View File

@@ -1,5 +1,8 @@
#!/bin/bash
# Uncomment #define DJPEG_MULTILINE in cdjpeg.h to fully exercise all of the
# partial image decompression code paths.
set -u
set -e
trap onexit INT