Statistics
| Branch: | Tag: | Revision:

root / Imaging / JpegLib / imjccoefct.pas @ 0:95bd93c28625

History | View | Annotate | Download (18.2 kB)

1
unit imjccoefct;
2
3
{ This file contains the coefficient buffer controller for compression.
4
  This controller is the top level of the JPEG compressor proper.
5
  The coefficient buffer lies between forward-DCT and entropy encoding steps.}
6
7
{ Original: jccoefct.c; Copyright (C) 1994-1997, Thomas G. Lane. }
8
9
interface
10
11
{$I imjconfig.inc}
12
13
uses
14
  imjmorecfg,
15
  imjinclude,
16
  imjerror,
17
  imjdeferr,
18
  imjutils,
19
  imjpeglib;
20
21
{ We use a full-image coefficient buffer when doing Huffman optimization,
22
  and also for writing multiple-scan JPEG files.  In all cases, the DCT
23
  step is run during the first pass, and subsequent passes need only read
24
  the buffered coefficients. }
25
{$ifdef ENTROPY_OPT_SUPPORTED}
26
  {$define FULL_COEF_BUFFER_SUPPORTED}
27
{$else}
28
  {$ifdef C_MULTISCAN_FILES_SUPPORTED}
29
    {$define FULL_COEF_BUFFER_SUPPORTED}
30
  {$endif}
31
{$endif}
32
33
{ Initialize coefficient buffer controller. }
34
35
{GLOBAL}
36
procedure jinit_c_coef_controller (cinfo : j_compress_ptr;
37
                                   need_full_buffer : boolean);
38
39
implementation
40
41
{ Private buffer controller object }
42
43
type
44
  my_coef_ptr = ^my_coef_controller;
45
  my_coef_controller = record
46
    pub : jpeg_c_coef_controller; { public fields }
