📄 fcbitmap.pas
字号:
unit fcBitmap;
{
//
// Components : TfcBitmap
//
// Copyright (c) 1999 by Woll2Woll Software
// 12/3/99 - Only use DibColor table if it is valid.
// Previously just checked if colors[0] was 0 for valid determination
// 12/4/99 - Support true color bitmaps in 256 color environments by creating
// half-tone palette
// 12/7/99 - new method Changecolor used by fcImgBtn
// 11/1/2001 - Use Draw when loading from graphic as this is more generic and allows Graphic to define how it is drawn to the bitmap.
}
interface
{$i fcIfDef.pas}
uses Windows, Graphics, Classes, fcGraphics, fcChangeLink, SysUtils;
type
TfcColor = record
b, g, r: Byte
end;
PfcColor = ^TfcColor;
TfcLine = array[0..0] of TfcColor;
PfcLine = ^TfcLine;
TfcPLines = array[0..0] of PfcLine;
PfcPLines = ^TfcPLines;
TfcBitmap = class(TGraphic)
private
FSmoothStretching: Boolean;
FTransparentColor: TColor;
FWidth: Integer;
FHeight: Integer;
FGap: Integer;
FMaskBitmap: TBitmap;
FRowInc: Integer;
FSize: Integer;
FBits: Pointer;
FHandle: Integer;
FDC: HDC;
FCanvas: TCanvas;
FMemoryImage: Pointer;
FMemorySize: Integer;
FMemoryDim: TSize;
FPixelFormat: TPixelFormat;
FPalette: HPALETTE;
FRespectPalette: Boolean;
FUseHalftonePalette: boolean;
FIgnoreChange: Boolean;
FChangeLinks: TList;
// FPicture: TPicture;
bmInfo: TBitmapInfo;
bmHeader: TBitmapInfoHeader;
function GetSleeping: Boolean;
procedure InitHeader;
protected
Assigning: Boolean;
SkipPalette: boolean;
Procedure RestoreBitmapPalette(ACanvas: TCanvas; OldPalette: HPalette); virtual;
Procedure SelectBitmapPalette(ACanvas: TCanvas; var OldPalette: HPalette); virtual;
function GetEmpty: Boolean; override;
function GetHeight: Integer; override;
function GetWidth: Integer; override;
procedure AssignTo(Dest: TPersistent); override;
procedure Changed(Sender: TObject); override;
procedure Draw(ACanvas: TCanvas; const Rect: TRect); override;
procedure SetHeight(Value: Integer); override;
procedure SetWidth(Value: Integer); override;
procedure CleanUp; virtual;
procedure Initialize; virtual;
procedure NotifyChanges; virtual;
procedure PaletteNeeded; virtual;
property Gap: Integer read FGap;
property RowInc: Integer read FRowInc;
property DC: HDC read FDC;
public
Patch: Variant;
Pixels: PfcPLines;
Colors: array[Byte] of TRGBQuad;
constructor Create; override;
destructor Destroy; override;
procedure Assign(Source: TPersistent); override;
procedure RegisterChanges(ChangeLink: TfcChangeLink); virtual;
procedure UnRegisterChanges(ChangeLink: TfcChangeLink); virtual;
procedure Clear; virtual;
procedure FreeMemoryImage; virtual;
procedure LoadBlank(AWidth, AHeight: Integer); virtual;
procedure LoadFromBitmap(Bitmap: TBitmap); virtual;
procedure LoadFromJPEG(JPEG: TGraphic); virtual;
procedure LoadFromClipboardFormat(AFormat: Word; AData: THandle;
APalette: HPALETTE); override;
procedure LoadFromGraphic(Graphic: TGraphic); virtual;
procedure LoadFromMemory(ABits: Pointer; ASize: Integer; Dimensions: TSize); virtual;
procedure LoadFromStream(Stream: TStream); override;
procedure SaveToBitmap(Bitmap: TBitmap); virtual;
procedure SaveToClipboardFormat(var AFormat: Word; var AData: THandle;
var APalette: HPALETTE); override;
procedure SaveToStream(Stream: TStream); override;
procedure SetSize(const AWidth, AHeight: Integer); virtual;
function GetMaskBitmap: TBitmap;
function CopyPixels: PfcPLines;
procedure Fill(Color: TColor);
procedure Resize(AWidth, AHeight: Integer); virtual;
procedure Sleep; virtual;
procedure SmoothStretchDraw(ACanvas: TCanvas; Rect: TRect); virtual;
procedure StretchDraw(ACanvas: TCanvas; const Rect: TRect); virtual;
procedure TileDraw(ACanvas: TCanvas; ARect: TRect); virtual;
procedure TransparentDraw(ACanvas: TCanvas; const Rect: TRect); virtual;
procedure Wake; virtual;
// Filters
procedure AlphaBlend(Bitmap: TfcBitmap; Alpha: Integer; Stretch: Boolean);
procedure Blur(Amount: Integer); virtual;
procedure Contrast(Amount: Integer); virtual;
procedure Emboss; virtual;
procedure Flip(Horizontal: Boolean); virtual;
procedure GaussianBlur(Amount: Integer); virtual;
procedure Grayscale; virtual;
procedure Invert; virtual;
procedure Brightness(Amount: Integer); virtual;
procedure Mask(MaskColor: TfcColor); virtual;
{ 12/7/99 - new method Changecolor used by fcImgBtn }
procedure ChangeColor(OldColor: TfcColor; NewColor: TfcColor); virtual;
procedure ColorTint(ra, ga, ba: Integer); virtual;
procedure Colorize(ra, ga, ba: Integer); virtual;
procedure Rotate(Center: TPoint; Angle: Extended); virtual;
procedure Saturation(Amount: Integer); virtual;
procedure Sharpen(Amount: Integer); virtual;
procedure Sponge(Amount: Integer); virtual;
procedure Wave(XDiv, YDiv, RatioVal: Extended; Wrap: Boolean); virtual;
property Bits: Pointer read FBits;
property Canvas: TCanvas read FCanvas;
property Handle: Integer read FHandle;
property IgnoreChange: Boolean read FIgnoreChange write FIgnoreChange;
property MaskBitmap: TBitmap read GetMaskBitmap;
property RespectPalette: Boolean read FRespectPalette write FRespectPalette;
property UseHalftonePalette: Boolean read FUseHalftonePalette write FUseHalftonePalette;
property SmoothStretching: Boolean read FSmoothStretching write FSmoothStretching;
property Sleeping: Boolean read GetSleeping;
property Size: Integer read FSize;
property TransparentColor: TColor read FTransparentColor write FTransparentColor;
end;
function fcGetColor(Color: TColor): TfcColor;
function fcGetStdColor(Color: TfcColor): TColor;
function fcRGB(r, g, b: Byte): TfcColor;
function fcIntToByte(Value: Integer): Byte;
function fcTrimInt(i, Min, Max: Integer): Integer;
implementation
uses
{$ifdef fcdelphi6Up}
variants,
{$endif}
fcCommon;
{$R-}
function fcGetColor(Color: TColor): TfcColor;
begin
//2/17/99 - Get Actual Color Value
Color := ColorToRGB(Color);
result.r := Color and $FF;
result.g := Color and $FF00 shr 8;
result.b := Color and $FF0000 shr 16;
end;
function fcGetStdColor(Color: TfcColor): TColor;
begin
with Color do result := RGB(r, g, b);
end;
function fcRGB(r, g, b: Byte): TfcColor;
begin
result.r := r;
result.g := g;
result.b := b;
end;
function fcIntToByte(Value: Integer): Byte;
begin
if Value > 255 then result := 255
else if Value < 0 then result := 0
else result := Value;
end;
function fcTrimInt(i, Min, Max: Integer): Integer;
begin
if i > Max then result := Max
else if i < Min then result := Min
else result := i;
end;
constructor TfcBitmap.Create;
begin
inherited;
FCanvas := TCanvas.Create;
FChangeLinks := TList.Create;
FTransparentColor := clNone;
FPixelFormat := pf24Bit;
Patch:= VarArrayCreate([0, 1], varVariant);
Patch[0]:= False; { Color table not valid }
Patch[1]:= False;
end;
destructor TfcBitmap.Destroy;
begin
FChangeLinks.Free;
if Sleeping then FreeMemoryImage;
CleanUp;
FCanvas.Free;
inherited;
end;
function TfcBitmap.GetSleeping: Boolean;
begin
result := (FMemorySize > 0) and (FMemoryImage <> nil);
end;
function TfcBitmap.GetEmpty: Boolean;
begin
result := FHandle = 0;
end;
function TfcBitmap.GetHeight: Integer;
begin
result := FHeight;
end;
function TfcBitmap.GetWidth: Integer;
begin
result := FWidth;
end;
procedure TfcBitmap.Assign(Source: TPersistent);
begin
if (Source is TBitmap) and not (Source as TBitmap).Empty then
begin
FPixelFormat := (Source as TBitmap).PixelFormat;
LoadFromBitmap(Source as TBitmap);
Transparent := (Source as TBitmap).Transparent;
// TransparentColor := (Source as TBitmap).TransparentColor;
end else if (Source = nil) or ((Source is TBitmap) and (Source as TBitmap).Empty) then
begin
CleanUp;
Changed(self);
end else if (Source is TGraphic) and not (Source is TfcBitmap) then
begin
LoadFromGraphic(Source as TGraphic);
end else inherited;
end;
procedure TfcBitmap.AssignTo(Dest: TPersistent);
begin
if Dest is TBitmap then
begin
(Dest as TBitmap).PixelFormat := self.FPixelFormat;
SaveToBitmap(Dest as TBitmap);
(Dest as TBitmap).Transparent := Transparent;
(Dest as TBitmap).TransparentColor := TransparentColor;
end else if Dest is TfcBitmap then
with TfcBitmap(Dest) do
begin
if not self.Empty then
begin
IgnoreChange := True;
RespectPalette := self.RespectPalette;
UseHalftonePalette:= self.UseHalftonePalette;
LoadBlank(self.Width, self.Height);
CopyMemory(TfcBitmap(Dest).Bits, self.Bits, self.Size);
Transparent := self.Transparent;
SmoothStretching := self.SmoothStretching;
TransparentColor := self.TransparentColor;
FPixelFormat := self.FPixelFormat;
CopyMemory(@(Dest as TfcBitmap).Colors, @self.Colors, SizeOf(self.Colors));
Patch[0]:= self.Patch[0];
Patch[1]:= self.Patch[1]; // Halftone value
// FHalfTone:= self.FHalfTone;
IgnoreChange := False;
Changed(Dest);
end else begin
CleanUp;
Changed(Dest);
end;
end else inherited;
end;
procedure TfcBitmap.Changed(Sender: TObject);
begin
if not IgnoreChange then
begin
inherited Changed(Sender);
NotifyChanges;
end;
end;
procedure TfcBitmap.NotifyChanges;
var i: Integer;
begin
for i := 0 to FChangeLinks.Count - 1 do with TfcChangeLink(FChangeLinks[i]) do
begin
Sender := self;
Change;
end;
end;
procedure TfcBitmap.RegisterChanges(ChangeLink: TfcChangeLink);
begin
FChangeLinks.Add(ChangeLink);
end;
procedure TfcBitmap.UnRegisterChanges(ChangeLink: TfcChangeLink);
begin
FChangeLinks.Remove(ChangeLink);
end;
procedure TfcBitmap.TransparentDraw(ACanvas: TCanvas; const Rect: TRect);
var Bmp: TBitmap;
begin
Bmp := TBitmap.Create;
Bmp.Width := Width;
Bmp.Height := Height;
Bmp.PixelFormat := pf24Bit;
Bmp.Canvas.CopyRect(Classes.Rect(0, 0, Width, Height), Canvas, Classes.Rect(0, 0, Width, Height));
fcDrawMask(ACanvas, Rect, Bmp, MaskBitmap, True);
Bmp.Free;
end;
procedure TfcBitmap.StretchDraw(ACanvas: TCanvas; const Rect: TRect);
var TempBitmap: TfcBitmap;
begin
if Transparent then
begin
TempBitmap := TfcBitmap.Create;
TempBitmap.LoadBlank(fcRectWidth(Rect), fcRectHeight(Rect));
StretchBlt(TempBitmap.Canvas.Handle, 0, 0, TempBitmap.Width, TempBitmap.Height,
FDC, 0, 0, FWidth, FHeight, SRCCOPY);
TempBitmap.TransparentDraw(ACanvas, Rect);
TempBitmap.Free;
end else begin
SetStretchBltMode(ACanvas.Handle, COLORONCOLOR);
with Rect do StretchBlt(ACanvas.Handle, Left, Top, Right - Left, Bottom - Top,
FDC, 0, 0, FWidth, FHeight, SRCCOPY);
end;
end;
Procedure TfcBitmap.RestoreBitmapPalette(ACanvas: TCanvas; OldPalette: HPalette);
begin
if (GetDeviceCaps(FDC, BITSPIXEL) <= 8)
and (RespectPalette or UseHalftonePalette) then
begin
SelectPalette(ACanvas.Handle, OldPalette, True);
if FPalette <> 0 then
begin
DeleteObject(FPalette);
FPalette := 0;
end;
end;
end;
Procedure TfcBitmap.SelectBitmapPalette(ACanvas: TCanvas; var OldPalette: HPalette);
var
DC: HDC;
begin
if (GetDeviceCaps(FDC, BITSPIXEL) <= 8) then begin
if RespectPalette or UseHalftonePalette then
begin
if RespectPalette then
begin
PaletteNeeded;
end
else if UseHalftonePalette then begin
DC := GetDC(0);
FPalette := CreateHalftonePalette(DC);
ReleaseDC(0, DC);
end;
OldPalette := SelectPalette(ACanvas.Handle, FPalette, True);
RealizePalette(ACanvas.Handle);
end
end
end;
procedure TfcBitmap.Draw(ACanvas: TCanvas; const Rect: TRect);
function Transparent: Boolean;
begin
result := self.Transparent and not Assigning;
end;
function SmoothStretching: Boolean;
begin
result := self.SmoothStretching and not Assigning;
end;
var OldPalette: HPALETTE;
// DC: HDC;
begin
OldPalette := 0;
if not SkipPalette then SelectBitmapPalette(ACanvas, OldPalette);
{ if (GetDeviceCaps(FDC, BITSPIXEL) <= 8) and (not SkipPalette) then begin
if RespectPalette or UseHalftonePalette then
begin
if RespectPalette then
begin
PaletteNeeded;
end
else if UseHalftonePalette then begin
DC := GetDC(0);
FPalette := CreateHalftonePalette(DC);
ReleaseDC(0, DC);
end;
OldPalette := SelectPalette(ACanvas.Handle, FPalette, True);
RealizePalette(ACanvas.Handle);
end
end;}
with Rect do
begin
if ((Right - Left) = Width) and ((Bottom - Top) = Height) then
begin
if Transparent then TransparentDraw(ACanvas, Rect)
else BitBlt(ACanvas.Handle, Left, Top, Right - Left, Bottom - Top, FDC, 0, 0, SRCCOPY);
end else begin
if FSmoothStretching then SmoothStretchDraw(ACanvas, Rect)
else StretchDraw(ACanvas, Rect);
end;
end;
if not SkipPalette then RestoreBitmapPalette(ACanvas, OldPalette);
{
if (GetDeviceCaps(FDC, BITSPIXEL) <= 8) and (not SkipPalette)
and (RespectPalette or UseHalftonePalette) then
begin
SelectPalette(ACanvas.Handle, OldPalette, True);
if FPalette <> 0 then
begin
DeleteObject(FPalette);
FPalette := 0;
end;
end;
}
end;
procedure TfcBitmap.Initialize;
var x, i: Integer;
TempDC: HDC;
begin
GetMem(Pixels, FHeight * SizeOf(PfcLine));
FRowInc := (FWidth * 3) + FWidth mod 4;
FGap := FWidth mod 4;
FSize := FRowInc * FHeight;
x := Integer(Bits);
for i := 0 to Height - 1 do
begin
Pixels[i] := Pointer(x);
Inc(x, RowInc);
end;
TempDC := GetDC(0);
FDC := CreateCompatibleDC(TempDC);
ReleaseDC(0, TempDC);
SelectObject(FDC, FHandle);
if Handle = 0 then CleanUp;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -