Index: jdapistd.c |
diff --git a/jdapistd.c b/jdapistd.c |
index 056fa1d07bc9979ec93ca412dbee7baecbed91d4..37afc8448b93ea0cad5e744b0ef899a0b7c316ec 100644 |
--- a/jdapistd.c |
+++ b/jdapistd.c |
@@ -4,9 +4,10 @@ |
* 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, D. R. Commander. |
+ * Copyright (C) 2010, 2015-2016, D. R. Commander. |
* Copyright (C) 2015, Google, Inc. |
- * For conditions of distribution and use, see the accompanying README file. |
+ * For conditions of distribution and use, see the accompanying README.ijg |
+ * file. |
* |
* This file contains application interface code for the decompression half |
* of the JPEG library. These are the "standard" API routines that are |
@@ -17,14 +18,14 @@ |
* whole decompression library into a transcoder. |
*/ |
+#include "jinclude.h" |
#include "jdmainct.h" |
#include "jdcoefct.h" |
#include "jdsample.h" |
#include "jmemsys.h" |
- |
/* Forward declarations */ |
-LOCAL(boolean) output_pass_setup JPP((j_decompress_ptr cinfo)); |
+LOCAL(boolean) output_pass_setup (j_decompress_ptr cinfo); |
/* |
@@ -56,24 +57,24 @@ jpeg_start_decompress (j_decompress_ptr cinfo) |
if (cinfo->inputctl->has_multiple_scans) { |
#ifdef D_MULTISCAN_FILES_SUPPORTED |
for (;;) { |
- int retcode; |
- /* Call progress monitor hook if present */ |
- if (cinfo->progress != NULL) |
- (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); |
- /* Absorb some more input */ |
- retcode = (*cinfo->inputctl->consume_input) (cinfo); |
- if (retcode == JPEG_SUSPENDED) |
- return FALSE; |
- if (retcode == JPEG_REACHED_EOI) |
- break; |
- /* Advance progress counter if appropriate */ |
- if (cinfo->progress != NULL && |
- (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) { |
- if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) { |
- /* jdmaster underestimated number of scans; ratchet up one scan */ |
- cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows; |
- } |
- } |
+ int retcode; |
+ /* Call progress monitor hook if present */ |
+ if (cinfo->progress != NULL) |
+ (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); |
+ /* Absorb some more input */ |
+ retcode = (*cinfo->inputctl->consume_input) (cinfo); |
+ if (retcode == JPEG_SUSPENDED) |
+ return FALSE; |
+ if (retcode == JPEG_REACHED_EOI) |
+ break; |
+ /* Advance progress counter if appropriate */ |
+ if (cinfo->progress != NULL && |
+ (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) { |
+ if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) { |
+ /* jdmaster underestimated number of scans; ratchet up one scan */ |
+ cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows; |
+ } |
+ } |
} |
#else |
ERREXIT(cinfo, JERR_NOT_COMPILED); |
@@ -112,16 +113,16 @@ output_pass_setup (j_decompress_ptr cinfo) |
JDIMENSION last_scanline; |
/* Call progress monitor hook if present */ |
if (cinfo->progress != NULL) { |
- cinfo->progress->pass_counter = (long) cinfo->output_scanline; |
- cinfo->progress->pass_limit = (long) cinfo->output_height; |
- (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); |
+ cinfo->progress->pass_counter = (long) cinfo->output_scanline; |
+ cinfo->progress->pass_limit = (long) cinfo->output_height; |
+ (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); |
} |
/* Process some data */ |
last_scanline = cinfo->output_scanline; |
(*cinfo->main->process_data) (cinfo, (JSAMPARRAY) NULL, |
- &cinfo->output_scanline, (JDIMENSION) 0); |
+ &cinfo->output_scanline, (JDIMENSION) 0); |
if (cinfo->output_scanline == last_scanline) |
- return FALSE; /* No progress made, must suspend */ |
+ return FALSE; /* No progress made, must suspend */ |
} |
/* Finish up dummy pass, and set up for another one */ |
(*cinfo->master->finish_output_pass) (cinfo); |
@@ -140,6 +141,110 @@ output_pass_setup (j_decompress_ptr cinfo) |
/* |
+ * Enable partial scanline decompression |
+ * |
+ * Must be called after jpeg_start_decompress() and before any calls to |
+ * jpeg_read_scanlines() or jpeg_skip_scanlines(). |
+ * |
+ * Refer to libjpeg.txt for more information. |
+ */ |
+ |
+GLOBAL(void) |
+jpeg_crop_scanline (j_decompress_ptr cinfo, JDIMENSION *xoffset, |
+ JDIMENSION *width) |
+{ |
+ int ci, align, orig_downsampled_width; |
+ JDIMENSION input_xoffset; |
+ boolean reinit_upsampler = FALSE; |
+ jpeg_component_info *compptr; |
+ |
+ if (cinfo->global_state != DSTATE_SCANNING || cinfo->output_scanline != 0) |
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); |
+ |
+ if (!xoffset || !width) |
+ ERREXIT(cinfo, JERR_BAD_CROP_SPEC); |
+ |
+ /* xoffset and width must fall within the output image dimensions. */ |
+ if (*width == 0 || *xoffset + *width > cinfo->output_width) |
+ ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); |
+ |
+ /* No need to do anything if the caller wants the entire width. */ |
+ if (*width == cinfo->output_width) |
+ return; |
+ |
+ /* Ensuring the proper alignment of xoffset is tricky. At minimum, it |
+ * must align with an MCU boundary, because: |
+ * |
+ * (1) The IDCT is performed in blocks, and it is not feasible to modify |
+ * the algorithm so that it can transform partial blocks. |
+ * (2) Because of the SIMD extensions, any input buffer passed to the |
+ * upsampling and color conversion routines must be aligned to the |
+ * SIMD word size (for instance, 128-bit in the case of SSE2.) The |
+ * easiest way to accomplish this without copying data is to ensure |
+ * that upsampling and color conversion begin at the start of the |
+ * first MCU column that will be inverse transformed. |
+ * |
+ * In practice, we actually impose a stricter alignment requirement. We |
+ * require that xoffset be a multiple of the maximum MCU column width of all |
+ * of the components (the "iMCU column width.") This is to simplify the |
+ * single-pass decompression case, allowing us to use the same MCU column |
+ * width for all of the components. |
+ */ |
+ align = cinfo->_min_DCT_scaled_size * cinfo->max_h_samp_factor; |
+ |
+ /* Adjust xoffset to the nearest iMCU boundary <= the requested value */ |
+ input_xoffset = *xoffset; |
+ *xoffset = (input_xoffset / align) * align; |
+ |
+ /* Adjust the width so that the right edge of the output image is as |
+ * requested (only the left edge is altered.) It is important that calling |
+ * programs check this value after this function returns, so that they can |
+ * allocate an output buffer with the appropriate size. |
+ */ |
+ *width = *width + input_xoffset - *xoffset; |
+ cinfo->output_width = *width; |
+ |
+ /* Set the first and last iMCU columns that we must decompress. These values |
+ * will be used in single-scan decompressions. |
+ */ |
+ cinfo->master->first_iMCU_col = |
+ (JDIMENSION) (long) (*xoffset) / (long) align; |
+ cinfo->master->last_iMCU_col = |
+ (JDIMENSION) jdiv_round_up((long) (*xoffset + cinfo->output_width), |
+ (long) align) - 1; |
+ |
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; |
+ ci++, compptr++) { |
+ /* Set downsampled_width to the new output width. */ |
+ orig_downsampled_width = compptr->downsampled_width; |
+ compptr->downsampled_width = |
+ (JDIMENSION) jdiv_round_up((long) (cinfo->output_width * |
+ compptr->h_samp_factor), |
+ (long) cinfo->max_h_samp_factor); |
+ if (compptr->downsampled_width < 2 && orig_downsampled_width >= 2) |
+ reinit_upsampler = TRUE; |
+ |
+ /* Set the first and last iMCU columns that we must decompress. These |
+ * values will be used in multi-scan decompressions. |
+ */ |
+ cinfo->master->first_MCU_col[ci] = |
+ (JDIMENSION) (long) (*xoffset * compptr->h_samp_factor) / |
+ (long) align; |
+ cinfo->master->last_MCU_col[ci] = |
+ (JDIMENSION) jdiv_round_up((long) ((*xoffset + cinfo->output_width) * |
+ compptr->h_samp_factor), |
+ (long) align) - 1; |
+ } |
+ |
+ if (reinit_upsampler) { |
+ cinfo->master->jinit_upsampler_no_alloc = TRUE; |
+ jinit_upsampler(cinfo); |
+ cinfo->master->jinit_upsampler_no_alloc = FALSE; |
+ } |
+} |
+ |
+ |
+/* |
* Read some scanlines of data from the JPEG decompressor. |
* |
* The return value will be the number of lines actually read. |
@@ -154,7 +259,7 @@ output_pass_setup (j_decompress_ptr cinfo) |
GLOBAL(JDIMENSION) |
jpeg_read_scanlines (j_decompress_ptr cinfo, JSAMPARRAY scanlines, |
- JDIMENSION max_lines) |
+ JDIMENSION max_lines) |
{ |
JDIMENSION row_ctr; |
@@ -180,7 +285,6 @@ jpeg_read_scanlines (j_decompress_ptr cinfo, JSAMPARRAY scanlines, |
} |
- |
/* Dummy color convert function used by jpeg_skip_scanlines() */ |
LOCAL(void) |
noop_convert (j_decompress_ptr cinfo, JSAMPIMAGE input_buf, |
@@ -196,6 +300,7 @@ noop_convert (j_decompress_ptr cinfo, JSAMPIMAGE input_buf, |
* we set up and tear down a dummy color converter in order to avoid valgrind |
* errors and to achieve the best possible performance. |
*/ |
+ |
LOCAL(void) |
read_and_discard_scanlines (j_decompress_ptr cinfo, JDIMENSION num_lines) |
{ |
@@ -213,6 +318,7 @@ read_and_discard_scanlines (j_decompress_ptr cinfo, JDIMENSION num_lines) |
cinfo->cconvert->color_convert = color_convert; |
} |
+ |
/* |
* Called by jpeg_skip_scanlines(). This partially skips a decompress block by |
* incrementing the rowgroup counter. |
@@ -416,7 +522,7 @@ jpeg_skip_scanlines (j_decompress_ptr cinfo, JDIMENSION num_lines) |
GLOBAL(JDIMENSION) |
jpeg_read_raw_data (j_decompress_ptr cinfo, JSAMPIMAGE data, |
- JDIMENSION max_lines) |
+ JDIMENSION max_lines) |
{ |
JDIMENSION lines_per_iMCU_row; |
@@ -441,7 +547,7 @@ jpeg_read_raw_data (j_decompress_ptr cinfo, JSAMPIMAGE data, |
/* Decompress directly into user's buffer. */ |
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. */ |
cinfo->output_scanline += lines_per_iMCU_row; |
@@ -497,9 +603,9 @@ jpeg_finish_output (j_decompress_ptr cinfo) |
} |
/* Read markers looking for SOS or EOI */ |
while (cinfo->input_scan_number <= cinfo->output_scan_number && |
- ! cinfo->inputctl->eoi_reached) { |
+ ! cinfo->inputctl->eoi_reached) { |
if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED) |
- return FALSE; /* Suspend, come back later */ |
+ return FALSE; /* Suspend, come back later */ |
} |
cinfo->global_state = DSTATE_BUFIMAGE; |
return TRUE; |