📄 transupp.pas
字号:
Unit transupp;
{* transupp.c
* transupp.h
Copyright (C) 1997, Thomas G. Lane.
This file is part of the Independent JPEG Group's software.
For conditions of distribution and use, see the accompanying README file.
This file contains image transformation routines and other utility code
used by the jpegtran sample application. These are NOT part of the core
JPEG library. But we keep these routines separate from jpegtran.c to
ease the task of maintaining jpegtran-like programs that have other user
interfaces.
NOTE: all the routines declared here have very specific requirements
about when they are to be executed during the reading and writing of the
source and destination files. See the comments in transupp.c, or see
jpegtran.c for an example of correct usage. }
interface
{$I jconfig.inc}
uses
jmorecfg,
jinclude,
jpeglib;
{ Short forms of external names for systems with brain-damaged linkers. }
{$ifdef NEED_SHORT_EXTERNAL_NAMES}
jtransform_request_workspace jTrRequest
jtransform_adjust_parameters jTrAdjust
jtransform_execute_transformation jTrExec
jcopy_markers_setup jCMrkSetup
jcopy_markers_execute jCMrkExec
{$endif} { NEED_SHORT_EXTERNAL_NAMES }
{ Codes for supported types of image transformations. }
type
JXFORM_CODE = (
JXFORM_NONE, { no transformation }
{$ifdef CROP_SUPPORTED}
JXFORM_CUT, { cut out part of the image }
{$endif}
JXFORM_FLIP_H, { horizontal flip }
JXFORM_FLIP_V, { vertical flip }
JXFORM_TRANSPOSE, { transpose across UL-to-LR axis }
JXFORM_TRANSVERSE, { transpose across UR-to-LL axis }
JXFORM_ROT_90, { 90-degree clockwise rotation }
JXFORM_ROT_180, { 180-degree rotation }
JXFORM_ROT_270 { 270-degree clockwise (or 90 ccw) }
);
{
Although rotating and flipping data expressed as DCT coefficients is not
hard, there is an asymmetry in the JPEG format specification for images
whose dimensions aren't multiples of the iMCU size. The right and bottom
image edges are padded out to the next iMCU boundary with junk data; but
no padding is possible at the top and left edges. If we were to flip
the whole image including the pad data, then pad garbage would become
visible at the top and/or left, and real pixels would disappear into the
pad margins --- perhaps permanently, since encoders & decoders may not
bother to preserve DCT blocks that appear to be completely outside the
nominal image area. So, we have to exclude any partial iMCUs from the
basic transformation.
Transpose is the only transformation that can handle partial iMCUs at the
right and bottom edges completely cleanly. flip_h can flip partial iMCUs
at the bottom, but leaves any partial iMCUs at the right edge untouched.
Similarly flip_v leaves any partial iMCUs at the bottom edge untouched.
The other transforms are defined as combinations of these basic transforms
and process edge blocks in a way that preserves the equivalence.
The "trim" option causes untransformable partial iMCUs to be dropped;
this is not strictly lossless, but it usually gives the best-looking
result for odd-size images. Note that when this option is active,
the expected mathematical equivalences between the transforms may not hold.
(For example, -rot 270 -trim trims only the bottom edge, but -rot 90 -trim
followed by -rot 180 -trim trims both edges.)
We also offer a "force to grayscale" option, which simply discards the
chrominance channels of a YCbCr image. This is lossless in the sense that
the luminance channel is preserved exactly. It's not the same kind of
thing as the rotate/flip transformations, but it's convenient to handle it
as part of this package, mainly because the transformation routines have to
be aware of the option to know how many components to work on.
}
type
jpeg_transform_info = record
{ Options: set by caller }
transform : JXFORM_CODE; { image transform operator }
trim : boolean; { if TRUE, trim partial MCUs as needed }
force_grayscale : boolean; { if TRUE, convert color image to grayscale }
{$ifdef CROP_SUPPORTED}
xoffs, yoffs, newwidth, newheight : JDIMENSION;
{$endif}
{ Internal workspace: caller should not touch these }
num_components : int; { # of components in workspace }
workspace_coef_arrays : jvirt_barray_tbl_ptr; { workspace for transformations }
end;
{$ifdef TRANSFORMS_SUPPORTED}
{ Request any required workspace }
procedure jtransform_request_workspace(srcinfo : j_decompress_ptr;
var info : jpeg_transform_info);
{ Adjust output image parameters }
function jtransform_adjust_parameters(
srcinfo : j_decompress_ptr;
dstinfo : j_compress_ptr;
src_coef_arrays : jvirt_barray_tbl_ptr;
var info : jpeg_transform_info) : jvirt_barray_tbl_ptr;
{ Execute the actual transformation, if any }
procedure jtransform_execute_transformation(
srcinfo : j_decompress_ptr;
dstinfo : j_compress_ptr;
src_coef_arrays : jvirt_barray_tbl_ptr;
var info : jpeg_transform_info);
{$endif} { TRANSFORMS_SUPPORTED }
{ Support for copying optional markers from source to destination file. }
type
JCOPY_OPTION = (
JCOPYOPT_NONE, { copy no optional markers }
JCOPYOPT_COMMENTS, { copy only comment (COM) markers }
JCOPYOPT_ALL { copy all optional markers }
);
const
JCOPYOPT_DEFAULT = JCOPYOPT_COMMENTS; { recommended default }
{ Setup decompression object to save desired markers in memory }
procedure jcopy_markers_setup(srcinfo : j_decompress_ptr;
option : JCOPY_OPTION);
{ Copy markers saved in the given source object to the destination object }
procedure jcopy_markers_execute(srcinfo : j_decompress_ptr;
dstinfo : j_compress_ptr;
option : JCOPY_OPTION);
implementation
{ Although this file really shouldn't have access to the library internals,
it's helpful to let it call jround_up() and jcopy_block_row(). }
uses
jutils,
jdeferr,
jerror,
{$ifdef SAVE_MARKERS_SUPPORTED}
jdmarker,
{$endif}
jcapimin,
jcparam; { set color space }
{$ifdef TRANSFORMS_SUPPORTED}
{ Lossless image transformation routines. These routines work on DCT
coefficient arrays and thus do not require any lossy decompression
or recompression of the image.
Thanks to Guido Vollbeding for the initial design and code of this feature.
Horizontal flipping is done in-place, using a single top-to-bottom
pass through the virtual source array. It will thus be much the
fastest option for images larger than main memory.
The other routines require a set of destination virtual arrays, so they
need twice as much memory as jpegtran normally does. The destination
arrays are always written in normal scan order (top to bottom) because
the virtual array manager expects this. The source arrays will be scanned
in the corresponding order, which means multiple passes through the source
arrays for most of the transforms. That could result in much thrashing
if the image is larger than main memory.
Some notes about the operating environment of the individual transform
routines:
1. Both the source and destination virtual arrays are allocated from the
source JPEG object, and therefore should be manipulated by calling the
source's memory manager.
2. The destination's component count should be used. It may be smaller
than the source's when forcing to grayscale.
3. Likewise the destination's sampling factors should be used. When
forcing to grayscale the destination's sampling factors will be all 1,
and we may as well take that as the effective iMCU size.
4. When "trim" is in effect, the destination's dimensions will be the
trimmed values but the source's will be untrimmed.
5. All the routines assume that the source and destination buffers are
padded out to a full iMCU boundary. This is true, although for the
source buffer it is an undocumented property of jdcoefct.c.
Notes 2,3,4 boil down to this: generally we should use the destination's
dimensions and ignore the source's. }
{LOCAL}
procedure do_flip_h (srcinfo : j_decompress_ptr;
dstinfo : j_compress_ptr;
src_coef_arrays : jvirt_barray_tbl_ptr);
{ Horizontal flip; done in-place, so no separate dest array is required }
var
MCU_cols, comp_width, blk_x, blk_y : JDIMENSION;
ci, k, offset_y : int;
buffer : JBLOCKARRAY;
ptr1, ptr2 : JCOEF_PTR;
temp1, temp2 : JCOEF;
compptr : jpeg_component_info_ptr;
begin
{ Horizontal mirroring of DCT blocks is accomplished by swapping
pairs of blocks in-place. Within a DCT block, we perform horizontal
mirroring by changing the signs of odd-numbered columns.
Partial iMCUs at the right edge are left untouched. }
MCU_cols := dstinfo^.image_width div (dstinfo^.max_h_samp_factor * DCTSIZE);
for ci := 0 to dstinfo^.num_components-1 do
begin
compptr := jpeg_component_info_ptr(dstinfo^.comp_info);
Inc(compptr, ci);
comp_width := MCU_cols * compptr^.h_samp_factor;
blk_y := 0;
while (blk_y < compptr^.height_in_blocks) do
begin
buffer := srcinfo^.mem^.access_virt_barray
(j_common_ptr(srcinfo), src_coef_arrays^[ci], blk_y,
JDIMENSION (compptr^.v_samp_factor), TRUE);
for offset_y := 0 to compptr^.v_samp_factor-1 do
begin
blk_x := 0;
while (blk_x * 2 < comp_width) do
begin
ptr1 := JCOEF_PTR(@(buffer^[offset_y]^[blk_x]));
ptr2 := JCOEF_PTR(@(buffer^[offset_y]^[comp_width - blk_x - 1]));
{ this unrolled loop doesn't need to know which row it's on... }
k := 0;
while (k < DCTSIZE2) do
begin
temp1 := ptr1^; { swap even column }
temp2 := ptr2^;
ptr1^ := temp2;
Inc(ptr1);
ptr2^ := temp1;
Inc(ptr2);
temp1 := ptr1^; { swap odd column with sign change }
temp2 := ptr2^;
ptr1^ := -temp2;
Inc(ptr1);
ptr2^ := -temp1;
Inc(ptr2);
Inc(k, 2);
end;
Inc(blk_x);
end;
end;
Inc(blk_y, compptr^.v_samp_factor);
end; { while }
end; { for ci }
end; { do_flip_h }
{LOCAL}
procedure do_flip_v (srcinfo : j_decompress_ptr;
dstinfo : j_compress_ptr;
src_coef_arrays : jvirt_barray_tbl_ptr;
dst_coef_arrays : jvirt_barray_tbl_ptr);
{ Vertical flip }
var
MCU_rows, comp_height, dst_blk_x, dst_blk_y : JDIMENSION;
ci, i, j, offset_y : int;
src_buffer, dst_buffer : JBLOCKARRAY;
src_row_ptr, dst_row_ptr : JBLOCKROW;
src_ptr, dst_ptr : JCOEF_PTR;
compptr : jpeg_component_info_ptr;
begin
{ We output into a separate array because we can't touch different
rows of the source virtual array simultaneously. Otherwise, this
is a pretty straightforward analog of horizontal flip.
Within a DCT block, vertical mirroring is done by changing the signs
of odd-numbered rows.
Partial iMCUs at the bottom edge are copied verbatim. }
MCU_rows := dstinfo^.image_height div (dstinfo^.max_v_samp_factor * DCTSIZE);
for ci := 0 to dstinfo^.num_components-1 do
begin
compptr := jpeg_component_info_ptr(dstinfo^.comp_info);
Inc(compptr, ci);
comp_height := MCU_rows * compptr^.v_samp_factor;
dst_blk_y := 0;
while (dst_blk_y < compptr^.height_in_blocks) do
begin
dst_buffer := srcinfo^.mem^.access_virt_barray
(j_common_ptr(srcinfo), dst_coef_arrays^[ci], dst_blk_y,
JDIMENSION(compptr^.v_samp_factor), TRUE);
if (dst_blk_y < comp_height) then
begin
{ Row is within the mirrorable area. }
src_buffer := srcinfo^.mem^.access_virt_barray
(j_common_ptr(srcinfo), src_coef_arrays^[ci],
comp_height - dst_blk_y - JDIMENSION(compptr^.v_samp_factor),
JDIMENSION (compptr^.v_samp_factor), FALSE);
end
else
begin
{ Bottom-edge blocks will be copied verbatim. }
src_buffer := srcinfo^.mem^.access_virt_barray
(j_common_ptr(srcinfo), src_coef_arrays^[ci], dst_blk_y,
JDIMENSION (compptr^.v_samp_factor), FALSE);
end;
for offset_y := 0 to compptr^.v_samp_factor-1 do
begin
if (dst_blk_y < comp_height) then
begin
{ Row is within the mirrorable area. }
dst_row_ptr := dst_buffer^[offset_y];
src_row_ptr := src_buffer^[compptr^.v_samp_factor - offset_y - 1];
for dst_blk_x := 0 to compptr^.width_in_blocks-1 do
begin
dst_ptr := JCOEF_PTR(@(dst_row_ptr^[dst_blk_x]));
src_ptr := JCOEF_PTR(@(src_row_ptr^[dst_blk_x]));
i := 0;
while (i < DCTSIZE) do
begin
{ copy even row }
for j := 0 to DCTSIZE-1 do
begin
dst_ptr^ := src_ptr^;
Inc(dst_ptr);
Inc(src_ptr);
end;
{ copy odd row with sign change }
for j := 0 to DCTSIZE-1 do
begin
dst_ptr^ := - (src_ptr^);
Inc(dst_ptr);
Inc(src_ptr);
end;
Inc(i, 2);
end;
end;
end
else
begin
{ Just copy row verbatim. }
jcopy_block_row(src_buffer^[offset_y], dst_buffer^[offset_y],
compptr^.width_in_blocks);
end;
end;
Inc(dst_blk_y, compptr^.v_samp_factor);
end; { while }
end; { for ci }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -