📄 pngimage.pas
字号:
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(TChunkpHYs);
RegisterChunk(TChunktIME);
RegisterChunk(TChunktEXt);
RegisterChunk(TChunkzTXt);
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;
{ZLIB support}
const
ZLIBAllocate = High(Word);
{Initializes ZLIB for decompression}
function ZLIBInitInflate(Stream: TStream): TZStreamRec2;
begin
{Fill record}
Fillchar(Result, SIZEOF(TZStreamRec2), #0);
{Set internal record information}
with Result do
begin
GetMem(Data, ZLIBAllocate);
fStream := Stream;
end;
{Init decompression}
InflateInit_(Result.zlib, zlib_version, SIZEOF(TZStreamRec));
end;
{Initializes ZLIB for compression}
function ZLIBInitDeflate(Stream: TStream;
Level: TCompressionlevel; Size: Cardinal): TZStreamRec2;
begin
{Fill record}
Fillchar(Result, SIZEOF(TZStreamRec2), #0);
{Set internal record information}
with Result, ZLIB do
begin
GetMem(Data, Size);
fStream := Stream;
next_out := Data;
avail_out := Size;
end;
{Inits compression}
deflateInit_(Result.zlib, Level, zlib_version, sizeof(TZStreamRec));
end;
{Terminates ZLIB for compression}
procedure ZLIBTerminateDeflate(var ZLIBStream: TZStreamRec2);
begin
{Terminates decompression}
DeflateEnd(ZLIBStream.zlib);
{Free internal record}
FreeMem(ZLIBStream.Data, ZLIBAllocate);
end;
{Terminates ZLIB for decompression}
procedure ZLIBTerminateInflate(var ZLIBStream: TZStreamRec2);
begin
{Terminates decompression}
InflateEnd(ZLIBStream.zlib);
{Free internal record}
FreeMem(ZLIBStream.Data, ZLIBAllocate);
end;
{Decompresses ZLIB into a memory address}
function DecompressZLIB(const Input: Pointer; InputSize: Integer;
var Output: Pointer; var OutputSize: Integer;
var ErrorOutput: String): Boolean;
var
StreamRec : TZStreamRec;
Buffer : Array[Byte] of Byte;
InflateRet: Integer;
begin
with StreamRec do
begin
{Initializes}
Result := True;
OutputSize := 0;
{Prepares the data to decompress}
FillChar(StreamRec, SizeOf(TZStreamRec), #0);
InflateInit_(StreamRec, zlib_version, SIZEOF(TZStreamRec));
next_in := Input;
avail_in := InputSize;
{Decodes data}
repeat
{In case it needs an output buffer}
if (avail_out = 0) then
begin
next_out := @Buffer;
avail_out := SizeOf(Buffer);
end {if (avail_out = 0)};
{Decompress and put in output}
InflateRet := inflate(StreamRec, 0);
if (InflateRet = Z_STREAM_END) or (InflateRet = 0) then
begin
{Reallocates output buffer}
inc(OutputSize, total_out);
if Output = nil then
GetMem(Output, OutputSize) else ReallocMem(Output, OutputSize);
{Copies the new data}
CopyMemory(Ptr(Longint(Output) + OutputSize - total_out),
@Buffer, total_out);
end {if (InflateRet = Z_STREAM_END) or (InflateRet = 0)}
{Now tests for errors}
else if InflateRet < 0 then
begin
Result := False;
ErrorOutput := StreamRec.msg;
InflateEnd(StreamRec);
Exit;
end {if InflateRet < 0}
until InflateRet = Z_STREAM_END;
{Terminates decompression}
InflateEnd(StreamRec);
end {with StreamRec}
end;
{Compresses ZLIB into a memory address}
function CompressZLIB(Input: Pointer; InputSize, CompressionLevel: Integer;
var Output: Pointer; var OutputSize: Integer;
var ErrorOutput: String): Boolean;
var
StreamRec : TZStreamRec;
Buffer : Array[Byte] of Byte;
DeflateRet: Integer;
begin
with StreamRec do
begin
Result := True; {By default returns TRUE as everything might have gone ok}
OutputSize := 0; {Initialize}
{Prepares the data to compress}
FillChar(StreamRec, SizeOf(TZStreamRec), #0);
DeflateInit_(StreamRec, CompressionLevel,zlib_version, SIZEOF(TZStreamRec));
next_in := Input;
avail_in := InputSize;
while avail_in > 0 do
begin
{When it needs new buffer to stores the compressed data}
if avail_out = 0 then
begin
{Restore buffer}
next_out := @Buffer;
avail_out := SizeOf(Buffer);
end {if avail_out = 0};
{Compresses}
DeflateRet := deflate(StreamRec, Z_FINISH);
if (DeflateRet = Z_STREAM_END) or (DeflateRet = 0) then
begin
{Updates the output memory}
inc(OutputSize, total_out);
if Output = nil then
GetMem(Output, OutputSize) else ReallocMem(Output, OutputSize);
{Copies the new data}
CopyMemory(Ptr(Longint(Output) + OutputSize - total_out),
@Buffer, total_out);
end {if (InflateRet = Z_STREAM_END) or (InflateRet = 0)}
{Now tests for errors}
else if DeflateRet < 0 then
begin
Result := False;
ErrorOutput := StreamRec.msg;
DeflateEnd(StreamRec);
Exit;
end {if InflateRet < 0}
end {while avail_in > 0};
{Finishes compressing}
DeflateEnd(StreamRec);
end {with StreamRec}
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) or (Count = 0) 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}
{Finds the first chunk of this class}
function TPNGList.FindChunk(ChunkClass: TChunkClass): TChunk;
var
i: Integer;
begin
Result := nil;
for i := 0 to Count - 1 do
if Item[i] is ChunkClass then
begin
Result := Item[i];
Break
end
end;
{Removes an item}
procedure TPNGList.RemoveChunk(Chunk: TChunk);
begin
Remove(Chunk);
Chunk.Free
end;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -