PageRenderTime 30ms CodeModel.GetById 24ms app.highlight 2ms RepoModel.GetById 1ms app.codeStats 0ms

/packages/pasjpeg/src/jctrans.pas

https://github.com/slibre/freepascal
Pascal | 459 lines | 274 code | 63 blank | 122 comment | 29 complexity | 642dfaa1e8843b23787ec2949788a25f MD5 | raw file
Possible License(s): LGPL-2.0, LGPL-2.1, LGPL-3.0
  1Unit JcTrans;
  2
  3{ This file contains library routines for transcoding compression,
  4  that is, writing raw DCT coefficient arrays to an output JPEG file.
  5  The routines in jcapimin.c will also be needed by a transcoder. }
  6
  7{ Original : jctrans.c - Copyright (C) 1995-1998, Thomas G. Lane. }
  8
  9interface
 10
 11{$I jconfig.inc}
 12
 13uses
 14  jmorecfg,
 15  jinclude,
 16  jdeferr,
 17  jerror,
 18  jutils,
 19  jpeglib,
 20  jcapimin, jcparam, jcomapi, jcmaster, jchuff, jcphuff, jcmarker;
 21
 22{ Compression initialization for writing raw-coefficient data.
 23  Before calling this, all parameters and a data destination must be set up.
 24  Call jpeg_finish_compress() to actually write the data.
 25
 26  The number of passed virtual arrays must match cinfo^.num_components.
 27  Note that the virtual arrays need not be filled or even realized at
 28  the time write_coefficients is called; indeed, if the virtual arrays
 29  were requested from this compression object's memory manager, they
 30  typically will be realized during this routine and filled afterwards. }
 31
 32{GLOBAL}
 33procedure jpeg_write_coefficients (cinfo : j_compress_ptr;
 34                                   coef_arrays : jvirt_barray_tbl_ptr);
 35
 36{ Initialize the compression object with default parameters,
 37  then copy from the source object all parameters needed for lossless
 38  transcoding.  Parameters that can be varied without loss (such as
 39  scan script and Huffman optimization) are left in their default states. }
 40
 41{GLOBAL}
 42procedure jpeg_copy_critical_parameters (srcinfo : j_decompress_ptr;
 43                                         dstinfo : j_compress_ptr);
 44
 45
 46implementation
 47
 48{ Forward declarations }
 49{LOCAL}
 50procedure  transencode_master_selection(cinfo : j_compress_ptr;
 51                                        coef_arrays : jvirt_barray_tbl_ptr);
 52                                        forward;
 53{LOCAL}
 54procedure  transencode_coef_controller(cinfo : j_compress_ptr;
 55                                       coef_arrays : jvirt_barray_tbl_ptr);
 56                                       forward;
 57
 58
 59{ Compression initialization for writing raw-coefficient data.
 60  Before calling this, all parameters and a data destination must be set up.
 61  Call jpeg_finish_compress() to actually write the data.
 62
 63  The number of passed virtual arrays must match cinfo^.num_components.
 64  Note that the virtual arrays need not be filled or even realized at
 65  the time write_coefficients is called; indeed, if the virtual arrays
 66  were requested from this compression object's memory manager, they
 67  typically will be realized during this routine and filled afterwards. }
 68
 69{GLOBAL}
 70procedure jpeg_write_coefficients (cinfo : j_compress_ptr;
 71                                   coef_arrays : jvirt_barray_tbl_ptr);
 72begin
 73  if (cinfo^.global_state <> CSTATE_START) then
 74    ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state);
 75  { Mark all tables to be written }
 76  jpeg_suppress_tables(cinfo, FALSE);
 77  { (Re)initialize error mgr and destination modules }
 78  cinfo^.err^.reset_error_mgr (j_common_ptr(cinfo));
 79  cinfo^.dest^.init_destination (cinfo);
 80  { Perform master selection of active modules }
 81  transencode_master_selection(cinfo, coef_arrays);
 82  { Wait for jpeg_finish_compress() call }
 83  cinfo^.next_scanline := 0;    { so jpeg_write_marker works }
 84  cinfo^.global_state := CSTATE_WRCOEFS;
 85end;
 86
 87
 88{ Initialize the compression object with default parameters,
 89  then copy from the source object all parameters needed for lossless
 90  transcoding.  Parameters that can be varied without loss (such as
 91  scan script and Huffman optimization) are left in their default states. }
 92
 93{GLOBAL}
 94procedure jpeg_copy_critical_parameters (srcinfo : j_decompress_ptr;
 95                                         dstinfo : j_compress_ptr);
 96var
 97  qtblptr : ^JQUANT_TBL_PTR;
 98  incomp, outcomp : jpeg_component_info_ptr;
 99  c_quant, slot_quant : JQUANT_TBL_PTR;
100  tblno, ci, coefi : int;
101begin
102
103  { Safety check to ensure start_compress not called yet. }
104  if (dstinfo^.global_state <> CSTATE_START) then
105    ERREXIT1(j_common_ptr(dstinfo), JERR_BAD_STATE, dstinfo^.global_state);
106  { Copy fundamental image dimensions }
107  dstinfo^.image_width := srcinfo^.image_width;
108  dstinfo^.image_height := srcinfo^.image_height;
109  dstinfo^.input_components := srcinfo^.num_components;
110  dstinfo^.in_color_space := srcinfo^.jpeg_color_space;
111  { Initialize all parameters to default values }
112  jpeg_set_defaults(dstinfo);
113  { jpeg_set_defaults may choose wrong colorspace, eg YCbCr if input is RGB.
114    Fix it to get the right header markers for the image colorspace. }
115
116  jpeg_set_colorspace(dstinfo, srcinfo^.jpeg_color_space);
117  dstinfo^.data_precision := srcinfo^.data_precision;
118  dstinfo^.CCIR601_sampling := srcinfo^.CCIR601_sampling;
119  { Copy the source's quantization tables. }
120  for tblno := 0 to pred(NUM_QUANT_TBLS) do
121  begin
122    if (srcinfo^.quant_tbl_ptrs[tblno] <> NIL) then
123    begin
124      qtblptr := @dstinfo^.quant_tbl_ptrs[tblno];
125      if (qtblptr^ = NIL) then
126        qtblptr^ := jpeg_alloc_quant_table(j_common_ptr(dstinfo));
127      MEMCOPY(@(qtblptr^)^.quantval,
128              @srcinfo^.quant_tbl_ptrs[tblno]^.quantval,
129              SIZEOF((qtblptr^)^.quantval));
130      (qtblptr^)^.sent_table := FALSE;
131    end;
132  end;
133  { Copy the source's per-component info.
134    Note we assume jpeg_set_defaults has allocated the dest comp_info array. }
135
136  dstinfo^.num_components := srcinfo^.num_components;
137  if (dstinfo^.num_components < 1) or
138     (dstinfo^.num_components > MAX_COMPONENTS) then
139    ERREXIT2(j_common_ptr(dstinfo), JERR_COMPONENT_COUNT,
140        dstinfo^.num_components,   MAX_COMPONENTS);
141  incomp := jpeg_component_info_ptr(srcinfo^.comp_info);
142  outcomp := jpeg_component_info_ptr(dstinfo^.comp_info);
143  for ci := 0 to pred(dstinfo^.num_components) do
144  begin
145
146    outcomp^.component_id := incomp^.component_id;
147    outcomp^.h_samp_factor := incomp^.h_samp_factor;
148    outcomp^.v_samp_factor := incomp^.v_samp_factor;
149    outcomp^.quant_tbl_no := incomp^.quant_tbl_no;
150    { Make sure saved quantization table for component matches the qtable
151      slot.  If not, the input file re-used this qtable slot.
152      IJG encoder currently cannot duplicate this. }
153
154    tblno := outcomp^.quant_tbl_no;
155    if (tblno < 0) or (tblno >= NUM_QUANT_TBLS) or
156       (srcinfo^.quant_tbl_ptrs[tblno] = NIL) then
157      ERREXIT1(j_common_ptr(dstinfo), JERR_NO_QUANT_TABLE, tblno);
158    slot_quant := srcinfo^.quant_tbl_ptrs[tblno];
159    c_quant := incomp^.quant_table;
160    if (c_quant <> NIL) then
161    begin
162      for coefi := 0 to pred(DCTSIZE2) do
163      begin
164        if (c_quant^.quantval[coefi] <> slot_quant^.quantval[coefi]) then
165          ERREXIT1(j_common_ptr(dstinfo), JERR_MISMATCHED_QUANT_TABLE, tblno);
166      end;
167    end;
168    { Note: we do not copy the source's Huffman table assignments;
169      instead we rely on jpeg_set_colorspace to have made a suitable choice. }
170    Inc(incomp);
171    Inc(outcomp);
172  end;
173  { Also copy JFIF version and resolution information, if available.
174    Strictly speaking this isn't "critical" info, but it's nearly
175    always appropriate to copy it if available.  In particular,
176    if the application chooses to copy JFIF 1.02 extension markers from
177    the source file, we need to copy the version to make sure we don't
178    emit a file that has 1.02 extensions but a claimed version of 1.01.
179    We will *not*, however, copy version info from mislabeled "2.01" files. }
180
181  if (srcinfo^.saw_JFIF_marker) then
182  begin
183    if (srcinfo^.JFIF_major_version = 1) then
184    begin
185      dstinfo^.JFIF_major_version := srcinfo^.JFIF_major_version;
186      dstinfo^.JFIF_minor_version := srcinfo^.JFIF_minor_version;
187    end;
188    dstinfo^.density_unit := srcinfo^.density_unit;
189    dstinfo^.X_density := srcinfo^.X_density;
190    dstinfo^.Y_density := srcinfo^.Y_density;
191  end;
192end;
193
194
195{ Master selection of compression modules for transcoding.
196  This substitutes for jcinit.c's initialization of the full compressor. }
197
198{LOCAL}
199procedure transencode_master_selection (cinfo : j_compress_ptr;
200                                        coef_arrays : jvirt_barray_tbl_ptr);
201begin
202  { Although we don't actually use input_components for transcoding,
203    jcmaster.c's initial_setup will complain if input_components is 0. }
204
205  cinfo^.input_components := 1;
206  { Initialize master control (includes parameter checking/processing) }
207  jinit_c_master_control(cinfo, TRUE { transcode only });
208
209  { Entropy encoding: either Huffman or arithmetic coding. }
210  if (cinfo^.arith_code) then
211  begin
212    ERREXIT(j_common_ptr(cinfo), JERR_ARITH_NOTIMPL);
213  end
214  else
215  begin
216    if (cinfo^.progressive_mode) then
217    begin
218{$ifdef C_PROGRESSIVE_SUPPORTED}
219      jinit_phuff_encoder(cinfo);
220{$else}
221      ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED);
222{$endif}
223    end
224    else
225      jinit_huff_encoder(cinfo);
226  end;
227
228  { We need a special coefficient buffer controller. }
229  transencode_coef_controller(cinfo, coef_arrays);
230
231  jinit_marker_writer(cinfo);
232
233  { We can now tell the memory manager to allocate virtual arrays. }
234  cinfo^.mem^.realize_virt_arrays (j_common_ptr(cinfo));
235
236  { Write the datastream header (SOI, JFIF) immediately.
237    Frame and scan headers are postponed till later.
238    This lets application insert special markers after the SOI. }
239
240  cinfo^.marker^.write_file_header (cinfo);
241end;
242
243
244{ The rest of this file is a special implementation of the coefficient
245  buffer controller.  This is similar to jccoefct.c, but it handles only
246  output from presupplied virtual arrays.  Furthermore, we generate any
247  dummy padding blocks on-the-fly rather than expecting them to be present
248  in the arrays. }
249
250{ Private buffer controller object }
251
252type
253  my_coef_ptr = ^my_coef_controller;
254  my_coef_controller = record
255    pub : jpeg_c_coef_controller; { public fields }
256
257    iMCU_row_num : JDIMENSION;    { iMCU row # within image }
258    mcu_ctr : JDIMENSION;         { counts MCUs processed in current row }
259    MCU_vert_offset : int;        { counts MCU rows within iMCU row }
260    MCU_rows_per_iMCU_row : int;  { number of such rows needed }
261
262    { Virtual block array for each component. }
263    whole_image : jvirt_barray_tbl_ptr;
264
265    { Workspace for constructing dummy blocks at right/bottom edges. }
266    dummy_buffer : array[0..C_MAX_BLOCKS_IN_MCU-1] of JBLOCKROW;
267  end; {my_coef_controller;}
268
269
270{LOCAL}
271procedure start_iMCU_row (cinfo : j_compress_ptr);
272{ Reset within-iMCU-row counters for a new row }
273var
274  coef : my_coef_ptr;
275begin
276  coef := my_coef_ptr (cinfo^.coef);
277
278  { In an interleaved scan, an MCU row is the same as an iMCU row.
279    In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
280    But at the bottom of the image, process only what's left. }
281
282  if (cinfo^.comps_in_scan > 1) then
283  begin
284    coef^.MCU_rows_per_iMCU_row := 1;
285  end
286  else
287  begin
288    if (coef^.iMCU_row_num < (cinfo^.total_iMCU_rows-1)) then
289      coef^.MCU_rows_per_iMCU_row := cinfo^.cur_comp_info[0]^.v_samp_factor
290    else
291      coef^.MCU_rows_per_iMCU_row := cinfo^.cur_comp_info[0]^.last_row_height;
292  end;
293
294  coef^.mcu_ctr := 0;
295  coef^.MCU_vert_offset := 0;
296end;
297
298
299{ Initialize for a processing pass. }
300
301{METHODDEF}
302procedure start_pass_coef (cinfo : j_compress_ptr;
303                           pass_mode :  J_BUF_MODE); far;
304var
305  coef : my_coef_ptr;
306begin
307  coef := my_coef_ptr (cinfo^.coef);
308
309  if (pass_mode <> JBUF_CRANK_DEST) then
310    ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
311
312  coef^.iMCU_row_num := 0;
313  start_iMCU_row(cinfo);
314end;
315
316
317{ Process some data.
318  We process the equivalent of one fully interleaved MCU row ("iMCU" row)
319  per call, ie, v_samp_factor block rows for each component in the scan.
320  The data is obtained from the virtual arrays and fed to the entropy coder.
321  Returns TRUE if the iMCU row is completed, FALSE if suspended.
322
323  NB: input_buf is ignored; it is likely to be a NIL pointer. }
324
325{METHODDEF}
326function compress_output (cinfo : j_compress_ptr;
327                          input_buf : JSAMPIMAGE) : boolean; far;
328var
329  coef : my_coef_ptr;
330  MCU_col_num : JDIMENSION;     { index of current MCU within row }
331  last_MCU_col : JDIMENSION;
332  last_iMCU_row : JDIMENSION;
333  blkn, ci, xindex, yindex, yoffset, blockcnt : int;
334  start_col : JDIMENSION;
335  buffer : array[0..MAX_COMPS_IN_SCAN-1] of JBLOCKARRAY;
336  MCU_buffer : array[0..C_MAX_BLOCKS_IN_MCU-1] of JBLOCKROW;
337  buffer_ptr : JBLOCKROW;
338  compptr : jpeg_component_info_ptr;
339begin
340  coef := my_coef_ptr (cinfo^.coef);
341  last_MCU_col := cinfo^.MCUs_per_row - 1;
342  last_iMCU_row := cinfo^.total_iMCU_rows - 1;
343
344  { Align the virtual buffers for the components used in this scan. }
345  for ci := 0 to pred(cinfo^.comps_in_scan) do
346  begin
347    compptr := cinfo^.cur_comp_info[ci];
348    buffer[ci] := cinfo^.mem^.access_virt_barray
349      (j_common_ptr(cinfo), coef^.whole_image^[compptr^.component_index],
350       coef^.iMCU_row_num * compptr^.v_samp_factor,
351       JDIMENSION(compptr^.v_samp_factor), FALSE);
352  end;
353
354  { Loop to process one whole iMCU row }
355  for yoffset := coef^.MCU_vert_offset to pred(coef^.MCU_rows_per_iMCU_row) do
356  begin
357    for MCU_col_num := coef^.mcu_ctr to pred(cinfo^.MCUs_per_row) do
358    begin
359      { Construct list of pointers to DCT blocks belonging to this MCU }
360      blkn := 0;                        { index of current DCT block within MCU }
361      for ci := 0 to pred(cinfo^.comps_in_scan) do
362      begin
363        compptr := cinfo^.cur_comp_info[ci];
364        start_col := MCU_col_num * compptr^.MCU_width;
365        if (MCU_col_num < last_MCU_col) then
366          blockcnt := compptr^.MCU_width
367        else
368          blockcnt := compptr^.last_col_width;
369        for yindex := 0 to pred(compptr^.MCU_height) do
370        begin
371          if (coef^.iMCU_row_num < last_iMCU_row) or
372             (yindex+yoffset < compptr^.last_row_height) then
373          begin
374            { Fill in pointers to real blocks in this row }
375            buffer_ptr := JBLOCKROW(@ buffer[ci]^[yindex+yoffset]^[start_col]);
376            for xindex := 0 to pred(blockcnt) do
377            begin
378              MCU_buffer[blkn] := buffer_ptr;
379              Inc(blkn);
380              Inc(JBLOCK_PTR(buffer_ptr));
381            end;
382            xindex := blockcnt;
383          end
384          else
385          begin
386            { At bottom of image, need a whole row of dummy blocks }
387            xindex := 0;
388          end;
389          { Fill in any dummy blocks needed in this row.
390            Dummy blocks are filled in the same way as in jccoefct.c:
391            all zeroes in the AC entries, DC entries equal to previous
392            block's DC value.  The init routine has already zeroed the
393            AC entries, so we need only set the DC entries correctly. }
394
395          while (xindex < compptr^.MCU_width) do
396          begin
397            MCU_buffer[blkn] := coef^.dummy_buffer[blkn];
398            MCU_buffer[blkn]^[0][0] := MCU_buffer[blkn-1]^[0][0];
399            Inc(xindex);
400            Inc(blkn);
401          end;
402        end;
403      end;
404      { Try to write the MCU. }
405      if (not cinfo^.entropy^.encode_mcu (cinfo, MCU_buffer)) then
406      begin
407        { Suspension forced; update state counters and exit }
408        coef^.MCU_vert_offset := yoffset;
409        coef^.mcu_ctr := MCU_col_num;
410        compress_output := FALSE;
411        exit;
412      end;
413    end;
414    { Completed an MCU row, but perhaps not an iMCU row }
415    coef^.mcu_ctr := 0;
416  end;
417  { Completed the iMCU row, advance counters for next one }
418  Inc(coef^.iMCU_row_num);
419  start_iMCU_row(cinfo);
420  compress_output := TRUE;
421end;
422
423
424{ Initialize coefficient buffer controller.
425
426  Each passed coefficient array must be the right size for that
427  coefficient: width_in_blocks wide and height_in_blocks high,
428  with unitheight at least v_samp_factor. }
429
430{LOCAL}
431procedure transencode_coef_controller (cinfo : j_compress_ptr;
432                                       coef_arrays : jvirt_barray_tbl_ptr);
433var
434  coef : my_coef_ptr;
435  buffer : JBLOCKROW;
436  i : int;
437begin
438  coef := my_coef_ptr(
439    cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
440                                SIZEOF(my_coef_controller)));
441  cinfo^.coef := jpeg_c_coef_controller_ptr (coef);
442  coef^.pub.start_pass := start_pass_coef;
443  coef^.pub.compress_data := compress_output;
444
445  { Save pointer to virtual arrays }
446  coef^.whole_image := coef_arrays;
447
448  { Allocate and pre-zero space for dummy DCT blocks. }
449  buffer := JBLOCKROW(
450    cinfo^.mem^.alloc_large (j_common_ptr(cinfo), JPOOL_IMAGE,
451                                C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK)) );
452  jzero_far({FAR} voidp(buffer), C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK));
453  for i := 0 to pred(C_MAX_BLOCKS_IN_MCU) do
454  begin
455    coef^.dummy_buffer[i] := JBLOCKROW(@ buffer^[i]);
456  end;
457end;
458
459end.