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;
'프로그래밍 > Delphi' 카테고리의 다른 글
[Delphi-Tip]지정된 프로그램이 실행중인지 체크 (1) | 2016.03.17 |
---|---|
[델파이] 바람직한 주석(Comment)달기 (0) | 2015.10.07 |
TcxGrid에서 Popup메뉴 열리기 전에 클릭된 컬럼 및 종류 알아내기 (0) | 2015.04.06 |
TRichEdit에서 전체선택(CTRL+A)시 문서 끝으로 자동 스크롤 시키기 (0) | 2014.12.18 |
TRichEdit에서 기본 컨텍스트팝업메뉴(Context Popup Menu) 활성화 시키기 (0) | 2014.12.18 |