xref: /plan9/sys/src/cmd/gs/jpeg/jccoefct.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
17dd7cddfSDavid du Colombier /*
27dd7cddfSDavid du Colombier  * jccoefct.c
37dd7cddfSDavid du Colombier  *
4*593dc095SDavid du Colombier  * Copyright (C) 1994-1997, Thomas G. Lane.
57dd7cddfSDavid du Colombier  * This file is part of the Independent JPEG Group's software.
67dd7cddfSDavid du Colombier  * For conditions of distribution and use, see the accompanying README file.
77dd7cddfSDavid du Colombier  *
87dd7cddfSDavid du Colombier  * This file contains the coefficient buffer controller for compression.
97dd7cddfSDavid du Colombier  * This controller is the top level of the JPEG compressor proper.
107dd7cddfSDavid du Colombier  * The coefficient buffer lies between forward-DCT and entropy encoding steps.
117dd7cddfSDavid du Colombier  */
127dd7cddfSDavid du Colombier 
137dd7cddfSDavid du Colombier #define JPEG_INTERNALS
147dd7cddfSDavid du Colombier #include "jinclude.h"
157dd7cddfSDavid du Colombier #include "jpeglib.h"
167dd7cddfSDavid du Colombier 
177dd7cddfSDavid du Colombier 
187dd7cddfSDavid du Colombier /* We use a full-image coefficient buffer when doing Huffman optimization,
197dd7cddfSDavid du Colombier  * and also for writing multiple-scan JPEG files.  In all cases, the DCT
207dd7cddfSDavid du Colombier  * step is run during the first pass, and subsequent passes need only read
217dd7cddfSDavid du Colombier  * the buffered coefficients.
227dd7cddfSDavid du Colombier  */
237dd7cddfSDavid du Colombier #ifdef ENTROPY_OPT_SUPPORTED
247dd7cddfSDavid du Colombier #define FULL_COEF_BUFFER_SUPPORTED
257dd7cddfSDavid du Colombier #else
267dd7cddfSDavid du Colombier #ifdef C_MULTISCAN_FILES_SUPPORTED
277dd7cddfSDavid du Colombier #define FULL_COEF_BUFFER_SUPPORTED
287dd7cddfSDavid du Colombier #endif
297dd7cddfSDavid du Colombier #endif
307dd7cddfSDavid du Colombier 
317dd7cddfSDavid du Colombier 
327dd7cddfSDavid du Colombier /* Private buffer controller object */
337dd7cddfSDavid du Colombier 
347dd7cddfSDavid du Colombier typedef struct {
357dd7cddfSDavid du Colombier   struct jpeg_c_coef_controller pub; /* public fields */
367dd7cddfSDavid du Colombier 
377dd7cddfSDavid du Colombier   JDIMENSION iMCU_row_num;	/* iMCU row # within image */
387dd7cddfSDavid du Colombier   JDIMENSION mcu_ctr;		/* counts MCUs processed in current row */
397dd7cddfSDavid du Colombier   int MCU_vert_offset;		/* counts MCU rows within iMCU row */
407dd7cddfSDavid du Colombier   int MCU_rows_per_iMCU_row;	/* number of such rows needed */
417dd7cddfSDavid du Colombier 
427dd7cddfSDavid du Colombier   /* For single-pass compression, it's sufficient to buffer just one MCU
437dd7cddfSDavid du Colombier    * (although this may prove a bit slow in practice).  We allocate a
447dd7cddfSDavid du Colombier    * workspace of C_MAX_BLOCKS_IN_MCU coefficient blocks, and reuse it for each
457dd7cddfSDavid du Colombier    * MCU constructed and sent.  (On 80x86, the workspace is FAR even though
467dd7cddfSDavid du Colombier    * it's not really very big; this is to keep the module interfaces unchanged
477dd7cddfSDavid du Colombier    * when a large coefficient buffer is necessary.)
487dd7cddfSDavid du Colombier    * In multi-pass modes, this array points to the current MCU's blocks
497dd7cddfSDavid du Colombier    * within the virtual arrays.
507dd7cddfSDavid du Colombier    */
517dd7cddfSDavid du Colombier   JBLOCKROW MCU_buffer[C_MAX_BLOCKS_IN_MCU];
527dd7cddfSDavid du Colombier 
537dd7cddfSDavid du Colombier   /* In multi-pass modes, we need a virtual block array for each component. */
547dd7cddfSDavid du Colombier   jvirt_barray_ptr whole_image[MAX_COMPONENTS];
557dd7cddfSDavid du Colombier } my_coef_controller;
567dd7cddfSDavid du Colombier 
577dd7cddfSDavid du Colombier typedef my_coef_controller * my_coef_ptr;
587dd7cddfSDavid du Colombier 
597dd7cddfSDavid du Colombier 
607dd7cddfSDavid du Colombier /* Forward declarations */
617dd7cddfSDavid du Colombier METHODDEF(boolean) compress_data
627dd7cddfSDavid du Colombier     JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf));
637dd7cddfSDavid du Colombier #ifdef FULL_COEF_BUFFER_SUPPORTED
647dd7cddfSDavid du Colombier METHODDEF(boolean) compress_first_pass
657dd7cddfSDavid du Colombier     JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf));
667dd7cddfSDavid du Colombier METHODDEF(boolean) compress_output
677dd7cddfSDavid du Colombier     JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf));
687dd7cddfSDavid du Colombier #endif
697dd7cddfSDavid du Colombier 
707dd7cddfSDavid du Colombier 
717dd7cddfSDavid du Colombier LOCAL(void)
start_iMCU_row(j_compress_ptr cinfo)727dd7cddfSDavid du Colombier start_iMCU_row (j_compress_ptr cinfo)
737dd7cddfSDavid du Colombier /* Reset within-iMCU-row counters for a new row */
747dd7cddfSDavid du Colombier {
757dd7cddfSDavid du Colombier   my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
767dd7cddfSDavid du Colombier 
777dd7cddfSDavid du Colombier   /* In an interleaved scan, an MCU row is the same as an iMCU row.
787dd7cddfSDavid du Colombier    * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
797dd7cddfSDavid du Colombier    * But at the bottom of the image, process only what's left.
807dd7cddfSDavid du Colombier    */
817dd7cddfSDavid du Colombier   if (cinfo->comps_in_scan > 1) {
827dd7cddfSDavid du Colombier     coef->MCU_rows_per_iMCU_row = 1;
837dd7cddfSDavid du Colombier   } else {
847dd7cddfSDavid du Colombier     if (coef->iMCU_row_num < (cinfo->total_iMCU_rows-1))
857dd7cddfSDavid du Colombier       coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor;
867dd7cddfSDavid du Colombier     else
877dd7cddfSDavid du Colombier       coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height;
887dd7cddfSDavid du Colombier   }
897dd7cddfSDavid du Colombier 
907dd7cddfSDavid du Colombier   coef->mcu_ctr = 0;
917dd7cddfSDavid du Colombier   coef->MCU_vert_offset = 0;
927dd7cddfSDavid du Colombier }
937dd7cddfSDavid du Colombier 
947dd7cddfSDavid du Colombier 
957dd7cddfSDavid du Colombier /*
967dd7cddfSDavid du Colombier  * Initialize for a processing pass.
977dd7cddfSDavid du Colombier  */
987dd7cddfSDavid du Colombier 
997dd7cddfSDavid du Colombier METHODDEF(void)
start_pass_coef(j_compress_ptr cinfo,J_BUF_MODE pass_mode)1007dd7cddfSDavid du Colombier start_pass_coef (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
1017dd7cddfSDavid du Colombier {
1027dd7cddfSDavid du Colombier   my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
1037dd7cddfSDavid du Colombier 
1047dd7cddfSDavid du Colombier   coef->iMCU_row_num = 0;
1057dd7cddfSDavid du Colombier   start_iMCU_row(cinfo);
1067dd7cddfSDavid du Colombier 
1077dd7cddfSDavid du Colombier   switch (pass_mode) {
1087dd7cddfSDavid du Colombier   case JBUF_PASS_THRU:
1097dd7cddfSDavid du Colombier     if (coef->whole_image[0] != NULL)
1107dd7cddfSDavid du Colombier       ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
1117dd7cddfSDavid du Colombier     coef->pub.compress_data = compress_data;
1127dd7cddfSDavid du Colombier     break;
1137dd7cddfSDavid du Colombier #ifdef FULL_COEF_BUFFER_SUPPORTED
1147dd7cddfSDavid du Colombier   case JBUF_SAVE_AND_PASS:
1157dd7cddfSDavid du Colombier     if (coef->whole_image[0] == NULL)
1167dd7cddfSDavid du Colombier       ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
1177dd7cddfSDavid du Colombier     coef->pub.compress_data = compress_first_pass;
1187dd7cddfSDavid du Colombier     break;
1197dd7cddfSDavid du Colombier   case JBUF_CRANK_DEST:
1207dd7cddfSDavid du Colombier     if (coef->whole_image[0] == NULL)
1217dd7cddfSDavid du Colombier       ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
1227dd7cddfSDavid du Colombier     coef->pub.compress_data = compress_output;
1237dd7cddfSDavid du Colombier     break;
1247dd7cddfSDavid du Colombier #endif
1257dd7cddfSDavid du Colombier   default:
1267dd7cddfSDavid du Colombier     ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
1277dd7cddfSDavid du Colombier     break;
1287dd7cddfSDavid du Colombier   }
1297dd7cddfSDavid du Colombier }
1307dd7cddfSDavid du Colombier 
1317dd7cddfSDavid du Colombier 
1327dd7cddfSDavid du Colombier /*
1337dd7cddfSDavid du Colombier  * Process some data in the single-pass case.
1347dd7cddfSDavid du Colombier  * We process the equivalent of one fully interleaved MCU row ("iMCU" row)
1357dd7cddfSDavid du Colombier  * per call, ie, v_samp_factor block rows for each component in the image.
1367dd7cddfSDavid du Colombier  * Returns TRUE if the iMCU row is completed, FALSE if suspended.
1377dd7cddfSDavid du Colombier  *
138*593dc095SDavid du Colombier  * NB: input_buf contains a plane for each component in image,
139*593dc095SDavid du Colombier  * which we index according to the component's SOF position.
1407dd7cddfSDavid du Colombier  */
1417dd7cddfSDavid du Colombier 
1427dd7cddfSDavid du Colombier METHODDEF(boolean)
compress_data(j_compress_ptr cinfo,JSAMPIMAGE input_buf)1437dd7cddfSDavid du Colombier compress_data (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
1447dd7cddfSDavid du Colombier {
1457dd7cddfSDavid du Colombier   my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
1467dd7cddfSDavid du Colombier   JDIMENSION MCU_col_num;	/* index of current MCU within row */
1477dd7cddfSDavid du Colombier   JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1;
1487dd7cddfSDavid du Colombier   JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
1497dd7cddfSDavid du Colombier   int blkn, bi, ci, yindex, yoffset, blockcnt;
1507dd7cddfSDavid du Colombier   JDIMENSION ypos, xpos;
1517dd7cddfSDavid du Colombier   jpeg_component_info *compptr;
1527dd7cddfSDavid du Colombier 
1537dd7cddfSDavid du Colombier   /* Loop to write as much as one whole iMCU row */
1547dd7cddfSDavid du Colombier   for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
1557dd7cddfSDavid du Colombier        yoffset++) {
1567dd7cddfSDavid du Colombier     for (MCU_col_num = coef->mcu_ctr; MCU_col_num <= last_MCU_col;
1577dd7cddfSDavid du Colombier 	 MCU_col_num++) {
1587dd7cddfSDavid du Colombier       /* Determine where data comes from in input_buf and do the DCT thing.
1597dd7cddfSDavid du Colombier        * Each call on forward_DCT processes a horizontal row of DCT blocks
1607dd7cddfSDavid du Colombier        * as wide as an MCU; we rely on having allocated the MCU_buffer[] blocks
1617dd7cddfSDavid du Colombier        * sequentially.  Dummy blocks at the right or bottom edge are filled in
1627dd7cddfSDavid du Colombier        * specially.  The data in them does not matter for image reconstruction,
1637dd7cddfSDavid du Colombier        * so we fill them with values that will encode to the smallest amount of
1647dd7cddfSDavid du Colombier        * data, viz: all zeroes in the AC entries, DC entries equal to previous
1657dd7cddfSDavid du Colombier        * block's DC value.  (Thanks to Thomas Kinsman for this idea.)
1667dd7cddfSDavid du Colombier        */
1677dd7cddfSDavid du Colombier       blkn = 0;
1687dd7cddfSDavid du Colombier       for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
1697dd7cddfSDavid du Colombier 	compptr = cinfo->cur_comp_info[ci];
1707dd7cddfSDavid du Colombier 	blockcnt = (MCU_col_num < last_MCU_col) ? compptr->MCU_width
1717dd7cddfSDavid du Colombier 						: compptr->last_col_width;
1727dd7cddfSDavid du Colombier 	xpos = MCU_col_num * compptr->MCU_sample_width;
1737dd7cddfSDavid du Colombier 	ypos = yoffset * DCTSIZE; /* ypos == (yoffset+yindex) * DCTSIZE */
1747dd7cddfSDavid du Colombier 	for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
1757dd7cddfSDavid du Colombier 	  if (coef->iMCU_row_num < last_iMCU_row ||
1767dd7cddfSDavid du Colombier 	      yoffset+yindex < compptr->last_row_height) {
1777dd7cddfSDavid du Colombier 	    (*cinfo->fdct->forward_DCT) (cinfo, compptr,
178*593dc095SDavid du Colombier 					 input_buf[compptr->component_index],
179*593dc095SDavid du Colombier 					 coef->MCU_buffer[blkn],
1807dd7cddfSDavid du Colombier 					 ypos, xpos, (JDIMENSION) blockcnt);
1817dd7cddfSDavid du Colombier 	    if (blockcnt < compptr->MCU_width) {
1827dd7cddfSDavid du Colombier 	      /* Create some dummy blocks at the right edge of the image. */
1837dd7cddfSDavid du Colombier 	      jzero_far((void FAR *) coef->MCU_buffer[blkn + blockcnt],
1847dd7cddfSDavid du Colombier 			(compptr->MCU_width - blockcnt) * SIZEOF(JBLOCK));
1857dd7cddfSDavid du Colombier 	      for (bi = blockcnt; bi < compptr->MCU_width; bi++) {
1867dd7cddfSDavid du Colombier 		coef->MCU_buffer[blkn+bi][0][0] = coef->MCU_buffer[blkn+bi-1][0][0];
1877dd7cddfSDavid du Colombier 	      }
1887dd7cddfSDavid du Colombier 	    }
1897dd7cddfSDavid du Colombier 	  } else {
1907dd7cddfSDavid du Colombier 	    /* Create a row of dummy blocks at the bottom of the image. */
1917dd7cddfSDavid du Colombier 	    jzero_far((void FAR *) coef->MCU_buffer[blkn],
1927dd7cddfSDavid du Colombier 		      compptr->MCU_width * SIZEOF(JBLOCK));
1937dd7cddfSDavid du Colombier 	    for (bi = 0; bi < compptr->MCU_width; bi++) {
1947dd7cddfSDavid du Colombier 	      coef->MCU_buffer[blkn+bi][0][0] = coef->MCU_buffer[blkn-1][0][0];
1957dd7cddfSDavid du Colombier 	    }
1967dd7cddfSDavid du Colombier 	  }
1977dd7cddfSDavid du Colombier 	  blkn += compptr->MCU_width;
1987dd7cddfSDavid du Colombier 	  ypos += DCTSIZE;
1997dd7cddfSDavid du Colombier 	}
2007dd7cddfSDavid du Colombier       }
2017dd7cddfSDavid du Colombier       /* Try to write the MCU.  In event of a suspension failure, we will
2027dd7cddfSDavid du Colombier        * re-DCT the MCU on restart (a bit inefficient, could be fixed...)
2037dd7cddfSDavid du Colombier        */
2047dd7cddfSDavid du Colombier       if (! (*cinfo->entropy->encode_mcu) (cinfo, coef->MCU_buffer)) {
2057dd7cddfSDavid du Colombier 	/* Suspension forced; update state counters and exit */
2067dd7cddfSDavid du Colombier 	coef->MCU_vert_offset = yoffset;
2077dd7cddfSDavid du Colombier 	coef->mcu_ctr = MCU_col_num;
2087dd7cddfSDavid du Colombier 	return FALSE;
2097dd7cddfSDavid du Colombier       }
2107dd7cddfSDavid du Colombier     }
2117dd7cddfSDavid du Colombier     /* Completed an MCU row, but perhaps not an iMCU row */
2127dd7cddfSDavid du Colombier     coef->mcu_ctr = 0;
2137dd7cddfSDavid du Colombier   }
2147dd7cddfSDavid du Colombier   /* Completed the iMCU row, advance counters for next one */
2157dd7cddfSDavid du Colombier   coef->iMCU_row_num++;
2167dd7cddfSDavid du Colombier   start_iMCU_row(cinfo);
2177dd7cddfSDavid du Colombier   return TRUE;
2187dd7cddfSDavid du Colombier }
2197dd7cddfSDavid du Colombier 
2207dd7cddfSDavid du Colombier 
2217dd7cddfSDavid du Colombier #ifdef FULL_COEF_BUFFER_SUPPORTED
2227dd7cddfSDavid du Colombier 
2237dd7cddfSDavid du Colombier /*
2247dd7cddfSDavid du Colombier  * Process some data in the first pass of a multi-pass case.
2257dd7cddfSDavid du Colombier  * We process the equivalent of one fully interleaved MCU row ("iMCU" row)
2267dd7cddfSDavid du Colombier  * per call, ie, v_samp_factor block rows for each component in the image.
2277dd7cddfSDavid du Colombier  * This amount of data is read from the source buffer, DCT'd and quantized,
2287dd7cddfSDavid du Colombier  * and saved into the virtual arrays.  We also generate suitable dummy blocks
2297dd7cddfSDavid du Colombier  * as needed at the right and lower edges.  (The dummy blocks are constructed
2307dd7cddfSDavid du Colombier  * in the virtual arrays, which have been padded appropriately.)  This makes
2317dd7cddfSDavid du Colombier  * it possible for subsequent passes not to worry about real vs. dummy blocks.
2327dd7cddfSDavid du Colombier  *
2337dd7cddfSDavid du Colombier  * We must also emit the data to the entropy encoder.  This is conveniently
2347dd7cddfSDavid du Colombier  * done by calling compress_output() after we've loaded the current strip
2357dd7cddfSDavid du Colombier  * of the virtual arrays.
2367dd7cddfSDavid du Colombier  *
2377dd7cddfSDavid du Colombier  * NB: input_buf contains a plane for each component in image.  All
2387dd7cddfSDavid du Colombier  * components are DCT'd and loaded into the virtual arrays in this pass.
2397dd7cddfSDavid du Colombier  * However, it may be that only a subset of the components are emitted to
2407dd7cddfSDavid du Colombier  * the entropy encoder during this first pass; be careful about looking
2417dd7cddfSDavid du Colombier  * at the scan-dependent variables (MCU dimensions, etc).
2427dd7cddfSDavid du Colombier  */
2437dd7cddfSDavid du Colombier 
2447dd7cddfSDavid du Colombier METHODDEF(boolean)
compress_first_pass(j_compress_ptr cinfo,JSAMPIMAGE input_buf)2457dd7cddfSDavid du Colombier compress_first_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
2467dd7cddfSDavid du Colombier {
2477dd7cddfSDavid du Colombier   my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
2487dd7cddfSDavid du Colombier   JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
2497dd7cddfSDavid du Colombier   JDIMENSION blocks_across, MCUs_across, MCUindex;
2507dd7cddfSDavid du Colombier   int bi, ci, h_samp_factor, block_row, block_rows, ndummy;
2517dd7cddfSDavid du Colombier   JCOEF lastDC;
2527dd7cddfSDavid du Colombier   jpeg_component_info *compptr;
2537dd7cddfSDavid du Colombier   JBLOCKARRAY buffer;
2547dd7cddfSDavid du Colombier   JBLOCKROW thisblockrow, lastblockrow;
2557dd7cddfSDavid du Colombier 
2567dd7cddfSDavid du Colombier   for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
2577dd7cddfSDavid du Colombier        ci++, compptr++) {
2587dd7cddfSDavid du Colombier     /* Align the virtual buffer for this component. */
2597dd7cddfSDavid du Colombier     buffer = (*cinfo->mem->access_virt_barray)
2607dd7cddfSDavid du Colombier       ((j_common_ptr) cinfo, coef->whole_image[ci],
2617dd7cddfSDavid du Colombier        coef->iMCU_row_num * compptr->v_samp_factor,
2627dd7cddfSDavid du Colombier        (JDIMENSION) compptr->v_samp_factor, TRUE);
2637dd7cddfSDavid du Colombier     /* Count non-dummy DCT block rows in this iMCU row. */
2647dd7cddfSDavid du Colombier     if (coef->iMCU_row_num < last_iMCU_row)
2657dd7cddfSDavid du Colombier       block_rows = compptr->v_samp_factor;
2667dd7cddfSDavid du Colombier     else {
2677dd7cddfSDavid du Colombier       /* NB: can't use last_row_height here, since may not be set! */
2687dd7cddfSDavid du Colombier       block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
2697dd7cddfSDavid du Colombier       if (block_rows == 0) block_rows = compptr->v_samp_factor;
2707dd7cddfSDavid du Colombier     }
2717dd7cddfSDavid du Colombier     blocks_across = compptr->width_in_blocks;
2727dd7cddfSDavid du Colombier     h_samp_factor = compptr->h_samp_factor;
2737dd7cddfSDavid du Colombier     /* Count number of dummy blocks to be added at the right margin. */
2747dd7cddfSDavid du Colombier     ndummy = (int) (blocks_across % h_samp_factor);
2757dd7cddfSDavid du Colombier     if (ndummy > 0)
2767dd7cddfSDavid du Colombier       ndummy = h_samp_factor - ndummy;
2777dd7cddfSDavid du Colombier     /* Perform DCT for all non-dummy blocks in this iMCU row.  Each call
2787dd7cddfSDavid du Colombier      * on forward_DCT processes a complete horizontal row of DCT blocks.
2797dd7cddfSDavid du Colombier      */
2807dd7cddfSDavid du Colombier     for (block_row = 0; block_row < block_rows; block_row++) {
2817dd7cddfSDavid du Colombier       thisblockrow = buffer[block_row];
2827dd7cddfSDavid du Colombier       (*cinfo->fdct->forward_DCT) (cinfo, compptr,
2837dd7cddfSDavid du Colombier 				   input_buf[ci], thisblockrow,
2847dd7cddfSDavid du Colombier 				   (JDIMENSION) (block_row * DCTSIZE),
2857dd7cddfSDavid du Colombier 				   (JDIMENSION) 0, blocks_across);
2867dd7cddfSDavid du Colombier       if (ndummy > 0) {
2877dd7cddfSDavid du Colombier 	/* Create dummy blocks at the right edge of the image. */
2887dd7cddfSDavid du Colombier 	thisblockrow += blocks_across; /* => first dummy block */
2897dd7cddfSDavid du Colombier 	jzero_far((void FAR *) thisblockrow, ndummy * SIZEOF(JBLOCK));
2907dd7cddfSDavid du Colombier 	lastDC = thisblockrow[-1][0];
2917dd7cddfSDavid du Colombier 	for (bi = 0; bi < ndummy; bi++) {
2927dd7cddfSDavid du Colombier 	  thisblockrow[bi][0] = lastDC;
2937dd7cddfSDavid du Colombier 	}
2947dd7cddfSDavid du Colombier       }
2957dd7cddfSDavid du Colombier     }
2967dd7cddfSDavid du Colombier     /* If at end of image, create dummy block rows as needed.
2977dd7cddfSDavid du Colombier      * The tricky part here is that within each MCU, we want the DC values
2987dd7cddfSDavid du Colombier      * of the dummy blocks to match the last real block's DC value.
2997dd7cddfSDavid du Colombier      * This squeezes a few more bytes out of the resulting file...
3007dd7cddfSDavid du Colombier      */
3017dd7cddfSDavid du Colombier     if (coef->iMCU_row_num == last_iMCU_row) {
3027dd7cddfSDavid du Colombier       blocks_across += ndummy;	/* include lower right corner */
3037dd7cddfSDavid du Colombier       MCUs_across = blocks_across / h_samp_factor;
3047dd7cddfSDavid du Colombier       for (block_row = block_rows; block_row < compptr->v_samp_factor;
3057dd7cddfSDavid du Colombier 	   block_row++) {
3067dd7cddfSDavid du Colombier 	thisblockrow = buffer[block_row];
3077dd7cddfSDavid du Colombier 	lastblockrow = buffer[block_row-1];
3087dd7cddfSDavid du Colombier 	jzero_far((void FAR *) thisblockrow,
3097dd7cddfSDavid du Colombier 		  (size_t) (blocks_across * SIZEOF(JBLOCK)));
3107dd7cddfSDavid du Colombier 	for (MCUindex = 0; MCUindex < MCUs_across; MCUindex++) {
3117dd7cddfSDavid du Colombier 	  lastDC = lastblockrow[h_samp_factor-1][0];
3127dd7cddfSDavid du Colombier 	  for (bi = 0; bi < h_samp_factor; bi++) {
3137dd7cddfSDavid du Colombier 	    thisblockrow[bi][0] = lastDC;
3147dd7cddfSDavid du Colombier 	  }
3157dd7cddfSDavid du Colombier 	  thisblockrow += h_samp_factor; /* advance to next MCU in row */
3167dd7cddfSDavid du Colombier 	  lastblockrow += h_samp_factor;
3177dd7cddfSDavid du Colombier 	}
3187dd7cddfSDavid du Colombier       }
3197dd7cddfSDavid du Colombier     }
3207dd7cddfSDavid du Colombier   }
3217dd7cddfSDavid du Colombier   /* NB: compress_output will increment iMCU_row_num if successful.
3227dd7cddfSDavid du Colombier    * A suspension return will result in redoing all the work above next time.
3237dd7cddfSDavid du Colombier    */
3247dd7cddfSDavid du Colombier 
3257dd7cddfSDavid du Colombier   /* Emit data to the entropy encoder, sharing code with subsequent passes */
3267dd7cddfSDavid du Colombier   return compress_output(cinfo, input_buf);
3277dd7cddfSDavid du Colombier }
3287dd7cddfSDavid du Colombier 
3297dd7cddfSDavid du Colombier 
3307dd7cddfSDavid du Colombier /*
3317dd7cddfSDavid du Colombier  * Process some data in subsequent passes of a multi-pass case.
3327dd7cddfSDavid du Colombier  * We process the equivalent of one fully interleaved MCU row ("iMCU" row)
3337dd7cddfSDavid du Colombier  * per call, ie, v_samp_factor block rows for each component in the scan.
3347dd7cddfSDavid du Colombier  * The data is obtained from the virtual arrays and fed to the entropy coder.
3357dd7cddfSDavid du Colombier  * Returns TRUE if the iMCU row is completed, FALSE if suspended.
3367dd7cddfSDavid du Colombier  *
3377dd7cddfSDavid du Colombier  * NB: input_buf is ignored; it is likely to be a NULL pointer.
3387dd7cddfSDavid du Colombier  */
3397dd7cddfSDavid du Colombier 
3407dd7cddfSDavid du Colombier METHODDEF(boolean)
compress_output(j_compress_ptr cinfo,JSAMPIMAGE input_buf)3417dd7cddfSDavid du Colombier compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
3427dd7cddfSDavid du Colombier {
3437dd7cddfSDavid du Colombier   my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
3447dd7cddfSDavid du Colombier   JDIMENSION MCU_col_num;	/* index of current MCU within row */
3457dd7cddfSDavid du Colombier   int blkn, ci, xindex, yindex, yoffset;
3467dd7cddfSDavid du Colombier   JDIMENSION start_col;
3477dd7cddfSDavid du Colombier   JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN];
3487dd7cddfSDavid du Colombier   JBLOCKROW buffer_ptr;
3497dd7cddfSDavid du Colombier   jpeg_component_info *compptr;
3507dd7cddfSDavid du Colombier 
3517dd7cddfSDavid du Colombier   /* Align the virtual buffers for the components used in this scan.
3527dd7cddfSDavid du Colombier    * NB: during first pass, this is safe only because the buffers will
3537dd7cddfSDavid du Colombier    * already be aligned properly, so jmemmgr.c won't need to do any I/O.
3547dd7cddfSDavid du Colombier    */
3557dd7cddfSDavid du Colombier   for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
3567dd7cddfSDavid du Colombier     compptr = cinfo->cur_comp_info[ci];
3577dd7cddfSDavid du Colombier     buffer[ci] = (*cinfo->mem->access_virt_barray)
3587dd7cddfSDavid du Colombier       ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index],
3597dd7cddfSDavid du Colombier        coef->iMCU_row_num * compptr->v_samp_factor,
3607dd7cddfSDavid du Colombier        (JDIMENSION) compptr->v_samp_factor, FALSE);
3617dd7cddfSDavid du Colombier   }
3627dd7cddfSDavid du Colombier 
3637dd7cddfSDavid du Colombier   /* Loop to process one whole iMCU row */
3647dd7cddfSDavid du Colombier   for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
3657dd7cddfSDavid du Colombier        yoffset++) {
3667dd7cddfSDavid du Colombier     for (MCU_col_num = coef->mcu_ctr; MCU_col_num < cinfo->MCUs_per_row;
3677dd7cddfSDavid du Colombier 	 MCU_col_num++) {
3687dd7cddfSDavid du Colombier       /* Construct list of pointers to DCT blocks belonging to this MCU */
3697dd7cddfSDavid du Colombier       blkn = 0;			/* index of current DCT block within MCU */
3707dd7cddfSDavid du Colombier       for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
3717dd7cddfSDavid du Colombier 	compptr = cinfo->cur_comp_info[ci];
3727dd7cddfSDavid du Colombier 	start_col = MCU_col_num * compptr->MCU_width;
3737dd7cddfSDavid du Colombier 	for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
3747dd7cddfSDavid du Colombier 	  buffer_ptr = buffer[ci][yindex+yoffset] + start_col;
3757dd7cddfSDavid du Colombier 	  for (xindex = 0; xindex < compptr->MCU_width; xindex++) {
3767dd7cddfSDavid du Colombier 	    coef->MCU_buffer[blkn++] = buffer_ptr++;
3777dd7cddfSDavid du Colombier 	  }
3787dd7cddfSDavid du Colombier 	}
3797dd7cddfSDavid du Colombier       }
3807dd7cddfSDavid du Colombier       /* Try to write the MCU. */
3817dd7cddfSDavid du Colombier       if (! (*cinfo->entropy->encode_mcu) (cinfo, coef->MCU_buffer)) {
3827dd7cddfSDavid du Colombier 	/* Suspension forced; update state counters and exit */
3837dd7cddfSDavid du Colombier 	coef->MCU_vert_offset = yoffset;
3847dd7cddfSDavid du Colombier 	coef->mcu_ctr = MCU_col_num;
3857dd7cddfSDavid du Colombier 	return FALSE;
3867dd7cddfSDavid du Colombier       }
3877dd7cddfSDavid du Colombier     }
3887dd7cddfSDavid du Colombier     /* Completed an MCU row, but perhaps not an iMCU row */
3897dd7cddfSDavid du Colombier     coef->mcu_ctr = 0;
3907dd7cddfSDavid du Colombier   }
3917dd7cddfSDavid du Colombier   /* Completed the iMCU row, advance counters for next one */
3927dd7cddfSDavid du Colombier   coef->iMCU_row_num++;
3937dd7cddfSDavid du Colombier   start_iMCU_row(cinfo);
3947dd7cddfSDavid du Colombier   return TRUE;
3957dd7cddfSDavid du Colombier }
3967dd7cddfSDavid du Colombier 
3977dd7cddfSDavid du Colombier #endif /* FULL_COEF_BUFFER_SUPPORTED */
3987dd7cddfSDavid du Colombier 
3997dd7cddfSDavid du Colombier 
4007dd7cddfSDavid du Colombier /*
4017dd7cddfSDavid du Colombier  * Initialize coefficient buffer controller.
4027dd7cddfSDavid du Colombier  */
4037dd7cddfSDavid du Colombier 
4047dd7cddfSDavid du Colombier GLOBAL(void)
jinit_c_coef_controller(j_compress_ptr cinfo,boolean need_full_buffer)4057dd7cddfSDavid du Colombier jinit_c_coef_controller (j_compress_ptr cinfo, boolean need_full_buffer)
4067dd7cddfSDavid du Colombier {
4077dd7cddfSDavid du Colombier   my_coef_ptr coef;
4087dd7cddfSDavid du Colombier 
4097dd7cddfSDavid du Colombier   coef = (my_coef_ptr)
4107dd7cddfSDavid du Colombier     (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
4117dd7cddfSDavid du Colombier 				SIZEOF(my_coef_controller));
4127dd7cddfSDavid du Colombier   cinfo->coef = (struct jpeg_c_coef_controller *) coef;
4137dd7cddfSDavid du Colombier   coef->pub.start_pass = start_pass_coef;
4147dd7cddfSDavid du Colombier 
4157dd7cddfSDavid du Colombier   /* Create the coefficient buffer. */
4167dd7cddfSDavid du Colombier   if (need_full_buffer) {
4177dd7cddfSDavid du Colombier #ifdef FULL_COEF_BUFFER_SUPPORTED
4187dd7cddfSDavid du Colombier     /* Allocate a full-image virtual array for each component, */
4197dd7cddfSDavid du Colombier     /* padded to a multiple of samp_factor DCT blocks in each direction. */
4207dd7cddfSDavid du Colombier     int ci;
4217dd7cddfSDavid du Colombier     jpeg_component_info *compptr;
4227dd7cddfSDavid du Colombier 
4237dd7cddfSDavid du Colombier     for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
4247dd7cddfSDavid du Colombier 	 ci++, compptr++) {
4257dd7cddfSDavid du Colombier       coef->whole_image[ci] = (*cinfo->mem->request_virt_barray)
4267dd7cddfSDavid du Colombier 	((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
4277dd7cddfSDavid du Colombier 	 (JDIMENSION) jround_up((long) compptr->width_in_blocks,
4287dd7cddfSDavid du Colombier 				(long) compptr->h_samp_factor),
4297dd7cddfSDavid du Colombier 	 (JDIMENSION) jround_up((long) compptr->height_in_blocks,
4307dd7cddfSDavid du Colombier 				(long) compptr->v_samp_factor),
4317dd7cddfSDavid du Colombier 	 (JDIMENSION) compptr->v_samp_factor);
4327dd7cddfSDavid du Colombier     }
4337dd7cddfSDavid du Colombier #else
4347dd7cddfSDavid du Colombier     ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
4357dd7cddfSDavid du Colombier #endif
4367dd7cddfSDavid du Colombier   } else {
4377dd7cddfSDavid du Colombier     /* We only need a single-MCU buffer. */
4387dd7cddfSDavid du Colombier     JBLOCKROW buffer;
4397dd7cddfSDavid du Colombier     int i;
4407dd7cddfSDavid du Colombier 
4417dd7cddfSDavid du Colombier     buffer = (JBLOCKROW)
4427dd7cddfSDavid du Colombier       (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
4437dd7cddfSDavid du Colombier 				  C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK));
4447dd7cddfSDavid du Colombier     for (i = 0; i < C_MAX_BLOCKS_IN_MCU; i++) {
4457dd7cddfSDavid du Colombier       coef->MCU_buffer[i] = buffer + i;
4467dd7cddfSDavid du Colombier     }
4477dd7cddfSDavid du Colombier     coef->whole_image[0] = NULL; /* flag for no virtual arrays */
4487dd7cddfSDavid du Colombier   }
4497dd7cddfSDavid du Colombier }
450