?? pngimage.pas
字號:
function TChunktEXt.LoadFromStream(Stream: TStream;
const ChunkName: TChunkName; Size: Integer): Boolean;
begin
{Load data from stream and validate}
Result := inherited LoadFromStream(Stream, ChunkName, Size);
if not Result or (Size < 3) then exit;
{Get text}
fKeyword := PChar(Data);
SetLength(fText, Size - Length(fKeyword) - 1);
CopyMemory(@fText[1], Ptr(Longint(Data) + Length(fKeyword) + 1),
Length(fText));
end;
{Saving the chunk to a stream}
function TChunktEXt.SaveToStream(Stream: TStream): Boolean;
begin
{Size is length from keyword, plus a null character to divide}
{plus the length of the text}
ResizeData(Length(fKeyword) + 1 + Length(fText));
Fillchar(Data^, DataSize, #0);
{Copy data}
if Keyword <> '' then
CopyMemory(Data, @fKeyword[1], Length(Keyword));
if Text <> '' then
CopyMemory(Ptr(Longint(Data) + Length(Keyword) + 1), @fText[1],
Length(Text));
{Let ancestor calculate crc and save}
Result := inherited SaveToStream(Stream);
end;
{TChunkIHDR implementation}
{Chunk being created}
constructor TChunkIHDR.Create(Owner: TPngObject);
begin
{Call inherited}
inherited Create(Owner);
{Prepare pointers}
ImageHandle := 0;
ImageDC := 0;
end;
{Chunk being destroyed}
destructor TChunkIHDR.Destroy;
begin
{Free memory}
FreeImageData();
{Calls TChunk destroy}
inherited Destroy;
end;
{Assigns from another IHDR chunk}
procedure TChunkIHDR.Assign(Source: TChunk);
begin
{Copy the IHDR data}
if Source is TChunkIHDR then
begin
{Copy IHDR values}
IHDRData := TChunkIHDR(Source).IHDRData;
{Prepare to hold data by filling BitmapInfo structure and}
{resizing ImageData and ImageAlpha memory allocations}
PrepareImageData();
{Copy image data}
CopyMemory(ImageData, TChunkIHDR(Source).ImageData,
BytesPerRow * Integer(Height));
CopyMemory(ImageAlpha, TChunkIHDR(Source).ImageAlpha,
Integer(Width) * Integer(Height));
{Copy palette colors}
BitmapInfo.bmiColors := TChunkIHDR(Source).BitmapInfo.bmiColors;
end
else
Owner.RaiseError(EPNGError, EPNGCannotAssignChunkText);
end;
{Release allocated image data}
procedure TChunkIHDR.FreeImageData;
begin
{Free old image data}
if ImageHandle <> 0 then DeleteObject(ImageHandle);
if ImageDC <> 0 then DeleteDC(ImageDC);
if ImageAlpha <> nil then FreeMem(ImageAlpha);
ImageHandle := 0; ImageDC := 0; ImageAlpha := nil; ImageData := nil;
end;
{Chunk being loaded from a stream}
function TChunkIHDR.LoadFromStream(Stream: TStream; const ChunkName: TChunkName;
Size: Integer): Boolean;
begin
{Let TChunk load it}
Result := inherited LoadFromStream(Stream, ChunkName, Size);
if not Result then Exit;
{Now check values}
{Note: It's recommended by png specification to make sure that the size}
{must be 13 bytes to be valid, but some images with 14 bytes were found}
{which could be loaded by internet explorer and other tools}
if (fDataSize < SIZEOF(TIHdrData)) then
begin
{Ihdr must always have at least 13 bytes}
Result := False;
Owner.RaiseError(EPNGInvalidIHDR, EPNGInvalidIHDRText);
exit;
end;
{Everything ok, reads IHDR}
IHDRData := pIHDRData(fData)^;
IHDRData.Width := ByteSwap(IHDRData.Width);
IHDRData.Height := ByteSwap(IHDRData.Height);
{The width and height must not be larger than 65535 pixels}
if (IHDRData.Width > High(Word)) or (IHDRData.Height > High(Word)) then
begin
Result := False;
Owner.RaiseError(EPNGSizeExceeds, EPNGSizeExceedsText);
exit;
end {if IHDRData.Width > High(Word)};
{Compression method must be 0 (inflate/deflate)}
if (IHDRData.CompressionMethod <> 0) then
begin
Result := False;
Owner.RaiseError(EPNGUnknownCompression, EPNGUnknownCompressionText);
exit;
end;
{Interlace must be either 0 (none) or 7 (adam7)}
if (IHDRData.InterlaceMethod <> 0) and (IHDRData.InterlaceMethod <> 1) then
begin
Result := False;
Owner.RaiseError(EPNGUnknownInterlace, EPNGUnknownInterlaceText);
exit;
end;
{Updates owner properties}
Owner.InterlaceMethod := TInterlaceMethod(IHDRData.InterlaceMethod);
{Prepares data to hold image}
PrepareImageData();
end;
{Saving the IHDR chunk to a stream}
function TChunkIHDR.SaveToStream(Stream: TStream): Boolean;
begin
{Ignore 2 bits images}
if BitDepth = 2 then BitDepth := 4;
{It needs to do is update the data with the IHDR data}
{structure containing the write values}
ResizeData(SizeOf(TIHDRData));
pIHDRData(fData)^ := IHDRData;
{..byteswap 4 byte types}
pIHDRData(fData)^.Width := ByteSwap(pIHDRData(fData)^.Width);
pIHDRData(fData)^.Height := ByteSwap(pIHDRData(fData)^.Height);
{..update interlace method}
pIHDRData(fData)^.InterlaceMethod := Byte(Owner.InterlaceMethod);
{..and then let the ancestor SaveToStream do the hard work}
Result := inherited SaveToStream(Stream);
end;
{Resizes the image data to fill the color type, bit depth, }
{width and height parameters}
procedure TChunkIHDR.PrepareImageData();
{Set the bitmap info}
procedure SetInfo(const Bitdepth: Integer; const Palette: Boolean);
begin
{Copy if the bitmap contain palette entries}
HasPalette := Palette;
{Initialize the structure with zeros}
fillchar(BitmapInfo, sizeof(BitmapInfo), #0);
{Fill the strucutre}
with BitmapInfo.bmiHeader do
begin
biSize := sizeof(TBitmapInfoHeader);
biHeight := Height;
biWidth := Width;
biPlanes := 1;
biBitCount := BitDepth;
biCompression := BI_RGB;
end {with BitmapInfo.bmiHeader}
end;
begin
{Prepare bitmap info header}
Fillchar(BitmapInfo, sizeof(TMaxBitmapInfo), #0);
{Release old image data}
FreeImageData();
{Obtain number of bits for each pixel}
case ColorType of
COLOR_GRAYSCALE, COLOR_PALETTE, COLOR_GRAYSCALEALPHA:
case BitDepth of
{These are supported by windows}
1, 4, 8: SetInfo(BitDepth, TRUE);
{2 bits for each pixel is not supported by windows bitmap}
2 : SetInfo(4, TRUE);
{Also 16 bits (2 bytes) for each pixel is not supported}
{and should be transormed into a 8 bit grayscale}
16 : SetInfo(8, TRUE);
end;
{Only 1 byte (8 bits) is supported}
COLOR_RGB, COLOR_RGBALPHA: SetInfo(24, FALSE);
end {case ColorType};
{Number of bytes for each scanline}
BytesPerRow := (((BitmapInfo.bmiHeader.biBitCount * Width) + 31)
and not 31) div 8;
{Build array for alpha information, if necessary}
if (ColorType = COLOR_RGBALPHA) or (ColorType = COLOR_GRAYSCALEALPHA) then
begin
GetMem(ImageAlpha, Integer(Width) * Integer(Height));
ZeroMemory(ImageAlpha, Integer(Width) * Integer(Height));
end;
{Creates the image to hold the data, CreateDIBSection does a better}
{work in allocating necessary memory}
ImageDC := CreateCompatibleDC(0);
ImageHandle := CreateDIBSection(ImageDC, pBitmapInfo(@BitmapInfo)^,
DIB_RGB_COLORS, ImageData, 0, 0);
{Build array and allocate bytes for each row}
zeromemory(ImageData, BytesPerRow * Integer(Height));
end;
{TChunktRNS implementation}
{$IFNDEF UseDelphi}
function CompareMem(P1, P2: pByte; const Size: Integer): Boolean;
var i: Integer;
begin
Result := True;
for i := 1 to Size do
begin
if P1^ <> P2^ then Result := False;
inc(P1); inc(P2);
end {for i}
end;
{$ENDIF}
{Sets the transpararent color}
procedure TChunktRNS.SetTransparentColor(const Value: ColorRef);
var
i: Byte;
LookColor: TRGBQuad;
begin
{Clears the palette values}
Fillchar(PaletteValues, SizeOf(PaletteValues), #0);
{Sets that it uses bit transparency}
fBitTransparency := True;
{Depends on the color type}
with Header do
case ColorType of
COLOR_GRAYSCALE:
begin
Self.ResizeData(BitDepth div 8);
PaletteValues[0] := GetRValue(Value);
end;
COLOR_RGB:
begin
Self.ResizeData((BitDepth div 8) * 3);
PaletteValues[0] := GetRValue(Value);
PaletteValues[1*(BitDepth div 8)] := GetGValue(Value);
PaletteValues[2*(BitDepth div 8)] := GetBValue(Value);
end;
COLOR_PALETTE:
begin
{Creates a RGBQuad to search for the color}
LookColor.rgbRed := GetRValue(Value);
LookColor.rgbGreen := GetGValue(Value);
LookColor.rgbBlue := GetBValue(Value);
{Look in the table for the entry}
for i := 0 to 255 do
if CompareMem(@BitmapInfo.bmiColors[i], @LookColor, 3) then
Break;
{Fill the transparency table}
Fillchar(PaletteValues, i, 255);
Self.ResizeData(i + 1)
end
end {case / with};
end;
{Returns the transparent color for the image}
function TChunktRNS.GetTransparentColor: ColorRef;
var
PaletteChunk: TChunkPLTE;
i: Integer;
begin
Result := 0; {Default: Unknown transparent color}
{Depends on the color type}
with Header do
case ColorType of
COLOR_GRAYSCALE: Result := RGB(PaletteValues[0], PaletteValues[0],
PaletteValues[0]);
COLOR_RGB:
if BitDepth = 8 then
Result := RGB(PaletteValues[0], PaletteValues[1], PaletteValues[2])
else
Result := RGB(PaletteValues[0], PaletteValues[2], PaletteValues[4]);
COLOR_PALETTE:
begin
{Obtains the palette chunk}
PaletteChunk := Owner.Chunks.ItemFromClass(TChunkPLTE) as TChunkPLTE;
{Looks for an entry with 0 transparency meaning that it is the}
{full transparent entry}
for i := 0 to Self.DataSize - 1 do
if PaletteValues[i] = 0 then
with PaletteChunk.GetPaletteItem(i) do
begin
Result := RGB(rgbRed, rgbGreen, rgbBlue);
break
end
end {COLOR_PALETTE}
end {case Header.ColorType};
end;
{Saving the chunk to a stream}
function TChunktRNS.SaveToStream(Stream: TStream): Boolean;
begin
{Copy palette into data buffer}
if DataSize <= 256 then
CopyMemory(fData, @PaletteValues[0], DataSize);
Result := inherited SaveToStream(Stream);
end;
{Assigns from another chunk}
procedure TChunktRNS.Assign(Source: TChunk);
begin
CopyMemory(@PaletteValues[0], @TChunkTrns(Source).PaletteValues[0], 256);
fBitTransparency := TChunkTrns(Source).fBitTransparency;
inherited Assign(Source);
end;
{Loads the chunk from a stream}
function TChunktRNS.LoadFromStream(Stream: TStream; const ChunkName: TChunkName;
Size: Integer): Boolean;
var
i, Differ255: Integer;
begin
{Let inherited load}
Result := inherited LoadFromStream(Stream, ChunkName, Size);
if not Result then Exit;
{Make sure size is correct}
if Size > 256 then Owner.RaiseError(EPNGInvalidPalette,
EPNGInvalidPaletteText);
{The unset items should have value 255}
Fillchar(PaletteValues[0], 256, 255);
{Copy the other values}
CopyMemory(@PaletteValues[0], fData, Size);
{Create the mask if needed}
case Header.ColorType of
{Mask for grayscale and RGB}
COLOR_RGB, COLOR_GRAYSCALE: fBitTransparency := True;
COLOR_PALETTE:
begin
Differ255 := 0; {Count the entries with a value different from 255}
{Tests if it uses bit transparency}
for i := 0 to Size - 1 do
if PaletteValues[i] <> 255 then inc(Differ255);
{If it has one value different from 255 it is a bit transparency}
fBitTransparency := (Differ255 = 1);
end {COLOR_PALETTE}
end {case Header.ColorType};
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: TCompressionleve
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -