mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-14 10:59:11 +02:00
* Implemented .ico + .cur writing
git-svn-id: trunk@16372 -
This commit is contained in:
parent
98c9fb0791
commit
301ebd9881
@ -217,6 +217,13 @@ type
|
|||||||
pfCustom
|
pfCustom
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const
|
||||||
|
PIXELFORMAT_BPP: array[TPixelFormat] of Byte = (
|
||||||
|
0, 1, 4, 8, 15, 16, 24, 32, 0
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
type
|
||||||
TTransparentMode = (
|
TTransparentMode = (
|
||||||
tmAuto,
|
tmAuto,
|
||||||
tmFixed
|
tmFixed
|
||||||
@ -1477,6 +1484,7 @@ type
|
|||||||
function GetRawImagePtr: PRawImage; override;
|
function GetRawImagePtr: PRawImage; override;
|
||||||
function GetRawImageDescriptionPtr: PRawImageDescription; override;
|
function GetRawImageDescriptionPtr: PRawImageDescription; override;
|
||||||
function GetTransparent: Boolean; override;
|
function GetTransparent: Boolean; override;
|
||||||
|
class function GetTypeID: Word; virtual;
|
||||||
class function GetSharedImageClass: TSharedRasterImageClass; override;
|
class function GetSharedImageClass: TSharedRasterImageClass; override;
|
||||||
procedure HandleNeeded; override;
|
procedure HandleNeeded; override;
|
||||||
function InternalReleaseBitmapHandle: HBITMAP; override;
|
function InternalReleaseBitmapHandle: HBITMAP; override;
|
||||||
@ -1521,6 +1529,7 @@ type
|
|||||||
function GetIconHandle: HICON;
|
function GetIconHandle: HICON;
|
||||||
procedure SetIconHandle(const AValue: HICON);
|
procedure SetIconHandle(const AValue: HICON);
|
||||||
protected
|
protected
|
||||||
|
class function GetTypeID: Word; override;
|
||||||
procedure HandleNeeded; override;
|
procedure HandleNeeded; override;
|
||||||
public
|
public
|
||||||
function ReleaseHandle: HICON;
|
function ReleaseHandle: HICON;
|
||||||
@ -1594,6 +1603,7 @@ type
|
|||||||
procedure HandleNeeded; override;
|
procedure HandleNeeded; override;
|
||||||
class function GetDefaultSize: TSize; override;
|
class function GetDefaultSize: TSize; override;
|
||||||
class function GetSharedImageClass: TSharedRasterImageClass; override;
|
class function GetSharedImageClass: TSharedRasterImageClass; override;
|
||||||
|
class function GetTypeID: Word; override;
|
||||||
public
|
public
|
||||||
class function GetFileExtensions: string; override;
|
class function GetFileExtensions: string; override;
|
||||||
function LazarusResourceTypeValid(const ResourceType: string): boolean; override;
|
function LazarusResourceTypeValid(const ResourceType: string): boolean; override;
|
||||||
|
@ -48,6 +48,11 @@ begin
|
|||||||
Result := TSharedCursorImage;
|
Result := TSharedCursorImage;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
class function TCursorImage.GetTypeID: Word;
|
||||||
|
begin
|
||||||
|
Result := 2;
|
||||||
|
end;
|
||||||
|
|
||||||
function TCursorImage.LazarusResourceTypeValid(const ResourceType: string): boolean;
|
function TCursorImage.LazarusResourceTypeValid(const ResourceType: string): boolean;
|
||||||
var
|
var
|
||||||
ResType: String;
|
ResType: String;
|
||||||
|
@ -527,6 +527,11 @@ begin
|
|||||||
Result := True;
|
Result := True;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
class function TCustomIcon.GetTypeID: Word;
|
||||||
|
begin
|
||||||
|
Result := 0;
|
||||||
|
end;
|
||||||
|
|
||||||
class function TCustomIcon.GetSharedImageClass: TSharedRasterImageClass;
|
class function TCustomIcon.GetSharedImageClass: TSharedRasterImageClass;
|
||||||
begin
|
begin
|
||||||
Result := TSharedIcon;
|
Result := TSharedIcon;
|
||||||
@ -943,8 +948,200 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TCustomIcon.WriteStream(AStream: TMemoryStream);
|
procedure TCustomIcon.WriteStream(AStream: TMemoryStream);
|
||||||
|
procedure GetMaskData(ARawImg: TRawImage; AMskPtr: Pointer; AMskSize, AWidth, AHeight: Cardinal);
|
||||||
|
var
|
||||||
|
SrcRawImg, DstRawImg: TRawImage;
|
||||||
|
SrcDesc: TRawImageDescription absolute SrcRawImg.Description;
|
||||||
|
DstDesc: TRawImageDescription absolute DstRawImg.Description;
|
||||||
|
SrcImage, DstImage: TLazIntfImage;
|
||||||
|
begin
|
||||||
|
|
||||||
|
SrcRawImg.Init;
|
||||||
|
SrcRawImg.Description := ARawImg.Description.GetDescriptionFromMask;
|
||||||
|
SrcRawImg.Data := ARawImg.Mask;
|
||||||
|
SrcRawImg.DataSize := ARawImg.MaskSize;
|
||||||
|
|
||||||
|
DstRawImg.Init;
|
||||||
|
DstRawImg.Data := AMskPtr;
|
||||||
|
DstRawImg.DataSize := AMskSize;
|
||||||
|
|
||||||
|
DstDesc.Format := ricfGray;
|
||||||
|
DstDesc.Width := AWidth;
|
||||||
|
DstDesc.Height := AHeight;
|
||||||
|
DstDesc.Depth := 1;
|
||||||
|
DstDesc.BitOrder := riboReversedBits;
|
||||||
|
DstDesc.ByteOrder := riboLSBFirst;
|
||||||
|
DstDesc.LineOrder := riloBottomToTop;
|
||||||
|
DstDesc.LineEnd := rileDWordBoundary;
|
||||||
|
DstDesc.BitsPerPixel := 1;
|
||||||
|
DstDesc.RedPrec := 1;
|
||||||
|
DstDesc.RedShift := 0;
|
||||||
|
|
||||||
|
if SrcDesc.IsEqual(DstDesc)
|
||||||
|
then begin
|
||||||
|
Move(ARawImg.Mask^, AMskPtr^, ARawImg.MaskSize);
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
SrcImage := TLazIntfImage.Create(SrcRawImg, False);
|
||||||
|
DstImage := TLazIntfImage.Create(DstRawImg, False);
|
||||||
|
DstImage.CopyPixels(SrcImage);
|
||||||
|
|
||||||
|
SrcImage.Free;
|
||||||
|
DstImage.Free;
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
Header: TIconHeader;
|
||||||
|
StreamStart: Int64;
|
||||||
|
IconDir: array of TIconDirEntry;
|
||||||
|
n, i: Integer;
|
||||||
|
ImageCount: Word;
|
||||||
|
Color: TColor;
|
||||||
|
IconImage: TIconImage;
|
||||||
|
IntfImage: TLazIntfImage;
|
||||||
|
PNGSig: array[0..7] of Byte;
|
||||||
|
PNGWriter: TFPWriterPNG;
|
||||||
|
BMPWriter: TFPWriterBMP;
|
||||||
|
BmpPtr: PByte;
|
||||||
|
MskPtr: PByte;
|
||||||
|
MskSize: Cardinal;
|
||||||
|
MemStream: TMemoryStream;
|
||||||
|
RawImg: TRawImage;
|
||||||
begin
|
begin
|
||||||
{$IFDEF VerboseLCLTodos}{$note implement me}{$ENDIF}
|
ImageCount := TSharedIcon(FSharedImage).Count;
|
||||||
|
StreamStart := AStream.Position;
|
||||||
|
|
||||||
|
Header.idReserved := 0;
|
||||||
|
Header.idType := NtoLE(GetTypeID);
|
||||||
|
Header.idCount := LEtoN(ImageCount);
|
||||||
|
AStream.Write(Header, SizeOf(Header));
|
||||||
|
|
||||||
|
if ImageCount = 0 then Exit;
|
||||||
|
|
||||||
|
SetLength(IconDir, ImageCount);
|
||||||
|
FillChar(IconDir[0], ImageCount * SizeOf(IconDir[0]), 0);
|
||||||
|
|
||||||
|
// write empty dirlist first, so the images can be written after it.
|
||||||
|
// we'll update it later
|
||||||
|
AStream.Write(IconDir[0], ImageCount * SizeOf(IconDir[0]));
|
||||||
|
|
||||||
|
PNGWriter := nil;
|
||||||
|
BMPWriter := nil;
|
||||||
|
MemStream := nil;
|
||||||
|
IntfImage := nil;
|
||||||
|
try
|
||||||
|
for n := 0 to ImageCount - 1 do
|
||||||
|
begin
|
||||||
|
IconImage := TIconImage(TSharedIcon(FSharedImage).FImages[n]);
|
||||||
|
RawImg := IconImage.FImage;
|
||||||
|
|
||||||
|
// set offset
|
||||||
|
IconDir[n].dwImageOffset := NtoLE(DWord(AStream.Position - StreamStart));
|
||||||
|
|
||||||
|
// create or reset intfimage
|
||||||
|
if IntfImage = nil
|
||||||
|
then IntfImage := TLazIntfImage.Create(RawImg, False)
|
||||||
|
else IntfImage.SetRawImage(RawImg, False);
|
||||||
|
|
||||||
|
// user temp mem stream for storage.
|
||||||
|
if MemStream = nil
|
||||||
|
then MemStream := TMemoryStream.Create
|
||||||
|
else MemStream.Position := 0;
|
||||||
|
|
||||||
|
// write image data
|
||||||
|
if (IconImage.Width >= 255) or (IconImage.Height >= 255)
|
||||||
|
then begin
|
||||||
|
// PNG or DIB image
|
||||||
|
// Vista icons are PNG in this case, but there exist also "old style" icons
|
||||||
|
// with DIB image, we use PNG
|
||||||
|
// (dir.width and dir.height stay 0 in this case)
|
||||||
|
|
||||||
|
if PNGWriter = nil
|
||||||
|
then begin
|
||||||
|
PNGWriter := TFPWriterPNG.Create;
|
||||||
|
PNGWriter.Indexed := False;
|
||||||
|
PNGWriter.WordSized := False;
|
||||||
|
end;
|
||||||
|
PNGWriter.GrayScale := RawImg.Description.Format = ricfGray;
|
||||||
|
PNGWriter.UseAlpha := RawImg.Description.AlphaPrec > 0;
|
||||||
|
PNGWriter.ImageWrite(MemStream, IntfImage);
|
||||||
|
|
||||||
|
IconDir[n].wBpp := NtoLE(Word(RawImg.Description.BitsPerPixel));
|
||||||
|
IconDir[n].dwBytesInRes := NtoLE(DWord(MemStream.Position));
|
||||||
|
|
||||||
|
MemStream.SaveToStream(AStream);
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
// DIB image
|
||||||
|
IconDir[n].bHeight := IconImage.Height;
|
||||||
|
IconDir[n].bWidth := IconImage.Width;
|
||||||
|
|
||||||
|
// since there is no DIB writer, write a BMP to a temp stream and skip the file header
|
||||||
|
|
||||||
|
if BMPWriter = nil
|
||||||
|
then begin
|
||||||
|
BMPWriter := TFPWriterBMP.Create;
|
||||||
|
BMPWriter.RLECompress := False;
|
||||||
|
end;
|
||||||
|
case IconImage.PixelFormat of
|
||||||
|
pfDevice: BMPWriter.BitsPerPixel := QueryDescription([riqfRGB]).BitsPerPixel;
|
||||||
|
pfCustom: BMPWriter.BitsPerPixel := RawImg.Description.BitsPerPixel;
|
||||||
|
else
|
||||||
|
BMPWriter.BitsPerPixel := PIXELFORMAT_BPP[IconImage.PixelFormat];
|
||||||
|
end;
|
||||||
|
|
||||||
|
BMPWriter.ImageWrite(MemStream, IntfImage);
|
||||||
|
// adjust BMP data so it is a IconDIB
|
||||||
|
BmpPtr := PByte(MemStream.Memory) + SizeOf(TBitMapFileHeader);
|
||||||
|
// double the height to accommodate the mask
|
||||||
|
PBitMapInfoHeader(BmpPtr)^.biHeight := NtoLE(LEtoN(PBitMapInfoHeader(BmpPtr)^.biHeight) * 2);
|
||||||
|
|
||||||
|
// write mask.
|
||||||
|
// align to dword
|
||||||
|
MskSize := (((IconImage.Width + 31) shr 5) shl 2) * IconImage.Height;
|
||||||
|
// alloc "buffer"
|
||||||
|
if MemStream.Size < MemStream.Position + MskSize
|
||||||
|
then begin
|
||||||
|
MemStream.Size := MemStream.Position + MskSize;
|
||||||
|
// reallocation, recalculate bmpptr
|
||||||
|
BmpPtr := PByte(MemStream.Memory) + SizeOf(TBitMapFileHeader);
|
||||||
|
end;
|
||||||
|
MskPtr := PByte(MemStream.Memory) + MemStream.Position;
|
||||||
|
MemStream.Seek(MskSize, soCurrent);
|
||||||
|
|
||||||
|
if (RawImg.Mask = nil)
|
||||||
|
or (RawImg.MaskSize = 0)
|
||||||
|
then FillChar(MskPtr^, MskSize, 0)
|
||||||
|
else GetMaskData(RawImg, MskPtr, MskSize, IconImage.Width, IconImage.Height);
|
||||||
|
|
||||||
|
// write
|
||||||
|
AStream.WriteBuffer(BmpPtr^, MemStream.Position - SizeOf(TBitMapFileHeader));
|
||||||
|
|
||||||
|
IconDir[n].dwBytesInRes := NtoLE(DWord(MemStream.Position - SizeOf(TBitMapFileHeader)));
|
||||||
|
IconDir[n].wBpp := NtoLE(Word(BMPWriter.BitsPerPixel));
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
if IconImage is TCursorImageImage
|
||||||
|
then begin
|
||||||
|
IconDir[n].wXHotSpot := NtoLE(Word(TCursorImageImage(IconImage).HotSpot.X));
|
||||||
|
IconDir[n].wYHotSpot := NtoLE(Word(TCursorImageImage(IconImage).HotSpot.Y));
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
IconDir[n].wPlanes := NtoLE(Word(1));
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
PNGWriter.Free;
|
||||||
|
BMPWriter.Free;
|
||||||
|
MemStream.Free;
|
||||||
|
IntfImage.Free;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// update directory
|
||||||
|
AStream.Seek(StreamStart + SizeOf(Header), soBeginning);
|
||||||
|
AStream.Write(IconDir[0], ImageCount * SizeOf(IconDir[0]));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -956,6 +1153,11 @@ begin
|
|||||||
Result := GetHandle;
|
Result := GetHandle;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
class function TIcon.GetTypeID: Word;
|
||||||
|
begin
|
||||||
|
Result := 1; //icon
|
||||||
|
end;
|
||||||
|
|
||||||
function TIcon.ReleaseHandle: HICON;
|
function TIcon.ReleaseHandle: HICON;
|
||||||
begin
|
begin
|
||||||
HandleNeeded;
|
HandleNeeded;
|
||||||
|
Loading…
Reference in New Issue
Block a user