From 60b10568792798c2e71eb0c8a91f94248f6cc3ca Mon Sep 17 00:00:00 2001 From: jesusr Date: Wed, 1 Dec 2010 21:41:42 +0000 Subject: [PATCH] PowerPDF, support for images with transparency/alfa channel git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@1394 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- components/powerpdf/PReport.pas | 10 ++- components/powerpdf/PdfDoc.pas | 1 + components/powerpdf/PdfImages.pas | 96 ++++++++++++++++++++++++---- components/powerpdf/PdfJpegImage.pas | 4 +- 4 files changed, 92 insertions(+), 19 deletions(-) diff --git a/components/powerpdf/PReport.pas b/components/powerpdf/PReport.pas index 4742bbe5d..2e1362b0a 100644 --- a/components/powerpdf/PReport.pas +++ b/components/powerpdf/PReport.pas @@ -473,6 +473,7 @@ type { TPRImage } TPRImage = class(TPRItem) private + FSharedName: string; procedure SetStretch(Value: boolean); protected FPicture: TPicture; @@ -484,6 +485,7 @@ type public constructor Create(AOwner: TComponent); override; destructor Destroy; override; + property SharedName: string read FSharedName write FSharedName; published property Picture: TPicture read FPicture write SetPicture; property SharedImage: boolean read FSharedImage write FSharedImage; @@ -2312,14 +2314,16 @@ var FIdx: integer; begin if (FPicture = nil) or (FPicture.Graphic = nil) or - (FPicture.Graphic.Empty) or not (FPicture.Graphic is TBitmap) then + (FPicture.Graphic.Empty) {or not (FPicture.Graphic is TFPImageBitmap)} then Exit; FDoc := ACanvas.PdfCanvas.Doc; if SharedImage then begin FXObjectName := Self.Name; + if FXObjectName='' then + FXObjectName := FSharedName; if FDoc.GetXObject(FXObjectName) = nil then - FDoc.AddXObject(FXObjectName, CreatePdfImage(FPicture.Graphic, 'Pdf-Bitmap')); + FDoc.AddXObject(FXObjectName, CreatePdfImage(FPicture.Graphic, 'Pdf-Bitmap', FDoc.ObjectMgr)); end else begin @@ -2334,7 +2338,7 @@ begin if FIdx >= MAX_IMAGE_NUMBER then FIdx := 0; end; - FDoc.AddXObject(FXObjectName, CreatePdfImage(FPicture.Graphic, 'Pdf-Bitmap')); + FDoc.AddXObject(FXObjectName, CreatePdfImage(FPicture.Graphic, 'Pdf-Bitmap', FDoc.ObjectMgr)); end; with ARect, ACanvas.PdfCanvas do if FStretch then diff --git a/components/powerpdf/PdfDoc.pas b/components/powerpdf/PdfDoc.pas index 3d8f85345..8ede8ec56 100644 --- a/components/powerpdf/PdfDoc.pas +++ b/components/powerpdf/PdfDoc.pas @@ -346,6 +346,7 @@ type property Info: TPdfInfo read GetInfo; property Root: TPdfCatalog read GetRoot; property OutlineRoot: TPdfOutlineRoot read GetOutlineRoot; + property ObjectMgr: TPdfXRef read FXRef; property DefaultPageWidth: word read FDefaultPageWidth write FDefaultPageWidth; property DefaultPageHeight: word read FDefaultPageHeight write FDefaultPageHeight; property CompressionMethod: TPdfCompressionMethod diff --git a/components/powerpdf/PdfImages.pas b/components/powerpdf/PdfImages.pas index fa7e96da5..8da828513 100644 --- a/components/powerpdf/PdfImages.pas +++ b/components/powerpdf/PdfImages.pas @@ -53,23 +53,26 @@ uses type TPdfImageCreator = class(TPersistent) public - function CreateImage(AImage: TGraphic): TPdfImage; virtual; + function CreateImage(AImage: TGraphic; ObjectMgr: TPdfObjectMgr=nil): TPdfImage; virtual; end; + { TPdfBitmapImage } + TPdfBitmapImage = class(TPdfImageCreator) private function CreateIndexedColorArray(ABitmap: TBitmap): TPdfArray; + function CreateMaskStream(AImage: TFPCustomImage): TPDfImage; public - function CreateImage(AImage: TGraphic): TPdfImage; override; + function CreateImage(AImage: TGraphic; ObjectMgr: TPdfObjectMgr=nil): TPdfImage; override; end; EPdfInvalidImageFormat = class(Exception); - function CreatePdfImage(AImage: TGraphic; ImageClassName: string): TPdfImage; + function CreatePdfImage(AImage: TGraphic; ImageClassName: string; ObjectMgr: TPdfObjectMgr=nil): TPdfImage; implementation -function CreatePdfImage(AImage: TGraphic; ImageClassName: string): TPdfImage; +function CreatePdfImage(AImage: TGraphic; ImageClassName: string; ObjectMgr: TPdfObjectMgr=nil): TPdfImage; var PdfImageCreator: TPdfImageCreator; begin @@ -82,14 +85,14 @@ begin try if PdfImageCreator = nil then raise Exception.CreateFmt('AddImage --InvalidImageClassName:%s', [ImageClassName]); - Result := PdfImageCreator.CreateImage(AImage); + Result := PdfImageCreator.CreateImage(AImage, ObjectMgr); finally PdfImageCreator.Free; end; end; { TPdfImageCreator } -function TPdfImageCreator.CreateImage(AImage: TGraphic): TPdfImage; +function TPdfImageCreator.CreateImage(AImage: TGraphic; ObjectMgr: TPdfObjectMgr=nil): TPdfImage; begin result := nil; end; @@ -161,7 +164,41 @@ begin end; end; -function TPdfBitmapImage.CreateImage(AImage: TGraphic): TPdfImage; +function TPdfBitmapImage.CreateMaskStream(AImage: TFPCustomImage): TPDfImage; +var + pb: PByteArray; + y: Integer; + x: Integer; +begin + result := TPdfImage.CreateStream(nil); + with result do + try + with Attributes do + begin + AddItem('Type', TPdfName.CreateName('XObject')); + AddItem('Subtype', TPdfName.CreateName('Image')); + AddItem('Width', TPdfNumber.CreateNumber(aImage.Width)); + AddItem('Height', TPdfNumber.CreateNumber(aImage.Height)); + AddItem('BitsPerComponent', TPdfNumber.CreateNumber(8)); + AddItem('ColorSpace',TPdfName.CreateName('DeviceGray')); + if USE_ZLIB then + PdfArrayByName('Filter').AddItem(TPdfName.CreateName('FlateDecode')); + + new(pb); + for y := 0 to AImage.Height - 1 do + begin + for x := 0 to AImage.Width-1 do + pb^[x] := AImage.Pixels[x,y]; + Stream.Write(pb^, AImage.Width); + end; + dispose(pb); + end; + + finally + end; +end; + +function TPdfBitmapImage.CreateImage(AImage: TGraphic; ObjectMgr: TPdfObjectMgr=nil): TPdfImage; var ABitmap: TBitmap; x, y: integer; @@ -170,14 +207,17 @@ var {$IFDEF LAZ_POWERPDF} aIntfImage: TLazIntfImage; aColor : TFPColor; + Alpha : TFPMemoryImage; + maskimage : TPDFImage; + hasAlpha : boolean; {$endif} + +{$IFDEF USE_CLX} const - {$IFDEF USE_CLX} PIXEL_COLOR_SIZE = 4; - {$ELSE} - PIXEL_COLOR_SIZE = 3; - {$ENDIF} +{$ENDIF} begin + result := TPdfImage.CreateStream(nil); with result do try @@ -197,8 +237,6 @@ begin aIntfImage := TLazIntfImage.Create(0,0); aIntfImage.LoadFromBitmap(aBitmap.Handle, aBitmap.MaskHandle); {$ENDIF} - - // if bitmap image has less then 8 bit color, set PixelFormat to 8 bit. if (PixelFormat = pf1bit) or {$IFNDEF USE_CLX} @@ -257,7 +295,22 @@ begin Stream.Write(pb[x], 3); x := x + PIXEL_COLOR_SIZE; end; + Attributes.AddItem('ColorSpace', TPdfName.CreateName('DeviceRGB')); + end; {$else} + Alpha := TFPMemoryImage.Create(AImage.Width, AImage.Height); + Alpha.UsePalette := true; + Alpha.Palette.Count := 256; + for x:=0 to $FF do + begin + aColor.Red:=x; + aColor.Red:=(aColor.Red shl 8) + aColor.Red; + aColor.Green:=aColor.Red; + aColor.Blue:=aColor.Red; + Alpha.Palette.Color[x]:=aColor; + end; + HasAlpha := false; + for y := 0 to aintfimage.Height - 1 do begin new(pb); @@ -268,11 +321,26 @@ begin pb[ 1 ] := acolor.green shr 8; pb[ 2 ] := acolor.blue shr 8; Stream.write(pb[ 0 ], 3); + + b := acolor.alpha shr 8; + Alpha.Pixels[x,y] := b; + + if acolor.Alpha<>AlphaOpaque then + HasAlpha := true; end; dispose(pb); -{$endif} Attributes.AddItem('ColorSpace', TPdfName.CreateName('DeviceRGB')); end; + + if HasAlpha then begin + MaskImage := CreateMaskStream(Alpha); + if ObjectMgr<>nil then + ObjectMgr.AddObject(MaskImage); + Attributes.AddItem('SMask', MaskImage); + end; + + Alpha.Free; +{$endif} end; with Attributes do diff --git a/components/powerpdf/PdfJpegImage.pas b/components/powerpdf/PdfJpegImage.pas index 29926a639..30b5e3394 100644 --- a/components/powerpdf/PdfJpegImage.pas +++ b/components/powerpdf/PdfJpegImage.pas @@ -35,13 +35,13 @@ type { TPdfJpegImage } TPdfJpegImage = class(TPdfImageCreator) public - function CreateImage(AImage: TGraphic): TPdfImage; override; + function CreateImage(AImage: TGraphic; ObjectMgr: TPdfObjectMgr=nil): TPdfImage; override; end; implementation // CreateImage -function TPdfJpegImage.CreateImage(AImage: TGraphic): TPdfImage; +function TPdfJpegImage.CreateImage(AImage: TGraphic; ObjectMgr: TPdfObjectMgr=nil): TPdfImage; begin // check whether specified graphic is valid image. if not (AImage is TJpegImage) then