47
48
    iMCU_row_num : JDIMENSION;        { iMCU row # within image }
49
    mcu_ctr : JDIMENSION;        { counts MCUs processed in current row }
50
    MCU_vert_offset : int;        { counts MCU rows within iMCU row }
51
    MCU_rows_per_iMCU_row : int;  { number of such rows needed }
52
53
    { For single-pass compression, it's sufficient to buffer just one MCU
54
      (although this may prove a bit slow in practice).  We allocate a
55
      workspace of C_MAX_BLOCKS_IN_MCU coefficient blocks, and reuse it for each
56
      MCU constructed and sent.  (On 80x86, the workspace is FAR even though
57
      it's not really very big; this is to keep the module interfaces unchanged
58
      when a large coefficient buffer is necessary.)
59
      In multi-pass modes, this array points to the current MCU's blocks
60
      within the virtual arrays. }
61
62
    MCU_buffer : array[0..C_MAX_BLOCKS_IN_MCU-1] of JBLOCKROW;
63
64
    { In multi-pass modes, we need a virtual block array for each component. }
65
    whole_image : array[0..MAX_COMPONENTS-1] of jvirt_barray_ptr;
66
  end;
67
68
69
{ Forward declarations }
70
{METHODDEF}
71
function compress_data(cinfo : j_compress_ptr;
72
                       input_buf : JSAMPIMAGE) : boolean; forward;
73
{$ifdef FULL_COEF_BUFFER_SUPPORTED}
74
{METHODDEF}
75
function compress_first_pass(cinfo : j_compress_ptr;
76
                             input_buf : JSAMPIMAGE) : boolean;  forward;
77
{METHODDEF}
78
function compress_output(cinfo : j_compress_ptr;
79
                         input_buf : JSAMPIMAGE) : boolean;  forward;
80
{$endif}
81
82
83
{LOCAL}
84
procedure start_iMCU_row (cinfo : j_compress_ptr);
85
{ Reset within-iMCU-row counters for a new row }
86
var
87
  coef : my_coef_ptr;
88
begin
89
  coef := my_coef_ptr (cinfo^.coef);
90
91
  { In an interleaved scan, an MCU row is the same as an iMCU row.
92
    In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
93
    But at the bottom of the image, process only what's left. }
94
  if (cinfo^.comps_in_scan > 1) then
95
  begin
96
    coef^.MCU_rows_per_iMCU_row := 1;
97
  end
98
  else
99
  begin
100
    if (coef^.iMCU_row_num < (cinfo^.total_iMCU_rows-1)) then
101
      coef^.MCU_rows_per_iMCU_row := cinfo^.cur_comp_info[0]^.v_samp_factor
102
    else
103
      coef^.MCU_rows_per_iMCU_row := cinfo^.cur_comp_info[0]^.last_row_height;
104
  end;
105
106
  coef^.mcu_ctr := 0;
107
  coef^.MCU_vert_offset := 0;
108
end;
109
110
111
{ Initialize for a processing pass. }
112
113
{METHODDEF}
114
procedure start_pass_coef (cinfo : j_compress_ptr;
115
                           pass_mode : J_BUF_MODE);  
116
var
117
  coef : my_coef_ptr;
118
begin
119
  coef := my_coef_ptr (cinfo^.coef);
120
121
  coef^.iMCU_row_num := 0;
122
  start_iMCU_row(cinfo);
123
124
  case (pass_mode) of
125
  JBUF_PASS_THRU:
126
    begin
127
      if (coef^.whole_image[0] <> NIL) then
128
        ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
129
      coef^.pub.compress_data := compress_data;
130
    end;
131
{$ifdef FULL_COEF_BUFFER_SUPPORTED}
132
  JBUF_SAVE_AND_PASS:
133
    begin
134
      if (coef^.whole_image[0] = NIL) then
135
        ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
136
      coef^.pub.compress_data := compress_first_pass;
137
    end;
138
  JBUF_CRANK_DEST:
139
    begin
140
      if (coef^.whole_image[0] = NIL) then
141
        ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
142
      coef^.pub.compress_data := compress_output;
143
    end;
144
{$endif}
145
  else
146
    ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
147
  end;
148
end;
149
150
151
{ Process some data in the single-pass case.
152
  We process the equivalent of one fully interleaved MCU row ("iMCU" row)
153
  per call, ie, v_samp_factor block rows for each component in the image.
154
  Returns TRUE if the iMCU row is completed, FALSE if suspended.
155
156
  NB: input_buf contains a plane for each component in image,
157
  which we index according to the component's SOF position. }
158
159
160
{METHODDEF}
161
function compress_data (cinfo : j_compress_ptr;
162
                        input_buf : JSAMPIMAGE) : boolean;
163
var
164
  coef : my_coef_ptr;
165
  MCU_col_num : JDIMENSION;        { index of current MCU within row }
166
  last_MCU_col : JDIMENSION;
167
  last_iMCU_row : JDIMENSION;
168
  blkn, bi, ci, yindex, yoffset, blockcnt : int;
169
  ypos, xpos : JDIMENSION;
170
  compptr : jpeg_component_info_ptr;
171
begin
172
  coef := my_coef_ptr (cinfo^.coef);
173
  last_MCU_col := cinfo^.MCUs_per_row - 1;
174
  last_iMCU_row := cinfo^.total_iMCU_rows - 1;
175
176
  { Loop to write as much as one whole iMCU row }
177
  for yoffset := coef^.MCU_vert_offset to pred(coef^.MCU_rows_per_iMCU_row) do
178
  begin
179
    for MCU_col_num := coef^.mcu_ctr to last_MCU_col do
180
    begin
181
      { Determine where data comes from in input_buf and do the DCT thing.
182
        Each call on forward_DCT processes a horizontal row of DCT blocks
183
        as wide as an MCU; we rely on having allocated the MCU_buffer[] blocks
184
        sequentially.  Dummy blocks at the right or bottom edge are filled in
185
        specially.  The data in them does not matter for image reconstruction,
186
        so we fill them with values that will encode to the smallest amount of
187
        data, viz: all zeroes in the AC entries, DC entries equal to previous
188
        block's DC value.  (Thanks to Thomas Kinsman for this idea.) }
189
190
      blkn := 0;
191
      for ci := 0 to pred(cinfo^.comps_in_scan) do
192
      begin
193
        compptr := cinfo^.cur_comp_info[ci];
194
        if (MCU_col_num < last_MCU_col)  then
195
          blockcnt := compptr^.MCU_width
196
        else
197
          blockcnt := compptr^.last_col_width;
198
        xpos := MCU_col_num * JDIMENSION(compptr^.MCU_sample_width);
199
        ypos := yoffset * DCTSIZE;      { ypos = (yoffset+yindex) * DCTSIZE }
200
        for yindex := 0 to pred(compptr^.MCU_height) do
201
        begin
202
          if (coef^.iMCU_row_num < last_iMCU_row) or
203
             (yoffset+yindex < compptr^.last_row_height) then
204
          begin
205
            cinfo^.fdct^.forward_DCT (cinfo, compptr,
206
                                      input_buf^[compptr^.component_index],
207
                                      coef^.MCU_buffer[blkn],
208
                                      ypos, xpos, JDIMENSION (blockcnt));
209
210
            if (blockcnt < compptr^.MCU_width) then
211
            begin
212
              { Create some dummy blocks at the right edge of the image. }
213
              jzero_far({FAR}pointer(coef^.MCU_buffer[blkn + blockcnt]),
214
                        (compptr^.MCU_width - blockcnt) * SIZEOF(JBLOCK));
215
              for bi := blockcnt to pred(compptr^.MCU_width) do
216
              begin
217
                coef^.MCU_buffer[blkn+bi]^[0][0] := coef^.MCU_buffer[blkn+bi-1]^[0][0];
218
              end;
219
            end;
220
          end
221
          else
222
          begin
223
            { Create a row of dummy blocks at the bottom of the image. }
224
            jzero_far({FAR}pointer(coef^.MCU_buffer[blkn]),
225
                      compptr^.MCU_width * SIZEOF(JBLOCK));
226
            for bi := 0 to pred(compptr^.MCU_width) do
227
            begin
228
              coef^.MCU_buffer[blkn+bi]^[0][0] := coef^.MCU_buffer[blkn-1]^[0][0];
229
            end;
230
          end;
231
          Inc(blkn, compptr^.MCU_width);
232
          Inc(ypos, DCTSIZE);
233
        end;
234
      end;
235
      { Try to write the MCU.  In event of a suspension failure, we will
236
        re-DCT the MCU on restart (a bit inefficient, could be fixed...) }
237
238
      if (not cinfo^.entropy^.encode_mcu (cinfo, JBLOCKARRAY(@coef^.MCU_buffer)^)) then
239
      begin
240
        { Suspension forced; update state counters and exit }
241
        coef^.MCU_vert_offset := yoffset;
242
        coef^.mcu_ctr := MCU_col_num;
243
        compress_data := FALSE;
244
        exit;
245
      end;
246
    end;
247
    { Completed an MCU row, but perhaps not an iMCU row }
248
    coef^.mcu_ctr := 0;
249
  end;
250
  { Completed the iMCU row, advance counters for next one }
251
  Inc(coef^.iMCU_row_num);
252
  start_iMCU_row(cinfo);
253
  compress_data := TRUE;
254
end;
255
256
257
{$ifdef FULL_COEF_BUFFER_SUPPORTED}
258
259
{ Process some data in the first pass of a multi-pass case.
260
  We process the equivalent of one fully interleaved MCU row ("iMCU" row)
261
  per call, ie, v_samp_factor block rows for each component in the image.
262
  This amount of data is read from the source buffer, DCT'd and quantized,
263
  and saved into the virtual arrays.  We also generate suitable dummy blocks
264
  as needed at the right and lower edges.  (The dummy blocks are constructed
265
  in the virtual arrays, which have been padded appropriately.)  This makes
266
  it possible for subsequent passes not to worry about real vs. dummy blocks.
267
268
  We must also emit the data to the entropy encoder.  This is conveniently
269
  done by calling compress_output() after we've loaded the current strip
270
  of the virtual arrays.
271
272
  NB: input_buf contains a plane for each component in image.  All
273
  components are DCT'd and loaded into the virtual arrays in this pass.
274
  However, it may be that only a subset of the components are emitted to
275
  the entropy encoder during this first pass; be careful about looking
276
  at the scan-dependent variables (MCU dimensions, etc). }
277
278
{METHODDEF}
279
function compress_first_pass (cinfo : j_compress_ptr;
280
                              input_buf : JSAMPIMAGE) : boolean;
281
var
282
  coef : my_coef_ptr;
283
  last_iMCU_row : JDIMENSION;
284
  blocks_across, MCUs_across, MCUindex : JDIMENSION;
285
  bi, ci, h_samp_factor, block_row, block_rows, ndummy : int;
286
  lastDC : JCOEF;
287
  compptr : jpeg_component_info_ptr;
288
  buffer : JBLOCKARRAY;
289
  thisblockrow, lastblockrow : JBLOCKROW;
290
begin
291
  coef := my_coef_ptr (cinfo^.coef);
292
  last_iMCU_row := cinfo^.total_iMCU_rows - 1;
293
294
  compptr := jpeg_component_info_ptr(cinfo^.comp_info);
295
  for ci := 0 to pred(cinfo^.num_components) do
296
  begin
297
    { Align the virtual buffer for this component. }
298
    buffer := cinfo^.mem^.access_virt_barray
299
      (j_common_ptr(cinfo), coef^.whole_image[ci],
300
       coef^.iMCU_row_num * JDIMENSION(compptr^.v_samp_factor),
301
       JDIMENSION (compptr^.v_samp_factor), TRUE);
302
    { Count non-dummy DCT block rows in this iMCU row. }
303
    if (coef^.iMCU_row_num < last_iMCU_row) then
304
      block_rows := compptr^.v_samp_factor
305
    else
306
    begin
307
      { NB: can't use last_row_height here, since may not be set! }
308
      block_rows := int (compptr^.height_in_blocks) mod compptr^.v_samp_factor;
309
      if (block_rows = 0) then
310
        block_rows := compptr^.v_samp_factor;
311
    end;
312
    blocks_across := compptr^.width_in_blocks;
313
    h_samp_factor := compptr^.h_samp_factor;
314
    { Count number of dummy blocks to be added at the right margin. }
315
    ndummy := int (blocks_across) mod h_samp_factor;
316
    if (ndummy > 0) then
317
      ndummy := h_samp_factor - ndummy;
318
    { Perform DCT for all non-dummy blocks in this iMCU row.  Each call
319
      on forward_DCT processes a complete horizontal row of DCT blocks. }
320
321
    for block_row := 0 to pred(block_rows) do
322
    begin
323
      thisblockrow := buffer^[block_row];
324
      cinfo^.fdct^.forward_DCT (cinfo, compptr,
325
                                input_buf^[ci],
326
                                thisblockrow,
327
                                JDIMENSION (block_row * DCTSIZE),
328
                                JDIMENSION (0),
329
                                blocks_across);
330
      if (ndummy > 0) then
331
      begin
332
        { Create dummy blocks at the right edge of the image. }
333
        Inc(JBLOCK_PTR(thisblockrow), blocks_across); { => first dummy block }
334
        jzero_far({FAR}pointer(thisblockrow), ndummy * SIZEOF(JBLOCK));
335
        {lastDC := thisblockrow^[-1][0];}
336
        { work around Range Checking }
337
        Dec(JBLOCK_PTR(thisblockrow));
338
        lastDC := thisblockrow^[0][0];
339
        Inc(JBLOCK_PTR(thisblockrow));
340
341
        for bi := 0 to pred(ndummy) do
342
        begin
343
          thisblockrow^[bi][0] := lastDC;
344
        end;
345
      end;
346
    end;
347
    { If at end of image, create dummy block rows as needed.
348
      The tricky part here is that within each MCU, we want the DC values
349
      of the dummy blocks to match the last real block's DC value.
350
      This squeezes a few more bytes out of the resulting file... }
351
352
    if (coef^.iMCU_row_num = last_iMCU_row) then
353
    begin
354
      Inc(blocks_across, ndummy);       { include lower right corner }
355
      MCUs_across := blocks_across div JDIMENSION(h_samp_factor);
356
      for block_row := block_rows to pred(compptr^.v_samp_factor) do
357
      begin
358
        thisblockrow := buffer^[block_row];
359
        lastblockrow := buffer^[block_row-1];
360
        jzero_far({FAR} pointer(thisblockrow),
361
                  size_t(blocks_across * SIZEOF(JBLOCK)));
362
        for MCUindex := 0 to pred(MCUs_across) do
363
        begin
364
          lastDC := lastblockrow^[h_samp_factor-1][0];
365
          for bi := 0 to pred(h_samp_factor) do
366
          begin
367
            thisblockrow^[bi][0] := lastDC;
368
          end;
369
          Inc(JBLOCK_PTR(thisblockrow), h_samp_factor); { advance to next MCU in row }
370
          Inc(JBLOCK_PTR(lastblockrow), h_samp_factor);
371
        end;
372
      end;
373
    end;
374
    Inc(compptr);
375
  end;
376
  { NB: compress_output will increment iMCU_row_num if successful.
377
    A suspension return will result in redoing all the work above next time.}
378
379
380
  { Emit data to the entropy encoder, sharing code with subsequent passes }
381
  compress_first_pass := compress_output(cinfo, input_buf);
382
end;
383
384
385
{ Process some data in subsequent passes of a multi-pass case.
386
  We process the equivalent of one fully interleaved MCU row ("iMCU" row)
387
  per call, ie, v_samp_factor block rows for each component in the scan.
388
  The data is obtained from the virtual arrays and fed to the entropy coder.
389
  Returns TRUE if the iMCU row is completed, FALSE if suspended.
390
391
  NB: input_buf is ignored; it is likely to be a NIL pointer. }
392
393
{METHODDEF}
394
function compress_output (cinfo : j_compress_ptr;
395
                          input_buf : JSAMPIMAGE) : boolean;
396
var
397
  coef : my_coef_ptr;
398
  MCU_col_num : JDIMENSION;        { index of current MCU within row }
399
  blkn, ci, xindex, yindex, yoffset : int;
400
  start_col : JDIMENSION;
401
  buffer : array[0..MAX_COMPS_IN_SCAN-1] of JBLOCKARRAY;
402
  buffer_ptr : JBLOCKROW;
403
  compptr : jpeg_component_info_ptr;
404
begin
405
  coef := my_coef_ptr (cinfo^.coef);
406
407
  { Align the virtual buffers for the components used in this scan.
408
    NB: during first pass, this is safe only because the buffers will
409
    already be aligned properly, so jmemmgr.c won't need to do any I/O. }
410
411
  for ci := 0 to pred(cinfo^.comps_in_scan) do
412
  begin
413
    compptr := cinfo^.cur_comp_info[ci];
414
    buffer[ci] := cinfo^.mem^.access_virt_barray (
415
       j_common_ptr(cinfo), coef^.whole_image[compptr^.component_index],
416
       coef^.iMCU_row_num * JDIMENSION(compptr^.v_samp_factor),
417
       JDIMENSION (compptr^.v_samp_factor), FALSE);
418
  end;
419
420
  { Loop to process one whole iMCU row }
421
  for yoffset := coef^.MCU_vert_offset to pred(coef^.MCU_rows_per_iMCU_row) do
422
  begin
423
    for MCU_col_num := coef^.mcu_ctr to pred(cinfo^.MCUs_per_row) do
424
    begin
425
      { Construct list of pointers to DCT blocks belonging to this MCU }
426
      blkn := 0;                        { index of current DCT block within MCU }
427
      for ci := 0 to pred(cinfo^.comps_in_scan) do
428
      begin
429
        compptr := cinfo^.cur_comp_info[ci];
430
        start_col := MCU_col_num * JDIMENSION(compptr^.MCU_width);
431
        for yindex := 0 to pred(compptr^.MCU_height) do
432
        begin
433
          buffer_ptr := JBLOCKROW(@ buffer[ci]^[yindex+yoffset]^[start_col]);
434
          for xindex := 0 to pred(compptr^.MCU_width) do
435
          begin
436
            coef^.MCU_buffer[blkn] := buffer_ptr;
437
            Inc(blkn);
438
            Inc(JBLOCK_PTR(buffer_ptr));
439
          end;
440
        end;
441
      end;
442
      { Try to write the MCU. }
443
      if (not cinfo^.entropy^.encode_mcu (cinfo, coef^.MCU_buffer)) then
444
      begin
445
        { Suspension forced; update state counters and exit }
446
        coef^.MCU_vert_offset := yoffset;
447
        coef^.mcu_ctr := MCU_col_num;
448
        compress_output := FALSE;
449
        exit;
450
      end;
451
    end;
452
    { Completed an MCU row, but perhaps not an iMCU row }
453
    coef^.mcu_ctr := 0;
454
  end;
455
  { Completed the iMCU row, advance counters for next one }
456
  Inc(coef^.iMCU_row_num);
457
  start_iMCU_row(cinfo);
458
  compress_output := TRUE;
459
end;
460
461
{$endif} { FULL_COEF_BUFFER_SUPPORTED }
462
463
464
{ Initialize coefficient buffer controller. }
465
466
{GLOBAL}
467
procedure jinit_c_coef_controller (cinfo : j_compress_ptr;
468
                                   need_full_buffer : boolean);
469
var
470
  coef : my_coef_ptr;
471
var
472
  buffer : JBLOCKROW;
473
  i : int;
474
var
475
  ci : int;
476
  compptr : jpeg_component_info_ptr;
477
begin
478
  coef := my_coef_ptr (
479
    cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
480
                                SIZEOF(my_coef_controller)) );
481
  cinfo^.coef := jpeg_c_coef_controller_ptr(coef);
482
  coef^.pub.start_pass := start_pass_coef;
483
484
  { Create the coefficient buffer. }
485
  if (need_full_buffer) then
486
  begin
487
{$ifdef FULL_COEF_BUFFER_SUPPORTED}
488
    { Allocate a full-image virtual array for each component, }
489
    { padded to a multiple of samp_factor DCT blocks in each direction. }
490
491
    compptr := jpeg_component_info_ptr(cinfo^.comp_info);
492
    for ci := 0 to pred(cinfo^.num_components) do
493
    begin
494
      coef^.whole_image[ci] := cinfo^.mem^.request_virt_barray
495
        (j_common_ptr(cinfo), JPOOL_IMAGE, FALSE,
496
         JDIMENSION (jround_up( long (compptr^.width_in_blocks),
497
                                long (compptr^.h_samp_factor) )),
498
         JDIMENSION (jround_up(long (compptr^.height_in_blocks),
499
                                long (compptr^.v_samp_factor))),
500
         JDIMENSION (compptr^.v_samp_factor));
501
      Inc(compptr);
502
    end;
503
{$else}
504
    ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
505
{$endif}
506
  end
507
  else
508
  begin
509
    { We only need a single-MCU buffer. }
510
    buffer := JBLOCKROW (
511
      cinfo^.mem^.alloc_large (j_common_ptr(cinfo), JPOOL_IMAGE,
512
                                  C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK)) );
513
    for i := 0 to pred(C_MAX_BLOCKS_IN_MCU) do
514
    begin
515
      coef^.MCU_buffer[i] := JBLOCKROW(@ buffer^[i]);
516
    end;
517
    coef^.whole_image[0] := NIL; { flag for no virtual arrays }
518
  end;
519
end;
520
521
end.