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
This commit is contained in:
jesusr
2010-12-01 21:41:42 +00:00
parent b34489c597
commit 60b1056879
4 changed files with 92 additions and 19 deletions

View File

@ -473,6 +473,7 @@ type
{ TPRImage } { TPRImage }
TPRImage = class(TPRItem) TPRImage = class(TPRItem)
private private
FSharedName: string;
procedure SetStretch(Value: boolean); procedure SetStretch(Value: boolean);
protected protected
FPicture: TPicture; FPicture: TPicture;
@ -484,6 +485,7 @@ type
public public
constructor Create(AOwner: TComponent); override; constructor Create(AOwner: TComponent); override;
destructor Destroy; override; destructor Destroy; override;
property SharedName: string read FSharedName write FSharedName;
published published
property Picture: TPicture read FPicture write SetPicture; property Picture: TPicture read FPicture write SetPicture;
property SharedImage: boolean read FSharedImage write FSharedImage; property SharedImage: boolean read FSharedImage write FSharedImage;
@ -2312,14 +2314,16 @@ var
FIdx: integer; FIdx: integer;
begin begin
if (FPicture = nil) or (FPicture.Graphic = nil) or 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; Exit;
FDoc := ACanvas.PdfCanvas.Doc; FDoc := ACanvas.PdfCanvas.Doc;
if SharedImage then if SharedImage then
begin begin
FXObjectName := Self.Name; FXObjectName := Self.Name;
if FXObjectName='' then
FXObjectName := FSharedName;
if FDoc.GetXObject(FXObjectName) = nil then 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 end
else else
begin begin
@ -2334,7 +2338,7 @@ begin
if FIdx >= MAX_IMAGE_NUMBER then if FIdx >= MAX_IMAGE_NUMBER then
FIdx := 0; FIdx := 0;
end; end;
FDoc.AddXObject(FXObjectName, CreatePdfImage(FPicture.Graphic, 'Pdf-Bitmap')); FDoc.AddXObject(FXObjectName, CreatePdfImage(FPicture.Graphic, 'Pdf-Bitmap', FDoc.ObjectMgr));
end; end;
with ARect, ACanvas.PdfCanvas do with ARect, ACanvas.PdfCanvas do
if FStretch then if FStretch then

View File

@ -346,6 +346,7 @@ type
property Info: TPdfInfo read GetInfo; property Info: TPdfInfo read GetInfo;
property Root: TPdfCatalog read GetRoot; property Root: TPdfCatalog read GetRoot;
property OutlineRoot: TPdfOutlineRoot read GetOutlineRoot; property OutlineRoot: TPdfOutlineRoot read GetOutlineRoot;
property ObjectMgr: TPdfXRef read FXRef;
property DefaultPageWidth: word read FDefaultPageWidth write FDefaultPageWidth; property DefaultPageWidth: word read FDefaultPageWidth write FDefaultPageWidth;
property DefaultPageHeight: word read FDefaultPageHeight write FDefaultPageHeight; property DefaultPageHeight: word read FDefaultPageHeight write FDefaultPageHeight;
property CompressionMethod: TPdfCompressionMethod property CompressionMethod: TPdfCompressionMethod

View File

