📄 pngfiltw.pas
字号:
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 := PNG_INTERLACE_ADAM7
else
interlace_type := PNG_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 := PNG_COLOR_TYPE_GRAY;
bit_depth := 1;
end
else
begin
// palette
color_type := PNG_COLOR_TYPE_PALETTE;
bit_depth := ioparams.BitsPerSample;
end;
end
else
begin
// true color
color_type := PNG_COLOR_TYPE_RGB;
bit_depth := 8;
end;
hasalpha := assigned(AlphaChannel) and (not AlphaChannel.Full);
if hasalpha and (color_type = PNG_COLOR_TYPE_RGB) then
color_type := color_type or PNG_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), -1, 0); // 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);
png_set_PLTE(png_ptr, info_ptr, png_colorp(ppalette), imin(bps + 1, 256));
if hasalpha then
begin
bb := 0;
png_set_tRNS(png_ptr, info_ptr, @bb, 1, nil);
end;
end
else
begin
// do not save alpha. Full gray and 16 bit gray supported
qt := TIEQuantizer.Create(wBitmap, palette, 256, -1, 0);
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
png_set_PLTE(png_ptr, info_ptr, png_colorp(ppalette), 256)
else
color_type := PNG_COLOR_TYPE_GRAY;
end;
end
else
begin
qt := nil;
ppalette := nil;
end;
png_set_IHDR(png_ptr, info_ptr, bitmap.width, bitmap.height, bit_depth, color_type,
interlace_type, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
// DPI
png_set_pHYs(png_ptr, info_ptr, round(ioparams.DPIX * 100 / 2.54), round(ioparams.DPIY * 100 / 2.54), PNG_RESOLUTION_METER);
//
case ioparams.PNG_Filter of
ioPNG_FILTER_NONE: png_set_filter(png_ptr, 0, PNG_FILTER_NONE);
ioPNG_FILTER_SUB: png_set_filter(png_ptr, 0, PNG_FILTER_SUB);
ioPNG_FILTER_PAETH: png_set_filter(png_ptr, 0, PNG_FILTER_PAETH);
end;
// set background
zeromemory(@background, sizeof(background));
if assigned(qt) then
background.index := qt.RGBIndex[ioparams.PNG_Background]
else
begin
background.red := ioparams.PNG_Background.r *257;
background.green := ioparams.PNG_Background.g *257;
background.blue := ioparams.PNG_Background.b *257;
end;
png_set_bKGD(png_ptr, info_ptr, @background);
//
png_set_compression_level(png_ptr, ioparams.PNG_Compression);
//
png_set_bgr(png_ptr);
// write text
num_text:=imin(IOParams.PNG_TextKeys.Count, IOParams.PNG_TextValues.Count);
getmem(png_text_mem, sizeof(tpng_text)*num_text);
png_text_idx:=png_text_mem;
for i:=0 to num_text-1 do
begin
png_text_idx^.compression:=-1;
png_text_idx^.key:=pchar(IOParams.PNG_TextKeys[i]);
png_text_idx^.text:=pchar(IOParams.PNG_TextValues[i]);
png_text_idx^.text_length:=length( IOParams.PNG_TextValues[i] );
inc(png_text_idx);
end;
png_set_text(png_ptr,info_ptr, png_text_mem, num_text);
png_write_info(png_ptr, info_ptr);
// write rows
number_passes := png_set_interlace_handling(png_ptr);
height := wbitmap.height;
width := wbitmap.width;
xProgress.per1 := 100 / (height * number_passes);
xProgress.val := 0;
px2 := nil;
if (color_type = PNG_COLOR_TYPE_PALETTE) or (color_type = PNG_COLOR_TYPE_GRAY) then
getmem(px, wbitmap.width * imax(1, bit_depth div 8));
if (color_type and PNG_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 PNG_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;
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;
png_write_rows(png_ptr, @px, 1);
end
else if (color_type and PNG_COLOR_MASK_COLOR) <> 0 then
begin
// truecolor
if (color_type and PNG_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;
png_write_rows(png_ptr, @px2, 1);
end
else
begin
ppx := wbitmap.scanline[y];
png_write_rows(png_ptr, @ppx, 1);
end;
end
else if (color_type = PNG_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;
png_write_rows(png_ptr, @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;
png_write_rows(png_ptr, @px, 1);
end
else
begin
ppx := wbitmap.scanline[y];
png_write_rows(png_ptr, @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;
if (color_type and PNG_COLOR_MASK_ALPHA) <> 0 then
freemem(px2);
if (color_type = PNG_COLOR_TYPE_PALETTE) or (color_type = PNG_COLOR_TYPE_GRAY) then
freemem(px);
// fine
if not xProgress.Aborting^ then
png_write_end(png_ptr, info_ptr);
if ppalette <> nil then
freemem(ppalette);
png_destroy_write_struct(@png_ptr, @info_ptr);
if FreeW then
FreeAndNil(WBitmap);
if assigned(qt) then
FreeAndNil(qt);
end;
{$ELSE} // IEINCLUDEPNG
interface
implementation
{$ENDIF}
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -