123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514 |
- Unit JdMerge;
- { This file contains code for merged upsampling/color conversion.
- This file combines functions from jdsample.c and jdcolor.c;
- read those files first to understand what's going on.
- When the chroma components are to be upsampled by simple replication
- (ie, box filtering), we can save some work in color conversion by
- calculating all the output pixels corresponding to a pair of chroma
- samples at one time. In the conversion equations
- R := Y + K1 * Cr
- G := Y + K2 * Cb + K3 * Cr
- B := Y + K4 * Cb
- only the Y term varies among the group of pixels corresponding to a pair
- of chroma samples, so the rest of the terms can be calculated just once.
- At typical sampling ratios, this eliminates half or three-quarters of the
- multiplications needed for color conversion.
- This file currently provides implementations for the following cases:
- YCbCr => RGB color conversion only.
- Sampling ratios of 2h1v or 2h2v.
- No scaling needed at upsample time.
- Corner-aligned (non-CCIR601) sampling alignment.
- Other special cases could be added, but in most applications these are
- the only common cases. (For uncommon cases we fall back on the more
- general code in jdsample.c and jdcolor.c.) }
- { Original: jdmerge.c ; Copyright (C) 1994-1996, Thomas G. Lane. }
- interface
- {$I jconfig.inc}
- uses
- jmorecfg,
- jinclude,
- jpeglib,
- jutils;
- { Module initialization routine for merged upsampling/color conversion.
- NB: this is called under the conditions determined by use_merged_upsample()
- in jdmaster.c. That routine MUST correspond to the actual capabilities
- of this module; no safety checks are made here. }
- {GLOBAL}
- procedure jinit_merged_upsampler (cinfo : j_decompress_ptr);
- implementation
- { Private subobject }
- type { the same definition as in JdColor }
- int_Color_Table = array[0..MAXJSAMPLE+1-1] of int;
- int_CConvertPtr = ^int_Color_Table;
- INT32_Color_Table = array[0..MAXJSAMPLE+1-1] of INT32;
- INT32_CConvertPtr = ^INT32_Color_Table;
- type
- my_upsample_ptr = ^my_upsampler;
- my_upsampler = record
- pub : jpeg_upsampler; { public fields }
- { Pointer to routine to do actual upsampling/conversion of one row group }
- upmethod : procedure (cinfo : j_decompress_ptr;
- input_buf : JSAMPIMAGE;
- in_row_group_ctr : JDIMENSION;
- output_buf : JSAMPARRAY);
- { Private state for YCC->RGB conversion }
- Cr_r_tab : int_CConvertPtr; { => table for Cr to R conversion }
- Cb_b_tab : int_CConvertPtr; { => table for Cb to B conversion }
- Cr_g_tab : INT32_CConvertPtr; { => table for Cr to G conversion }
- Cb_g_tab : INT32_CConvertPtr; { => table for Cb to G conversion }
- { For 2:1 vertical sampling, we produce two output rows at a time.
- We need a "spare" row buffer to hold the second output row if the
- application provides just a one-row buffer; we also use the spare
- to discard the dummy last row if the image height is odd. }
- spare_row : JSAMPROW;
- spare_full : boolean; { TRUE if spare buffer is occupied }
- out_row_width : JDIMENSION; { samples per output row }
- rows_to_go : JDIMENSION; { counts rows remaining in image }
- end; {my_upsampler;}
- const
- SCALEBITS = 16; { speediest right-shift on some machines }
- ONE_HALF = (INT32(1) shl (SCALEBITS-1));
- { Initialize tables for YCC->RGB colorspace conversion.
- This is taken directly from jdcolor.c; see that file for more info. }
- {LOCAL}
- procedure build_ycc_rgb_table (cinfo : j_decompress_ptr);
- const
- FIX_1_40200 = INT32( Round(1.40200 * (INT32(1) shl SCALEBITS)) );
- FIX_1_77200 = INT32( Round(1.77200 * (INT32(1) shl SCALEBITS)) );
- FIX_0_71414 = INT32( Round(0.71414 * (INT32(1) shl SCALEBITS)) );
- FIX_0_34414 = INT32( Round(0.34414 * (INT32(1) shl SCALEBITS)) );
- var
- upsample : my_upsample_ptr;
- i : int;
- x : INT32;
- var
- shift_temp : INT32;
- begin
- upsample := my_upsample_ptr (cinfo^.upsample);
- upsample^.Cr_r_tab := int_CConvertPtr (
- cinfo^.mem^.alloc_small (j_common_ptr (cinfo), JPOOL_IMAGE,
- (MAXJSAMPLE+1) * SIZEOF(int)) );
- upsample^.Cb_b_tab := int_CConvertPtr (
- cinfo^.mem^.alloc_small (j_common_ptr (cinfo), JPOOL_IMAGE,
- (MAXJSAMPLE+1) * SIZEOF(int)) );
- upsample^.Cr_g_tab := INT32_CConvertPtr (
- cinfo^.mem^.alloc_small (j_common_ptr (cinfo), JPOOL_IMAGE,
- (MAXJSAMPLE+1) * SIZEOF(INT32)) );
- upsample^.Cb_g_tab := INT32_CConvertPtr (
- cinfo^.mem^.alloc_small (j_common_ptr (cinfo), JPOOL_IMAGE,
- (MAXJSAMPLE+1) * SIZEOF(INT32)) );
- x := -CENTERJSAMPLE;
- for i := 0 to pred(MAXJSAMPLE) do
- begin
- { i is the actual input pixel value, in the range 0..MAXJSAMPLE }
- { The Cb or Cr value we are thinking of is x := i - CENTERJSAMPLE }
- { Cr=>R value is nearest int to 1.40200 * x }
- {upsample^.Cr_r_tab^[i] := int(
- RIGHT_SHIFT(FIX_1_40200 * x + ONE_HALF, SCALEBITS) );}
- shift_temp := FIX_1_40200 * x + ONE_HALF;
- if shift_temp < 0 then { SHIFT arithmetic RIGHT }
- upsample^.Cr_r_tab^[i] := int((shift_temp shr SCALEBITS)
- or ( (not INT32(0)) shl (32-SCALEBITS)))
- else
- upsample^.Cr_r_tab^[i] := int(shift_temp shr SCALEBITS);
- { Cb=>B value is nearest int to 1.77200 * x }
- {upsample^.Cb_b_tab^[i] := int(
- RIGHT_SHIFT(FIX_1_77200 * x + ONE_HALF, SCALEBITS) );}
- shift_temp := FIX_1_77200 * x + ONE_HALF;
- if shift_temp < 0 then { SHIFT arithmetic RIGHT }
- upsample^.Cb_b_tab^[i] := int((shift_temp shr SCALEBITS)
- or ( (not INT32(0)) shl (32-SCALEBITS)))
- else
- upsample^.Cb_b_tab^[i] := int(shift_temp shr SCALEBITS);
- { Cr=>G value is scaled-up -0.71414 * x }
- upsample^.Cr_g_tab^[i] := (- FIX_0_71414) * x;
- { Cb=>G value is scaled-up -0.34414 * x }
- { We also add in ONE_HALF so that need not do it in inner loop }
- upsample^.Cb_g_tab^[i] := (- FIX_0_34414) * x + ONE_HALF;
- Inc(x);
- end;
- end;
- { Initialize for an upsampling pass. }
- {METHODDEF}
- procedure start_pass_merged_upsample (cinfo : j_decompress_ptr); far;
- var
- upsample : my_upsample_ptr;
- begin
- upsample := my_upsample_ptr (cinfo^.upsample);
- { Mark the spare buffer empty }
- upsample^.spare_full := FALSE;
- { 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).
- The control routine just handles the row buffering considerations. }
- {METHODDEF}
- procedure merged_2v_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); far;
- { 2:1 vertical sampling case: may need a spare row. }
- var
- upsample : my_upsample_ptr;
- work_ptrs : array[0..2-1] of JSAMPROW;
- num_rows : JDIMENSION; { number of rows returned to caller }
- begin
- upsample := my_upsample_ptr (cinfo^.upsample);
- if (upsample^.spare_full) then
- begin
- { If we have a spare row saved from a previous cycle, just return it. }
- jcopy_sample_rows(JSAMPARRAY(@upsample^.spare_row),
- 0,
- JSAMPARRAY(@ output_buf^[out_row_ctr]),
- 0, 1, upsample^.out_row_width);
- num_rows := 1;
- upsample^.spare_full := FALSE;
- end
- else
- begin
- { Figure number of rows to return to caller. }
- num_rows := 2;
- { Not more than the distance to the end of the image. }
- 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, {var} out_row_ctr);
- if (num_rows > out_rows_avail) then
- num_rows := out_rows_avail;
- { Create output pointer array for upsampler. }
- work_ptrs[0] := output_buf^[out_row_ctr];
- if (num_rows > 1) then
- begin
- work_ptrs[1] := output_buf^[out_row_ctr + 1];
- end
- else
- begin
- work_ptrs[1] := upsample^.spare_row;
- upsample^.spare_full := TRUE;
- end;
- { Now do the upsampling. }
- upsample^.upmethod (cinfo, input_buf, {var}in_row_group_ctr,
- JSAMPARRAY(@work_ptrs));
- end;
- { Adjust counts }
- Inc(out_row_ctr, num_rows);
- Dec(upsample^.rows_to_go, num_rows);
- { When the buffer is emptied, declare this input row group consumed }
- if (not upsample^.spare_full) then
- Inc(in_row_group_ctr);
- end;
- {METHODDEF}
- procedure merged_1v_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); far;
- { 1:1 vertical sampling case: much easier, never need a spare row. }
- var
- upsample : my_upsample_ptr;
- begin
- upsample := my_upsample_ptr (cinfo^.upsample);
- { Just do the upsampling. }
- upsample^.upmethod (cinfo, input_buf, in_row_group_ctr,
- JSAMPARRAY(@ output_buf^[out_row_ctr]));
- { Adjust counts }
- Inc(out_row_ctr);
- Inc(in_row_group_ctr);
- end;
- { These are the routines invoked by the control routines to do
- the actual upsampling/conversion. One row group is processed per call.
- Note: since we may be writing directly into application-supplied buffers,
- we have to be honest about the output width; we can't assume the buffer
- has been rounded up to an even width. }
- { Upsample and color convert for the case of 2:1 horizontal and 1:1 vertical. }
- {METHODDEF}
- procedure h2v1_merged_upsample (cinfo : j_decompress_ptr;
- input_buf : JSAMPIMAGE;
- in_row_group_ctr : JDIMENSION;
- output_buf : JSAMPARRAY); far;
- var
- upsample : my_upsample_ptr;
- {register} y, cred, cgreen, cblue : int;
- cb, cr : int;
- {register} outptr : JSAMPROW;
- inptr0, inptr1, inptr2 : JSAMPLE_PTR;
- col : JDIMENSION;
- { copy these pointers into registers if possible }
- {register} range_limit : range_limit_table_ptr;
- Crrtab : int_CConvertPtr;
- Cbbtab : int_CConvertPtr;
- Crgtab : INT32_CConvertPtr;
- Cbgtab : INT32_CConvertPtr;
- var
- shift_temp : INT32;
- begin
- upsample := my_upsample_ptr (cinfo^.upsample);
- range_limit := cinfo^.sample_range_limit;
- Crrtab := upsample^.Cr_r_tab;
- Cbbtab := upsample^.Cb_b_tab;
- Crgtab := upsample^.Cr_g_tab;
- Cbgtab := upsample^.Cb_g_tab;
- inptr0 := JSAMPLE_PTR(input_buf^[0]^[in_row_group_ctr]);
- inptr1 := JSAMPLE_PTR(input_buf^[1]^[in_row_group_ctr]);
- inptr2 := JSAMPLE_PTR(input_buf^[2]^[in_row_group_ctr]);
- outptr := output_buf^[0];
- { Loop for each pair of output pixels }
- for col := pred(cinfo^.output_width shr 1) downto 0 do
- begin
- { Do the chroma part of the calculation }
- cb := GETJSAMPLE(inptr1^);
- Inc(inptr1);
- cr := GETJSAMPLE(inptr2^);
- Inc(inptr2);
- cred := Crrtab^[cr];
- {cgreen := int( RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS) );}
- shift_temp := Cbgtab^[cb] + Crgtab^[cr];
- if shift_temp < 0 then { SHIFT arithmetic RIGHT }
- cgreen := int((shift_temp shr SCALEBITS)
- or ( (not INT32(0)) shl (32-SCALEBITS)))
- else
- cgreen := int(shift_temp shr SCALEBITS);
- cblue := Cbbtab^[cb];
- { Fetch 2 Y values and emit 2 pixels }
- y := GETJSAMPLE(inptr0^);
- Inc(inptr0);
- outptr^[RGB_RED] := range_limit^[y + cred];
- outptr^[RGB_GREEN] := range_limit^[y + cgreen];
- outptr^[RGB_BLUE] := range_limit^[y + cblue];
- Inc(JSAMPLE_PTR(outptr), RGB_PIXELSIZE);
- y := GETJSAMPLE(inptr0^);
- Inc(inptr0);
- outptr^[RGB_RED] := range_limit^[y + cred];
- outptr^[RGB_GREEN] := range_limit^[y + cgreen];
- outptr^[RGB_BLUE] := range_limit^[y + cblue];
- Inc(JSAMPLE_PTR(outptr), RGB_PIXELSIZE);
- end;
- { If image width is odd, do the last output column separately }
- if Odd(cinfo^.output_width) then
- begin
- cb := GETJSAMPLE(inptr1^);
- cr := GETJSAMPLE(inptr2^);
- cred := Crrtab^[cr];
- {cgreen := int ( RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS) );}
- shift_temp := Cbgtab^[cb] + Crgtab^[cr];
- if shift_temp < 0 then { SHIFT arithmetic RIGHT }
- cgreen := int((shift_temp shr SCALEBITS)
- or ( (not INT32(0)) shl (32-SCALEBITS)))
- else
- cgreen := int(shift_temp shr SCALEBITS);
- cblue := Cbbtab^[cb];
- y := GETJSAMPLE(inptr0^);
- outptr^[RGB_RED] := range_limit^[y + cred];
- outptr^[RGB_GREEN] := range_limit^[y + cgreen];
- outptr^[RGB_BLUE] := range_limit^[y + cblue];
- end;
- end;
- { Upsample and color convert for the case of 2:1 horizontal and 2:1 vertical. }
- {METHODDEF}
- procedure h2v2_merged_upsample (cinfo : j_decompress_ptr;
- input_buf : JSAMPIMAGE;
- in_row_group_ctr : JDIMENSION;
- output_buf : JSAMPARRAY); far;
- var
- upsample : my_upsample_ptr;
- {register} y, cred, cgreen, cblue : int;
- cb, cr : int;
- {register} outptr0, outptr1 : JSAMPROW;
- inptr00, inptr01, inptr1, inptr2 : JSAMPLE_PTR;
- col : JDIMENSION;
- { copy these pointers into registers if possible }
- {register} range_limit : range_limit_table_ptr;
- Crrtab : int_CConvertPtr;
- Cbbtab : int_CConvertPtr;
- Crgtab : INT32_CConvertPtr;
- Cbgtab : INT32_CConvertPtr;
- var
- shift_temp : INT32;
- begin
- upsample := my_upsample_ptr (cinfo^.upsample);
- range_limit := cinfo^.sample_range_limit;
- Crrtab := upsample^.Cr_r_tab;
- Cbbtab := upsample^.Cb_b_tab;
- Crgtab := upsample^.Cr_g_tab;
- Cbgtab := upsample^.Cb_g_tab;
- inptr00 := JSAMPLE_PTR(input_buf^[0]^[in_row_group_ctr*2]);
- inptr01 := JSAMPLE_PTR(input_buf^[0]^[in_row_group_ctr*2 + 1]);
- inptr1 := JSAMPLE_PTR(input_buf^[1]^[in_row_group_ctr]);
- inptr2 := JSAMPLE_PTR(input_buf^[2]^[in_row_group_ctr]);
- outptr0 := output_buf^[0];
- outptr1 := output_buf^[1];
- { Loop for each group of output pixels }
- for col := pred(cinfo^.output_width shr 1) downto 0 do
- begin
- { Do the chroma part of the calculation }
- cb := GETJSAMPLE(inptr1^);
- Inc(inptr1);
- cr := GETJSAMPLE(inptr2^);
- Inc(inptr2);
- cred := Crrtab^[cr];
- {cgreen := int( RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS) );}
- shift_temp := Cbgtab^[cb] + Crgtab^[cr];
- if shift_temp < 0 then { SHIFT arithmetic RIGHT }
- cgreen := int((shift_temp shr SCALEBITS)
- or ( (not INT32(0)) shl (32-SCALEBITS)))
- else
- cgreen := int(shift_temp shr SCALEBITS);
- cblue := Cbbtab^[cb];
- { Fetch 4 Y values and emit 4 pixels }
- y := GETJSAMPLE(inptr00^);
- Inc(inptr00);
- outptr0^[RGB_RED] := range_limit^[y + cred];
- outptr0^[RGB_GREEN] := range_limit^[y + cgreen];
- outptr0^[RGB_BLUE] := range_limit^[y + cblue];
- Inc(JSAMPLE_PTR(outptr0), RGB_PIXELSIZE);
- y := GETJSAMPLE(inptr00^);
- Inc(inptr00);
- outptr0^[RGB_RED] := range_limit^[y + cred];
- outptr0^[RGB_GREEN] := range_limit^[y + cgreen];
- outptr0^[RGB_BLUE] := range_limit^[y + cblue];
- Inc(JSAMPLE_PTR(outptr0), RGB_PIXELSIZE);
- y := GETJSAMPLE(inptr01^);
- Inc(inptr01);
- outptr1^[RGB_RED] := range_limit^[y + cred];
- outptr1^[RGB_GREEN] := range_limit^[y + cgreen];
- outptr1^[RGB_BLUE] := range_limit^[y + cblue];
- Inc(JSAMPLE_PTR(outptr1), RGB_PIXELSIZE);
- y := GETJSAMPLE(inptr01^);
- Inc(inptr01);
- outptr1^[RGB_RED] := range_limit^[y + cred];
- outptr1^[RGB_GREEN] := range_limit^[y + cgreen];
- outptr1^[RGB_BLUE] := range_limit^[y + cblue];
- Inc(JSAMPLE_PTR(outptr1), RGB_PIXELSIZE);
- end;
- { If image width is odd, do the last output column separately }
- if Odd(cinfo^.output_width) then
- begin
- cb := GETJSAMPLE(inptr1^);
- cr := GETJSAMPLE(inptr2^);
- cred := Crrtab^[cr];
- {cgreen := int (RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS));}
- shift_temp := Cbgtab^[cb] + Crgtab^[cr];
- if shift_temp < 0 then { SHIFT arithmetic RIGHT }
- cgreen := int((shift_temp shr SCALEBITS)
- or ( (not INT32(0)) shl (32-SCALEBITS)))
- else
- cgreen := int(shift_temp shr SCALEBITS);
- cblue := Cbbtab^[cb];
- y := GETJSAMPLE(inptr00^);
- outptr0^[RGB_RED] := range_limit^[y + cred];
- outptr0^[RGB_GREEN] := range_limit^[y + cgreen];
- outptr0^[RGB_BLUE] := range_limit^[y + cblue];
- y := GETJSAMPLE(inptr01^);
- outptr1^[RGB_RED] := range_limit^[y + cred];
- outptr1^[RGB_GREEN] := range_limit^[y + cgreen];
- outptr1^[RGB_BLUE] := range_limit^[y + cblue];
- end;
- end;
- { Module initialization routine for merged upsampling/color conversion.
- NB: this is called under the conditions determined by use_merged_upsample()
- in jdmaster.c. That routine MUST correspond to the actual capabilities
- of this module; no safety checks are made here. }
- {GLOBAL}
- procedure jinit_merged_upsampler (cinfo : j_decompress_ptr);
- var
- upsample : my_upsample_ptr;
- 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_merged_upsample;
- upsample^.pub.need_context_rows := FALSE;
- upsample^.out_row_width := cinfo^.output_width * cinfo^.out_color_components;
- if (cinfo^.max_v_samp_factor = 2) then
- begin
- upsample^.pub.upsample := merged_2v_upsample;
- upsample^.upmethod := h2v2_merged_upsample;
- { Allocate a spare row buffer }
- upsample^.spare_row := JSAMPROW(
- cinfo^.mem^.alloc_large ( j_common_ptr(cinfo), JPOOL_IMAGE,
- size_t (upsample^.out_row_width * SIZEOF(JSAMPLE))) );
- end
- else
- begin
- upsample^.pub.upsample := merged_1v_upsample;
- upsample^.upmethod := h2v1_merged_upsample;
- { No spare row needed }
- upsample^.spare_row := NIL;
- end;
- build_ycc_rgb_table(cinfo);
- end;
- end.
|