//------------------------------------------------------------------------------
//
//  Portal Adventure - 2nd PGD Challenge: The Journey
//  Copyright (C) 2012 by Jim Valavanis
//
//  This program is free software; you can redistribute it and/or
//  modify it under the terms of the GNU General Public License
//  as published by the Free Software Foundation; either version 2
//  of the License, or (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
//  02111-1307, USA.
//
//------------------------------------------------------------------------------
//  E-Mail: jimmyvalavanis@yahoo.gr - jvalavanis@gmail.com
//------------------------------------------------------------------------------

{$I portal.inc}

unit jpg_dPostCt;

{ Original: jdpostct.c ; Copyright (C) 1994-1996, Thomas G. Lane. }

{ This file contains the decompression postprocessing controller.
  This controller manages the upsampling, color conversion, and color
  quantization/reduction steps; specifically, it controls the buffering
  between upsample/color conversion and color quantization/reduction.

  If no color quantization/reduction is required, then this module has no
  work to do, and it just hands off to the upsample/color conversion code.
  An integrated upsample/convert/quantize process would replace this module
  entirely. }

interface

uses
  jpg_morecfg,
  jpg_error,
  jpg_utils,
  jpg_lib;

{$I jconfig.inc}

{ Initialize postprocessing controller. }

{GLOBAL}
procedure jinit_d_post_controller (cinfo: j_decompress_ptr;
                                   need_full_buffer: boolean);
implementation

uses
  jpg_defErr;

{ Private buffer controller object }

type
  my_post_ptr = ^my_post_controller;
  my_post_controller = record
    pub: jpeg_d_post_controller; { public fields }

    { Color quantization source buffer: this holds output data from
      the upsample/color conversion step to be passed to the quantizer.
      For two-pass color quantization, we need a full-image buffer;
      for one-pass operation, a strip buffer is sufficient. }

    whole_image: jvirt_sarray_ptr;   { virtual array, or nil if one-pass }
    buffer: JSAMPARRAY;    { strip buffer, or current strip of virtual }
    strip_height: JDIMENSION;  { buffer size in rows }
    { for two-pass mode only: }
    starting_row: JDIMENSION;  { row # of first row in current strip }
    next_row: JDIMENSION;    { index of next row to fill/empty in strip }
  end;

{ Forward declarations }
{METHODDEF}
procedure post_process_1pass(cinfo: j_decompress_ptr; input_buf: JSAMPIMAGE;
  var in_row_group_ctr: JDIMENSION; in_row_groups_avail: JDIMENSION;
  output_buf: JSAMPARRAY; var out_row_ctr: JDIMENSION;
  out_rows_avail: JDIMENSION); far; forward;
{$ifdef QUANT_2PASS_SUPPORTED}
{METHODDEF}
procedure post_process_prepass(cinfo: j_decompress_ptr; input_buf: JSAMPIMAGE;
  var in_row_group_ctr: JDIMENSION; in_row_groups_avail: JDIMENSION;
  output_buf: JSAMPARRAY; var out_row_ctr: JDIMENSION;
  out_rows_avail: JDIMENSION); far;  forward;
{METHODDEF}
procedure post_process_2pass(cinfo: j_decompress_ptr;
                  input_buf: JSAMPIMAGE;
                             var in_row_group_ctr: JDIMENSION;
                 in_row_groups_avail: JDIMENSION;
                 output_buf: JSAMPARRAY;
                             var out_row_ctr: JDIMENSION;
                 out_rows_avail: JDIMENSION); far;  forward;
{$endif}


{ Initialize for a processing pass. }

{METHODDEF}
procedure start_pass_dpost (cinfo: j_decompress_ptr; pass_mode: J_BUF_MODE); far;
var
  post: my_post_ptr;
begin
  post := my_post_ptr(cinfo^.post);

  case (pass_mode) of
  JBUF_PASS_THRU:
    if (cinfo^.quantize_colors) then
    begin
      { Single-pass processing with color quantization. }
      post^.pub.post_process_data := post_process_1pass;
      { We could be doing buffered-image output before starting a 2-pass
        color quantization; in that case, jinit_d_post_controller did not
        allocate a strip buffer.  Use the virtual-array buffer as workspace. }
      if (post^.buffer = nil) then
      begin
  post^.buffer := cinfo^.mem^.access_virt_sarray
    (j_common_ptr(cinfo), post^.whole_image,
     JDIMENSION(0), post^.strip_height, TRUE);
      end;
    end
    else
    begin
      { For single-pass processing without color quantization,
        I have no work to do; just call the upsampler directly. }

      post^.pub.post_process_data := cinfo^.upsample^.upsample;
    end;

{$ifdef QUANT_2PASS_SUPPORTED}
  JBUF_SAVE_AND_PASS:
    begin
      { First pass of 2-pass quantization }
      if (post^.whole_image = nil) then
        ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
      post^.pub.post_process_data := post_process_prepass;
    end;
  JBUF_CRANK_DEST:
    begin
      { Second pass of 2-pass quantization }
      if (post^.whole_image = nil) then
        ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
      post^.pub.post_process_data := post_process_2pass;
    end;
{$endif} { QUANT_2PASS_SUPPORTED }
  else
    ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
  end;
  post^.next_row := 0;
  post^.starting_row := 0;
end;


{ Process some data in the one-pass (strip buffer) case.
  This is used for color precision reduction as well as one-pass quantization. }

{METHODDEF}
procedure post_process_1pass (cinfo: j_decompress_ptr; input_buf: JSAMPIMAGE;
  var in_row_group_ctr: JDIMENSION; in_row_groups_avail: JDIMENSION;
  output_buf: JSAMPARRAY; var out_row_ctr: JDIMENSION; out_rows_avail: JDIMENSION);
var
  post: my_post_ptr;
  num_rows, max_rows: JDIMENSION;
begin
  post := my_post_ptr (cinfo^.post);

  { Fill the buffer, but not more than what we can dump out in one go. }
  { Note we rely on the upsampler to detect bottom of image. }
  max_rows := out_rows_avail - out_row_ctr;
  if (max_rows > post^.strip_height) then
    max_rows := post^.strip_height;
  num_rows := 0;
  cinfo^.upsample^.upsample (cinfo,
                 input_buf,
                             in_row_group_ctr,
                             in_row_groups_avail,
                 post^.buffer,
                             num_rows,  { var }
                             max_rows);
  { Quantize and emit data. }

  cinfo^.cquantize^.color_quantize (cinfo,
    post^.buffer,
                JSAMPARRAY(@ output_buf^[out_row_ctr]),
                int(num_rows));

  Inc(out_row_ctr, num_rows);
end;


{$ifdef QUANT_2PASS_SUPPORTED}

{ Process some data in the first pass of 2-pass quantization. }

{METHODDEF}
procedure post_process_prepass(cinfo: j_decompress_ptr; input_buf: JSAMPIMAGE;
  var in_row_group_ctr: JDIMENSION; in_row_groups_avail: JDIMENSION;
  output_buf: JSAMPARRAY; var out_row_ctr: JDIMENSION; out_rows_avail:JDIMENSION);
var
  post: my_post_ptr;
  old_next_row, num_rows: JDIMENSION;
begin
  post := my_post_ptr(cinfo^.post);

  { Reposition virtual buffer if at start of strip. }
  if (post^.next_row = 0) then
  begin
    post^.buffer := cinfo^.mem^.access_virt_sarray
  (j_common_ptr(cinfo), post^.whole_image,
   post^.starting_row, post^.strip_height, TRUE);
  end;

  { Upsample some data (up to a strip height's worth). }
  old_next_row := post^.next_row;
  cinfo^.upsample^.upsample (cinfo,
    input_buf, in_row_group_ctr, in_row_groups_avail,
    post^.buffer, post^.next_row, post^.strip_height);

  { Allow quantizer to scan new data.  No data is emitted, }
  { but we advance out_row_ctr so outer loop can tell when we're done. }
  if (post^.next_row > old_next_row) then
  begin
    num_rows := post^.next_row - old_next_row;


    cinfo^.cquantize^.color_quantize (cinfo,
                      JSAMPARRAY(@ post^.buffer^[old_next_row]),
      JSAMPARRAY(nil),
                        int(num_rows));
    Inc(out_row_ctr, num_rows);
  end;

  { Advance if we filled the strip. }
  if (post^.next_row >= post^.strip_height) then
  begin
    Inc(post^.starting_row, post^.strip_height);
    post^.next_row := 0;
  end;
end;


{ Process some data in the second pass of 2-pass quantization. }

{METHODDEF}
procedure post_process_2pass(cinfo: j_decompress_ptr; input_buf: JSAMPIMAGE;
  var in_row_group_ctr: JDIMENSION; in_row_groups_avail: JDIMENSION;
  output_buf: JSAMPARRAY; var out_row_ctr: JDIMENSION; out_rows_avail: JDIMENSION);
var
  post: my_post_ptr;
  num_rows, max_rows: JDIMENSION;
begin
  post := my_post_ptr(cinfo^.post);

  { Reposition virtual buffer if at start of strip. }
  if (post^.next_row = 0) then
  begin
    post^.buffer := cinfo^.mem^.access_virt_sarray
  (j_common_ptr(cinfo), post^.whole_image,
   post^.starting_row, post^.strip_height, FALSE);
  end;

  { Determine number of rows to emit. }
  num_rows := post^.strip_height - post^.next_row; { available in strip }
  max_rows := out_rows_avail - out_row_ctr; { available in output area }
  if (num_rows > max_rows) then
    num_rows := max_rows;
  { We have to check bottom of image here, can't depend on upsampler. }
  max_rows := cinfo^.output_height - post^.starting_row;
  if (num_rows > max_rows) then
    num_rows := max_rows;

  { Quantize and emit data. }
  cinfo^.cquantize^.color_quantize (cinfo,
                JSAMPARRAY(@ post^.buffer^[post^.next_row]),
                JSAMPARRAY(@ output_buf^[out_row_ctr]),
    int(num_rows));
  Inc(out_row_ctr, num_rows);

  { Advance if we filled the strip. }
  Inc(post^.next_row, num_rows);
  if (post^.next_row >= post^.strip_height) then
  begin
    Inc(post^.starting_row, post^.strip_height);
    post^.next_row := 0;
  end;
end;

{$endif} { QUANT_2PASS_SUPPORTED }


{ Initialize postprocessing controller. }

{GLOBAL}
procedure jinit_d_post_controller (cinfo: j_decompress_ptr;
                                   need_full_buffer: boolean);
var
  post: my_post_ptr;
begin
  post := my_post_ptr(
    cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
        SizeOf(my_post_controller)) );
  cinfo^.post := jpeg_d_post_controller_ptr (post);
  post^.pub.start_pass := start_pass_dpost;
  post^.whole_image := nil;  { flag for no virtual arrays }
  post^.buffer := nil;    { flag for no strip buffer }

  { Create the quantization buffer, if needed }
  if (cinfo^.quantize_colors) then
  begin
    { The buffer strip height is max_v_samp_factor, which is typically
      an efficient number of rows for upsampling to return.
      (In the presence of output rescaling, we might want to be smarter?) }

    post^.strip_height := JDIMENSION (cinfo^.max_v_samp_factor);
    if (need_full_buffer) then
    begin
      { Two-pass color quantization: need full-image storage. }
      { We round up the number of rows to a multiple of the strip height. }
{$ifdef QUANT_2PASS_SUPPORTED}
      post^.whole_image := cinfo^.mem^.request_virt_sarray
        (j_common_ptr(cinfo), JPOOL_IMAGE, FALSE,
         cinfo^.output_width * cinfo^.out_color_components,
         JDIMENSION (jround_up( long(cinfo^.output_height),
        long(post^.strip_height)) ),
       post^.strip_height);
{$else}
      ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
{$endif} { QUANT_2PASS_SUPPORTED }
    end
    else
    begin
      { One-pass color quantization: just make a strip buffer. }
      post^.buffer := cinfo^.mem^.alloc_sarray
        (j_common_ptr (cinfo), JPOOL_IMAGE,
         cinfo^.output_width * cinfo^.out_color_components,
         post^.strip_height);
    end;
  end;
end;

end.