@ -53,23 +53,26 @@ uses
type type
TPdfImageCreator = class(TPersistent) TPdfImageCreator = class(TPersistent)
public public
function CreateImage(AImage: TGraphic): TPdfImage; virtual; function CreateImage(AImage: TGraphic; ObjectMgr: TPdfObjectMgr=nil): TPdfImage; virtual;
end; end;
{ TPdfBitmapImage }
TPdfBitmapImage = class(TPdfImageCreator) TPdfBitmapImage = class(TPdfImageCreator)
private private
function CreateIndexedColorArray(ABitmap: TBitmap): TPdfArray; function CreateIndexedColorArray(ABitmap: TBitmap): TPdfArray;
function CreateMaskStream(AImage: TFPCustomImage): TPDfImage;
public public
function CreateImage(AImage: TGraphic): TPdfImage; override; function CreateImage(AImage: TGraphic; ObjectMgr: TPdfObjectMgr=nil): TPdfImage; override;
end; end;
EPdfInvalidImageFormat = class(Exception); EPdfInvalidImageFormat = class(Exception);
function CreatePdfImage(AImage: TGraphic; ImageClassName: string): TPdfImage; function CreatePdfImage(AImage: TGraphic; ImageClassName: string; ObjectMgr: TPdfObjectMgr=nil): TPdfImage;
implementation implementation
function CreatePdfImage(AImage: TGraphic; ImageClassName: string): TPdfImage; function CreatePdfImage(AImage: TGraphic; ImageClassName: string; ObjectMgr: TPdfObjectMgr=nil): TPdfImage;
var var
PdfImageCreator: TPdfImageCreator; PdfImageCreator: TPdfImageCreator;
begin begin
@ -82,14 +85,14 @@ begin
try try
if PdfImageCreator = nil then if PdfImageCreator = nil then
raise Exception.CreateFmt('AddImage --InvalidImageClassName:%s', [ImageClassName]); raise Exception.CreateFmt('AddImage --InvalidImageClassName:%s', [ImageClassName]);
Result := PdfImageCreator.CreateImage(AImage); Result := PdfImageCreator.CreateImage(AImage, ObjectMgr);
finally finally
PdfImageCreator.Free; PdfImageCreator.Free;
end; end;
end; end;
{ TPdfImageCreator } { TPdfImageCreator }
function TPdfImageCreator.CreateImage(AImage: TGraphic): TPdfImage; function TPdfImageCreator.CreateImage(AImage: TGraphic; ObjectMgr: TPdfObjectMgr=nil): TPdfImage;
begin begin
result := nil; result := nil;
end; end;
@ -161,7 +164,41 @@ begin
end; end;
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 var
ABitmap: TBitmap; ABitmap: TBitmap;
x, y: integer; x, y: integer;
@ -170,14 +207,17 @@ var
{$IFDEF LAZ_POWERPDF} {$IFDEF LAZ_POWERPDF}
aIntfImage: TLazIntfImage; aIntfImage: TLazIntfImage;
aColor : TFPColor; aColor : TFPColor;
Alpha : TFPMemoryImage;
maskimage : TPDFImage;
hasAlpha : boolean;
{$endif} {$endif}
{$IFDEF USE_CLX}
const const
{$IFDEF USE_CLX}
PIXEL_COLOR_SIZE = 4; PIXEL_COLOR_SIZE = 4;
{$ELSE} {$ENDIF}
PIXEL_COLOR_SIZE = 3;
{$ENDIF}
begin begin
result := TPdfImage.CreateStream(nil); result := TPdfImage.CreateStream(nil);
with result do with result do
try try
@ -197,8 +237,6 @@ begin
aIntfImage := TLazIntfImage.Create(0,0); aIntfImage := TLazIntfImage.Create(0,0);
aIntfImage.LoadFromBitmap(aBitmap.Handle, aBitmap.MaskHandle); aIntfImage.LoadFromBitmap(aBitmap.Handle, aBitmap.MaskHandle);
{$ENDIF} {$ENDIF}
// if bitmap image has less then 8 bit color, set PixelFormat to 8 bit. // if bitmap image has less then 8 bit color, set PixelFormat to 8 bit.
if (PixelFormat = pf1bit) or if (PixelFormat = pf1bit) or
{$IFNDEF USE_CLX} {$IFNDEF USE_CLX}
@ -257,7 +295,22 @@ begin
Stream.Write(pb[x], 3); Stream.Write(pb[x], 3);
x := x + PIXEL_COLOR_SIZE; x := x + PIXEL_COLOR_SIZE;
end; end;
Attributes.AddItem('ColorSpace', TPdfName.CreateName('DeviceRGB'));
end;
{$else} {$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 for y := 0 to aintfimage.Height - 1 do
begin begin
new(pb); new(pb);
@ -268,11 +321,26 @@ begin
pb[ 1 ] := acolor.green shr 8; pb[ 1 ] := acolor.green shr 8;
pb[ 2 ] := acolor.blue shr 8; pb[ 2 ] := acolor.blue shr 8;
Stream.write(pb[ 0 ], 3); Stream.write(pb[ 0 ], 3);
b := acolor.alpha shr 8;
Alpha.Pixels[x,y] := b;
if acolor.Alpha<>AlphaOpaque then
HasAlpha := true;
end; end;
dispose(pb); dispose(pb);
{$endif}
Attributes.AddItem('ColorSpace', TPdfName.CreateName('DeviceRGB')); Attributes.AddItem('ColorSpace', TPdfName.CreateName('DeviceRGB'));
end; end;
if HasAlpha then begin
MaskImage := CreateMaskStream(Alpha);
if ObjectMgr<>nil then
ObjectMgr.AddObject(MaskImage);
Attributes.AddItem('SMask', MaskImage);
end;
Alpha.Free;
{$endif}
end; end;
with Attributes do with Attributes do

View File

@ -35,13 +35,13 @@ type
{ TPdfJpegImage } { TPdfJpegImage }
TPdfJpegImage = class(TPdfImageCreator) TPdfJpegImage = class(TPdfImageCreator)
public public
function CreateImage(AImage: TGraphic): TPdfImage; override; function CreateImage(AImage: TGraphic; ObjectMgr: TPdfObjectMgr=nil): TPdfImage; override;
end; end;
implementation implementation
// CreateImage // CreateImage
function TPdfJpegImage.CreateImage(AImage: TGraphic): TPdfImage; function TPdfJpegImage.CreateImage(AImage: TGraphic; ObjectMgr: TPdfObjectMgr=nil): TPdfImage;
begin begin
// check whether specified graphic is valid image. // check whether specified graphic is valid image.
if not (AImage is TJpegImage) then if not (AImage is TJpegImage) then