1. 개요
투명한 PNG 이미지를 투명 배경을 흰색 바탕으로 처리한 다른 이미지로 저장해 보자.
2. 증상 분석
투명 PNG 이미지를 투명부분을 흰색 배경으로 처리한채 다른 이미지포멧(BMP 또는 JPG)로 저장하고자 할 경우에 일반적으로 다음 과 같은 방법을 시도하여 변환을 시도할 것이다.
var
bmp : TBitmap;
jpg : TJpegImage;
png : TPngObject;
begin
try
bmp := TBitmap.Create;
jpg := TJpegImage.Create;
png := TPngObject;
png .LoadFromFile(APngFileName);
bmp.Assign(png);
jpg.Assign(bmp);
jpg.SaveToFile(AJpegName);
finally
jpg.free;
png.free;
bmp.Free;
end;
end;
위와 같이 처리하게 되면 PNG이미지의 투명한 부분이 아마도 다음과 같이 black으로 나오는 것을 경험하게 될 것이다.
3. 처리방안
GR32를 이용하여 투명 이미지를 배경을 흰색으로 지정한 다른 이미지로 변경해 보자
GR32의 TBitmap32도 TBitmap과 마찬가지로 직접 사용하게 되면 동일하게 원치 않는 결과를 얻는데
다음 소스를 이용하여 처리해 보도록 하자.
-라이브러리(GR32_PNG, 기존 Graphics 라이브러리에 포함된 소스는 아님)
//*******************************************************************
//
// UNIT: G r 3 2 _ P N G 15.Jan.2005, 19. March 2010
//
// PNG Graphic Unit for graphics32 library v1.7.x and higher
// to load and save PNG images (Portable Network Graphics)
// Tested with graphics32 v1.9.0 2010-03-08
//
// needs TPNGImage component from Gustavo Daud (✉uol.com.br)
// http://pngdelphi.sourceforge.net/
//
// Tested with: graphics32 v1.9.0 2010-03-08
// PNGImage v1.564 2006-07-25.
//
// FAQ:
// Q: Is there a PNG library for GR32 which supports loading and saving
// an image and its alpha channel at the same time?
//
// A: Yes, you need TPNGImage component from Gustavo Daud
// and this unit to load and save PNG images.
//
// LoadPNGintoBitmap32 code taken from
// http://graphics32.org/wiki/pub/page/FAQ/ImageFormatRelated
//
// note: if you use standard picture file dialogs of type TOpenPictureDialog
// or TSavePictureDialog to load or save PNG pictures, you have to add
// string "Portable Network Graphics (*.png)" and "*.png"
// to filter property !
//
// --- functions and procedures ---
//
// LoadPNGintoBitmap32 load PNG image file into Bitmap32
// SaveBitmap32ToPNG save Bitmap32 to PNG image file
//
// Bitmap32ToPNG convert Bitmap32 to PNG object
//
//*******************************************************************
unit GR32_PNG;
INTERFACE
uses SysUtils, Classes, Graphics, GR32, PNGImage;
function LoadPNGintoBitmap32 (destBitmap: TBitmap32;
srcStream: TStream;
out transparent: Boolean): boolean; overload;
function LoadPNGintoBitmap32 (destBitmap: TBitmap32;
filename: String;
out transparent: Boolean): boolean; overload;
function SaveBitmap32ToPNG (sourceBitmap: TBitmap32;
transparent: Boolean;
bgColor32: TColor32;
filename: String;
compressionLevel: TCompressionLevel = 9;
interlaceMethod: TInterlaceMethod = imNone): boolean;
function Bitmap32ToPNG (sourceBitmap: TBitmap32;
paletted, transparent: Boolean;
bgColor: TColor;
compressionLevel: TCompressionLevel = 9;
interlaceMethod: TInterlaceMethod = imNone): tPNGObject;
IMPLEMENTATION
//*********************************************************
// load PNG image from source stream
// input: destBitmap: TBitmap32; destination bitmap
// srcStream: TStream; source stream
// output: transparent: boolean; =true: alpha channel used
// return: boolean; =true: png image file loaded
// destBitmap: TBitmap32; destination bitmap data
//---------------------------------------------------------
function LoadPNGintoBitmap32 (destBitmap: TBitmap32;
srcStream: TStream;
out transparent: Boolean): boolean;
var
PNGObject: TPNGObject;
TransparentColor: TColor32;
PixelPtr: PColor32;
AlphaPtr: PByte;
X, Y: Integer;
begin
PNGObject := nil;
try
result := false;
// if two images with same size are loaded and 2nd has transparent pixel
// the color value are not cleared -> this is a BUG
destBitmap.Clear($FF000000); // bug correction!
PNGObject := TPngObject.Create;
PNGObject.LoadFromStream(srcStream);
destBitmap.Assign(PNGObject);
// destBitmap.ResetAlpha; // bug correction!
case PNGObject.TransparencyMode of
ptmPartial:
begin
if (PNGObject.Header.ColorType = COLOR_GRAYSCALEALPHA) or
(PNGObject.Header.ColorType = COLOR_RGBALPHA) then
begin
PixelPtr := PColor32(@destBitmap.Bits[0]);
for Y := 0 to destBitmap.Height - 1 do
begin
AlphaPtr := PByte(PNGObject.AlphaScanline[Y]);
for X := 0 to destBitmap.Width - 1 do
begin
PixelPtr^ := (PixelPtr^ and $00FFFFFF) or (TColor32(AlphaPtr^) shl 24);
Inc(PixelPtr); Inc(AlphaPtr); end;
end;
transparent := True;
end;
end;
ptmBit:
begin
TransparentColor := Color32(PNGObject.TransparentColor);
PixelPtr := PColor32(@destBitmap.Bits[0]);
for X := 0 to (destBitmap.Height - 1) * (destBitmap.Width - 1) do
begin
if PixelPtr^ = TransparentColor then
PixelPtr^ := PixelPtr^ and $00FFFFFF;
Inc(PixelPtr);
end;
transparent := True;
end;
ptmNone:
transparent := False;
end;
result := true;
finally
if Assigned(PNGObject) then PNGObject.Free;
end;
end;
//*********************************************************
// load PNG image file into Bitmap32
// input: destBitmap: TBitmap32; destination bitmap
// filename: String; name of PNG image file
// output: transparent: boolean; =true: alpha channel used
// return: boolean; =true: png image file loaded
//---------------------------------------------------------
function LoadPNGintoBitmap32 (destBitmap: TBitmap32;
filename: String;
out transparent: boolean): boolean;
var
FileStream: TFileStream;
begin
result := false;
try
FileStream := TFileStream.Create(filename, fmOpenRead);
try
result := LoadPNGintoBitmap32(destBitmap, FileStream, transparent);
finally
FileStream.Free;
end;
except
end;
end;
//*********************************************************
// convert Bitmap32 to PNG image
// input: sourceBitmap source bitmap 32 bit
// paletted =true: PixelFormat is pf8bit
// transparent =true: transparent pixels
// bgColor background color
// compressionLevel compression level, range 0..9, default = 9
// interlaceMethod interlaced method, use imNone or imAdam7
// return: tPNGObject PNG image object
//---------------------------------------------------------
function Bitmap32ToPNG (sourceBitmap: TBitmap32;
paletted, transparent: Boolean;
bgColor: TColor;
compressionLevel: TCompressionLevel = 9;
interlaceMethod: TInterlaceMethod = imNone): tPNGObject;
var
bm: TBitmap;
png: TPngObject;
TRNS: TCHUNKtRNS;
p: pngImage.PByteArray;
x, y: Integer;
begin
Result := nil;
png := TPngObject.Create;
try
bm := TBitmap.Create;
try
bm.Assign (sourceBitmap); // convert data into bitmap
// force paletted on TBitmap, transparent for the web must be 8bit
if paletted then
bm.PixelFormat := pf8bit;
png.interlaceMethod := interlaceMethod;
png.compressionLevel := compressionLevel;
png.Assign(bm); // convert bitmap into PNG
finally
FreeAndNil(bm);
end;
if transparent then begin
if png.Header.ColorType in [COLOR_PALETTE] then begin
if (png.Chunks.ItemFromClass(TChunktRNS) = nil) then png.CreateAlpha;
TRNS := png.Chunks.ItemFromClass(TChunktRNS) as TChunktRNS;
if Assigned(TRNS) then TRNS.TransparentColor := bgColor;
end;
if png.Header.ColorType in [COLOR_RGB, COLOR_GRAYSCALE] then png.CreateAlpha;
if png.Header.ColorType in [COLOR_RGBALPHA, COLOR_GRAYSCALEALPHA] then
begin
for y := 0 to png.Header.Height - 1 do begin
p := png.AlphaScanline[y];
for x := 0 to png.Header.Width - 1
do p[x] := AlphaComponent(sourceBitmap.Pixel[x,y]); // TARGB(bm.Pixel[x,y]).a;
end;
end;
end;
Result := png;
except
png.Free;
end;
end;
//*********************************************************
// save Bitmap32 to PNG image file
// input: srcBitmap source bitmap
// transparent =true: transparent pixels
// bgColor32 background color 32 bit
// compressionLevel compression level, range 0..9, default = 9
// interlaceMethod interlaced method, use imNone or imAdam7
// return: boolean =true: bitmap saved as PNG image file
//---------------------------------------------------------
function SaveBitmap32ToPNG (sourceBitmap: TBitmap32;
transparent: Boolean;
bgColor32: TColor32;
filename: String;
compressionLevel: TCompressionLevel = 9;
interlaceMethod: TInterlaceMethod = imNone): boolean;
var png: tPNGObject;
begin
result := false;
try
png := Bitmap32ToPNG (sourceBitmap, false, transparent, WinColor(bgColor32),
compressionLevel, interlaceMethod);
try
png.SaveToFile (filename);
result := true;
finally
png.Free;
end;
except
end;
end;
//---------------------------------------------------------
// file stream variant to save bitmap32 as PNG picture file
//---------------------------------------------------------
(*
function xSaveBitmap32ToPNG (sourceBitmap: TBitmap32;
transparent: Boolean;
bgColor32: TColor32;
filename: String;
compressionLevel: TCompressionLevel = 9;
interlaceMethod: TInterlaceMethod = imNone): boolean;
var png: tPNGObject;
FileStream: TFileStream;
begin
result := false;
try
FileStream := TFileStream.Create(filename, fmCreate);
try
png := Bitmap32ToPNG (sourceBitmap, false, transparent, WinColor(bgColor32),
compressionLevel, interlaceMethod);
try
png.SaveToStream (FileStream);
result := true;
finally
png.Free;
end;
finally
FileStream.Free;
end;
except
end;
end;
*)
//*********************************************************
// code example of loading and saving a PNG image file
//---------------------------------------------------------
procedure PNGExample;
var transparent: boolean;
myBitmap: tBitmap32;
begin
myBitmap := TBitmap32.Create;
transparent := true;
if LoadPNGintoBitmap32 (MyBitmap, 'example1.png', transparent)
then begin
if transparent then
// add anything else that should be on transparent PNG image...
MyBitmap.DrawMode := dmBlend
else
MyBitmap.DrawMode := dmOpaque;
SaveBitmap32ToPNG (myBitmap, transparent, clBlack, 'savetest.png', 5);
end;
myBitmap.Free;
end;
begin
// PNGExample; // delete comment to test loading and saving PNG image
end.
처리 예제)
var
bmp : TBitmap;
bmp32 : TBitmap32;
jpg : TJpegImage;
trans : Boolean;
begin
bmp := TBitmap.Create;
bmp32 := TBitmap32.Create;
jpg := TJpegImage.Create;
try
LoadPNGintoBitmap32(bmp32, AImageFileName, trans);
bmp.Assign(bmp32);
jpg.Assign(bmp);
jpg.CompressionQuality := 80;
jpg.SaveToFile(newFn);
finally
jpg.Free;
bmp.Free;
bmp32.Free;
end;
end;
반응형
'IT > 델파이' 카테고리의 다른 글
델파이 PNG파일 Image32로드 하기 (0) | 2024.02.05 |
---|---|
[Delphi] 워터마크 표시와 이미지 줄이기 (0) | 2023.11.10 |
TcxGrid에서 Popup메뉴 열리기 전에 클릭된 컬럼 및 종류 알아내기 (0) | 2023.02.15 |
TRichEdit에서 전체선택(CTRL+A)시 문서 끝으로 자동 스크롤 시키기 (0) | 2023.02.15 |
TRichEdit에서 기본 컨텍스트팝업메뉴(Context Popup Menu) 활성화 시키기 (0) | 2023.02.15 |