1254 lines
38 KiB
Plaintext
1254 lines
38 KiB
Plaintext
(* ImageEn Build 7.0.0.06.2637 @ 7-4-17 14:58:42.679 *)
|
|
(*
|
|
Copyright (c) 1998-2017 by Carlotta Calandra. All rights reserved.
|
|
Copyright (c) 2011-2017 by Xequte Software.
|
|
|
|
This software comes without express or implied warranty.
|
|
In no case shall the author be liable for any damage or unwanted behavior of any
|
|
computer hardware and/or software.
|
|
|
|
Author grants you the right to include the component
|
|
in your application, whether COMMERCIAL, SHAREWARE, or FREEWARE.
|
|
|
|
ImageEn, IEvolution and ImageEn ActiveX may not be included in any
|
|
commercial, shareware or freeware libraries or components.
|
|
|
|
www.ImageEn.com
|
|
*)
|
|
|
|
(*
|
|
File version 1005
|
|
*)
|
|
|
|
unit pngfiltw;
|
|
|
|
{$R-}
|
|
{$Q-}
|
|
|
|
{$I ie.inc}
|
|
|
|
{$IFDEF IEINCLUDEPNG}
|
|
|
|
interface
|
|
|
|
uses
|
|
Windows, Graphics, classes, sysutils, ImageEnIO, hyiedefs, iexBitmaps;
|
|
|
|
|
|
procedure WritePNGStream(Stream: TStream; bitmap: TIEBitmap; var IOParams: TIOParams; var xProgress: TProgressRec; AlphaChannel: TIEMask);
|
|
|
|
|
|
implementation
|
|
|
|
uses
|
|
math, ImageEnProc, hyieutils,
|
|
{$ifdef IEUSEVCLZLIB}zlib, {$else}iezlib, {$endif}
|
|
pngfilt, neurquant, ievision;
|
|
|
|
|
|
|
|
const
|
|
IEPNG_COLOR_MASK_PALETTE = 1;
|
|
IEPNG_COLOR_MASK_COLOR = 2;
|
|
IEPNG_COLOR_MASK_ALPHA = 4;
|
|
|
|
IEPNG_COLOR_TYPE_GRAY = 0;
|
|
IEPNG_COLOR_TYPE_PALETTE = IEPNG_COLOR_MASK_COLOR or IEPNG_COLOR_MASK_PALETTE;
|
|
IEPNG_COLOR_TYPE_RGB = IEPNG_COLOR_MASK_COLOR;
|
|
IEPNG_COLOR_TYPE_RGB_ALPHA = IEPNG_COLOR_MASK_COLOR or IEPNG_COLOR_MASK_ALPHA;
|
|
IEPNG_COLOR_TYPE_GRAY_ALPHA = IEPNG_COLOR_MASK_ALPHA;
|
|
|
|
IEPNG_INTERLACE_NONE = 0;
|
|
IEPNG_INTERLACE_ADAM7 = 1;
|
|
|
|
IEPNG_COMPRESSION_TYPE_BASE = 0;
|
|
IEPNG_COMPRESSION_TYPE_DEFAULT = IEPNG_COMPRESSION_TYPE_BASE;
|
|
|
|
IEPNG_FILTER_TYPE_BASE = 0;
|
|
IEPNG_FILTER_TYPE_DEFAULT = IEPNG_FILTER_TYPE_BASE;
|
|
|
|
IEPNG_RESOLUTION_UNKNOWN = 0;
|
|
IEPNG_RESOLUTION_METER = 1;
|
|
|
|
IEPNG_NO_FILTERS = $00;
|
|
IEPNG_FILTER_NONE = $08;
|
|
IEPNG_FILTER_SUB = $10;
|
|
IEPNG_FILTER_UP = $20;
|
|
IEPNG_FILTER_AVG = $40;
|
|
IEPNG_FILTER_PAETH = $80;
|
|
IEPNG_ALL_FILTERS = IEPNG_FILTER_NONE or IEPNG_FILTER_SUB or IEPNG_FILTER_UP or IEPNG_FILTER_AVG or IEPNG_FILTER_PAETH;
|
|
|
|
|
|
type
|
|
EIEPNGException = class(Exception);
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// static png library wrappers
|
|
|
|
|
|
{$ifndef IEUSEDLLPNGLIB}
|
|
|
|
{$Z4}
|
|
|
|
type
|
|
png_uint_32 = Cardinal;
|
|
png_uint_32p = ^png_uint_32;
|
|
png_int_32 = integer;
|
|
png_uint_16 = Word;
|
|
png_int_16 = Smallint;
|
|
png_byte = Byte;
|
|
png_size_t = png_uint_32;
|
|
png_charpp = ^png_charp;
|
|
png_charp = PAnsiChar;
|
|
float = single;
|
|
int = integer;
|
|
png_bytepp = ^png_bytep;
|
|
png_bytep = ^png_byte;
|
|
png_uint_16p = ^png_uint_16;
|
|
png_uint_16pp = ^png_uint_16p;
|
|
png_voidp = pointer;
|
|
time_t = Longint;
|
|
png_doublep = ^png_double;
|
|
png_double = double;
|
|
|
|
user_error_ptr = Pointer;
|
|
png_error_ptrp = ^png_error_ptr;
|
|
png_rw_ptrp = ^png_rw_ptr;
|
|
png_flush_ptrp = ^png_flush_ptr;
|
|
png_progressive_info_ptrp = ^png_progressive_info_ptr;
|
|
png_progressive_end_ptrp = ^png_progressive_end_ptr;
|
|
png_progressive_row_ptrp = ^png_progressive_row_ptr;
|
|
|
|
png_error_ptr = procedure(png_ptr: Pointer; msg: Pointer); cdecl;
|
|
png_rw_ptr = procedure(png_ptr: Pointer; data: Pointer; length: png_size_t); cdecl;
|
|
png_flush_ptr = procedure(png_ptr: Pointer); cdecl;
|
|
png_progressive_info_ptr = procedure(png_ptr: Pointer; info_ptr: Pointer); cdecl;
|
|
png_progressive_end_ptr = procedure(png_ptr: Pointer; info_ptr: Pointer); cdecl;
|
|
png_progressive_row_ptr = procedure(png_ptr: Pointer; data: Pointer; length: png_uint_32; count: int); cdecl;
|
|
png_read_status_ptr = procedure(png_ptr: Pointer; row_number: png_uint_32; pass: int); cdecl;
|
|
png_write_status_ptr = procedure(png_ptr: Pointer; row_number: png_uint_32; pass: int); cdecl;
|
|
png_user_transform_ptr = procedure(png_ptr: Pointer; row_info: Pointer; data: png_bytep); cdecl;
|
|
|
|
png_colorpp = ^png_colorp;
|
|
png_colorp = ^png_color;
|
|
png_color = packed record
|
|
red, green, blue: png_byte;
|
|
end;
|
|
|
|
png_color_16pp = ^png_color_16p;
|
|
png_color_16p = ^png_color_16;
|
|
png_color_16 = packed record
|
|
index: png_byte; //used for palette files
|
|
red, green, blue: png_uint_16; //for use in red green blue files
|
|
gray: png_uint_16; //for use in grayscale files
|
|
end;
|
|
|
|
png_color_8pp = ^png_color_8p;
|
|
png_color_8p = ^png_color_8;
|
|
png_color_8 = packed record
|
|
red, green, blue: png_byte; //for use in red green blue files
|
|
gray: png_byte; //for use in grayscale files
|
|
alpha: png_byte; //for alpha channel files
|
|
end;
|
|
|
|
png_textpp = ^png_textp;
|
|
png_textp = ^tpng_text;
|
|
tpng_text = packed record
|
|
compression: int; //compression value
|
|
key: png_charp; //keyword, 1-79 character description of "text"
|
|
text: png_charp; //comment, may be empty ("")
|
|
text_length: png_size_t; //length of text field
|
|
end;
|
|
|
|
png_timepp = ^png_timep;
|
|
png_timep = ^tpng_time;
|
|
tpng_time = packed record
|
|
year: png_uint_16; //yyyy
|
|
month: png_byte; //1..12
|
|
day: png_byte; //1..31
|
|
hour: png_byte; //0..23
|
|
minute: png_byte; //0..59
|
|
second: png_byte; //0..60 (leap seconds)
|
|
end;
|
|
|
|
png_infopp = ^png_infop;
|
|
png_infop = Pointer;
|
|
|
|
png_row_infopp = ^png_row_infop;
|
|
png_row_infop = ^png_row_info;
|
|
png_row_info = packed record
|
|
width: png_uint_32; //width of row
|
|
rowbytes: png_size_t; //number of bytes in row
|
|
color_type: png_byte; //color type of row
|
|
bit_depth: png_byte; //bit depth of row
|
|
channels: png_byte; //number of channels (1, 2, 3, or 4)
|
|
pixel_depth: png_byte; //bits per pixel (depth * channels)
|
|
end;
|
|
|
|
png_structpp = ^png_structp;
|
|
png_structp = Pointer;
|
|
|
|
// Supported compression types for text in PNG files (tEXt, and zTXt).
|
|
// The values of the PNG_TEXT_COMPRESSION_ defines should NOT be changed.
|
|
|
|
const
|
|
PNG_TEXT_COMPRESSION_NONE_WR = -3;
|
|
PNG_TEXT_COMPRESSION_zTXt_WR = -2;
|
|
PNG_TEXT_COMPRESSION_NONE = -1;
|
|
PNG_TEXT_COMPRESSION_zTXt = 0;
|
|
|
|
// These describe the color_type field in png_info.
|
|
// color type masks
|
|
|
|
PNG_COLOR_MASK_PALETTE = 1;
|
|
PNG_COLOR_MASK_COLOR = 2;
|
|
PNG_COLOR_MASK_ALPHA = 4;
|
|
|
|
// color types. Note that not all combinations are legal
|
|
|
|
PNG_COLOR_TYPE_GRAY = 0;
|
|
PNG_COLOR_TYPE_PALETTE = PNG_COLOR_MASK_COLOR or PNG_COLOR_MASK_PALETTE;
|
|
PNG_COLOR_TYPE_RGB = PNG_COLOR_MASK_COLOR;
|
|
PNG_COLOR_TYPE_RGB_ALPHA = PNG_COLOR_MASK_COLOR or PNG_COLOR_MASK_ALPHA;
|
|
PNG_COLOR_TYPE_GRAY_ALPHA = PNG_COLOR_MASK_ALPHA;
|
|
|
|
// These are for the interlacing type. These values should NOT be changed.
|
|
|
|
PNG_INTERLACE_NONE = 0; // Non-interlaced image
|
|
PNG_INTERLACE_ADAM7 = 1; // Adam7 interlacing
|
|
|
|
// These are for the oFFs chunk. These values should NOT be changed.
|
|
|
|
PNG_OFFSET_PIXEL = 0; // Offset in pixels
|
|
PNG_OFFSET_MICROMETER = 1; // Offset in micrometers (1/10^6 meter)
|
|
|
|
// These are for the pCAL chunk. These values should NOT be changed.
|
|
|
|
PNG_EQUATION_LINEAR = 0; // Linear transformation
|
|
PNG_EQUATION_BASE_E = 1; // Exponential base e transform
|
|
PNG_EQUATION_ARBITRARY = 2; // Arbitrary base exponential transform
|
|
PNG_EQUATION_HYPERBOLIC = 3; // Hyperbolic sine transformation
|
|
|
|
// These are for the sRGB chunk. These values should NOT be changed.
|
|
PNG_sRGB_INTENT_SATURATION = 0;
|
|
PNG_sRGB_INTENT_PERCEPTUAL = 1;
|
|
PNG_sRGB_INTENT_ABSOLUTE = 2;
|
|
PNG_sRGB_INTENT_RELATIVE = 3;
|
|
|
|
// Handle alpha and tRNS by replacing with a background color.
|
|
PNG_BACKGROUND_GAMMA_UNKNOWN = 0;
|
|
PNG_BACKGROUND_GAMMA_SCREEN = 1;
|
|
PNG_BACKGROUND_GAMMA_FILE = 2;
|
|
PNG_BACKGROUND_GAMMA_UNIQUE = 3;
|
|
|
|
// Values for png_set_crc_action() to say how to handle CRC errors in
|
|
// ancillary and critical chunks, and whether to use the data contained
|
|
// therein. Note that it is impossible to "discard" data in a critical
|
|
// chunk. For versions prior to 0.90, the action was always error/quit,
|
|
// whereas in version 0.90 and later, the action for CRC errors in ancillary
|
|
// chunks is warn/discard. These values should NOT be changed.
|
|
|
|
// value action: critical action: ancillary
|
|
|
|
PNG_CRC_DEFAULT = 0; // error/quit warn/discard data
|
|
PNG_CRC_ERROR_QUIT = 1; // error/quit error/quit
|
|
PNG_CRC_WARN_DISCARD = 2; // (INVALID) warn/discard data
|
|
PNG_CRC_WARN_USE = 3; // warn/use data warn/use data
|
|
PNG_CRC_QUIET_USE = 4; // quiet/use data quiet/use data
|
|
PNG_CRC_NO_CHANGE = 5; // use current value use current value
|
|
|
|
|
|
// Filter values (not flags) - used in pngwrite.c, pngwutil.c for now.
|
|
// These defines should NOT be changed.
|
|
|
|
PNG_FILTER_VALUE_NONE = 0;
|
|
PNG_FILTER_VALUE_SUB = 1;
|
|
PNG_FILTER_VALUE_UP = 2;
|
|
PNG_FILTER_VALUE_AVG = 3;
|
|
PNG_FILTER_VALUE_PAETH = 4;
|
|
|
|
// Heuristic used for row filter selection. These defines should NOT be
|
|
// changed.
|
|
|
|
PNG_FILTER_HEURISTIC_DEFAULT = 0; // Currently "UNWEIGHTED"
|
|
PNG_FILTER_HEURISTIC_UNWEIGHTED = 1; // Used by libpng < 0.95
|
|
PNG_FILTER_HEURISTIC_WEIGHTED = 2; // Experimental feature
|
|
PNG_FILTER_HEURISTIC_LAST = 3; // Not a valid value
|
|
|
|
|
|
|
|
{$R-}
|
|
|
|
var
|
|
__turboFloat: LongBool = False;
|
|
|
|
|
|
function memcmp(buf1, buf2: pbyte; count: integer): integer; cdecl;
|
|
begin
|
|
if count = 0 then
|
|
result := 0
|
|
else
|
|
begin
|
|
while true do
|
|
begin
|
|
dec(count);
|
|
if (count=0) or (buf1^<>buf2^) then
|
|
break;
|
|
inc(buf1);
|
|
inc(buf2);
|
|
end;
|
|
result := buf1^ - buf2^;
|
|
end;
|
|
end;
|
|
|
|
function strncpy(dest, src: PAnsiChar; maxlen: integer): PAnsiChar; cdecl;
|
|
begin
|
|
result := IEStrMove(dest, src, maxlen);
|
|
end;
|
|
|
|
function strcpy(dest, src: PAnsiChar): PAnsiChar; cdecl;
|
|
begin
|
|
result := IEStrCopy(dest, src);
|
|
end;
|
|
|
|
|
|
function fabs(v: double): double; cdecl;
|
|
begin
|
|
result := abs(v);
|
|
end;
|
|
|
|
function pow(Base, Exponent: double): double; cdecl;
|
|
begin
|
|
result := Power(Base, Exponent);
|
|
end;
|
|
|
|
function strtod(s: PAnsiChar; var vp: PAnsiChar): double; cdecl;
|
|
begin
|
|
vp := @s[IEStrLen(s) - 1]; // !!
|
|
result := IEStrToFloatDefA(s, 0);
|
|
end;
|
|
|
|
function malloc(size: Integer): Pointer; cdecl;
|
|
begin
|
|
result := allocmem(size);
|
|
end;
|
|
|
|
procedure free(P: Pointer); cdecl;
|
|
begin
|
|
FreeMem(P);
|
|
end;
|
|
|
|
function memset(P: Pointer; B: Byte; count: Integer): pointer; cdecl;
|
|
begin
|
|
FillChar(P^, count, B);
|
|
result := P;
|
|
end;
|
|
|
|
function memcpy(dest, source: Pointer; count: Integer): pointer; cdecl;
|
|
begin
|
|
Move(source^, dest^, count);
|
|
result := dest;
|
|
end;
|
|
|
|
function _ftol: integer; cdecl;
|
|
var
|
|
f: double;
|
|
begin
|
|
asm
|
|
lea eax, f // BC++ passes floats on the FPU stack
|
|
fstp qword ptr [eax] // Delphi passes floats on the CPU stack
|
|
end;
|
|
if f > 2147483647.0 then
|
|
f := 2147483647.0;
|
|
if f < -2147483648.0 then
|
|
f := 2147483648.0;
|
|
result := integer(Trunc(f));
|
|
end;
|
|
|
|
function memmove(dest, source: Pointer; count: Integer): pointer; cdecl;
|
|
begin
|
|
Move(source^, dest^, count);
|
|
result := dest;
|
|
end;
|
|
|
|
function strlen(str: PAnsiChar): integer; cdecl;
|
|
begin
|
|
result := IEStrLen(str);
|
|
end;
|
|
|
|
function realloc(block: pointer; size: integer): pointer; cdecl;
|
|
begin
|
|
reallocmem(block, size);
|
|
result := block;
|
|
end;
|
|
|
|
function fscanf(f: pointer; format: PAnsiChar): integer; cdecl;
|
|
begin
|
|
result := 0;
|
|
end;
|
|
|
|
|
|
{$L pngset.obj}
|
|
{$L pngtrans.obj}
|
|
{$L pngmem.obj}
|
|
{$L pngerror.obj}
|
|
|
|
{$L pngwrite.obj}
|
|
{$L pngwio.obj}
|
|
{$L pngwtran.obj}
|
|
{$L pngwutil.obj}
|
|
|
|
{$L pngget.obj}
|
|
{$L png.obj}
|
|
|
|
procedure png_set_error_fn(png_ptr: png_structp; error_ptr: png_voidp; error_fn, warning_fn: png_error_ptr); cdecl; external;
|
|
function png_set_interlace_handling(png_ptr: png_structp): int; cdecl; external;
|
|
procedure png_chunk_warning(png_ptr: png_structp; const mess: png_charp); cdecl; external;
|
|
function png_create_write_struct(user_png_ver: png_charp; error_ptr: user_error_ptr; error_fn: png_error_ptr; warn_fn: png_error_ptr): png_structp; cdecl; external;
|
|
function png_create_info_struct(png_ptr: png_structp): png_infop; cdecl; external;
|
|
procedure png_destroy_write_struct(png_ptr_ptr: png_structpp; info_ptr_ptr: png_infopp); cdecl; external;
|
|
procedure png_set_IHDR(png_ptr: png_structp; info_ptr: png_infop; width, height: png_uint_32; bit_depth, color_type, interlace_type, compression_type, filter_type: int); cdecl; external;
|
|
procedure png_set_PLTE(png_ptr: png_structp; info_ptr: png_infop; palette: png_colorp; num_palette: int); cdecl; external;
|
|
procedure png_set_bKGD(png_ptr: png_structp; info_ptr: png_infop; background: png_color_16p); cdecl; external;
|
|
procedure png_set_tRNS(png_ptr: png_structp; info_ptr: png_infop; trans: png_bytep; num_trans: integer; trans_values: png_color_16p); cdecl; external;
|
|
procedure png_write_info(png_ptr: png_structp; info_ptr: png_infop); cdecl; external;
|
|
procedure png_set_bgr(png_ptr: png_structp); cdecl; external;
|
|
procedure png_set_write_fn(png_ptr: png_structp; io_ptr: png_voidp; write_data_fn: png_rw_ptr; output_flush_fn: png_flush_ptr); cdecl; external;
|
|
function png_get_io_ptr(png_ptr: png_structp): png_voidp; cdecl; external;
|
|
procedure png_write_rows(png_ptr: png_structp; row: png_bytepp; num_rows: png_uint_32); cdecl; external;
|
|
procedure png_write_end(png_ptr: png_structp; info_ptr: png_infop); cdecl; external;
|
|
procedure png_set_pHYs(png_ptr: png_structp; info_ptr: png_infop; res_x, res_y: png_uint_32; unit_type: int); cdecl; external;
|
|
procedure png_set_filter(png_ptr: png_structp; method, filters: int); cdecl; external;
|
|
procedure png_set_compression_level(png_ptr: png_structp; level: int); cdecl; external;
|
|
procedure png_set_sBIT(png_ptr: png_structp; info_ptr: png_infop; sig_bits: png_color_8p); cdecl; external;
|
|
procedure png_set_text(png_ptr: png_structp; info_ptr: png_infop; text_ptr: png_textp; num_text: int); cdecl; external;
|
|
function png_get_error_ptr(png_ptr: png_structp): png_voidp; cdecl; external;
|
|
|
|
procedure PNG_MEMSET_CHECK; external;
|
|
procedure PNG_CREATE_STRUCT; external;
|
|
procedure PNG_DESTROY_STRUCT; external;
|
|
procedure png_warning; external;
|
|
procedure png_malloc; external;
|
|
procedure png_free; external;
|
|
procedure png_memcpy_check; external;
|
|
procedure PNG_DO_STRIP_FILLER; external;
|
|
procedure PNG_DO_PACKSWAP; external;
|
|
procedure PNG_DO_SWAP; external;
|
|
procedure PNG_DO_BGR; external;
|
|
procedure PNG_DO_INVERT; external;
|
|
procedure PNG_WRITE_DATA; external;
|
|
procedure png_create_struct_2; external;
|
|
procedure PNG_SET_MEM_FN; external;
|
|
procedure png_destroy_struct_2; external;
|
|
procedure PNG_SET_INVERT_ALPHA; external;
|
|
procedure PNG_SET_INVERT_MONO; external;
|
|
procedure PNG_SET_SHIFT; external;
|
|
procedure PNG_SET_PACKING; external;
|
|
procedure PNG_SET_SWAP_ALPHA; external;
|
|
procedure PNG_SET_FILLER; external;
|
|
procedure PNG_SET_SWAP; external;
|
|
procedure PNG_SET_PACKSWAP; external;
|
|
procedure PNG_WRITE_FLUSH; external;
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
type
|
|
|
|
IEPNG_Compressor_t = record
|
|
pngPtr: png_structp;
|
|
infoPtr: png_infop;
|
|
end;
|
|
|
|
IEPNG_Compressor = ^IEPNG_Compressor_t;
|
|
IEPNG_Color = png_colorp;
|
|
IEPNG_TextList = array of tpng_text;
|
|
|
|
|
|
function IEPNG_getIOPtr(pngPtr: pointer): pointer; // this must be pngPtr not IEPNG_Decompressor or IEPNG_Compressor
|
|
begin
|
|
result := png_get_io_ptr(pngPtr);
|
|
end;
|
|
|
|
function IEPNG_getErrorPtr(pngPtr: pointer): pointer; // this must be pngPtr not IEPNG_Decompressor or IEPNG_Compressor
|
|
begin
|
|
result := png_get_error_ptr(pngPtr);
|
|
end;
|
|
|
|
procedure IEPNG_Comp_destroy(var comp: IEPNG_Compressor);
|
|
begin
|
|
if comp <> nil then
|
|
begin
|
|
if comp^.pngPtr <> nil then
|
|
png_destroy_write_struct(@comp^.pngPtr, @comp^.infoPtr); // png_destroy_write_struct accepts comp^.infoPtr=nil
|
|
FreeMem(comp);
|
|
comp := nil;
|
|
end;
|
|
end;
|
|
|
|
function IEPNG_Comp_create(errorPtr: pointer; errorFunc: pointer; warnFunc: pointer): IEPNG_Compressor;
|
|
begin
|
|
result := AllocMem(sizeof(IEPNG_Compressor_t)); // zero filled
|
|
result^.pngPtr := png_create_write_struct('1.2.14', errorPtr, errorFunc, warnFunc);
|
|
if result^.pngPtr <> nil then
|
|
result^.infoPtr := png_create_info_struct(result^.pngPtr);
|
|
if (result^.pngPtr = nil) or (result^.infoPtr = nil) then
|
|
IEPNG_Comp_destroy(result); // this also sets result=nil
|
|
end;
|
|
|
|
procedure IEPNG_Comp_setWriteFunction(comp: IEPNG_Compressor; ioPtr: pointer; writeFunc: pointer; flushFunc: pointer);
|
|
begin
|
|
png_set_write_fn(comp^.pngPtr, ioPtr, writeFunc, flushFunc);
|
|
end;
|
|
|
|
procedure IEPNG_setPalette(comp: IEPNG_Compressor; palette: IEPNG_Color; numPalette: integer);
|
|
begin
|
|
png_set_PLTE(comp^.pngPtr, comp^.infoPtr, palette, numPalette);
|
|
end;
|
|
|
|
procedure IEPNG_setTRNS(comp: IEPNG_Compressor; trans: pbyte; numTrans: integer);
|
|
begin
|
|
png_set_tRNS(comp^.pngPtr, comp^.infoPtr, png_bytep(trans), numTrans, nil);
|
|
end;
|
|
|
|
procedure IEPNG_setIHDR(comp: IEPNG_Compressor; width: dword; height: dword; bitDepth: integer; colorType: integer; interlaceType: integer; compressionType: integer; filterType: integer);
|
|
begin
|
|
png_set_IHDR(comp^.pngPtr, comp^.infoPtr, width, height, bitDepth, colorType, interlaceType, compressionType, filterType);
|
|
end;
|
|
|
|
procedure IEPNG_setPHYS(comp: IEPNG_Compressor; resX: dword; resY: dword; unitType: integer);
|
|
begin
|
|
png_set_pHYs(comp^.pngPtr, comp^.infoPtr, resX, resY, unitType);
|
|
end;
|
|
|
|
procedure IEPNG_setFilter(comp: IEPNG_Compressor; method: integer; filters: integer);
|
|
begin
|
|
png_set_filter(comp^.pngPtr, method, filters);
|
|
end;
|
|
|
|
procedure IEPNG_setBackground(comp: IEPNG_Compressor; colorValue: TRGB; colorIndex: byte);
|
|
var
|
|
color16: png_color_16;
|
|
begin
|
|
ZeroMemory(@color16, sizeof(png_color_16));
|
|
color16.index := colorIndex;
|
|
color16.red := colorValue.r * 257;
|
|
color16.green := colorValue.g * 257;
|
|
color16.blue := colorValue.b * 257;
|
|
png_set_bKGD(comp^.pngPtr, comp^.infoPtr, @color16);
|
|
end;
|
|
|
|
procedure IEPNG_setCompressionLevel(comp: IEPNG_Compressor; level: integer);
|
|
begin
|
|
png_set_compression_level(comp^.pngPtr, level);
|
|
end;
|
|
|
|
procedure IEPNG_setBGR(comp: IEPNG_Compressor);
|
|
begin
|
|
png_set_bgr(comp^.pngPtr);
|
|
end;
|
|
|
|
procedure IEPNG_Comp_writeInfo(comp: IEPNG_Compressor);
|
|
begin
|
|
png_write_info(comp^.pngPtr, comp^.infoPtr);
|
|
end;
|
|
|
|
function IEPNG_Comp_setInterlaceHandling(comp: IEPNG_Compressor): integer;
|
|
begin
|
|
result := png_set_interlace_handling(comp^.pngPtr);
|
|
end;
|
|
|
|
procedure IEPNG_Comp_writeRows(comp: IEPNG_Compressor; row: pointer; numRows: dword);
|
|
begin
|
|
png_write_rows(comp^.pngPtr, row, numRows);
|
|
end;
|
|
|
|
procedure IEPNG_Comp_writeEnd(comp: IEPNG_Compressor);
|
|
begin
|
|
png_write_end(comp^.pngPtr, comp^.infoPtr);
|
|
end;
|
|
|
|
procedure IEPNG_Comp_setText(comp: IEPNG_Compressor; textList: IEPNG_TextList);
|
|
begin
|
|
png_set_text(comp^.pngPtr, comp^.infoPtr, @textList[0], length(textList));
|
|
end;
|
|
|
|
function IEPNG_createTextList(size: integer): IEPNG_TextList;
|
|
begin
|
|
SetLength(result, size);
|
|
end;
|
|
|
|
procedure IEPNG_textListSet(var textList: IEPNG_TextList; index: integer; compression: integer; key: string; text: string);
|
|
begin
|
|
textList[index].compression := compression;
|
|
textList[index].key := IEStrDup(PAnsiChar(AnsiString(key)));
|
|
textList[index].text := IEStrDup(PAnsiChar(AnsiString(text)));
|
|
textList[index].text_length := length( text );
|
|
end;
|
|
|
|
procedure IEPNG_destroyTextList(var textList: IEPNG_TextList);
|
|
var
|
|
i: integer;
|
|
begin
|
|
for i := 0 to length(textList) - 1 do
|
|
begin
|
|
freemem( textList[i].key );
|
|
freemem( textList[i].text );
|
|
end;
|
|
SetLength(textList, 0);
|
|
end;
|
|
|
|
|
|
{$endif} // not IEUSEDLLPNGLIB
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// dynamic (DLL) png library wrappers
|
|
|
|
|
|
{$ifdef IEUSEDLLPNGLIB}
|
|
|
|
|
|
type
|
|
|
|
IEPNG_Compressor = TIELibPNGCompressor;
|
|
IEPNG_Color = pointer;
|
|
IEPNG_TextList = TIELibPNGTextList;
|
|
|
|
|
|
|
|
|
|
function IEPNG_getIOPtr(pngPtr: pointer): pointer; // this must be pngPtr not IEPNG_Decompressor
|
|
begin
|
|
result := IELib.PNGGetIOPtr(pngPtr);
|
|
end;
|
|
|
|
function IEPNG_getErrorPtr(pngPtr: pointer): pointer; // this must be pngPtr not IEPNG_Decompressor or IEPNG_Compressor
|
|
begin
|
|
result := IELib.PNGGetErrorPtr(pngPtr);
|
|
end;
|
|
|
|
procedure IEPNG_Comp_destroy(var comp: IEPNG_Compressor);
|
|
begin
|
|
comp := nil;
|
|
end;
|
|
|
|
function IEPNG_Comp_create(errorPtr: pointer; errorFunc: pointer; warnFunc: pointer): IEPNG_Compressor;
|
|
begin
|
|
if IELibAvailable() then
|
|
begin
|
|
result := IELib.createPNGCompressor(errorPtr, errorFunc, warnFunc);
|
|
if not result.isValid() then
|
|
result := nil;
|
|
end
|
|
else
|
|
raise EIEPNGException.Create(IERS_IEVISIONNOTFOUND);
|
|
end;
|
|
|
|
procedure IEPNG_Comp_setWriteFunction(comp: IEPNG_Compressor; ioPtr: pointer; writeFunc: pointer; flushFunc: pointer);
|
|
begin
|
|
comp.setWriteFunction(ioPtr, writeFunc, flushFunc);
|
|
end;
|
|
|
|
procedure IEPNG_setPalette(comp: IEPNG_Compressor; palette: IEPNG_Color; numPalette: integer);
|
|
begin
|
|
comp.setPalette(palette, numPalette);
|
|
end;
|
|
|
|
procedure IEPNG_setTRNS(comp: IEPNG_Compressor; trans: pbyte; numTrans: integer);
|
|
begin
|
|
comp.setTRNS(trans, numTrans);
|
|
end;
|
|
|
|
procedure IEPNG_setIHDR(comp: IEPNG_Compressor; width: dword; height: dword; bitDepth: integer; colorType: integer; interlaceType: integer; compressionType: integer; filterType: integer);
|
|
begin
|
|
comp.setIHDR(width, height, bitDepth, colorType, interlaceType, compressionType, filterType);
|
|
end;
|
|
|
|
procedure IEPNG_setPHYS(comp: IEPNG_Compressor; resX: dword; resY: dword; unitType: integer);
|
|
begin
|
|
comp.setPHYS(resX, resY, unitType);
|
|
end;
|
|
|
|
procedure IEPNG_setFilter(comp: IEPNG_Compressor; method: integer; filters: integer);
|
|
begin
|
|
comp.setFilter(method, filters);
|
|
end;
|
|
|
|
procedure IEPNG_setBackground(comp: IEPNG_Compressor; colorValue: TRGB; colorIndex: byte);
|
|
begin
|
|
comp.setBackground(IETRGBToVisionBGR8(colorValue), colorIndex);
|
|
end;
|
|
|
|
procedure IEPNG_setCompressionLevel(comp: IEPNG_Compressor; level: integer);
|
|
begin
|
|
comp.setCompressionLevel(level);
|
|
end;
|
|
|
|
procedure IEPNG_setBGR(comp: IEPNG_Compressor);
|
|
begin
|
|
comp.setBGR();
|
|
end;
|
|
|
|
function IEPNG_createTextList(size: integer): IEPNG_TextList;
|
|
begin
|
|
result := IELib.createPNGTextList(size);
|
|
end;
|
|
|
|
procedure IEPNG_textListSet(var textList: IEPNG_TextList; index: integer; compression: integer; key: string; text: string);
|
|
begin
|
|
textList.assign(index, compression, PAnsiChar(AnsiString(key)), PAnsiChar(AnsiString(text)));
|
|
end;
|
|
|
|
procedure IEPNG_destroyTextList(var textList: IEPNG_TextList);
|
|
begin
|
|
textList := nil;
|
|
end;
|
|
|
|
procedure IEPNG_Comp_setText(comp: IEPNG_Compressor; textList: IEPNG_TextList);
|
|
begin
|
|
comp.setText(textList);
|
|
end;
|
|
|
|
procedure IEPNG_Comp_writeInfo(comp: IEPNG_Compressor);
|
|
begin
|
|
comp.writeInfo();
|
|
end;
|
|
|
|
function IEPNG_Comp_setInterlaceHandling(comp: IEPNG_Compressor): integer;
|
|
begin
|
|
result := comp.setInterlaceHandling();
|
|
end;
|
|
|
|
procedure IEPNG_Comp_writeRows(comp: IEPNG_Compressor; row: pointer; numRows: dword);
|
|
begin
|
|
comp.writeRows(row, numRows);
|
|
end;
|
|
|
|
procedure IEPNG_Comp_writeEnd(comp: IEPNG_Compressor);
|
|
begin
|
|
comp.writeEnd();
|
|
end;
|
|
|
|
|
|
{$endif} // IEUSEDLLPNGLIB
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
type
|
|
TIOData = record
|
|
Stream: TStream;
|
|
Aborting: pboolean;
|
|
end;
|
|
PIOData = ^TIOData;
|
|
|
|
|
|
procedure ErrorFunc(png_ptr: pointer; msg: pointer); cdecl;
|
|
begin
|
|
raise EInvalidGraphic.create('Error on creating PNG');
|
|
end;
|
|
|
|
procedure WarnFunc(png_ptr: pointer; msg: Pointer); cdecl;
|
|
begin
|
|
end;
|
|
|
|
procedure WriteFunc(png_ptr: pointer; data: pointer; length: dword); cdecl;
|
|
var
|
|
iodata: PIOData;
|
|
begin
|
|
iodata := IEPNG_getIOPtr(png_ptr);
|
|
if dword(iodata.Stream.Write(PAnsiChar(data)^, length)) < length then
|
|
iodata.Aborting^ := true;
|
|
end;
|
|
|
|
procedure FlushFunc(png_ptr: pointer); cdecl;
|
|
begin
|
|
end;
|
|
|
|
|
|
procedure WritePNGStream(Stream: TStream; bitmap: TIEBitmap; var IOParams: TIOParams; var xProgress: TProgressRec; AlphaChannel: TIEMask);
|
|
var
|
|
comp: IEPNG_Compressor;
|
|
bit_depth, color_type, interlace_type: integer;
|
|
WBitmap: TIEBitmap;
|
|
BackCol, ForeCol: TRGB;
|
|
FreeW: boolean; // if true then free WBitmap
|
|
qt: TIEQuantizer;
|
|
palette: array[0..255] of TRGB;
|
|
ppalette: PRGBROW;
|
|
number_passes, pass, y, x, height, width: integer;
|
|
px, ppx: pointer;
|
|
pp: PRGB;
|
|
brow: pbyte;
|
|
pw: pword;
|
|
NullProgress: TProgressRec;
|
|
bitmapwidth1: integer;
|
|
iodata: TIOData;
|
|
px2, px4: PRGBA;
|
|
px_byte, px3: pbyte;
|
|
bb: byte;
|
|
bps: integer;
|
|
hasalpha: boolean;
|
|
px_word: pword;
|
|
i, altindex: integer;
|
|
d, dt: double;
|
|
tcl: TRGB;
|
|
textList: IEPNG_TextList;
|
|
num_text: integer;
|
|
begin
|
|
NullProgress := NullProgressRec( xProgress.Aborting, False );
|
|
|
|
ppalette := nil;
|
|
WBitmap := nil;
|
|
qt := nil;
|
|
textList := nil;
|
|
color_type := 0;
|
|
|
|
comp := IEPNG_Comp_create(nil, @ErrorFunc, @WarnFunc);
|
|
if comp = nil then
|
|
raise EInvalidGraphic.create('Error on creating PNG');
|
|
|
|
FreeW := false;
|
|
|
|
try
|
|
|
|
iodata.Stream := Stream;
|
|
iodata.Aborting := xProgress.Aborting;
|
|
IEPNG_Comp_setWriteFunction(comp, @iodata, @WriteFunc, @FlushFunc);
|
|
|
|
// Adjusts unsupported BitsPerSample and SamplesPerPixel
|
|
if (IOParams.BitsPerSample > 8) then // i.e. 9, 10...forced to be 16
|
|
IOParams.BitsPerSample := 16;
|
|
if (IOParams.SamplesPerPixel = 1) and (IOParams.BitsPerSample <> 1) and (IOParams.BitsPerSample <> 8) and (IOParams.BitsPerSample <> 16) then
|
|
IOParams.BitsPerSample := 8;
|
|
|
|
// The bitmap to write will be contained in WBitmap
|
|
if (IOParams.BitsPerSample = 1) then
|
|
begin
|
|
// required to save to b/w
|
|
if (Bitmap.PixelFormat = ie1g) then
|
|
WBitmap := Bitmap
|
|
else
|
|
begin
|
|
// convert to 1 bit
|
|
WBitmap := _ConvertTo1bitEx(Bitmap, BackCol, ForeCol);
|
|
if WBitmap = nil then
|
|
begin
|
|
// impossible to convert to 1 bit, convert to ordered dither
|
|
WBitmap := TIEBitmap.Create;
|
|
WBitmap.Assign(Bitmap);
|
|
WBitmap.PixelFormat := ie1g;
|
|
end;
|
|
FreeW := true;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
// required to save in true color
|
|
if Bitmap.PixelFormat = ie1g then
|
|
begin
|
|
// convert to 24 bit
|
|
WBitmap := TIEBitmap.Create;
|
|
WBitmap.Assign(Bitmap);
|
|
WBitmap.PixelFormat := ie24RGB;
|
|
FreeW := true;
|
|
end
|
|
else
|
|
WBitmap := Bitmap;
|
|
end;
|
|
// assign interlace_type
|
|
if IOParams.PNG_Interlaced then
|
|
interlace_type := IEPNG_INTERLACE_ADAM7
|
|
else
|
|
interlace_type := IEPNG_INTERLACE_NONE;
|
|
// assign bit_depth and color_type
|
|
if IOParams.SamplesPerPixel = 1 then
|
|
begin
|
|
// B/W or palette
|
|
if wbitmap.PixelFormat = ie1g then
|
|
begin
|
|
// B/W
|
|
color_type := IEPNG_COLOR_TYPE_GRAY;
|
|
bit_depth := 1;
|
|
end
|
|
else
|
|
begin
|
|
// palette
|
|
color_type := IEPNG_COLOR_TYPE_PALETTE;
|
|
bit_depth := IOParams.BitsPerSample;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
// true color
|
|
color_type := IEPNG_COLOR_TYPE_RGB;
|
|
bit_depth := 8;
|
|
end;
|
|
hasalpha := assigned(AlphaChannel) and (not AlphaChannel.Full);
|
|
if hasalpha and (color_type = IEPNG_COLOR_TYPE_RGB) then
|
|
color_type := color_type or IEPNG_COLOR_MASK_ALPHA;
|
|
|
|
// Create palette if needed
|
|
if (IOParams.SamplesPerPixel = 1) and (IOParams.BitsPerSample > 1) and (wbitmap.PixelFormat <> ie1g) then
|
|
begin
|
|
if hasalpha then
|
|
begin
|
|
// save alpha channel as an entry in the color map (here 16 bit gray isn't supported)
|
|
bit_depth := 8;
|
|
bps := 1 shl IOParams.BitsPerSample;
|
|
qt := TIEQuantizer.Create(wBitmap, palette, imin(bps, 255)); // entry 0 reserved for transparent layer
|
|
getmem(ppalette, 256 * sizeof(TRGB));
|
|
CopyMemory(@(ppalette[1]), @(palette[0]), 255 * sizeof(TRGB));
|
|
with ppalette[0] do
|
|
begin
|
|
r := IOParams.PNG_Background.r;
|
|
g := IOParams.PNG_Background.g;
|
|
b := IOParams.PNG_Background.b;
|
|
end;
|
|
for x := 0 to 255 do
|
|
bswap(ppalette^[x].r, ppalette^[x].b);
|
|
IEPNG_setPalette(comp, IEPNG_Color(ppalette), imin(bps + 1, 256));
|
|
if hasalpha then
|
|
begin
|
|
bb := 0;
|
|
IEPNG_setTRNS(comp, @bb, 1);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
// do not save alpha. Full gray and 16 bit gray supported
|
|
qt := TIEQuantizer.Create(wBitmap, palette, 256);
|
|
getmem(ppalette, 256 * sizeof(TRGB));
|
|
CopyMemory(@(ppalette[0]), @(palette[0]), 256 * sizeof(TRGB));
|
|
for x := 0 to 255 do
|
|
bswap(ppalette^[x].r, ppalette^[x].b);
|
|
if not qt.GrayScale then
|
|
IEPNG_setPalette(comp, IEPNG_Color(ppalette), 256)
|
|
else
|
|
color_type := IEPNG_COLOR_TYPE_GRAY;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
qt := nil;
|
|
ppalette := nil;
|
|
end;
|
|
|
|
IEPNG_setIHDR(comp, bitmap.Width, bitmap.Height, bit_depth, color_type, interlace_type, IEPNG_COMPRESSION_TYPE_DEFAULT, IEPNG_FILTER_TYPE_DEFAULT);
|
|
|
|
// DPI
|
|
IEPNG_setPHYS(comp, round(IOParams.DPIX * 100 / CM_per_Inch), round(IOParams.DPIY * 100 / CM_per_Inch), IEPNG_RESOLUTION_METER);
|
|
|
|
// filter
|
|
case IOParams.PNG_Filter of
|
|
ioPNG_FILTER_NONE: IEPNG_setFilter(comp, 0, IEPNG_FILTER_NONE);
|
|
ioPNG_FILTER_SUB: IEPNG_setFilter(comp, 0, IEPNG_FILTER_SUB);
|
|
ioPNG_FILTER_PAETH: IEPNG_setFilter(comp, 0, IEPNG_FILTER_PAETH);
|
|
ioPNG_FILTER_UP: IEPNG_setFilter(comp, 0, IEPNG_FILTER_UP);
|
|
ioPNG_FILTER_AVG: IEPNG_setFilter(comp, 0, IEPNG_FILTER_AVG);
|
|
ioPNG_FILTER_ALL: IEPNG_setFilter(comp, 0, IEPNG_ALL_FILTERS);
|
|
end;
|
|
|
|
// set background
|
|
if assigned(qt) then
|
|
IEPNG_setBackground(comp, CreateRGB(0, 0, 0), qt.RGBIndex[IOParams.PNG_Background])
|
|
else
|
|
IEPNG_setBackground(comp, IOParams.PNG_Background, 0);
|
|
|
|
IEPNG_setCompressionLevel(comp, IOParams.PNG_Compression);
|
|
|
|
IEPNG_setBGR(comp);
|
|
|
|
// write text
|
|
num_text := imin(IOParams.PNG_TextKeys.Count, IOParams.PNG_TextValues.Count);
|
|
textList := IEPNG_createTextList(num_text);
|
|
for i := 0 to num_text - 1 do
|
|
IEPNG_textListSet(textList, i, -1, IOParams.PNG_TextKeys[i], IOParams.PNG_TextValues[i]);
|
|
IEPNG_Comp_setText(comp, textList);
|
|
|
|
IEPNG_Comp_writeInfo(comp);
|
|
|
|
// write rows
|
|
number_passes := IEPNG_Comp_setInterlaceHandling(comp);
|
|
height := wbitmap.Height;
|
|
width := wbitmap.Width;
|
|
xProgress.per1 := 100 / (height * number_passes);
|
|
xProgress.val := 0;
|
|
px2 := nil;
|
|
if (color_type = IEPNG_COLOR_TYPE_PALETTE) or (color_type = IEPNG_COLOR_TYPE_GRAY) then
|
|
getmem(px, wbitmap.width * imax(1, bit_depth div 8));
|
|
if (color_type and IEPNG_COLOR_MASK_ALPHA) <> 0 then
|
|
getmem(px2, wbitmap.width * sizeof(TRGBA));
|
|
for pass := 0 to number_passes - 1 do
|
|
begin
|
|
for y := 0 to height - 1 do
|
|
begin
|
|
if (color_type and IEPNG_COLOR_MASK_PALETTE) <> 0 then
|
|
begin
|
|
// palette
|
|
brow := px;
|
|
pp := wbitmap.Scanline[y];
|
|
px_byte := pbyte(pp);
|
|
bitmapwidth1 := wbitmap.Width - 1;
|
|
if assigned(AlphaChannel) and (not AlphaChannel.Full) then
|
|
begin
|
|
// alpha channel
|
|
case wbitmap.PixelFormat of
|
|
ie24RGB:
|
|
begin
|
|
px3 := alphachannel.Scanline[y];
|
|
for x := 0 to bitmapwidth1 do
|
|
begin
|
|
if px3^ < 255 then
|
|
brow^ := 0
|
|
else
|
|
brow^ := qt.RGBIndex[pp^] + 1;
|
|
inc(brow);
|
|
inc(pp);
|
|
inc(px3);
|
|
end;
|
|
end;
|
|
ie8p:
|
|
begin
|
|
// search an alternate color for indexes with transparent index
|
|
d := 100000;
|
|
tcl := wbitmap.Palette[0];
|
|
altindex := 0;
|
|
for i := 1 to wbitmap.PaletteLength-1 do
|
|
begin
|
|
with wbitmap.Palette[i] do
|
|
begin
|
|
dt := sqr(r-tcl.r)+sqr(g-tcl.g)+sqr(b-tcl.b);
|
|
if dt < d then
|
|
begin
|
|
d := dt;
|
|
altindex := i;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
for x := 0 to bitmapwidth1 do
|
|
begin
|
|
brow^ := px_byte^;
|
|
if brow^ = 0 then
|
|
brow^ := altindex;
|
|
inc(brow);
|
|
inc(px_byte);
|
|
end;
|
|
end;
|
|
ie8g:
|
|
begin
|
|
px3 := alphachannel.Scanline[y];
|
|
for x := 0 to bitmapwidth1 do
|
|
begin
|
|
brow^ := px_byte^;
|
|
if px3^ < 255 then
|
|
brow^ := 0
|
|
else
|
|
if brow^ = 0 then
|
|
brow^ := 1;
|
|
inc(brow);
|
|
inc(px_byte);
|
|
inc(px3);
|
|
end;
|
|
end;
|
|
end
|
|
end
|
|
else
|
|
begin
|
|
// simple palette
|
|
case wbitmap.PixelFormat of
|
|
ie24RGB:
|
|
for x := 0 to bitmapwidth1 do
|
|
begin
|
|
brow^ := qt.RGBIndex[pp^];
|
|
inc(brow);
|
|
inc(pp);
|
|
end;
|
|
ie8p:
|
|
for x := 0 to bitmapwidth1 do
|
|
begin
|
|
brow^ := px_byte^;
|
|
inc(brow);
|
|
inc(px_byte);
|
|
end;
|
|
end;
|
|
end;
|
|
IEPNG_Comp_writeRows(comp, @px, 1);
|
|
end
|
|
else
|
|
if (color_type and IEPNG_COLOR_MASK_COLOR) <> 0 then
|
|
begin
|
|
// truecolor
|
|
if (color_type and IEPNG_COLOR_MASK_ALPHA) <> 0 then
|
|
begin
|
|
// alpha channel
|
|
pp := wbitmap.Scanline[y];
|
|
px3 := alphachannel.Scanline[y];
|
|
px4 := px2;
|
|
for x := 0 to width - 1 do
|
|
begin
|
|
with px4^ do
|
|
begin
|
|
r := pp^.r;
|
|
g := pp^.g;
|
|
b := pp^.b;
|
|
a := px3^;
|
|
end;
|
|
inc(pp);
|
|
inc(px3);
|
|
inc(px4);
|
|
end;
|
|
IEPNG_Comp_writeRows(comp, @px2, 1);
|
|
end
|
|
else
|
|
begin
|
|
ppx := wbitmap.Scanline[y];
|
|
IEPNG_Comp_writeRows(comp, @ppx, 1);
|
|
end;
|
|
end
|
|
else
|
|
if (color_type = IEPNG_COLOR_TYPE_GRAY) then
|
|
begin
|
|
// gray scale
|
|
if bit_depth = 16 then
|
|
begin
|
|
case wbitmap.PixelFormat of
|
|
ie24RGB:
|
|
begin
|
|
pp := wbitmap.Scanline[y];
|
|
pw := px;
|
|
for x := 0 to width - 1 do
|
|
begin
|
|
pw^ := qt.RGBIndex[pp^];
|
|
inc(pw);
|
|
inc(pp);
|
|
end;
|
|
end;
|
|
ie16g:
|
|
begin
|
|
px_word := wbitmap.Scanline[y];
|
|
pw := px;
|
|
for x := 0 to width - 1 do
|
|
begin
|
|
pw^ := px_word^ shr 8;
|
|
inc(pw);
|
|
inc(px_word);
|
|
end;
|
|
end;
|
|
end;
|
|
IEPNG_Comp_writeRows(comp, @px, 1);
|
|
end
|
|
else
|
|
if bit_depth = 8 then
|
|
begin
|
|
case wbitmap.PixelFormat of
|
|
ie24RGB:
|
|
begin
|
|
pp := wbitmap.Scanline[y];
|
|
brow := px;
|
|
for x := 0 to width - 1 do
|
|
begin
|
|
brow^ := qt.RGBIndex[pp^];
|
|
inc(brow);
|
|
inc(pp);
|
|
end;
|
|
end;
|
|
ie8g:
|
|
begin
|
|
px_byte := wbitmap.Scanline[y];
|
|
brow := px;
|
|
for x := 0 to width - 1 do
|
|
begin
|
|
brow^ := px_byte^;
|
|
inc(brow);
|
|
inc(px_byte);
|
|
end;
|
|
end;
|
|
end;
|
|
IEPNG_Comp_writeRows(comp, @px, 1);
|
|
end
|
|
else
|
|
begin
|
|
ppx := wbitmap.Scanline[y];
|
|
IEPNG_Comp_writeRows(comp, @ppx, 1);
|
|
end;
|
|
end;
|
|
// OnProgress
|
|
with xProgress do
|
|
begin
|
|
inc(val);
|
|
if assigned(fOnProgress) then
|
|
fOnProgress(Sender, trunc(per1 * val));
|
|
end;
|
|
if xProgress.Aborting^ then
|
|
break;
|
|
end;
|
|
if xProgress.Aborting^ then
|
|
break;
|
|
end;
|
|
|
|
finally
|
|
|
|
if (color_type and IEPNG_COLOR_MASK_ALPHA) <> 0 then
|
|
freemem(px2);
|
|
if (color_type = IEPNG_COLOR_TYPE_PALETTE) or (color_type = IEPNG_COLOR_TYPE_GRAY) then
|
|
freemem(px);
|
|
|
|
// cleanup
|
|
|
|
try
|
|
if not xProgress.Aborting^ then
|
|
IEPNG_Comp_writeEnd(comp);
|
|
finally
|
|
|
|
if ppalette <> nil then
|
|
freemem(ppalette);
|
|
|
|
IEPNG_Comp_destroy(comp);
|
|
|
|
if FreeW then
|
|
FreeAndNil(WBitmap);
|
|
if assigned(qt) then
|
|
FreeAndNil(qt);
|
|
|
|
IEPNG_destroyTextList(textList);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{$ELSE} // IEINCLUDEPNG
|
|
|
|
interface
|
|
implementation
|
|
|
|
{$ENDIF}
|
|
|
|
|
|
|
|
|
|
end.
|
|
|