lazarus-ccr/components/thtmlport/package/gdipl2a.pas
2009-11-08 22:47:15 +00:00

445 lines
14 KiB
ObjectPascal

{Version 9.45}
{$i htmlcons.inc}
unit GDIPL2A;
interface
uses
{$IFNDEF LCL} Windows, ActiveX, {$ELSE} LclIntf, LclType, Types, DynLibs, HtmlMisc, {$ENDIF}
SysUtils, Graphics;
var
GDIPlusActive: boolean;
type
TGpImage = class(TObject)
private
fHandle: integer;
fWidth, fHeight: integer;
fFilename: string;
function GetHeight: integer;
function GetWidth: integer;
public
constructor Create(Filename: string; TmpFile: boolean = False); overload;
constructor Create(IStr: IStream); overload;
destructor Destroy; override;
function GetTBitmap: TBitmap;
property Height: integer read GetHeight;
property Width: integer read GetWidth;
end;
TGpGraphics = class;
TGpBitmap = class(TGpImage)
public
constructor Create(W, H: integer); overload;
constructor Create(IStr: IStream); overload;
constructor Create(W, H: integer; Graphics: TGpGraphics); overload;
function GetPixel(X, Y: integer): DWord;
procedure SetPixel(X, Y: integer; Color: DWord);
end;
TGpGraphics = class(TObject)
private
fGraphics: integer;
procedure DrawSmallStretchedImage (Image: TGPImage; X, Y, Width, Height: Integer);
public
constructor Create(Handle: HDC); overload;
constructor Create(Image: TGpImage); overload;
destructor Destroy; override;
procedure DrawImage (Image: TGPImage; X, Y: Integer); overload;
procedure DrawImage (Image: TGPImage; X, Y, Width, Height: Integer); overload;
procedure DrawImage(Image: TGpImage; x, y, srcx, srcy, srcwidth, srcheight: integer); overload;
procedure DrawImage(Image: TGpImage; dx, dy, dw, dh, sx, sy, sw, sh: integer); overload;
procedure Clear(Color: Cardinal);
procedure ScaleTransform(sx, sy: Single);
end;
procedure CheckInitGDIPlus;
procedure CheckExitGDIPlus;
implementation
const
GdiPlusLib = 'GdiPlus.dll';
type
EGDIPlus = class (Exception);
TRectF = record
X: Single;
Y: Single;
Width: Single;
Height: Single;
end;
ImageCodecInfo = packed record
Clsid : TGUID;
FormatID : TGUID;
CodecName : PWCHAR;
DllName : PWCHAR;
FormatDescription : PWCHAR;
FilenameExtension : PWCHAR;
MimeType : PWCHAR;
Flags : DWORD;
Version : DWORD;
SigCount : DWORD;
SigSize : DWORD;
SigPattern : PBYTE;
SigMask : PBYTE;
end;
TImageCodecInfo = ImageCodecInfo;
PImageCodecInfo = ^TImageCodecInfo;
var
{$ifndef NoGDIPlus}
GdiplusStartup: function(var Token: DWord; const Input, Output: Pointer): Integer; stdcall;
GdiplusShutdown: procedure(Token: DWord); stdcall;
GdipDrawImageI: function(Graphics, Image, X, Y: Integer): Integer; stdcall;
GdipCreateHBITMAPFromBitmap: function(bitmap: integer; out hbmReturn: HBITMAP;
background: DWord): integer; stdcall;
GdipGetInterpolationMode: function(graphics: integer; var interpolationMode: integer): integer; stdcall;
{$endif$}
GdipDeleteGraphics: function(Graphics: Integer): Integer; stdcall;
GdipCreateFromHDC: function(hdc: HDC; var Graphics: Integer): Integer; stdcall;
GdipDrawImageRectI: function (Graphics, Image, X, Y, Width, Height: Integer): Integer; stdcall;
GdipLoadImageFromFile: function (const FileName: PWideChar; var Image: Integer): Integer; stdcall;
GdipLoadImageFromStream: function(stream: ISTREAM;
out image: integer): integer; stdcall;
GdipCreateBitmapFromStream: function(stream: ISTREAM; out bitmap: integer): integer; stdcall;
GdipDisposeImage: function (Image: Integer): Integer; stdcall;
GdipGetImageWidth: function (Image: Integer; var Width: Integer): Integer; stdcall;
GdipGetImageHeight: function(Image: Integer; var Height: Integer): Integer; stdcall;
GdipGetImageGraphicsContext: function(Image: integer; out graphics: integer): integer; stdcall;
GdipGraphicsClear: function(Graphics: Integer; Color: Cardinal): Integer; stdcall;
GdipCreateBitmapFromScan0: function(width: Integer; height: Integer;
stride: Integer; pixelformat: dword; scan0: Pointer;
out bitmap: integer): integer; stdcall;
GdipDrawImagePointRect: function(graphics: integer; image: integer;
x: Single; y: Single; srcx: Single; srcy: Single; srcwidth: Single;
srcheight: Single; srcUnit: integer): integer; stdcall;
GdipScaleWorldTransform: function(graphics: integer; sx: Single; sy: Single;
order: integer): integer; stdcall;
GdipCreateBitmapFromGraphics: function(width, height: Integer;
Graphics: integer; out Bitmap: integer): integer; stdcall;
GdipBitmapGetPixel: function(bitmap, x, y: Integer; var color: DWord): integer; stdcall;
GdipDrawImageRectRectI: function(graphics, image,
dstx, dsty, dstwidth, dstheight, srcx, srcy, srcwidth, srcheight,
srcUnit, imageAttributes: integer;
callback: Pointer; callbackData: integer): integer; stdcall;
GdipSetInterpolationMode: function(graphics, interpolationMode: integer): integer; stdcall;
GdipBitmapSetPixel: function(bitmap, x, y: Integer; color: DWord): Integer; stdcall;
type
TGDIStartup = packed record
Version: Integer; // Must be one
DebugEventCallback: Pointer; // Only for debug builds
SuppressBackgroundThread: Bool; // True if replacing GDI+ background processing
SuppressExternalCodecs: Bool; // True if only using internal codecs
end;
var
Err: Integer;
{ TGpGraphics }
constructor TGpGraphics.Create(Handle: HDC);
var
err: integer;
begin
inherited Create;
err := GdipCreateFromHDC (Handle, fGraphics);
if err <> 0 then
raise EGDIPlus.Create('Can''t Create Graphics');
end;
constructor TGpGraphics.Create(Image: TGpImage);
var
err: integer;
begin
inherited Create;
err := GdipGetImageGraphicsContext(image.fHandle, fgraphics);
if err <> 0 then
raise EGDIPlus.Create('Can''t Create Graphics');
end;
destructor TGpGraphics.Destroy;
begin
if fGraphics <> 0 then
GdipDeleteGraphics (fGraphics);
inherited;
end;
procedure TGpGraphics.DrawImage(Image: TGPImage; X, Y, Width, Height: Integer);
begin
if ((Image.Width <= 10) and (Width > Image.Width)) or
((Image.Height <= 10) and (Height > Image.Height)) then
DrawSmallStretchedImage(Image, X, Y, Width, Height)
else
GdipDrawImageRectI (fGraphics, Image.fHandle, X, Y, Width, Height);
end;
procedure TGpGraphics.DrawSmallStretchedImage (Image: TGPImage; X, Y, Width, Height: Integer);
{when a small image is getting enlarged, add a row and column to it copying
the last row/column to the new row/column. This gives much better interpolation.}
const
NearestNeighbor = 5;
var
g1, g2: TGpGraphics;
BM1, BM2: TGpBitmap;
W, H: integer;
Pixel: DWord;
begin
W := Image.Width+1; {new dimensions}
H := Image.Height+1;
BM1 := TGpBitmap.Create(W, H); {new bitmap with extra row and column}
try
g1 := TGpGraphics.Create(BM1);
try
g1.DrawImage(Image, 0, 0); {draw the original image}
g1.DrawImage(Image, W-1, 0, 1, H, {copy the column, then the row}
W-2, 0, 1, H);
g1.DrawImage(Image, 0, H-1, W, 1,
0, H-2, W, 1);
Pixel := BM1.GetPixel(W-2, H-2); {for some reason also need to set the lower right pixel}
BM1.SetPixel(W-1, H-1, Pixel);
BM2 := TGpBitmap.Create(Width, Height);
try
g2 := TGpGraphics.Create(BM2);
try
GdipSetInterpolationMode(g2.fGraphics, NearestNeighbor);
g2.DrawImage(BM1, 0, 0, Width, Height, {now draw the image stretched where needed}
0, 0, Image.Width, Image.Height);
DrawImage(BM2, X, Y); {now draw the image stretched where needed}
finally
g2.Free;
end;
finally
BM2.Free;
end;
finally
g1.Free;
end;
finally
BM1.Free;
end;
end;
procedure TGpGraphics.DrawImage(Image: TGPImage; X, Y: Integer);
begin
GdipDrawImageRectI (fGraphics, Image.fHandle, X, Y, Image.Width, Image.Height);
end;
procedure TGPGraphics.DrawImage(Image: TGpImage; x, y,
srcx, srcy, srcwidth, srcheight: integer);
const
UnitPixel = 2;
begin
GdipDrawImagePointRect(fGraphics, Image.fHandle, x, y,
srcx, srcy, srcwidth, srcheight, UnitPixel);
end;
procedure TGPGraphics.DrawImage(Image: TGpImage; dx, dy, dw, dh, sx, sy, sw, sh: integer);
const
UnitPixel = 2;
begin
GdipDrawImageRectRectI(fGraphics, Image.fHandle, dx, dy, dw, dh,
sx, sy, sw, sh, UnitPixel, 0, Nil, 0);
end;
procedure TGpGraphics.Clear (Color: Cardinal);
begin
GdipGraphicsClear (fGraphics, Color);
end;
procedure TGPGraphics.ScaleTransform(sx, sy: Single);
const
MatrixOrderPrepend = 0;
begin
GdipScaleWorldTransform(fGraphics, sx, sy, MatrixOrderPrepend);
end;
{ TGpImage }
constructor TGpImage.Create(Filename: string; TmpFile: boolean = False);
var
err: Integer;
Buffer: array [0..511] of WideChar;
begin
Inherited Create;
if not FileExists (FileName) then
raise EGDIPlus.Create (Format ('Image file %s not found.', [FileName]));
err := GdipLoadImageFromFile (StringToWideChar (FileName, Buffer, sizeof (Buffer)), fHandle);
if err <> 0 then
raise EGDIPlus.Create(Format ('Can''t load image file %s.', [FileName]));
if TmpFile then
fFilename := Filename;
end;
constructor TGpImage.Create(IStr: IStream);
var
err: Integer;
begin
Inherited Create;
err := GdipLoadImageFromStream(IStr, fHandle);
if err <> 0 then
raise EGDIPlus.Create('Can''t load image stream');
end;
destructor TGpImage.Destroy;
begin
GdipDisposeImage (fHandle);
if Length(fFilename) > 0 then
try
DeleteFile(fFilename);
except
end;
inherited;
end;
function TGpImage.GetWidth: integer;
begin
if fWidth = 0 then
GdipGetImageWidth (fHandle, fWidth);
Result := fWidth;
end;
function TGpImage.GetHeight: integer;
begin
if fHeight = 0 then
GdipGetImageHeight (fHandle, fHeight);
Result := fHeight;
end;
function TGpImage.GetTBitmap: TBitmap;
var
g: TGpGraphics;
begin
Result := TBitmap.Create;
Result.Width := GetWidth;
Result.Height := GetHeight;
PatBlt(Result.Canvas.Handle, 0, 0, Result.Width, Result.Height, Whiteness);
g := TGpGraphics.Create(Result.Canvas.Handle);
g.DrawImage(Self, 0, 0, Result.Width, Result.Height);
g.Free;
end;
constructor TGpBitmap.Create(W, H: integer);
const
PixelFormatGDI = $00020000; // Is a GDI-supported format
PixelFormatAlpha = $00040000; // Has an alpha component
PixelFormatCanonical = $00200000;
PixelFormat32bppARGB = (10 or (32 shl 8) or PixelFormatAlpha or PixelFormatGDI
or PixelFormatCanonical);
var
err: integer;
begin
inherited Create;
err := GdipCreateBitmapFromScan0(W, H, 0, PixelFormat32bppARGB, nil, fHandle);
if err <> 0 then
raise EGDIPlus.Create('Can''t create bitmap');
end;
constructor TGpBitmap.Create(IStr: IStream);
var
err: integer;
begin
inherited Create;
err := GdipCreateBitmapFromStream(IStr, fHandle);
if err <> 0 then
raise EGDIPlus.Create('Can''t create bitmap');
end;
constructor TGpBitmap.Create(W, H: integer; Graphics: TGpGraphics);
begin
inherited Create;
err := GdipCreateBitmapFromGraphics(W, H, Graphics.fGraphics, fHandle);
if err <> 0 then
raise EGDIPlus.Create('Can''t create bitmap');
end;
function TGpBitmap.GetPixel(X, Y: integer): DWord;
begin
GdipBitmapGetPixel(fHandle, X, Y, Result);
end;
procedure TGpBitmap.SetPixel(X, Y: integer; Color: DWord);
begin
GdipBitmapSetPixel(fHandle, X, Y, Color);
end;
{$ifndef NoGDIPlus}
var
InitToken: DWord;
Startup: TGDIStartup;
LibHandle: THandle;
GDIPlusCount: integer;
{$endif}
procedure CheckInitGDIPlus;
begin
{$ifndef NoGDIPlus}
if GDIPlusCount = 0 then
begin
LibHandle := LoadLibrary(GdiPlusLib);
if LibHandle <> 0 then
begin
@GdiplusStartup := GetProcAddress(LibHandle, 'GdiplusStartup');
@GdiplusShutdown := GetProcAddress(LibHandle, 'GdiplusShutdown');
@GdipDeleteGraphics := GetProcAddress(LibHandle, 'GdipDeleteGraphics');
@GdipCreateFromHDC := GetProcAddress(LibHandle, 'GdipCreateFromHDC');
@GdipDrawImageI := GetProcAddress(LibHandle, 'GdipDrawImageI');
@GdipDrawImageRectI := GetProcAddress(LibHandle, 'GdipDrawImageRectI');
@GdipLoadImageFromFile := GetProcAddress(LibHandle, 'GdipLoadImageFromFile');
@GdipLoadImageFromStream := GetProcAddress(LibHandle, 'GdipLoadImageFromStream');
@GdipCreateBitmapFromStream:= GetProcAddress(LibHandle, 'GdipCreateBitmapFromStream');
@GdipDisposeImage := GetProcAddress(LibHandle, 'GdipDisposeImage');
@GdipGetImageWidth := GetProcAddress(LibHandle, 'GdipGetImageWidth');
@GdipGetImageHeight := GetProcAddress(LibHandle, 'GdipGetImageHeight');
@GdipGetImageGraphicsContext := GetProcAddress(LibHandle, 'GdipGetImageGraphicsContext');
@GdipGraphicsClear := GetProcAddress(LibHandle, 'GdipGraphicsClear');
@GdipCreateBitmapFromScan0 := GetProcAddress(LibHandle, 'GdipCreateBitmapFromScan0');
@GdipDrawImagePointRect := GetProcAddress(LibHandle, 'GdipDrawImagePointRect');
@GdipScaleWorldTransform := GetProcAddress(LibHandle, 'GdipScaleWorldTransform');
@GdipCreateBitmapFromGraphics := GetProcAddress(LibHandle, 'GdipCreateBitmapFromGraphics');
@GdipBitmapGetPixel := GetProcAddress(LibHandle, 'GdipBitmapGetPixel');
@GdipDrawImageRectRectI := GetProcAddress(LibHandle, 'GdipDrawImageRectRectI');
@GdipCreateHBITMAPFromBitmap := GetProcAddress(LibHandle, 'GdipCreateHBITMAPFromBitmap');
@GdipSetInterpolationMode := GetProcAddress(LibHandle, 'GdipSetInterpolationMode');
@GdipGetInterpolationMode := GetProcAddress(LibHandle, 'GdipGetInterpolationMode');
@GdipBitmapSetPixel := GetProcAddress(LibHandle, 'GdipBitmapSetPixel');
FillChar (Startup, sizeof (Startup), 0);
Startup.Version := 1;
Err := GdiPlusStartup (InitToken, @Startup, nil);
GDIPlusActive := Err = 0;
if not GDIPlusActive then
FreeLibrary(LibHandle);
end;
end;
Inc(GDIPlusCount);
{$endif}
end;
procedure CheckExitGDIPlus;
begin
{$ifndef NoGDIPlus}
Dec(GDIPlusCount);
if GDIPlusCount = 0 then
if GDIPlusActive then
begin
GdiplusShutdown (InitToken);
FreeLibrary(LibHandle);
GDIPlusActive := False;
end;
{$endif}
end;
end.