📄 pngimage.pas
字号:
bmAndMem := CreateCompatibleBitmap(dc, ptSize.x, ptSize.y);
// Each DC must select a bitmap object to store pixel data.
bmBackOld := SelectObject(hdcBack, bmAndBack);
bmObjectOld := SelectObject(hdcObject, bmAndObject);
bmMemOld := SelectObject(hdcMem, bmAndMem);
// Set the background color of the source DC to the color.
// contained in the parts of the bitmap that should be transparent
cColor := SetBkColor(hdcTemp, cTransparentColor);
// Create the object mask for the bitmap by performing a BitBlt
// from the source bitmap to a monochrome bitmap.
StretchBlt(hdcObject, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0,
orgSize.x, orgSize.y, SRCCOPY);
// Set the background color of the source DC back to the original
// color.
SetBkColor(hdcTemp, cColor);
// Create the inverse of the object mask.
BitBlt(hdcBack, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0,
NOTSRCCOPY);
// Copy the background of the main DC to the destination.
BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, dc, Rect.Left, Rect.Top,
SRCCOPY);
// Mask out the places where the bitmap will be placed.
BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0, SRCAND);
// Mask out the transparent colored pixels on the bitmap.
// BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcBack, 0, 0, SRCAND);
StretchBlt(hdcTemp, 0, 0, OrgSize.x, OrgSize.y, hdcBack, 0, 0,
PtSize.x, PtSize.y, SRCAND);
// XOR the bitmap with the background on the destination DC.
StretchBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0,
OrgSize.x, OrgSize.y, SRCPAINT);
// Copy the destination to the screen.
BitBlt(dc, Rect.Left, Rect.Top, ptSize.x, ptSize.y, hdcMem, 0, 0,
SRCCOPY);
// Delete the memory bitmaps.
DeleteObject(SelectObject(hdcBack, bmBackOld));
DeleteObject(SelectObject(hdcObject, bmObjectOld));
DeleteObject(SelectObject(hdcMem, bmMemOld));
DeleteObject(SelectObject(hdcTemp, OldBitmap));
// Delete the memory DCs.
DeleteDC(hdcMem);
DeleteDC(hdcBack);
DeleteDC(hdcObject);
DeleteDC(hdcTemp);
end;
{Make the table for a fast CRC.}
procedure make_crc_table;
var
c: Cardinal;
n, k: Integer;
begin
{fill the crc table}
for n := 0 to 255 do
begin
c := Cardinal(n);
for k := 0 to 7 do
begin
if Boolean(c and 1) then
c := $edb88320 xor (c shr 1)
else
c := c shr 1;
end;
crc_table[n] := c;
end;
{The table has already being computated}
crc_table_computed := true;
end;
{Update a running CRC with the bytes buf[0..len-1]--the CRC
should be initialized to all 1's, and the transmitted value
is the 1's complement of the final running CRC (see the
crc() routine below)).}
function update_crc(crc: {$IFNDEF DelphiBuilder3Less}Cardinal{$ELSE}Integer
{$ENDIF}; buf: pByteArray; len: Integer): Cardinal;
var
c: Cardinal;
n: Integer;
begin
c := crc;
{Create the crc table in case it has not being computed yet}
if not crc_table_computed then make_crc_table;
{Update}
for n := 0 to len - 1 do
c := crc_table[(c XOR buf^[n]) and $FF] XOR (c shr 8);
{Returns}
Result := c;
end;
{$IFNDEF UseDelphi}
function FileExists(Filename: String): Boolean;
var
FindFile: THandle;
FindData: TWin32FindData;
begin
FindFile := FindFirstFile(PChar(Filename), FindData);
Result := FindFile <> INVALID_HANDLE_VALUE;
if Result then Windows.FindClose(FindFile);
end;
{$ENDIF}
{$IFNDEF UseDelphi}
{Exception implementation}
constructor Exception.Create(Msg: String);
begin
end;
{$ENDIF}
{Calculates the paeth predictor}
function PaethPredictor(a, b, c: Byte): Byte;
var
pa, pb, pc: Integer;
begin
{ a = left, b = above, c = upper left }
pa := abs(b - c); { distances to a, b, c }
pb := abs(a - c);
pc := abs(a + b - c * 2);
{ return nearest of a, b, c, breaking ties in order a, b, c }
if (pa <= pb) and (pa <= pc) then
Result := a
else
if pb <= pc then
Result := b
else
Result := c;
end;
{Invert bytes using assembly}
function ByteSwap(const a: integer): integer;
asm
bswap eax
end;
{Calculates number of bytes for the number of pixels using the}
{color mode in the paramenter}
function BytesForPixels(const Pixels: Integer; const ColorType,
BitDepth: Byte): Integer;
begin
case ColorType of
{Palette and grayscale contains a single value, for palette}
{an value of size 2^bitdepth pointing to the palette index}
{and grayscale the value from 0 to 2^bitdepth with color intesity}
COLOR_GRAYSCALE, COLOR_PALETTE:
Result := (Pixels * BitDepth + 7) div 8;
{RGB contains 3 values R, G, B with size 2^bitdepth each}
COLOR_RGB:
Result := (Pixels * BitDepth * 3) div 8;
{Contains one value followed by alpha value booth size 2^bitdepth}
COLOR_GRAYSCALEALPHA:
Result := (Pixels * BitDepth * 2) div 8;
{Contains four values size 2^bitdepth, Red, Green, Blue and alpha}
COLOR_RGBALPHA:
Result := (Pixels * BitDepth * 4) div 8;
else
Result := 0;
end {case ColorType}
end;
type
pChunkClassInfo = ^TChunkClassInfo;
TChunkClassInfo = record
ClassName: TChunkClass;
end;
{Register a chunk type}
procedure RegisterChunk(ChunkClass: TChunkClass);
var
NewClass: pChunkClassInfo;
begin
{In case the list object has not being created yet}
if ChunkClasses = nil then ChunkClasses := TPngPointerList.Create(nil);
{Add this new class}
new(NewClass);
NewClass^.ClassName := ChunkClass;
ChunkClasses.Add(NewClass);
end;
{Free chunk class list}
procedure FreeChunkClassList;
var
i: Integer;
begin
if (ChunkClasses <> nil) then
begin
FOR i := 0 TO ChunkClasses.Count - 1 do
Dispose(pChunkClassInfo(ChunkClasses.Item[i]));
ChunkClasses.Free;
end;
end;
{Registering of common chunk classes}
procedure RegisterCommonChunks;
begin
{Important chunks}
RegisterChunk(TChunkIEND);
RegisterChunk(TChunkIHDR);
RegisterChunk(TChunkIDAT);
RegisterChunk(TChunkPLTE);
RegisterChunk(TChunkgAMA);
RegisterChunk(TChunktRNS);
{Not so important chunks}
RegisterChunk(TChunktIME);
RegisterChunk(TChunktEXt);
end;
{Creates a new chunk of this class}
function CreateClassChunk(Owner: TPngObject; Name: TChunkName): TChunk;
var
i : Integer;
NewChunk: TChunkClass;
begin
{Looks for this chunk}
NewChunk := TChunk; {In case there is no registered class for this}
{Looks for this class in all registered chunks}
if Assigned(ChunkClasses) then
FOR i := 0 TO ChunkClasses.Count - 1 DO
begin
if pChunkClassInfo(ChunkClasses.Item[i])^.ClassName.GetName = Name then
begin
NewChunk := pChunkClassInfo(ChunkClasses.Item[i])^.ClassName;
break;
end;
end;
{Returns chunk class}
Result := NewChunk.Create(Owner);
Result.fName := Name;
end;
{TPngPointerList implementation}
{Object being created}
constructor TPngPointerList.Create(AOwner: TPNGObject);
begin
inherited Create; {Let ancestor work}
{Holds owner}
fOwner := AOwner;
{Memory pointer not being used yet}
fMemory := nil;
{No items yet}
fCount := 0;
end;
{Removes value from the list}
function TPngPointerList.Remove(Value: Pointer): Pointer;
var
I, Position: Integer;
begin
{Gets item position}
Position := -1;
FOR I := 0 TO Count - 1 DO
if Value = Item[I] then Position := I;
{In case a match was found}
if Position >= 0 then
begin
Result := Item[Position]; {Returns pointer}
{Remove item and move memory}
Dec(fCount);
if Position < Integer(FCount) then
System.Move(fMemory^[Position + 1], fMemory^[Position],
(Integer(fCount) - Position) * SizeOf(Pointer));
end {if Position >= 0} else Result := nil
end;
{Add a new value in the list}
procedure TPngPointerList.Add(Value: Pointer);
begin
Count := Count + 1;
Item[Count - 1] := Value;
end;
{Object being destroyed}
destructor TPngPointerList.Destroy;
begin
{Release memory if needed}
if fMemory <> nil then
FreeMem(fMemory, fCount * sizeof(Pointer));
{Free things}
inherited Destroy;
end;
{Returns one item from the list}
function TPngPointerList.GetItem(Index: Cardinal): Pointer;
begin
if (Index <= Count - 1) then
Result := fMemory[Index]
else
{In case it's out of bounds}
Result := nil;
end;
{Inserts a new item in the list}
procedure TPngPointerList.Insert(Value: Pointer; Position: Cardinal);
begin
if (Position < Count) then
begin
{Increase item count}
SetSize(Count + 1);
{Move other pointers}
if Position < Count then
System.Move(fMemory^[Position], fMemory^[Position + 1],
(Count - Position - 1) * SizeOf(Pointer));
{Sets item}
Item[Position] := Value;
end;
end;
{Sets one item from the list}
procedure TPngPointerList.SetItem(Index: Cardinal; const Value: Pointer);
begin
{If index is in bounds, set value}
if (Index <= Count - 1) then
fMemory[Index] := Value
end;
{This method resizes the list}
procedure TPngPointerList.SetSize(const Size: Cardinal);
begin
{Sets the size}
if (fMemory = nil) and (Size > 0) then
GetMem(fMemory, Size * SIZEOF(Pointer))
else
if Size > 0 then {Only realloc if the new size is greater than 0}
ReallocMem(fMemory, Size * SIZEOF(Pointer))
else
{In case user is resize to 0 items}
begin
FreeMem(fMemory);
fMemory := nil;
end;
{Update count}
fCount := Size;
end;
{TPNGList implementation}
{Removes an item}
procedure TPNGList.RemoveChunk(Chunk: TChunk);
begin
Remove(Chunk);
Chunk.Free
end;
{Add a new item}
function TPNGList.Add(ChunkClass: TChunkClass): TChunk;
var
IHDR: TChunkIHDR;
IEND: TChunkIEND;
IDAT: TChunkIDAT;
PLTE: TChunkPLTE;
begin
Result := nil; {Default result}
{Adding these is not allowed}
if (ChunkClass = TChunkIHDR) or (ChunkClass = TChunkIDAT) or
(ChunkClass = TChunkPLTE) or (ChunkClass = TChunkIEND) then
fOwner.RaiseError(EPngError, EPNGCannotAddChunkText)
{Two of these is not allowed}
else if ((ChunkClass = TChunkgAMA) and (ItemFromClass(TChunkgAMA) <> nil)) or
((ChunkClass = TChunktRNS) and (ItemFromClass(TChunktRNS) <> nil)) then
fOwner.RaiseError(EPngError, EPNGCannotAddChunkText)
{There must have an IEND and IHDR chunk}
else if (ItemFromClass(TChunkIEND) = nil) or
(ItemFromClass(TChunkIHDR) = nil) then
fOwner.RaiseError(EPngError, EPNGCannotAddInvalidImageText)
else
begin
{Get common chunks}
IHDR := ItemFromClass(TChunkIHDR) as TChunkIHDR;
IEND := ItemFromClass(TChunkIEND) as TChunkIEND;
{Create new chunk}
Result := ChunkClass.Create(Owner);
{Add to the list}
if (ChunkClass = TChunkgAMA) then
Insert(Result, IHDR.Index + 1)
{Transparency chunk (fix by Ian Boyd)}
else if (ChunkClass = TChunktRNS) then
begin
{Transparecy chunk must be after PLTE; before IDAT}
IDAT := ItemFromClass(TChunkIDAT) as TChunkIDAT;
PLTE := ItemFromClass(TChunkPLTE) as TChunkPLTE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -