2022-05-08 10:47:53 +02:00
|
|
|
unit imjdsample;
|
|
|
|
|
|
|
|
{ Original: jdsample.c; Copyright (C) 1991-1996, Thomas G. Lane. }
|
|
|
|
|
|
|
|
{ This file contains upsampling routines.
|
|
|
|
|
|
|
|
Upsampling input data is counted in "row groups". A row group
|
|
|
|
is defined to be (v_samp_factor * DCT_scaled_size / min_DCT_scaled_size)
|
|
|
|
sample rows of each component. Upsampling will normally produce
|
|
|
|
max_v_samp_factor pixel rows from each row group (but this could vary
|
|
|
|
if the upsampler is applying a scale factor of its own).
|
|
|
|
|
|
|
|
An excellent reference for image resampling is
|
|
|
|
Digital Image Warping, George Wolberg, 1990.
|
|
|
|
Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7.}
|
|
|
|
|
|
|
|
interface
|
|
|
|
|
|
|
|
{$I imjconfig.inc}
|
|
|
|
|
|
|
|
uses
|
|
|
|
imjmorecfg,
|
|
|
|
imjinclude,
|
|
|
|
imjutils,
|
|
|
|
imjpeglib,
|
|
|
|
imjdeferr,
|
|
|
|
imjerror;
|
|
|
|
|
|
|
|
|
|
|
|
{ Pointer to routine to upsample a single component }
|
|
|
|
type
|
|
|
|
upsample1_ptr = procedure (cinfo : j_decompress_ptr;
|
|
|
|
compptr : jpeg_component_info_ptr;
|
|
|
|
input_data : JSAMPARRAY;
|
|
|
|
var output_data_ptr : JSAMPARRAY);
|
|
|
|
|
|
|
|
{ Module initialization routine for upsampling. }
|
|
|
|
|
|
|
|
{GLOBAL}
|
|
|
|
procedure jinit_upsampler (cinfo : j_decompress_ptr);
|
|
|
|
|
|
|
|
implementation
|
|
|
|
|
|
|
|
{ Private subobject }
|
|
|
|
|
|
|
|
type
|
|
|
|
my_upsample_ptr = ^my_upsampler;
|
|
|
|
my_upsampler = record
|
|
|
|
pub : jpeg_upsampler; { public fields }
|
|
|
|
|
|
|
|
{ Color conversion buffer. When using separate upsampling and color
|
|
|
|
conversion steps, this buffer holds one upsampled row group until it
|
|
|
|
has been color converted and output.
|
|
|
|
Note: we do not allocate any storage for component(s) which are full-size,
|
|
|
|
ie do not need rescaling. The corresponding entry of color_buf[] is
|
|
|
|
simply set to point to the input data array, thereby avoiding copying.}
|
|
|
|
|
|
|
|
color_buf : array[0..MAX_COMPONENTS-1] of JSAMPARRAY;
|
|
|
|
|
|
|
|
{ Per-component upsampling method pointers }
|
|
|
|
methods : array[0..MAX_COMPONENTS-1] of upsample1_ptr;
|
|
|
|
|
|
|
|
next_row_out : int; { counts rows emitted from color_buf }
|
|
|
|
rows_to_go : JDIMENSION; { counts rows remaining in image }
|
|
|
|
|
|
|
|
{ Height of an input row group for each component. }
|
|
|
|
rowgroup_height : array[0..MAX_COMPONENTS-1] of int;
|
|
|
|
|
|
|
|
{ These arrays save pixel expansion factors so that int_expand need not
|
|
|
|
recompute them each time. They are unused for other upsampling methods.}
|
|
|
|
h_expand : array[0..MAX_COMPONENTS-1] of UINT8 ;
|
|
|
|
v_expand : array[0..MAX_COMPONENTS-1] of UINT8 ;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
{ Initialize for an upsampling pass. }
|
|
|
|
|
|
|
|
{METHODDEF}
|
|
|
|
procedure start_pass_upsample (cinfo : j_decompress_ptr);
|
|
|
|
var
|
|
|
|
upsample : my_upsample_ptr;
|
|
|
|
begin
|
|
|
|
upsample := my_upsample_ptr (cinfo^.upsample);
|
|
|
|
|
|
|
|
{ Mark the conversion buffer empty }
|
|
|
|
upsample^.next_row_out := cinfo^.max_v_samp_factor;
|
|
|
|
{ Initialize total-height counter for detecting bottom of image }
|
|
|
|
upsample^.rows_to_go := cinfo^.output_height;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
{ Control routine to do upsampling (and color conversion).
|
|
|
|
|
|
|
|
In this version we upsample each component independently.
|
|
|
|
We upsample one row group into the conversion buffer, then apply
|
|
|
|
color conversion a row at a time. }
|
|
|
|
|
|
|
|
{METHODDEF}
|
|
|
|
procedure sep_upsample (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
|
|
|
|
upsample : my_upsample_ptr;
|
|
|
|
ci : int;
|
|
|
|
compptr : jpeg_component_info_ptr;
|
|
|
|
num_rows : JDIMENSION;
|
|
|
|
begin
|
|
|
|
upsample := my_upsample_ptr (cinfo^.upsample);
|
|
|
|
|
|
|
|
{ Fill the conversion buffer, if it's empty }
|
|
|
|
if (upsample^.next_row_out >= cinfo^.max_v_samp_factor) then
|
|
|
|
begin
|
|
|
|
compptr := jpeg_component_info_ptr(cinfo^.comp_info);
|
|
|
|
for ci := 0 to pred(cinfo^.num_components) do
|
|
|
|
begin
|
|
|
|
{ Invoke per-component upsample method. Notice we pass a POINTER
|
|
|
|
to color_buf[ci], so that fullsize_upsample can change it. }
|
|
|
|
|
|
|
|
upsample^.methods[ci] (cinfo, compptr,
|
|
|
|
JSAMPARRAY(@ input_buf^[ci]^
|
|
|
|
[LongInt(in_row_group_ctr) * upsample^.rowgroup_height[ci]]),
|
|
|
|
upsample^.color_buf[ci]);
|
|
|
|
|
|
|
|
Inc(compptr);
|
|
|
|
end;
|
|
|
|
upsample^.next_row_out := 0;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{ Color-convert and emit rows }
|
|
|
|
|
|
|
|
{ How many we have in the buffer: }
|
|
|
|
num_rows := JDIMENSION (cinfo^.max_v_samp_factor - upsample^.next_row_out);
|
|
|
|
{ Not more than the distance to the end of the image. Need this test
|
|
|
|
in case the image height is not a multiple of max_v_samp_factor: }
|
|
|
|
|
|
|
|
if (num_rows > upsample^.rows_to_go) then
|
|
|
|
num_rows := upsample^.rows_to_go;
|
|
|
|
{ And not more than what the client can accept: }
|
|
|
|
Dec(out_rows_avail, out_row_ctr);
|
|
|
|
if (num_rows > out_rows_avail) then
|
|
|
|
num_rows := out_rows_avail;
|
|
|
|
|
|
|
|
cinfo^.cconvert^.color_convert (cinfo,
|
|
|
|
JSAMPIMAGE(@(upsample^.color_buf)),
|
|
|
|
JDIMENSION (upsample^.next_row_out),
|
|
|
|
JSAMPARRAY(@(output_buf^[out_row_ctr])),
|
|
|
|
int (num_rows));
|
|
|
|
|
|
|
|
{ Adjust counts }
|
|
|
|
Inc(out_row_ctr, num_rows);
|
|
|
|
Dec(upsample^.rows_to_go, num_rows);
|
|
|
|
Inc(upsample^.next_row_out, num_rows);
|
|
|
|
{ When the buffer is emptied, declare this input row group consumed }
|
|
|
|
if (upsample^.next_row_out >= cinfo^.max_v_samp_factor) then
|
|
|
|
Inc(in_row_group_ctr);
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
{ These are the routines invoked by sep_upsample to upsample pixel values
|
|
|
|
of a single component. One row group is processed per call. }
|
|
|
|
|
|
|
|
|
|
|
|
{ For full-size components, we just make color_buf[ci] point at the
|
|
|
|
input buffer, and thus avoid copying any data. Note that this is
|
|
|
|
safe only because sep_upsample doesn't declare the input row group
|
|
|
|
"consumed" until we are done color converting and emitting it. }
|
|
|
|
|
|
|
|
{METHODDEF}
|
|
|
|
procedure fullsize_upsample (cinfo : j_decompress_ptr;
|
|
|
|
compptr : jpeg_component_info_ptr;
|
|
|
|
input_data : JSAMPARRAY;
|
|
|
|
var output_data_ptr : JSAMPARRAY);
|
|
|
|
begin
|
|
|
|
output_data_ptr := input_data;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
{ This is a no-op version used for "uninteresting" components.
|
|
|
|
These components will not be referenced by color conversion. }
|
|
|
|
|
|
|
|
{METHODDEF}
|
|
|
|
procedure noop_upsample (cinfo : j_decompress_ptr;
|
|
|
|
compptr : jpeg_component_info_ptr;
|
|
|
|
input_data : JSAMPARRAY;
|
|
|
|
var output_data_ptr : JSAMPARRAY);
|
|
|
|
begin
|
|
|
|
output_data_ptr := NIL; { safety check }
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
{ This version handles any integral sampling ratios.
|
|
|
|
This is not used for typical JPEG files, so it need not be fast.
|
|
|
|
Nor, for that matter, is it particularly accurate: the algorithm is
|
|
|
|
simple replication of the input pixel onto the corresponding output
|
|
|
|
pixels. The hi-falutin sampling literature refers to this as a
|
|
|
|
"box filter". A box filter tends to introduce visible artifacts,
|
|
|
|
so if you are actually going to use 3:1 or 4:1 sampling ratios
|
|
|
|
you would be well advised to improve this code. }
|
|
|
|
|
|
|
|
{METHODDEF}
|
|
|
|
procedure int_upsample (cinfo : j_decompress_ptr;
|
|
|
|
compptr : jpeg_component_info_ptr;
|
|
|
|
input_data : JSAMPARRAY;
|
|
|
|
var output_data_ptr : JSAMPARRAY);
|
|
|
|
var
|
|
|
|
upsample : my_upsample_ptr;
|
|
|
|
output_data : JSAMPARRAY;
|
|
|
|
{register} inptr, outptr : JSAMPLE_PTR;
|
|
|
|
{register} invalue : JSAMPLE;
|
|
|
|
{register} h : int;
|
|
|
|
{outend}
|
|
|
|
h_expand, v_expand : int;
|
|
|
|
inrow, outrow : int;
|
|
|
|
var
|
|
|
|
outcount : int; { Nomssi: avoid pointer arithmetic }
|
|
|
|
begin
|
|
|
|
upsample := my_upsample_ptr (cinfo^.upsample);
|
|
|
|
output_data := output_data_ptr;
|
|
|
|
|
|
|
|
h_expand := upsample^.h_expand[compptr^.component_index];
|
|
|
|
v_expand := upsample^.v_expand[compptr^.component_index];
|
|
|
|
|
|
|
|
inrow := 0;
|
|
|
|
outrow := 0;
|
|
|
|
while (outrow < cinfo^.max_v_samp_factor) do
|
|
|
|
begin
|
|
|
|
{ Generate one output row with proper horizontal expansion }
|
|
|
|
inptr := JSAMPLE_PTR(input_data^[inrow]);
|
|
|
|
outptr := JSAMPLE_PTR(output_data^[outrow]);
|
|
|
|
outcount := cinfo^.output_width;
|
|
|
|
while (outcount > 0) do { Nomssi }
|
|
|
|
begin
|
|
|
|
invalue := inptr^; { don't need GETJSAMPLE() here }
|
|
|
|
Inc(inptr);
|
|
|
|
for h := pred(h_expand) downto 0 do
|
|
|
|
begin
|
|
|
|
outptr^ := invalue;
|
|
|
|
inc(outptr); { <-- fix: this was left out in PasJpeg 1.0 }
|
|
|
|
Dec(outcount); { thanks to Jannie Gerber for the report }
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{ Generate any additional output rows by duplicating the first one }
|
|
|
|
if (v_expand > 1) then
|
|
|
|
begin
|
|
|
|
jcopy_sample_rows(output_data, outrow, output_data, outrow+1,
|
|
|
|
v_expand-1, cinfo^.output_width);
|
|
|
|
end;
|
|
|
|
Inc(inrow);
|
|
|
|
Inc(outrow, v_expand);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
{ Fast processing for the common case of 2:1 horizontal and 1:1 vertical.
|
|
|
|
It's still a box filter. }
|
|
|
|
|
|
|
|
{METHODDEF}
|
|
|
|
procedure h2v1_upsample (cinfo : j_decompress_ptr;
|
|
|
|
compptr : jpeg_component_info_ptr;
|
|
|
|
input_data : JSAMPARRAY;
|
|
|
|
var output_data_ptr : JSAMPARRAY);
|
|
|
|
var
|
|
|
|
output_data : JSAMPARRAY;
|
|
|
|
{register} inptr, outptr : JSAMPLE_PTR;
|
|
|
|
{register} invalue : JSAMPLE;
|
|
|
|
{outend : JSAMPROW;}
|
|
|
|
outcount : int;
|
|
|
|
inrow : int;
|
|
|
|
begin
|
|
|
|
output_data := output_data_ptr;
|
|
|
|
|
|
|
|
for inrow := 0 to pred(cinfo^.max_v_samp_factor) do
|
|
|
|
begin
|
|
|
|
inptr := JSAMPLE_PTR(input_data^[inrow]);
|
|
|
|
outptr := JSAMPLE_PTR(output_data^[inrow]);
|
|
|
|
{outend := outptr + cinfo^.output_width;}
|
|
|
|
outcount := cinfo^.output_width;
|
|
|
|
while (outcount > 0) do
|
|
|
|
begin
|
|
|
|
invalue := inptr^; { don't need GETJSAMPLE() here }
|
|
|
|
Inc(inptr);
|
|
|
|
outptr^ := invalue;
|
|
|
|
Inc(outptr);
|
|
|
|
outptr^ := invalue;
|
|
|
|
Inc(outptr);
|
|
|
|
Dec(outcount, 2); { Nomssi: to avoid pointer arithmetic }
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
{ Fast processing for the common case of 2:1 horizontal and 2:1 vertical.
|
|
|
|
It's still a box filter. }
|
|
|
|
|
|
|
|
{METHODDEF}
|
|
|
|
procedure h2v2_upsample (cinfo : j_decompress_ptr;
|
|
|
|
compptr : jpeg_component_info_ptr;
|
|
|
|
input_data : JSAMPARRAY;
|
|
|
|
var output_data_ptr : JSAMPARRAY);
|
|
|
|
var
|
|
|
|
output_data : JSAMPARRAY;
|
|
|
|
{register} inptr, outptr : JSAMPLE_PTR;
|
|
|
|
{register} invalue : JSAMPLE;
|
|
|
|
{outend : JSAMPROW;}
|
|
|
|
outcount : int;
|
|
|
|
inrow, outrow : int;
|
|
|
|
begin
|
|
|
|
output_data := output_data_ptr;
|
|
|
|
|
|
|
|
inrow := 0;
|
|
|
|
outrow := 0;
|
|
|
|
while (outrow < cinfo^.max_v_samp_factor) do
|
|
|
|
begin
|
|
|
|
inptr := JSAMPLE_PTR(input_data^[inrow]);
|
|
|
|
outptr := JSAMPLE_PTR(output_data^[outrow]);
|
|
|
|
{outend := outptr + cinfo^.output_width;}
|
|
|
|
outcount := cinfo^.output_width;
|
|
|
|
while (outcount > 0) do
|
|
|
|
begin
|
|
|
|
invalue := inptr^; { don't need GETJSAMPLE() here }
|
|
|
|
Inc(inptr);
|
|
|
|
outptr^ := invalue;
|
|
|
|
Inc(outptr);
|
|
|
|
outptr^ := invalue;
|
|
|
|
Inc(outptr);
|
|
|
|
Dec(outcount, 2);
|
|
|
|
end;
|
|
|
|
jcopy_sample_rows(output_data, outrow, output_data, outrow+1,
|
|
|
|
1, cinfo^.output_width);
|
|
|
|
Inc(inrow);
|
|
|
|
Inc(outrow, 2);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
{ Fancy processing for the common case of 2:1 horizontal and 1:1 vertical.
|
|
|
|
|
|
|
|
The upsampling algorithm is linear interpolation between pixel centers,
|
|
|
|
also known as a "triangle filter". This is a good compromise between
|
|
|
|
speed and visual quality. The centers of the output pixels are 1/4 and 3/4
|
|
|
|
of the way between input pixel centers.
|
|
|
|
|
|
|
|
A note about the "bias" calculations: when rounding fractional values to
|
|
|
|
integer, we do not want to always round 0.5 up to the next integer.
|
|
|
|
If we did that, we'd introduce a noticeable bias towards larger values.
|
|
|
|
Instead, this code is arranged so that 0.5 will be rounded up or down at
|
|
|
|
alternate pixel locations (a simple ordered dither pattern). }
|
|
|
|
|
|
|
|
{METHODDEF}
|
|
|
|
procedure h2v1_fancy_upsample (cinfo : j_decompress_ptr;
|
|
|
|
compptr : jpeg_component_info_ptr;
|
|
|
|
input_data : JSAMPARRAY;
|
|
|
|
var output_data_ptr : JSAMPARRAY);
|
|
|
|
var
|
|
|
|
output_data : JSAMPARRAY;
|
|
|
|
{register} pre_inptr, inptr, outptr : JSAMPLE_PTR;
|
|
|
|
{register} invalue : int;
|
|
|
|
{register} colctr : JDIMENSION;
|
|
|
|
inrow : int;
|
|
|
|
begin
|
|
|
|
output_data := output_data_ptr;
|
|
|
|
|
|
|
|
for inrow := 0 to pred(cinfo^.max_v_samp_factor) do
|
|
|
|
begin
|
|
|
|
inptr := JSAMPLE_PTR(input_data^[inrow]);
|
|
|
|
outptr := JSAMPLE_PTR(output_data^[inrow]);
|
|
|
|
{ Special case for first column }
|
|
|
|
pre_inptr := inptr;
|
|
|
|
invalue := GETJSAMPLE(inptr^);
|
|
|
|
Inc(inptr);
|
|
|
|
outptr^ := JSAMPLE (invalue);
|
|
|
|
Inc(outptr);
|
|
|
|
outptr^ := JSAMPLE ((invalue * 3 + GETJSAMPLE(inptr^) + 2) shr 2);
|
|
|
|
Inc(outptr);
|
|
|
|
|
|
|
|
for colctr := pred(compptr^.downsampled_width - 2) downto 0 do
|
|
|
|
begin
|
|
|
|
{ General case: 3/4 * nearer pixel + 1/4 * further pixel }
|
|
|
|
invalue := GETJSAMPLE(inptr^) * 3;
|
|
|
|
Inc(inptr);
|
|
|
|
outptr^ := JSAMPLE ((invalue + GETJSAMPLE(pre_inptr^) + 1) shr 2);
|
|
|
|
Inc(pre_inptr);
|
|
|
|
Inc(outptr);
|
|
|
|
outptr^ := JSAMPLE ((invalue + GETJSAMPLE(inptr^) + 2) shr 2);
|
|
|
|
Inc(outptr);
|
|
|
|
end;
|
|
|
|
|
|
|
|
{ Special case for last column }
|
|
|
|
invalue := GETJSAMPLE(inptr^);
|
|
|
|
outptr^ := JSAMPLE ((invalue * 3 + GETJSAMPLE(pre_inptr^) + 1) shr 2);
|
|
|
|
Inc(outptr);
|
|
|
|
outptr^ := JSAMPLE (invalue);
|
|
|
|
{Inc(outptr); - value never used }
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
{ Fancy processing for the common case of 2:1 horizontal and 2:1 vertical.
|
|
|
|
Again a triangle filter; see comments for h2v1 case, above.
|
|
|
|
|
|
|
|
It is OK for us to reference the adjacent input rows because we demanded
|
|
|
|
context from the main buffer controller (see initialization code). }
|
|
|
|
|
|
|
|
{METHODDEF}
|
|
|
|
procedure h2v2_fancy_upsample (cinfo : j_decompress_ptr;
|
|
|
|
compptr : jpeg_component_info_ptr;
|
|
|
|
input_data : JSAMPARRAY;
|
|
|
|
var output_data_ptr : JSAMPARRAY);
|
|
|
|
var
|
|
|
|
output_data : JSAMPARRAY;
|
|
|
|
{register} inptr0, inptr1, outptr : JSAMPLE_PTR;
|
|
|
|
{$ifdef BITS_IN_JSAMPLE_IS_8}
|
|
|
|
{register} thiscolsum, lastcolsum, nextcolsum : int;
|
|
|
|
{$else}
|
|
|
|
{register} thiscolsum, lastcolsum, nextcolsum : INT32;
|
|
|
|
{$endif}
|
|
|
|
{register} colctr : JDIMENSION;
|
|
|
|
inrow, outrow, v : int;
|
|
|
|
var
|
|
|
|
prev_input_data : JSAMPARRAY; { Nomssi work around }
|
|
|
|
begin
|
|
|
|
output_data := output_data_ptr;
|
|
|
|
|
|
|
|
outrow := 0;
|
|
|
|
inrow := 0;
|
|
|
|
while (outrow < cinfo^.max_v_samp_factor) do
|
|
|
|
begin
|
|
|
|
for v := 0 to pred(2) do
|
|
|
|
begin
|
|
|
|
{ inptr0 points to nearest input row, inptr1 points to next nearest }
|
|
|
|
inptr0 := JSAMPLE_PTR(input_data^[inrow]);
|
|
|
|
if (v = 0) then { next nearest is row above }
|
|
|
|
begin
|
|
|
|
{inptr1 := JSAMPLE_PTR(input_data^[inrow-1]);}
|
|
|
|
prev_input_data := input_data; { work around }
|
|
|
|
Dec(JSAMPROW_PTR(prev_input_data)); { negative offsets }
|
|
|
|
inptr1 := JSAMPLE_PTR(prev_input_data^[inrow]);
|
|
|
|
end
|
|
|
|
else { next nearest is row below }
|
|
|
|
inptr1 := JSAMPLE_PTR(input_data^[inrow+1]);
|
|
|
|
outptr := JSAMPLE_PTR(output_data^[outrow]);
|
|
|
|
Inc(outrow);
|
|
|
|
|
|
|
|
{ Special case for first column }
|
|
|
|
thiscolsum := GETJSAMPLE(inptr0^) * 3 + GETJSAMPLE(inptr1^);
|
|
|
|
Inc(inptr0);
|
|
|
|
Inc(inptr1);
|
|
|
|
nextcolsum := GETJSAMPLE(inptr0^) * 3 + GETJSAMPLE(inptr1^);
|
|
|
|
Inc(inptr0);
|
|
|
|
Inc(inptr1);
|
|
|
|
|
|
|
|
outptr^ := JSAMPLE ((thiscolsum * 4 + 8) shr 4);
|
|
|
|
Inc(outptr);
|
|
|
|
outptr^ := JSAMPLE ((thiscolsum * 3 + nextcolsum + 7) shr 4);
|
|
|
|
Inc(outptr);
|
|
|
|
lastcolsum := thiscolsum; thiscolsum := nextcolsum;
|
|
|
|
|
|
|
|
for colctr := pred(compptr^.downsampled_width - 2) downto 0 do
|
|
|
|
begin
|
|
|
|
{ General case: 3/4 * nearer pixel + 1/4 * further pixel in each }
|
|
|
|
{ dimension, thus 9/16, 3/16, 3/16, 1/16 overall }
|
|
|
|
nextcolsum := GETJSAMPLE(inptr0^) * 3 + GETJSAMPLE(inptr1^);
|
|
|
|
Inc(inptr0);
|
|
|
|
Inc(inptr1);
|
|
|
|
outptr^ := JSAMPLE ((thiscolsum * 3 + lastcolsum + 8) shr 4);
|
|
|
|
Inc(outptr);
|
|
|
|
outptr^ := JSAMPLE ((thiscolsum * 3 + nextcolsum + 7) shr 4);
|
|
|
|
Inc(outptr);
|
|
|
|
lastcolsum := thiscolsum;
|
|
|
|
thiscolsum := nextcolsum;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{ Special case for last column }
|
|
|
|
outptr^ := JSAMPLE ((thiscolsum * 3 + lastcolsum + 8) shr 4);
|
|
|
|
Inc(outptr);
|
|
|
|
outptr^ := JSAMPLE ((thiscolsum * 4 + 7) shr 4);
|
|
|
|
{Inc(outptr); - value never used }
|
|
|
|
end;
|
|
|
|
Inc(inrow);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
{ Module initialization routine for upsampling. }
|
|
|
|
|
|
|
|
{GLOBAL}
|
|
|
|
procedure jinit_upsampler (cinfo : j_decompress_ptr);
|
|
|
|
var
|
|
|
|
upsample : my_upsample_ptr;
|
|
|
|
ci : int;
|
|
|
|
compptr : jpeg_component_info_ptr;
|
|
|
|
need_buffer, do_fancy : boolean;
|
|
|
|
h_in_group, v_in_group, h_out_group, v_out_group : int;
|
|
|
|
begin
|
|
|
|
upsample := my_upsample_ptr (
|
|
|
|
cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
|
|
|
|
SIZEOF(my_upsampler)) );
|
|
|
|
cinfo^.upsample := jpeg_upsampler_ptr (upsample);
|
|
|
|
upsample^.pub.start_pass := start_pass_upsample;
|
|
|
|
upsample^.pub.upsample := sep_upsample;
|
|
|
|
upsample^.pub.need_context_rows := FALSE; { until we find out differently }
|
|
|
|
|
|
|
|
if (cinfo^.CCIR601_sampling) then { this isn't supported }
|
|
|
|
ERREXIT(j_common_ptr(cinfo), JERR_CCIR601_NOTIMPL);
|
|
|
|
|
|
|
|
{ jdmainct.c doesn't support context rows when min_DCT_scaled_size := 1,
|
|
|
|
so don't ask for it. }
|
|
|
|
|
|
|
|
do_fancy := cinfo^.do_fancy_upsampling and (cinfo^.min_DCT_scaled_size > 1);
|
|
|
|
|
|
|
|
{ Verify we can handle the sampling factors, select per-component methods,
|
|
|
|
and create storage as needed. }
|
|
|
|
|
|
|
|
compptr := jpeg_component_info_ptr(cinfo^.comp_info);
|
|
|
|
for ci := 0 to pred(cinfo^.num_components) do
|
|
|
|
begin
|
|
|
|
{ Compute size of an "input group" after IDCT scaling. This many samples
|
|
|
|
are to be converted to max_h_samp_factor * max_v_samp_factor pixels. }
|
|
|
|
|
|
|
|
h_in_group := (compptr^.h_samp_factor * compptr^.DCT_scaled_size) div
|
|
|
|
cinfo^.min_DCT_scaled_size;
|
|
|
|
v_in_group := (compptr^.v_samp_factor * compptr^.DCT_scaled_size) div
|
|
|
|
cinfo^.min_DCT_scaled_size;
|
|
|
|
h_out_group := cinfo^.max_h_samp_factor;
|
|
|
|
v_out_group := cinfo^.max_v_samp_factor;
|
|
|
|
upsample^.rowgroup_height[ci] := v_in_group; { save for use later }
|
|
|
|
need_buffer := TRUE;
|
|
|
|
if (not compptr^.component_needed) then
|
|
|
|
begin
|
|
|
|
{ Don't bother to upsample an uninteresting component. }
|
|
|
|
upsample^.methods[ci] := noop_upsample;
|
|
|
|
need_buffer := FALSE;
|
|
|
|
end
|
|
|
|
else
|
|
|
|
if (h_in_group = h_out_group) and (v_in_group = v_out_group) then
|
|
|
|
begin
|
|
|
|
{ Fullsize components can be processed without any work. }
|
|
|
|
upsample^.methods[ci] := fullsize_upsample;
|
|
|
|
need_buffer := FALSE;
|
|
|
|
end
|
|
|
|
else
|
|
|
|
if (h_in_group * 2 = h_out_group) and
|
|
|
|
(v_in_group = v_out_group) then
|
|
|
|
begin
|
|
|
|
{ Special cases for 2h1v upsampling }
|
|
|
|
if (do_fancy) and (compptr^.downsampled_width > 2) then
|
|
|
|
upsample^.methods[ci] := h2v1_fancy_upsample
|
|
|
|
else
|
|
|
|
upsample^.methods[ci] := h2v1_upsample;
|
|
|
|
end
|
|
|
|
else
|
|
|
|
if (h_in_group * 2 = h_out_group) and
|
|
|
|
(v_in_group * 2 = v_out_group) then
|
|
|
|
begin
|
|
|
|
{ Special cases for 2h2v upsampling }
|
|
|
|
if (do_fancy) and (compptr^.downsampled_width > 2) then
|
|
|
|
begin
|
|
|
|
upsample^.methods[ci] := h2v2_fancy_upsample;
|
|
|
|
upsample^.pub.need_context_rows := TRUE;
|
|
|
|
end
|
|
|
|
else
|
|
|
|
upsample^.methods[ci] := h2v2_upsample;
|
|
|
|
end
|
|
|
|
else
|
|
|
|
if ((h_out_group mod h_in_group) = 0) and
|
|
|
|
((v_out_group mod v_in_group) = 0) then
|
|
|
|
begin
|
|
|
|
{ Generic integral-factors upsampling method }
|
|
|
|
upsample^.methods[ci] := int_upsample;
|
|
|
|
upsample^.h_expand[ci] := UINT8 (h_out_group div h_in_group);
|
|
|
|
upsample^.v_expand[ci] := UINT8 (v_out_group div v_in_group);
|
|
|
|
end
|
|
|
|
else
|
|
|
|
ERREXIT(j_common_ptr(cinfo), JERR_FRACT_SAMPLE_NOTIMPL);
|
|
|
|
if (need_buffer) then
|
|
|
|
begin
|
|
|
|
upsample^.color_buf[ci] := cinfo^.mem^.alloc_sarray
|
|
|
|
(j_common_ptr(cinfo), JPOOL_IMAGE,
|
|
|
|
JDIMENSION (jround_up( long (cinfo^.output_width),
|
|
|
|
long (cinfo^.max_h_samp_factor))),
|
|
|
|
JDIMENSION (cinfo^.max_v_samp_factor));
|
|
|
|
end;
|
|
|
|
Inc(compptr);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
end.
|