UPD: New icon load function (Windows)

This commit is contained in:
Alexander Koblov 2020-08-15 19:39:39 +00:00
commit 49e01361e3
6 changed files with 25 additions and 864 deletions

View file

@ -127,12 +127,10 @@ uses
, ComObj, fMain, DCOSUtils, uOSUtils, uFileSystemFileSource
, uTotalCommander, FileUtil, Windows, ShlObj, uShlObjAdditional
, uWinNetFileSource, uVfsModule, uLng, uMyWindows, DCStrUtils
, uDCReadSVG, uFileSourceUtil, uGdiPlusJPEG
, Dialogs, Clipbrd, uShowMsg, uDebug, JwaDbt
, uDCReadSVG, uFileSourceUtil, uGdiPlusJPEG, uListGetPreviewBitmap
, Dialogs, Clipbrd, uShowMsg, uDebug, JwaDbt, uThumbnailProvider
{$IFDEF LCLQT5}
, qt5, qtwidgets, uDarkStyle
{$ELSE}
, uListGetPreviewBitmap, uThumbnailProvider
{$ENDIF}
{$ENDIF}
{$IFDEF UNIX}

View file

@ -338,7 +338,7 @@ uses
, uPixMapGtk, gdk2pixbuf, gdk2, glib2
{$ENDIF}
{$IFDEF MSWINDOWS}
, CommCtrl, ShellAPI, Windows, DCFileAttributes, uIcoFiles, uGdiPlus,
, CommCtrl, ShellAPI, Windows, DCFileAttributes, uBitmap, uGdiPlus,
IntfGraphics, uShlObjAdditional
{$ELSE}
, StrUtils, Types, DCBasicTypes
@ -515,7 +515,6 @@ var
phIcon: HICON = INVALID_HANDLE_VALUE;
phIconLarge : HICON = 0;
phIconSmall : HICON = 0;
Icon : TIcon = nil;
IconFileName: String;
{$ENDIF}
AFile: TFile;
@ -551,15 +550,11 @@ begin
end;
if phIcon <> INVALID_HANDLE_VALUE then
try
Icon:= CreateIconFromHandle(phIcon);
bmStandartBitmap := Graphics.TBitMap.Create;
bmStandartBitmap.Assign(Icon);
bmStandartBitmap.Masked := True; // Need to explicitly set Masked=True, Lazarus issue #0019747
if fromWhatItWasLoaded<> nil then fromWhatItWasLoaded^ := fwbwlResourceFileExtracted;
finally
FreeThenNil(Icon);
end;
begin
bmStandartBitmap := BitmapCreateFromHICON(phIcon);
bmStandartBitmap.Masked := True; // Need to explicitly set Masked=True, Lazarus issue #0019747
if fromWhatItWasLoaded<> nil then fromWhatItWasLoaded^ := fwbwlResourceFileExtracted;
end;
DestroyIcon(phIconLarge);
DestroyIcon(phIconSmall);
end;
@ -1612,7 +1607,6 @@ var
PixmapFromList: Boolean = False;
{$IFDEF MSWINDOWS}
hicn: HICON;
Icon: TIcon = nil;
{$ENDIF}
begin
FPixmapsLock.Acquire;
@ -1643,15 +1637,12 @@ begin
Result:= nil;
hicn:= ImageList_GetIcon(FSysImgList, iIndex - SystemIconIndexStart, ILD_NORMAL);
if hicn <> 0 then
try
Icon := CreateIconFromHandle(hicn);
Result := Graphics.TBitmap.Create;
Result.Assign(Icon);
Result.Masked := True; // Need to explicitly set Masked=True, Lazarus issue #0019747
finally
FreeThenNil(Icon);
DestroyIcon(hicn);
end
try
Result := BitmapCreateFromHICON(hicn);
Result.Masked := True; // Need to explicitly set Masked=True, Lazarus issue #0019747
finally
DestroyIcon(hicn);
end
end
else
{$ENDIF}
@ -1695,7 +1686,6 @@ var
{$IFDEF MSWINDOWS}
hicn: HICON;
cx, cy: Integer;
Icon: TIcon;
{$ENDIF}
{$IFDEF LCLGTK2}
pbPicture : PGdkPixbuf;
@ -1761,12 +1751,12 @@ begin
{$ELSEIF DEFINED(LCLQT5)}
hicn:= ImageList_GetIcon(FSysImgList, iIndex - SystemIconIndexStart, ILD_NORMAL);
try
Icon:= CreateIconFromHandle(hicn);
Bitmap:= BitmapCreateFromHICON(hicn);
aRect := Classes.Bounds(X, Y, Width, Height);
Canvas.StretchDraw(aRect, Icon);
Canvas.StretchDraw(aRect, Bitmap);
finally
FreeAndNil(Icon);
DestroyIcon(hicn);
FreeAndNil(Bitmap);
end
{$ENDIF}
except
@ -2121,7 +2111,6 @@ function TPixMapManager.GetDriveIcon(Drive : PDrive; IconSize : Integer; clBackC
{$IFDEF MSWINDOWS}
var
SFI: TSHFileInfoW;
Icon: TIcon = nil;
uFlags: UINT;
iIconSmall,
iIconLarge: Integer;
@ -2153,13 +2142,11 @@ begin
begin
if (SFI.hIcon <> 0) then
try
Icon := CreateIconFromHandle(SFI.hIcon);
Result.Assign(Icon);
Result:= BitmapCreateFromHICON(SFI.hIcon);
Result.Masked := True; // Need to explicitly set Masked=True, Lazarus issue #0019747
if (IconSize <> iIconSmall) and (IconSize <> iIconLarge) then // non standart icon size
Result := StretchBitmap(Result, IconSize, clBackColor, True);
finally
FreeAndNil(Icon);
DestroyIcon(SFI.hIcon);
end;
end;

View file

@ -1,822 +0,0 @@
// Copyright (C) ßí - ßíû÷.selfip.com
// Òóò âñ¸, ÷òî êàñàåòñÿ ñîõðàíåíèÿ èêîíîê â ôàéë
// Âñ¸ â îäíîì êëàññå, êîòîðûé íà ñàìîì äåëå ëåãêî ìîæåò áûòü è íå êëàññîì âîâñå.
// Òóò ïîêàçàíî êàê ïðî÷èòàòü "âëîæåííûå" çíà÷êè èç ôàéëà, êàê ïîëó÷èòü àññîöèèðîâàííóþ ñ
// òèïîì ôàéëà èêîíêó, êàê ïîëó÷èòü äàííûå òàêîé èêîíêè ïî õýíäëó, êàê çàïèñàòü äàííûå
// èêîíêè â ôàéë, êàê ñêîíâåðòèðîâàòü èêîíêó â png, êàê ïðîâåðèòü, åñòü ëè â èêîíêå alpha-êàíàë,
// è êàê ñêîíâåðòèðîâàòü èêîíêó èç 32 áèòà â true color áåç àëüôàêàíàëà.
//
// Ýòîò èñõîäíèê ñûðîé, ÿ åãî ïðÿìî ñåé÷àñ äîïèñûâàþ, íî ÿ êîãäà íà÷èíàë ðàçáèðàòüñÿ
// è òàêîìó áûë áû ðàä
// Ñâîþ ïîñëåäíþþ âåðñèþ âûëîæó çäåñü æå, íà http://janych.selfip.com/examples/Delphi/Icons/
// *********************************************************************************************
// Copyright (C) 2007 Koblov Alexander (Alexx2000@mail.ru)
// Add some changes for compiling under FPC/Lazarus
// Add function CreateIconFromHandle
unit uIcoFiles;
{$mode delphi}
interface
uses
Classes,Graphics,Windows, JwaWinGDI;
{$ASSERTIONS ON}
const
rc3_StockIcon = 0;
rc3_Icon = 1;
rc3_Cursor = 2;
{ currentlly defined blend function }
AC_SRC_OVER = $00;
AC_SRC_ALPHA = $01;
type
TCursorOrIcon = packed record
Reserved: Word;
wType: Word;
Count: Word;
end;
TIconRec = packed record // Îïðåäåëåíà â ìîäóëå Graphics
Width: Byte;
Height: Byte;
Colors: Word;
Reserved1: Word;
Reserved2: Word;
DIBSize: Longint;
DIBOffset: Longint;
end;
TBits = array of Byte;
TIconData = packed record // Äàííûå îá îäèíî÷íîé èêîíêå
Info: TIconRec; // Çàãîëîâîê èç ôàéëà èëè ñîçäàííûé èç õýíäëà
BitmapInfo, // Çàãîëîâîê çíà÷êà, èñïîëüçóþùèéñÿ è äëÿ ðèñîâàíèÿ
MaskBitmapInfo: PBitmapInfo; // Çàãîëîâîê ìàñêè - â ôàéë íå ñîõðàíÿåòñÿ, ñîçäà¸òñÿ needMaskBitmapInfo
ImageLineWidth, // Èñïîëüçóåòñÿ â IsValidAlpha è ConvertToPNG
MaskLineWidth: Integer; // Èñïîëüçóåòñÿ â ConvertToPNG
ImageBits: TBits; // Áèòû èçîáðàæåíèÿ
MaskBits: TBits; // Áèòû ìàñêè
iRgbTable: integer; // Ðàçìåð ïàëèòðû, âêëþ÷¸ííîé â BitmapInfo
end;
TIcons = array of TIconData; // Íàáîð "âëîæåííûõ" çíà÷êîâ èç îäíîãî ôàéëà
type
TIcoFile = class(TComponent)
private
FIcons: TIcons;
public
destructor Destroy;override;
procedure loadFromStream(Stream:TStream);
procedure loadFromHandle(h:hicon);
procedure saveTrueColorFrom32(icoNo:integer;out IconData:TIconData);
procedure saveToStream(Stream:TStream);
procedure check;
procedure draw(icoNo,x,y:integer;dest:hdc;drawMask,drawImage,drawAlpha:boolean);overload;
procedure draw(IconData:TIconData;x,y:integer;dest:hdc;drawMask,drawImage,drawAlpha:boolean);overload;
function IsValidAlpha(icoNo:integer): boolean; // Ïðîâåðèòü, åñòü ëè àëüôà-êàíàë
property Icons: TIcons read FIcons write FIcons;
{
procedure ConvertToPNG(icoNo:integer;Stream:TStream);
procedure saveAsPng(icoNo:integer;fn:string);
}
procedure Add(IconData:TIconData);
procedure AddCopy(IconData:TIconData);
procedure DestroyIconData(IconData: TIconData);
end;
function getIconHandleForFile(fn:string;large:boolean): hicon;
function CreateIconFromHandle(IconHandle : HIcon) : TIcon;
implementation
uses sysUtils,
ShellAPI; // Èñïîëüçóåòñÿ òîëüêî äëÿ getIconHandleForFile
//pngimage; // Èñïîëüçóåòñÿ òîëüêî äëÿ ConvertToPNG/saveAsPng, ìîæíî óáðàòü, åñëè íå èíòåðåñíî
type
TRGBQuadArray = array[byte] of TRGBQuad;
PRGBQuadArray = ^TRGBQuadArray;
function BytesPerScanline(PixelsPerScanline, BitsPerPixel, Alignment: Longint): Longint;
begin
Dec(Alignment);
Result := ((PixelsPerScanline * BitsPerPixel) + Alignment) and not Alignment;
Result := Result div 8;
end;
{ TIcoFile }
destructor TIcoFile.Destroy;
var
i: integer;
begin
if Length(FIcons) > 0 then
for i:=low(FIcons) to high(FIcons) do
DestroyIconData(FIcons[i]);
inherited;
end;
procedure TIcoFile.loadFromStream(Stream:TStream);
var
FileHeader: TCursorOrIcon;
i,Size: integer;
begin
Stream.ReadBuffer(FileHeader,SizeOf(FileHeader)); // ×èòàåì çàãîëîâîê
if (FileHeader.Reserved<>0) or not (FileHeader.wType in [RC3_ICON,RC3_CURSOR]) then
raise Exception.Create('Invalid icon');
SetLength(FIcons,FileHeader.Count); // Ñîçäà¸ì ìàññèâ èêîíîê. Ïðè ÷òåíèè èç íàøåãî Stream âñåãäà 1 ýëåìåíò
for i:=0 to FileHeader.Count-1 do // ×èòàåì çàãîëîâêè âëîæåííûõ èêîíîê ÷òîáû íå ñêàêàòü òóäà-ñþäà ïî ôàéëó
with FIcons[i] do
Stream.ReadBuffer(Info,SizeOf(TIconRec));
for i:=0 to FileHeader.Count-1 do
begin
with FIcons[i] do
begin
Stream.Position := Info.DIBOffset;
getMem(BitmapInfo,SizeOf(BitmapInfo^.bmiHeader));
Stream.ReadBuffer(BitmapInfo^.bmiHeader,SizeOf(BitmapInfo^.bmiHeader)); // ×èòàåì çàãîëîâîê áèòìàïà
with BitmapInfo^.bmiHeader do
begin
if biBitCount > 16 then
iRgbTable := 0
else
if (biBitCount < 16) then
iRgbTable := (1 shl biBitCount)*sizeof(RGBQUAD)
else
Assert(false); // Ñ òàêèìè õèòðûìè èêîíêàìè íå ðàáîòàåì
end;
BitmapInfo := ReallocMemory(BitmapInfo,sizeof(BITMAPINFOHEADER)+iRgbTable);
if iRgbTable <> 0 then
Stream.ReadBuffer(BitmapInfo^.bmiColors,iRgbTable);
with BitmapInfo^.bmiHeader do
begin
ImageLineWidth := BytesPerScanline(biWidth,biBitCount,32); // Ïî íåìó îïðåäåëÿåì ðàçìåð ëèíèè
Assert((biWidth*biBitCount+31) div 32*4 = ImageLineWidth);
Size := (biHeight div 2)*ImageLineWidth; // È ðàçìåð âñåãî áèòìàïà
SetLength(ImageBits,Size); // Áèòû èçîáðàæåíèÿ
Stream.ReadBuffer(ImageBits[0],Size); // ×èòàåì
MaskLineWidth := BytesPerScanline(biWidth,1,32);
Size := (biHeight div 2)*MaskLineWidth; // Ðàçìåð ìàñêè (1-áèòíîé)
Assert((biWidth+31) div 32*4*(biHeight div 2) = Size);
end;
SetLength(MaskBits,Size);
Stream.ReadBuffer(MaskBits[0],Size); // ×èòàåì
end;
end;
end;
function InternalGetDIB(Bitmap:HBITMAP;out iRgbTable:integer;out BitmapInfo:PBitmapInfo;var Bits:TBits): Boolean;
var
DC: HDC;
DS: TDIBSection;
Bytes: Integer;
begin
iRgbTable := 0;
getMem(BitmapInfo,SizeOf(TBitmapInfo.bmiHeader));
try
FillChar(BitmapInfo^.bmiHeader,sizeof(TBitmapInfo.bmiHeader),0);
with BitmapInfo^ do
begin
DS.dsbmih.biSize := 0;
Bytes := GetObject(Bitmap,SizeOf(DS),@DS);
Assert(Bytes<>0);
if (Bytes>=(sizeof(DS.dsbm)+sizeof(DS.dsbmih))) and
(DS.dsbmih.biSize>=DWORD(sizeof(DS.dsbmih))) then
bmiHeader := DS.dsbmih
else
begin
bmiHeader.biSize := SizeOf(bmiHeader);
bmiHeader.biWidth := DS.dsbm.bmWidth;
bmiHeader.biHeight := DS.dsbm.bmHeight;
bmiHeader.biBitCount := DS.dsbm.bmBitsPixel;
bmiHeader.biPlanes := DS.dsbm.bmPlanes;
end;
if bmiHeader.biClrImportant > bmiHeader.biClrUsed then
bmiHeader.biClrImportant := bmiHeader.biClrUsed;
if bmiHeader.biSizeImage = 0 then
bmiHeader.biSizeImage := BytesPerScanLine(bmiHeader.biWidth,bmiHeader.biBitCount,32)*Abs(bmiHeader.biHeight);
Assert(bmiHeader.biCompression=0);
if bmiHeader.biBitCount > 16 then
iRgbTable := 0
else if bmiHeader.biClrUsed = 0 then
iRgbTable := SizeOf(TRGBQuad)*(1 shl bmiHeader.biBitCount)
else
iRgbTable := SizeOf(TRGBQuad)*bmiHeader.biClrUsed;
end;
if iRgbTable > 0 then
BitmapInfo := ReallocMemory(BitmapInfo,SizeOf(TBitmapInfoHeader)+iRgbTable);
setLength(Bits,BitmapInfo^.bmiHeader.biSizeImage);
DC := CreateCompatibleDC(0);
try
Result := GetDIBits(DC,Bitmap,0,BitmapInfo^.bmiHeader.biHeight,@Bits[0],BitmapInfo^,DIB_RGB_COLORS)<>0;
finally
DeleteDC(DC);
end;
except
freeMem(BitmapInfo);
BitmapInfo := nil;
raise;
end;
end;
procedure TIcoFile.loadFromHandle(h:hicon);
var
IconInfo: TIconInfo;
Size: Cardinal;
i: integer;
begin
if not GetIconInfo(h, IconInfo) then
Exit;
try
try
setLength(FIcons,length(FIcons)+1);
with FIcons[high(FIcons)] do
begin
InternalGetDIB(IconInfo.hbmColor,iRgbTable,BitmapInfo,ImageBits);
InternalGetDIB(IconInfo.hbmMask,i,MaskBitmapInfo,MaskBits);
// MaskBitmapInfo ìîæåò ïîíàäîáèòüñÿ òîëüêî äëÿ îòðèñîâêè, äëÿ ñîõðàíåíèÿ â ôàéë îíà íå íóæíà}
with Info do
begin
Colors := 0;
Width := BitmapInfo^.bmiHeader.biWidth;
Height := BitmapInfo^.bmiHeader.biHeight;
Reserved1 := MaskBitmapInfo^.bmiHeader.biBitCount;
Reserved2 := BitmapInfo^.bmiHeader.biBitCount;
DIBSize := MaskBitmapInfo^.bmiHeader.biSizeImage+DWORD(iRgbTable)+BitmapInfo^.bmiHeader.biSize+BitmapInfo^.bmiHeader.biSizeImage;
DIBOffset := -1; // Íàäî ïðîñòàâèòü ïðè ñîõðàíåíèè.
end;
with BitmapInfo^.bmiHeader do
begin
ImageLineWidth := BytesPerScanline(biWidth,biBitCount,32); // Ïî íåìó îïðåäåëÿåì ðàçìåð ëèíèè
Assert((biWidth*biBitCount+31) div 32*4 = ImageLineWidth);
Size := biHeight*ImageLineWidth; // È äîëæåí ïîëó÷èòüñÿ ðàçìåð âñåãî áèòìàïà
Assert(Size=biSizeImage);
biHeight := biHeight*2; // Òàê äîëæíî áûòü ÿêîáû èç-çà íàëè÷èÿ ìàñêè
end;
with MaskBitmapInfo^.bmiHeader do
begin
MaskLineWidth := BytesPerScanline(biWidth,biBitCount,32);
Assert((biWidth+31) div 32*4 = MaskLineWidth); // Ïðîâåðêè
Size := biHeight*MaskLineWidth; // Ðàçìåð ìàñêè (1-áèòíîé)
Assert(Size=biSizeImage);
end;
end;
except
setLength(FIcons,length(FIcons)-1);
end;
finally
DeleteObject(IconInfo.hbmColor);
DeleteObject(IconInfo.hbmMask);
end;
end;
procedure TIcoFile.saveTrueColorFrom32(icoNo:integer;out IconData:TIconData);
var
useAlpha: boolean;
Bitmap1,Bitmap2: Graphics.TBitmap;
Size: integer;
procedure setNewBitmap(h:HBITMAP);
begin
with IconData do
begin
if BitmapInfo <> nil then
begin
freeMem(BitmapInfo);
BitmapInfo := nil;
end;
InternalGetDIB(h,iRgbTable,BitmapInfo,ImageBits);
Assert(BitmapInfo <> nil);
with Info do
begin
Colors := 0;
Width := BitmapInfo^.bmiHeader.biWidth;
Height := BitmapInfo^.bmiHeader.biHeight;
Reserved1 := MaskBitmapInfo^.bmiHeader.biBitCount;
Reserved2 := BitmapInfo^.bmiHeader.biBitCount;
DIBSize := MaskBitmapInfo^.bmiHeader.biSizeImage+DWORD(iRgbTable)+BitmapInfo^.bmiHeader.biSize+BitmapInfo^.bmiHeader.biSizeImage;
DIBOffset := -1; // Íàäî ïðîñòàâèòü ïðè ñîõðàíåíèè.
end;
with BitmapInfo^.bmiHeader do
begin
ImageLineWidth := BytesPerScanline(biWidth,biBitCount,32); // Ïî íåìó îïðåäåëÿåì ðàçìåð ëèíèè
Assert((biWidth*biBitCount+31) div 32*4 = ImageLineWidth);
Size := biHeight*ImageLineWidth; // Ïðîâåðÿåì ðàçìåð âñåãî áèòìàïà
Assert(Size=biSizeImage);
biHeight := biHeight*2;
end;
end;
end;
begin
useAlpha := FIcons[icoNo].BitmapInfo.bmiHeader.biBitCount=32;
if useAlpha then
useAlpha := IsValidAlpha(icoNo);
try
IconData := FIcons[high(FIcons)];
Bitmap1 := Graphics.TBitmap.Create;
Bitmap2 := Graphics.TBitmap.Create;
try
with IconData do
begin
MaskBits := copy(FIcons[high(FIcons)].MaskBits);
getMem(MaskBitmapInfo,sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*2);
move(FIcons[high(FIcons)].MaskBitmapInfo^,MaskBitmapInfo^,sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*2);
with MaskBitmapInfo^.bmiHeader do
begin
Assert(MaskLineWidth=BytesPerScanline(biWidth,biBitCount,32));
MaskLineWidth := BytesPerScanline(biWidth,biBitCount,32);
Assert((biWidth+31) div 32*4 = MaskLineWidth);
Size := biHeight*MaskLineWidth;
Assert(Size=biSizeImage);
end;
BitmapInfo := nil; // Èáî çäåñü áûëà êîïèÿ àäðåñà, à íå àäðåñ êîïèè
with FIcons[high(FIcons)] do
begin
Bitmap2.Width := Info.Width;
Bitmap2.Height := Info.Height;
Bitmap2.PixelFormat := pf24bit;
if useAlpha then
begin
Bitmap1.Width := Info.Width;
Bitmap1.Height := Info.Height;
Bitmap1.PixelFormat := pf24bit;
Bitmap1.Canvas.Brush.Color := clWhite;
Bitmap1.Canvas.FillRect(Classes.Rect(0,0,Bitmap1.Width,Bitmap1.Height));
// Òåïåðü â Bitmap1 ÷¸ðíûé ôîí ïî ôîðìå ìàñêè
setNewBitmap(Bitmap1.Handle);
Bitmap2.Canvas.Brush.Color := clWhite;
Bitmap2.Canvas.FillRect(Classes.Rect(0,0,Bitmap2.Width,Bitmap2.Height));
draw(IconData,0,0,Bitmap2.Canvas.Handle,true,true,false);
// Òåïåðü âî âòîðîì áèòìàïå - áåëûé ôîí ïî ôîðìå ìàñêè
draw(IcoNo,0,0,Bitmap2.Canvas.Handle,true,true,useAlpha);
end
else
begin
// Åñëè íåò àëüôàêàíàëà, òî ïðîñòî âûâîäèì íà ÷¸ðíîì ôîíå
Bitmap2.Canvas.Brush.Color := clBlack;
Bitmap2.Canvas.FillRect(Classes.Rect(0,0,Bitmap2.Width,Bitmap2.Height));
draw(IcoNo,0,0,Bitmap2.Canvas.Handle,true,true,useAlpha);
end;
setNewBitmap(Bitmap2.Handle);
end;
end;
finally
Bitmap1.Free;
Bitmap2.Free;
end;
except
setLength(FIcons,length(FIcons)-1);
end;
end;
procedure TIcoFile.saveToStream(Stream:TStream);
var
FileHeader: TCursorOrIcon;
i: integer;
offset: integer;
begin
FileHeader.Reserved := 0;
FileHeader.wType := RC3_ICON;
FileHeader.Count := length(FIcons);
Stream.WriteBuffer(FileHeader,SizeOf(FileHeader));
offset := Stream.Position+length(FIcons)*SizeOf(TIconRec); // Áèòìàïû íà÷íóòñÿ çäåñü
if Length(FIcons) > 0 then
begin
for i:=low(FIcons) to high(FIcons) do
with FIcons[i] do
begin
Info.DIBOffset := offset;
Stream.WriteBuffer(Info,SizeOf(TIconRec));
offset := offset+SizeOf(BitmapInfo^.bmiHeader)+iRgbTable+length(ImageBits)+length(MaskBits);
end;
for i:=low(FIcons) to high(FIcons) do
with FIcons[i] do
begin
Stream.WriteBuffer(BitmapInfo^.bmiHeader,SizeOf(BitmapInfo^.bmiHeader)+iRgbTable);
Stream.WriteBuffer(ImageBits[0],length(ImageBits));
Stream.WriteBuffer(MaskBits[0],length(MaskBits));
end;
end;
end;
procedure TIcoFile.check;
var
i: integer;
begin
// Ýòî ÷òîáû óáåäèòüñÿ, ÷òî ÿ ïðàâèëüíî ïîíèìàþ, ÷òî ê ÷åìó.
// Ìîæíî òàêæå ïðèìåíÿòü, ÷òîáû ïðîâåðèòü ïðàâèëüíîñòü çàãðóçêè è âîîáùå íà âñÿêèé ñëó÷àé
// ÷òîáû îòëîâèòü ãëþêè.
// "Ñîöèàëèçì - ýòî êîíòðîëü è ó÷¸ò."
if Length(FIcons) > 0 then
for i:=low(FIcons) to high(FIcons) do
with FIcons[i] do
begin
Assert((Info.Reserved1=0) = (Info.Reserved2=0)); // Ðàâíû íóëþ òîëüêî îäíîâðåìåííî
Assert((Info.Colors<>0) or (Info.Reserved1<>0));
Assert(Info.Reserved1 in [0,1]);
with BitmapInfo^.bmiHeader do
begin
Assert(biSize=sizeOf(BitmapInfo^.bmiHeader));
Assert(Info.Width=biWidth);
Assert(Info.Height*2=biHeight);
Assert(biPlanes=1);
Assert(Info.Reserved2 in [0,biBitCount]);
Assert(biBitCount in [1,4,8,16,24,32]);
Assert(biCompression=BI_RGB{=0});
Assert(biXPelsPerMeter=0);
Assert(biYPelsPerMeter=0);
end;
end;
end;
procedure TIcoFile.draw(icoNo,x,y:integer;dest:hdc;drawMask,drawImage,drawAlpha:boolean);
begin
draw(Icons[icoNo],x,y,dest,drawMask,drawImage,drawAlpha);
end;
procedure TIcoFile.draw(IconData:TIconData;x,y:integer;dest:hdc;drawMask,drawImage,drawAlpha:boolean);
var
h,hdcColor,hdcMask: hdc;
pcolorBits: pointer;
colorBitmap,hOldC,maskBitmap,hOldM: HBITMAP;
pmaskBits: pointer;
blend: BLENDFUNCTION;
procedure needMaskBitmapInfo(var IconData:TIconData);
begin
with IconData do
begin
if MaskBitmapInfo <> nil then
exit;
// Ýòî äëÿ ñîõðàíåíèÿ â ôàéë íå íóæíî àáñîëþòíî
getMem(MaskBitmapInfo,sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*2);
FillChar(MaskBitmapInfo^,sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*2,0);
with MaskBitmapInfo^ do
begin
bmiHeader.biSize := sizeof(BITMAPINFOHEADER);
bmiHeader.biWidth := BitmapInfo^.bmiHeader.biWidth;
bmiHeader.biHeight := BitmapInfo^.bmiHeader.biHeight;
bmiHeader.biPlanes := 1;
bmiHeader.biBitCount := 1;
bmiHeader.biSizeImage := length(MaskBits);
bmiColors[0].rgbReserved := 0;
bmiColors[0].rgbRed := 0;
bmiColors[0].rgbBlue := 0;
bmiColors[0].rgbGreen := 0;
with PRGBQuadArray(@bmiColors)^[1] do
begin
rgbReserved := 0;
rgbRed := 255;
rgbBlue := 255;
rgbGreen := 255;
end;
end;
end;
end;
begin
h := GetDC(0);
pcolorBits := nil;
colorBitmap := CreateDIBSection(h,IconData.BitmapInfo,DIB_RGB_COLORS,pcolorBits,0,0);
hdcColor := CreateCompatibleDC(h);
ReleaseDC(0,h);
hOldC := SelectObject(hdcColor,colorBitmap);
with IconData do
begin
if not drawAlpha then
begin
needMaskBitmapInfo(IconData);
pmaskBits := nil;
maskBitmap := CreateDIBSection(0,MaskBitmapInfo,DIB_RGB_COLORS,pmaskBits,0,0);
hdcMask := CreateCompatibleDC(0);
hOldM := SelectObject(hdcMask,maskBitmap);
SetDIBitsToDevice(hdcMask,0,0,Info.Width,Info.Height,0,0,0,Info.Height,MaskBits,MaskBitmapInfo^,DIB_RGB_COLORS);
if drawMask then
BitBlt(dest,0,0,Info.Width,Info.Height,hdcMask,0,0,SRCAND);
end
else
begin // Ïîäàâëÿåì õèíòû êîìïèëÿòîðà
hdcMask := 0;
maskBitmap := 0;
hOldM := 0;
end;
SetDIBitsToDevice(hdcColor,0,0,Info.Width,Info.Height,0,0,0,Info.Height,ImageBits,BitmapInfo^,DIB_RGB_COLORS);
if drawImage then
if not drawAlpha then
BitBlt(dest,0,0,Info.Width,Info.Height,hdcColor,0,0,SRCINVERT)
else
begin
// Èíèöèàëèçèðóåì ñòðóêòóðó äëÿ ó÷¸òà àëüôà-êàíàëà ïèêñåëà
blend.BlendOp := AC_SRC_OVER;
blend.BlendFlags := 0;
blend.SourceConstantAlpha := 255;
blend.AlphaFormat := AC_SRC_ALPHA;
AlphaBlend(dest,0,0,Info.Width,Info.Height,hdcColor,0,0,Info.Width,Info.Height,blend);
end;
end;
//Îñâîáîæäàåì çàäåéñòâîâàííûå îáúåêòû GDI è óíè÷òîæàåì äèíàìè÷åñêèå ìàññèâû, ÷òîáû èçáåæàòü óòå÷åê ðåñóðñîâ, âûäåëÿåìûõ ñèñòåìîé íàøåìó ïðèëîæåíèþ.
SelectObject(hdcColor,hOldC);
if not drawAlpha then
begin
SelectObject(hdcMask,hOldM);
DeleteObject(hdcMask);
DeleteObject(maskBitmap);
end;
DeleteObject(hdcColor);
DeleteObject(colorBitmap);
end;
function TIcoFile.IsValidAlpha(icoNo:integer): boolean;
var
X,Y: integer;
Line32: PRGBQuadArray;
begin
with Icons[icoNo] do
begin
result := false;
if BitmapInfo.bmiHeader.biBitCount <= 24 then
exit;
Result := true;
for Y:=0 to Info.Height-1 do
begin
Line32 := @ImageBits[Y*ImageLineWidth];
for X:=0 to Info.Width-1 do // Èíîãäà shGetFileInfo âîçâðàùàåò èêîíêè ñ ïóñòûì àëüôà-êàíàëîì
if not Line32[X].rgbReserved=0 then
exit;
end;
end;
Result := false;
end;
function getIconHandleForFile(fn:string;large:boolean): hicon;
var
shfi: TShFileInfo;
flag: integer;
begin
fillChar(shfi,SizeOf(TShFileInfo),0);
if large then
flag := SHGFI_LARGEICON
else
flag := SHGFI_SMALLICON;
shGetFileInfo(pchar(fn),0,shfi,SizeOf(shfi),SHGFI_ICON or flag or SHGFI_SYSICONINDEX);
Result := shfi.hIcon;
end;
function CreateIconFromHandle(IconHandle : HIcon) : TIcon;
var
I : Integer;
IconData : TIconData;
IcoFile : TIcoFile = nil;
TempStream : TMemoryStream = nil;
ColorDepth : Integer = 32;
ActiveWindow: HWND;
DeviceContext: HDC;
begin
Result := TIcon.Create;
ActiveWindow := GetActiveWindow;
DeviceContext := GetDC(ActiveWindow);
// Get display color depth
if (DeviceContext <> 0) then
begin
ColorDepth := GetDeviceCaps(DeviceContext, BITSPIXEL);
ReleaseDC(ActiveWindow, DeviceContext);
end;
// Alpha channel can be used only with 24-32 bit color depth
// otherwise use standard method to get icon from handle
// because our method don't work in this case
if (ColorDepth < 24) then
Result.Handle:= IconHandle
else
begin
IcoFile := TIcoFile.Create(nil);
TempStream := TMemoryStream.Create;
try
IcoFile.loadFromHandle(IconHandle);
if Length(IcoFile.Icons) = 0 then
Result.Handle:= IconHandle
else
begin
for I := Low(IcoFile.Icons) to High(IcoFile.Icons) do
begin
// If icon has invalid alpha channel
// then display it as 24 bit icon
if not IcoFile.IsValidAlpha(I) then
begin
IcoFile.saveTrueColorFrom32(I, IconData);
IcoFile.DestroyIconData(IcoFile.Icons[I]);
IcoFile.Icons[I] := IconData;
end;
end;
IcoFile.saveToStream(TempStream);
TempStream.Seek(0, soBeginning);
Result.LoadFromStream(TempStream);
end;
finally
FreeAndNil(IcoFile);
FreeAndNil(TempStream);
end;
end;
end;
{
type
TChunkIHDRHack = class(TChunkIHDR);
procedure Convert(const PNG:TPNGObject;const IconData:TIconData);
var
X,Y,Y2,BitCount: Integer;
BitBuf: Byte;
Line32: PRGBQuadArray;
PNGLine: pRGBLine;
Alpha: PByteArray;
Mask: PByte;
OnlyAlpha: boolean;
begin
with IconData do
begin
PNG.Header.Width := Info.Width;
PNG.Header.Height := Info.Height;
PNG.Header.BitDepth := 8;
PNG.Header.ColorType := COLOR_RGBALPHA;
TChunkIHDRHack(PNG.Header).PrepareImageData;
BitBuf := 0;
onlyAlpha := true;
for Y:=0 to Info.Height-1 do
begin
Line32 := @ImageBits[Y*ImageLineWidth];
for X:=0 to Info.Width-1 do
if Line32[X].rgbReserved=0
then
begin
onlyAlpha := false;
break;
end;
if not onlyAlpha
then
break;
end;
for Y:=0 to Info.Height-1 do
begin
Line32 := @ImageBits[Y*ImageLineWidth];
Mask := @MaskBits[Y*MaskLineWidth];
Y2 := Info.Height-Y-1;
Alpha := PNG.AlphaScanline[Y2];
PNGLine := PNG.ScanLine[Y2];
BitCount := 0;
for X:=0 to Info.Width-1 do
begin
if BitCount=0
then
begin
BitCount := 8;
BitBuf := Mask^;
Inc(Mask);
end;
if BitBuf and $80=0
then
with PNGLine[X],Line32[X] do
begin
rgbtRed := rgbRed;
rgbtGreen := rgbGreen;
rgbtBlue := rgbBlue;
if not onlyAlpha
then
Alpha[X] := rgbReserved
else
Alpha[X] := $FF;
end
else
with PNGLine[X] do
begin
rgbtRed := 0;
rgbtGreen := 0;
rgbtBlue := 0;
Alpha[X] := 0;
end;
BitBuf := BitBuf shl 1;
Dec(BitCount);
end;
end;
end;
end;
procedure TIcoFile.ConvertToPNG(icoNo:integer;Stream:TStream);
var
PNG: TPNGObject;
begin
with Icons[icoNo] do
begin
Assert(BitmapInfo.bmiHeader.biBitCount>=24);
if IsValidAlpha(icoNo)
then
PNG := TPNGObject.CreateBlank(COLOR_RGBALPHA,8,Info.Width,Info.Height)
else
PNG := TPNGObject.CreateBlank(COLOR_RGB,8,Info.Width,Info.Height);
try
Convert(PNG,Icons[icoNo]);
PNG.CompressionLevel := 9;
PNG.SaveToStream(Stream);
finally
PNG.Free;
end;
end;
end;
procedure TIcoFile.saveAsPng(icoNo:integer;fn:string);
var
Stream: TStream;
begin
Stream := TFileStream.Create(fn,fmCreate);
try
ConvertToPNG(icoNo,Stream);
finally
Stream.Free;
end;
end;
}
procedure TIcoFile.Add(IconData:TIconData);
begin
setLength(FIcons,length(FIcons)+1);
Icons[high(FIcons)] := IconData;
end;
procedure TIcoFile.AddCopy(IconData:TIconData);
begin
setLength(FIcons,length(FIcons)+1);
Icons[high(FIcons)] := IconData;
with Icons[high(FIcons)] do
begin
ImageBits := copy(IconData.ImageBits);
MaskBits := copy(IconData.MaskBits);
getMem(BitmapInfo,sizeof(BITMAPINFOHEADER)+iRgbTable);
getMem(MaskBitmapInfo,sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*2);
move(IconData.BitmapInfo^,BitmapInfo^,sizeof(BITMAPINFOHEADER)+iRgbTable);
move(IconData.MaskBitmapInfo^,MaskBitmapInfo^,sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*2);
end;
end;
procedure TIcoFile.DestroyIconData(IconData: TIconData);
begin
with IconData do
begin
if BitmapInfo<>nil then
FreeMem(BitmapInfo);
BitmapInfo := nil;
if MaskBitmapInfo<>nil then
FreeMem(MaskBitmapInfo);
MaskBitmapInfo := nil;
end;
end;
end.

View file

@ -32,7 +32,7 @@ uses
implementation
uses
Types, Graphics, DCOSUtils, uThumbnails, uWlxModule, uGlobs;
Types, Graphics, DCOSUtils, uThumbnails, uWlxModule, uBitmap, uGlobs;
function GetThumbnail(const aFileName: String; aSize: TSize): Graphics.TBitmap;
const
@ -63,8 +63,7 @@ begin
Bitmap:= Module.CallListGetPreviewBitmap(aFileName, aSize.cx, aSize.cy, Data);
if Bitmap <> 0 then
begin
Result:= Graphics.TBitmap.Create;
Result.Handle:= Bitmap;
Result:= BitmapCreateFromHBITMAP(Bitmap);
Exit;
end;
end;

View file

@ -32,7 +32,7 @@ uses
implementation
uses
SysUtils, Forms, Graphics, Windows, ActiveX, ShlObj;
SysUtils, Forms, Graphics, Windows, ActiveX, ShlObj, uBitmap;
const
SIIGBF_RESIZETOFIT = $00000000;
@ -142,8 +142,7 @@ begin
if Succeeded(Status) then
begin
Result:= Graphics.TBitmap.Create;
Result.Handle:= Bitmap;
Result:= BitmapCreateFromHBITMAP(Bitmap);
end;
end;

View file

@ -30,7 +30,7 @@ implementation
{$IF DEFINED(MSWINDOWS)}
uses
Windows, uIcoFiles;
Windows, uBitmap;
{$ENDIF}
type
@ -97,14 +97,14 @@ const
IDI_SHIELD = PAnsiChar(32518);
var
hIcon: THandle;
AIcon: Graphics.TIcon;
AIcon: Graphics.TBitmap;
{$ENDIF}
begin
{$IF DEFINED(MSWINDOWS)}
hIcon:= LoadImage(0, IDI_SHIELD, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE or LR_SHARED);
if (hIcon <> 0) then
begin
AIcon:= CreateIconFromHandle(hIcon);
AIcon:= BitmapCreateFromHICON(hIcon);
imgShield.Picture.Assign(AIcon);
AIcon.Free;
end;