问题描述
我有ImageList大小为72x72,由SHGetFileInfo获取的图标(HICON)处理(例如大小为32x32的大图标)。如何添加到这个ImageList保持透明度,但没有拉伸?现在我在一个临时位图所需大小的中间绘制图标,然后将其添加到ImageList。 SHGetFileInfo(PChar Path + sr.Name),sr.FindData.dwFileAttributes,fi,SizeOf(fi),SHGFI_ICON或SHGFI_LARGEICON或SHGFI_USEFILEATTRIBUTES);
Bmp:= TBitmap.Create;
Bmp.PixelFormat:= pf32bit;
Bmp.SetSize(72,72);
DrawIcon(Bmp.Canvas.Handle,20,20,fi.hIcon);
iIcon:= ImageList_AddMasked(ilThumbs.Handle,Bmp.Handle,0);
Bmp.Free;
但我认为一种更快的方式(没有绘制临时位图)。 ImageList中的图像也会失去透明度,当我在ListView item.ImageIndex的ImageList中设置索引时,它看起来不漂亮(当选择此项目时,白色背景存在)。有没有办法解决这个问题?
谢谢。
这是我用来执行此任务的代码。
请注意,我假设原始图标使用32位颜色和Alpha通道。在使用此代码的设置中,这是合理的,但我无法确定您是否合理。
使用
Windows,Graphics;
函数CreateIconFromSmallerIcon(IconSize:Integer; SmallerIcon:HICON):HICON;
程序GetDIBheaderAndBits(bmp:HBITMAP; out bih:BITMAPINFOHEADER; out bits:Pointer);
var
pbih:^ BITMAPINFOHEADER;
bihSize,bitsSize:DWORD;
begin
位:= nil;
GetDIBSizes(bmp,bihSize,bitsSize);
pbih:= AllocMem(bihSize);
尝试
位:= AllocMem(bitsSize);
GetDIB(bmp,0,pbih ^,bits ^);
如果pbih.biSize< SizeOf(bih)然后开始
FreeMem(bits);
位:= nil;
退出;
结束
bih:= pbih ^;
最后
FreeMem(pbih);
结束;
结束
procedure InitializeBitmapInfoHeader(var bih:BITMAPINFOHEADER);
begin
bih.biSize:= SizeOf(BITMAPINFOHEADER);
bih.biWidth:= IconSize;
bih.biHeight:= 2 * IconSize; // xor位图的高度加上位图
bih.biPlanes:= 1;
bih.biBitCount:= 32;
bih.biCompression:= BI_RGB;
结束
程序CreateXORbitmap(const sbih,dbih:BITMAPINFOHEADER; sptr,dptr:PDWORD);
var
line,xOffset,yOffset:Integer;
begin
xOffset:=(IconSize-sbih.biWidth)div 2;
yOffset:=(IconSize-sbih.biHeight)div 2;
inc(dptr,xOffset + IconSize * yOffset);
for line:= 0 to sbih.biHeight-1 do begin
Move(sptr ^,dptr ^,sbih.biWidth * SizeOf(DWORD));
inc(dptr,IconSize); //依赖于RGBA扫描线不需要填充的事实
inc(sptr,sbih.biWidth); //同样
end;
结束
var
SmallerIconInfo:TIconInfo;
sBits,xorBits:PDWORD;
xorScanSize,andScanSize:Integer;
xorBitsSize,andBitsSize:Integer;
sbih:BITMAPINFOHEADER;
dbih:^ BITMAPINFOHEADER;
resbitsSize:DWORD;
resbits:指针;
begin
结果:= 0;
尝试
如果不是GetIconInfo(SmallerIcon,SmallerIconInfo)然后开始
exit;
结束
尝试
GetDIBheaderAndBits(SmallerIconInfo.hbmColor,sbih,Pointer(sBits));
如果分配(sBits)然后开始
尝试
if(sbih.biWidth> IconSize)或(sbih.biHeight> IconSize)或(sbih.biPlanes 1)或(sbih。 biBitCount 32)然后开始
exit;
结束
xorScanSize:= BytesPerScanline(IconSize,32,32);
Assert(xorScanSize = SizeOf(DWORD)* IconSize);
andScanSize:= BytesPerScanline(IconSize,1,32);
xorBitsSize:= IconSize * xorScanSize;
和BitsSize:= IconSize * andScanSize;
resbitsSize:= SizeOf(BITMAPINFOHEADER)+ xorBitsSize + andBitsSize;
resbits:= AllocMem(resbitsSize); // AllocMem将内存置零
尝试
dbih:= resbits;
InitialiseBitmapInfoHeader(dbih ^);
xorBits:= resbits;
inc(PByte(xorBits),SizeOf(BITMAPINFOHEADER));
CreateXORbitmap(sbih,dbih ^,sBits,xorBits);结果:= CreateIconFromResourceEx(resbits,resbitsSize,True,$ 00030000,IconSize,IconSize,LR_DEFAULTCOLOR);
//使用RGBA
时不需要填写掩码位图
最后
FreeMem(resbits);
结束;
最后
FreeMem(sBits);
结束;
结束
最后
如果SmallerIconInfo.hbmMask<> 0然后开始
DeleteObject(SmallerIconInfo.hbmMask);
结束
如果SmallerIconInfo.hbmColor<> 0则开始
DeleteObject(SmallerIconInfo.hbmColor);
结束
结束;
最后
DestroyIcon(SmallerIcon);
结束;
结束
I have ImageList sized 72x72, handle to the icon (HICON), obtained by SHGetFileInfo (for example a large icon sized 32x32). How to add it to this ImageList keeping transparency, but without stretching? Now I draw the icon in the middle of a temporary bitmap desired size, then add it to the ImageList.
SHGetFileInfo(PChar(Path + sr.Name), sr.FindData.dwFileAttributes, fi, SizeOf(fi), SHGFI_ICON or SHGFI_LARGEICON or SHGFI_USEFILEATTRIBUTES);
Bmp:=TBitmap.Create;
Bmp.PixelFormat:=pf32bit;
Bmp.SetSize(72, 72);
DrawIcon(Bmp.Canvas.Handle, 20, 20, fi.hIcon);
iIcon:=ImageList_AddMasked(ilThumbs.Handle, Bmp.Handle, 0);
Bmp.Free;
But I think a way faster exists (without drawing on temporary bitmap). Also image in ImageList loses transparency and when I set index of this Image in ImageList for ListView item.ImageIndex it looks not pretty (when this item is selected, white background around is present). Is any way to solve this problem?
Thanks.
This is the code that I use to perform this task.
Note that I am assuming that the original icon uses 32 bit colour, with alpha channel. That's reasonable in the settings that I use this code, but I can't be sure whether or not it's reasonable for you.
uses
Windows, Graphics;
function CreateIconFromSmallerIcon(IconSize: Integer; SmallerIcon: HICON): HICON;
procedure GetDIBheaderAndBits(bmp: HBITMAP; out bih: BITMAPINFOHEADER; out bits: Pointer);
var
pbih: ^BITMAPINFOHEADER;
bihSize, bitsSize: DWORD;
begin
bits := nil;
GetDIBSizes(bmp, bihSize, bitsSize);
pbih := AllocMem(bihSize);
Try
bits := AllocMem(bitsSize);
GetDIB(bmp, 0, pbih^, bits^);
if pbih.biSize<SizeOf(bih) then begin
FreeMem(bits);
bits := nil;
exit;
end;
bih := pbih^;
Finally
FreeMem(pbih);
End;
end;
procedure InitialiseBitmapInfoHeader(var bih: BITMAPINFOHEADER);
begin
bih.biSize := SizeOf(BITMAPINFOHEADER);
bih.biWidth := IconSize;
bih.biHeight := 2*IconSize;//height of xor bitmap plus height of and bitmap
bih.biPlanes := 1;
bih.biBitCount := 32;
bih.biCompression := BI_RGB;
end;
procedure CreateXORbitmap(const sbih, dbih: BITMAPINFOHEADER; sptr, dptr: PDWORD);
var
line, xOffset, yOffset: Integer;
begin
xOffset := (IconSize-sbih.biWidth) div 2;
yOffset := (IconSize-sbih.biHeight) div 2;
inc(dptr, xOffset + IconSize*yOffset);
for line := 0 to sbih.biHeight-1 do begin
Move(sptr^, dptr^, sbih.biWidth*SizeOf(DWORD));
inc(dptr, IconSize);//relies on the fact that no padding is needed for RGBA scanlines
inc(sptr, sbih.biWidth);//likewise
end;
end;
var
SmallerIconInfo: TIconInfo;
sBits, xorBits: PDWORD;
xorScanSize, andScanSize: Integer;
xorBitsSize, andBitsSize: Integer;
sbih: BITMAPINFOHEADER;
dbih: ^BITMAPINFOHEADER;
resbitsSize: DWORD;
resbits: Pointer;
begin
Result := 0;
Try
if not GetIconInfo(SmallerIcon, SmallerIconInfo) then begin
exit;
end;
Try
GetDIBheaderAndBits(SmallerIconInfo.hbmColor, sbih, Pointer(sBits));
if Assigned(sBits) then begin
Try
if (sbih.biWidth>IconSize) or (sbih.biHeight>IconSize) or (sbih.biPlanes<>1) or (sbih.biBitCount<>32) then begin
exit;
end;
xorScanSize := BytesPerScanline(IconSize, 32, 32);
Assert(xorScanSize=SizeOf(DWORD)*IconSize);
andScanSize := BytesPerScanline(IconSize, 1, 32);
xorBitsSize := IconSize*xorScanSize;
andBitsSize := IconSize*andScanSize;
resbitsSize := SizeOf(BITMAPINFOHEADER) + xorBitsSize + andBitsSize;
resbits := AllocMem(resbitsSize);//AllocMem zeroises the memory
Try
dbih := resbits;
InitialiseBitmapInfoHeader(dbih^);
xorBits := resbits;
inc(PByte(xorBits), SizeOf(BITMAPINFOHEADER));
CreateXORbitmap(sbih, dbih^, sBits, xorBits);
//don't need to fill in the mask bitmap when using RGBA
Result := CreateIconFromResourceEx(resbits, resbitsSize, True, $00030000, IconSize, IconSize, LR_DEFAULTCOLOR);
Finally
FreeMem(resbits);
End;
Finally
FreeMem(sBits);
End;
end;
Finally
if SmallerIconInfo.hbmMask<>0 then begin
DeleteObject(SmallerIconInfo.hbmMask);
end;
if SmallerIconInfo.hbmColor<>0 then begin
DeleteObject(SmallerIconInfo.hbmColor);
end;
End;
Finally
DestroyIcon(SmallerIcon);
End;
end;
这篇关于如何添加一个图标到ImageList更大的大小没有拉伸?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!