📄 dib.pas
字号:
TempImage: TDIBSharedImage;
begin
if (FImage.RefCount>1) or (FImage.FCompressed) or ((not MemoryImage) and (FImage.FMemoryImage)) then
begin
TempImage := TDIBSharedImage.Create;
try
TempImage.Decompress(FImage, FImage.FMemoryImage and MemoryImage);
except
TempImage.Free;
raise;
end;
SetImage(TempImage);
end;
end;
procedure TDIB.AllocHandle;
var
TempImage: TDIBSharedImage;
begin
if FImage.FMemoryImage then
begin
TempImage := TDIBSharedImage.Create;
try
TempImage.Decompress(FImage, False);
except
TempImage.Free;
raise;
end;
SetImage(TempImage);
end;
end;
procedure TDIB.Compress;
var
TempImage: TDIBSharedImage;
begin
if (not FImage.FCompressed) and (BitCount in [4, 8]) then
begin
TempImage := TDIBSharedImage.Create;
try
TempImage.Compress(FImage);
except
TempImage.Free;
raise;
end;
SetImage(TempImage);
end;
end;
procedure TDIB.Decompress;
var
TempImage: TDIBSharedImage;
begin
if FImage.FCompressed then
begin
TempImage := TDIBSharedImage.Create;
try
TempImage.Decompress(FImage, FImage.FMemoryImage);
except
TempImage.Free;
raise;
end;
SetImage(TempImage);
end;
end;
procedure TDIB.FreeHandle;
var
TempImage: TDIBSharedImage;
begin
if not FImage.FMemoryImage then
begin
TempImage := TDIBSharedImage.Create;
try
TempImage.Duplicate(FImage, True);
except
TempImage.Free;
raise;
end;
SetImage(TempImage);
end;
end;
function TDIB.GetBitmapInfo: PBitmapInfo;
begin
Result := FImage.FBitmapInfo;
end;
function TDIB.GetBitmapInfoSize: Integer;
begin
Result := FImage.FBitmapInfoSize;
end;
function TDIB.GetCanvas: TCanvas;
begin
if (FCanvas=nil) or (FCanvas.Handle=0) then
begin
AllocHandle;
FCanvas := TCanvas.Create;
FCanvas.Handle := FImage.FDC;
FCanvas.OnChanging := CanvasChanging;
end;
Result := FCanvas;
end;
function TDIB.GetEmpty: Boolean;
begin
Result := Size=0;
end;
function TDIB.GetHandle: THandle;
begin
Changing(True);
Result := FImage.FHandle;
end;
function TDIB.GetHeight: Integer;
begin
Result := FHeight;
end;
function TDIB.GetPalette: HPalette;
begin
Result := FImage.GetPalette;
end;
function TDIB.GetPaletteCount: Integer;
begin
Result := FImage.FPaletteCount;
end;
function TDIB.GetPBits: Pointer;
begin
Changing(True);
if not FImage.FMemoryImage then
GDIFlush;
Result := FPBits;
end;
function TDIB.GetPBitsReadOnly: Pointer;
begin
if not FImage.FMemoryImage then
GDIFlush;
Result := FPBits;
end;
function TDIB.GetScanLine(Y: Integer): Pointer;
begin
Changing(True);
if (Y<0) or (Y>=FHeight) then
raise EInvalidGraphicOperation.CreateFmt(SScanline, [Y]);
if not FImage.FMemoryImage then
GDIFlush;
Result := Pointer(Integer(FTopPBits)+Y*FNextLine);
end;
function TDIB.GetScanLineReadOnly(Y: Integer): Pointer;
begin
if (Y<0) or (Y>=FHeight) then
raise EInvalidGraphicOperation.CreateFmt(SScanline, [Y]);
if not FImage.FMemoryImage then
GDIFlush;
Result := Pointer(Integer(FTopPBits)+Y*FNextLine);
end;
function TDIB.GetTopPBits: Pointer;
begin
Changing(True);
if not FImage.FMemoryImage then
GDIFlush;
Result := FTopPBits;
end;
function TDIB.GetTopPBitsReadOnly: Pointer;
begin
if not FImage.FMemoryImage then
GDIFlush;
Result := FTopPBits;
end;
function TDIB.GetWidth: Integer;
begin
Result := FWidth;
end;
const
Mask1: array[0..7] of DWORD = ($80, $40, $20, $10, $08, $04, $02, $01);
Mask1n: array[0..7] of DWORD = ($FFFFFF7F, $FFFFFFBF, $FFFFFFDF, $FFFFFFEF,
$FFFFFFF7, $FFFFFFFB, $FFFFFFFD, $FFFFFFFE);
Mask4: array[0..1] of DWORD = ($F0, $0F);
Mask4n: array[0..1] of DWORD = ($FFFFFF0F, $FFFFFFF0);
Shift1: array[0..7] of DWORD = (7, 6, 5, 4, 3, 2, 1, 0);
Shift4: array[0..1] of DWORD = (4, 0);
function TDIB.GetPixel(X, Y: Integer): DWORD;
begin
Decompress;
Result := 0;
if (X>=0) and (X<FWidth) and (Y>=0) and (Y<FHeight) then
begin
case FBitCount of
1 : Result := (PArrayByte(Integer(FTopPBits)+Y*FNextLine)[X shr 3] and Mask1[X and 7]) shr Shift1[X and 7];
4 : Result := (PArrayByte(Integer(FTopPBits)+Y*FNextLine)[X shr 1] and Mask4[X and 1]) shr Shift4[X and 1];
8 : Result := PArrayByte(Integer(FTopPBits)+Y*FNextLine)[X];
16: Result := PArrayWord(Integer(FTopPBits)+Y*FNextLine)[X];
24: with PArrayBGR(Integer(FTopPBits)+Y*FNextLine)[X] do
Result := R or (G shl 8) or (B shl 16);
32: Result := PArrayDWord(Integer(FTopPBits)+Y*FNextLine)[X];
end;
end;
end;
procedure TDIB.SetPixel(X, Y: Integer; Value: DWORD);
var
P: PByte;
begin
Changing(True);
if (X>=0) and (X<FWidth) and (Y>=0) and (Y<FHeight) then
begin
case FBitCount of
1 : begin
P := @PArrayByte(Integer(FTopPBits)+Y*FNextLine)[X shr 3];
P^ := (P^ and Mask1n[X and 7]) or ((Value and 1) shl Shift1[X and 7]);
end;
4 : begin
P := @PArrayByte(Integer(FTopPBits)+Y*FNextLine)[X shr 3];
P^ := (P^ and Mask4n[X and 1]) or ((Value and 15) shl Shift4[X and 1]);
end;
8 : PArrayByte(Integer(FTopPBits)+Y*FNextLine)[X] := Value;
16: PArrayWord(Integer(FTopPBits)+Y*FNextLine)[X] := Value;
24: with PArrayBGR(Integer(FTopPBits)+Y*FNextLine)[X] do
begin
B := Byte(Value shr 16);
G := Byte(Value shr 8);
R := Byte(Value);
end;
32: PArrayDWord(Integer(FTopPBits)+Y*FNextLine)[X] := Value;
end;
end;
end;
procedure TDIB.DefineProperties(Filer: TFiler);
begin
inherited DefineProperties(Filer);
{ For interchangeability with an old version. }
Filer.DefineBinaryProperty('DIB', LoadFromStream, nil, False);
end;
type
TGlobalMemoryStream = class(TMemoryStream)
private
FHandle: THandle;
public
constructor Create(AHandle: THandle);
destructor Destroy; override;
end;
constructor TGlobalMemoryStream.Create(AHandle: THandle);
begin
inherited Create;
FHandle := AHandle;
SetPointer(GlobalLock(AHandle), GlobalSize(AHandle));
end;
destructor TGlobalMemoryStream.Destroy;
begin
GlobalUnLock(FHandle);
SetPointer(nil, 0);
inherited Destroy;
end;
procedure TDIB.LoadFromClipboardFormat(AFormat: Word; AData: THandle;
APalette: HPALETTE);
var
Stream: TGlobalMemoryStream;
begin
Stream := TGlobalMemoryStream.Create(AData);
try
ReadData(Stream);
finally
Stream.Free;
end;
end;
const
BitmapFileType = Ord('B') + Ord('M')*$100;
procedure TDIB.LoadFromStream(Stream: TStream);
var
BF: TBitmapFileHeader;
i: Integer;
begin
{ File header reading }
i := Stream.Read(BF, SizeOf(TBitmapFileHeader));
if i=0 then Exit;
if i<>SizeOf(TBitmapFileHeader) then
raise EInvalidGraphic.Create(SInvalidDIB);
{ Is the head 'BM'? }
if BF.bfType<>BitmapFileType then
raise EInvalidGraphic.Create(SInvalidDIB);
ReadData(Stream);
end;
procedure TDIB.ReadData(Stream: TStream);
var
TempImage: TDIBSharedImage;
begin
TempImage := TDIBSharedImage.Create;
try
TempImage.ReadData(Stream, FImage.FMemoryImage);
except
TempImage.Free;
raise;
end;
SetImage(TempImage);
end;
procedure TDIB.SaveToClipboardFormat(var AFormat: Word; var AData: THandle;
var APalette: HPALETTE);
var
P: Pointer;
Stream: TMemoryStream;
begin
AFormat := CF_DIB;
APalette := 0;
Stream := TMemoryStream.Create;
try
WriteData(Stream);
AData := GlobalAlloc(GHND, Stream.Size);
if AData=0 then OutOfMemoryError;
P := GlobalLock(AData);
Move(Stream.Memory^, P^, Stream.Size);
GlobalUnLock(AData);
finally
Stream.Free;
end;
end;
procedure TDIB.SaveToStream(Stream: TStream);
var
BF: TBitmapFileHeader;
begin
if Empty then Exit;
with BF do
begin
bfType := BitmapFileType;
bfOffBits := SizeOf(TBitmapFileHeader)+BitmapInfoSize;
bfSize := bfOffBits+FImage.FBitmapInfo^.bmiHeader.biSizeImage;
bfReserved1 := 0;
bfReserved2 := 0;
end;
Stream.WriteBuffer(BF, SizeOf(TBitmapFileHeader));
WriteData(Stream);
end;
procedure TDIB.WriteData(Stream: TStream);
begin
if Empty then Exit;
if not FImage.FMemoryImage then
GDIFlush;
Stream.WriteBuffer(FImage.FBitmapInfo^, FImage.FBitmapInfoSize);
Stream.WriteBuffer(FImage.FPBits^, FImage.FBitmapInfo.bmiHeader.biSizeImage);
end;
procedure TDIB.SetBitCount(Value: Integer);
begin
if Value<=0 then
Clear
else
begin
if Empty then
begin
SetSize(Max(Width, 1), Max(Height, 1), Value)
end else
begin
ConvertBitCount(Value);
end;
end;
end;
procedure TDIB.SetHeight(Value: Integer);
begin
if Value<=0 then
Clear
else
begin
if Empty then
SetSize(Max(Width, 1), Value, 8)
else
SetSize(Width, Value, BitCount);
end;
end;
procedure TDIB.SetWidth(Value: Integer);
begin
if Value<=0 then
Clear
else
begin
if Empty then
SetSize(Value, Max(Height, 1), 8)
else
SetSize(Value, Height, BitCount);
end;
end;
procedure TDIB.SetImage(Value: TDIBSharedImage);
begin
if FImage<>Value then
begin
if FCanvas<>nil then
FCanvas.Handle := 0;
FImage.Release;
FImage := Value;
FImage.Reference;
if FCanvas<>nil then
FCanvas.Handle := FImage.FDC;
ColorTable := FImage.FColorTable;
PixelFormat := FImage.FPixelFormat;
FBitCount := FImage.FBitCount;
FHeight := FImage.FHeight;
FNextLine := FImage.FNextLine;
FNowPixelFormat := FImage.FPixelFormat;
FPBits := FImage.FPBits;
FSize := FImage.FSize;
FTopPBits := FImage.FTopPBits;
FWidth := FImage.FWidth;
FWidthBytes := FImage.FWidthBytes;
end;
end;
procedure TDIB.SetNowPixelFormat(const Value: TDIBPixelFormat);
var
Temp: TDIB;
begin
if CompareMem(@Value, @FImage.FPixelFormat, SizeOf(TDIBPixelFormat)) then exit;
PixelFormat := Value;
Temp := TDIB.Create;
try
Temp.Assign(Self);
SetSize(Width, Height, BitCount);
Canvas.Draw(0, 0, Temp);
finally
Temp.Free;
end;
end;
procedure TDIB.SetPalette(Value: HPalette);
var
PaletteEntries: TPaletteEntries;
begin
GetPaletteEntries(Value, 0, 256, PaletteEntries);
DeleteObject(Value);
ColorTable := PaletteEntriesToRGBQuads(PaletteEntries);
UpdatePalette;
end;
procedure TDIB.SetSize(AWidth, AHeight, ABitCount: Integer);
var
TempImage: TDIBSharedImage;
begin
if (AWidth=Width) and (AHeight=Height) and (ABitCount=BitCount) and
(NowPixelFormat.RBitMask=PixelFormat.RBitMask) and
(NowPixelFormat.GBitMask=PixelFormat.GBitMask) and
(NowPixelFormat.BBitMask=PixelFormat.BBitMask) then Exit;
if (AWidth<=0) or (AHeight<=0) then
begin
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -