Vista पर और कई नए कार्यों को जोड़ा गया जो इस कार्य को तुच्छ बनाते हैं। यह समारोह यहां सबसे उपयुक्त है LoadIconWithScaleDown
है।
यह फ़ंक्शन पहले आइकन के लिए आइकन फ़ाइल को बिल्कुल उसी आकार के लिए खोजेगा। यदि कोई मिलान नहीं मिलता है, तब तक जब तक दोनों सीएक्स और साइ मानक आइकन आकार -16, 32, 48, या 256 पिक्सेल से मेल नहीं खाते हैं- अगला सबसे बड़ा आइकन चुना जाता है और फिर वांछित आकार में स्केल किया जाता है। उदाहरण के लिए, यदि कॉलिग एप्लिकेशन द्वारा 40 पिक्सेल के एक्स आयाम वाले आइकन का अनुरोध किया गया है, तो 48-पिक्सेल आइकन का उपयोग किया जाता है और 40 पिक्सेल तक स्केल किया जाता है। इसके विपरीत, लोडइमेज फ़ंक्शन 32-पिक्सेल आइकन का चयन करता है और इसे 40 पिक्सेल तक स्केल करता है।
यदि फ़ंक्शन एक बड़े आइकन का पता लगाने में असमर्थ है, तो यह अगले छोटे आइकन को ढूंढने और वांछित आकार तक स्केल करने के मानक व्यवहार के लिए डिफ़ॉल्ट रूप से डिफ़ॉल्ट होता है।
मेरे अनुभव में यह कार्य स्केलिंग का उत्कृष्ट काम करता है और परिणाम एलियासिंग का कोई संकेत नहीं दिखाते हैं।
विंडोज के पुराने संस्करणों के लिए, मेरे ज्ञान के सबसे अच्छे से, कोई भी कार्य नहीं है जो इस कार्य को पर्याप्त रूप से कर सकता है। LoadImage
से प्राप्त परिणाम बहुत खराब गुणवत्ता वाले हैं।
- संसाधन में उपलब्ध छवियों की जांच सबसे बड़े आकार कि वांछित आइकन आकार की तुलना में कम है के साथ छवि को खोजने के लिए: इसके बजाय सबसे अच्छा तरीका मैं पाया है इस प्रकार है।
- वांछित आकार का एक नया आइकन बनाएं और इसे पूरी तरह पारदर्शी होने के लिए प्रारंभ करें।
- नए (बड़े) आइकन के केंद्र में संसाधन से छोटे आइकन को रखें।
इसका मतलब है कि आइकन के चारों ओर एक छोटी पारदर्शी सीमा होगी, लेकिन आम तौर पर यह महत्वहीन होने के लिए काफी छोटा है। आदर्श विकल्प कोड का उपयोग करना होगा जो LoadIconWithScaleDown
के अनुसार स्केल कर सकता है, लेकिन यह लिखना गैर-तुच्छ है।
तो, बिना किसी विज्ञापन के कोड मैं उपयोग करता हूं।
unit uLoadIconResource;
interface
uses
SysUtils, Math, Classes, Windows, Graphics, CommCtrl;
function LoadIconResourceSize(const ResourceName: string; IconSize: Integer): HICON;//will not throw an exception
function LoadIconResourceMetric(const ResourceName: string; IconMetric: Integer): HICON;
implementation
function IconSizeFromMetric(IconMetric: Integer): Integer;
begin
case IconMetric of
ICON_SMALL:
Result := GetSystemMetrics(SM_CXSMICON);
ICON_BIG:
Result := GetSystemMetrics(SM_CXICON);
else
raise EAssertionFailed.Create('Invalid IconMetric');
end;
end;
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;
function CreateIconFromSmallerIcon(IconSize: Integer; SmallerIcon: HICON): HICON;
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;
function LoadIconResourceSize(const ResourceName: string; IconSize: Integer): HICON;//will not throw an exception
function LoadImage(IconSize: Integer): HICON;
begin
Result := Windows.LoadImage(HInstance, PChar(ResourceName), IMAGE_ICON, IconSize, IconSize, LR_DEFAULTCOLOR);
end;
type
TGrpIconDir = packed record
idReserved: Word;
idType: Word;
idCount: Word;
end;
TGrpIconDirEntry = packed record
bWidth: Byte;
bHeight: Byte;
bColorCount: Byte;
bReserved: Byte;
wPlanes: Word;
wBitCount: Word;
dwBytesInRes: DWORD;
wID: WORD;
end;
var
i, BestAvailableIconSize, ThisSize: Integer;
ResourceNameWide: WideString;
Stream: TResourceStream;
IconDir: TGrpIconDir;
IconDirEntry: TGrpIconDirEntry;
begin
//LoadIconWithScaleDown does high quality scaling and so we simply use it if it's available
ResourceNameWide := ResourceName;
if Succeeded(LoadIconWithScaleDown(HInstance, PWideChar(ResourceNameWide), IconSize, IconSize, Result)) then begin
exit;
end;
//XP: find the closest sized smaller icon and draw without stretching onto the centre of a canvas of the right size
Try
Stream := TResourceStream.Create(HInstance, ResourceName, RT_GROUP_ICON);
Try
Stream.Read(IconDir, SizeOf(IconDir));
Assert(IconDir.idCount>0);
BestAvailableIconSize := high(BestAvailableIconSize);
for i := 0 to IconDir.idCount-1 do begin
Stream.Read(IconDirEntry, SizeOf(IconDirEntry));
Assert(IconDirEntry.bWidth=IconDirEntry.bHeight);
ThisSize := IconDirEntry.bHeight;
if ThisSize=0 then begin//indicates a 256px icon
continue;
end;
if ThisSize=IconSize then begin
//a perfect match, no need to continue
Result := LoadImage(IconSize);
exit;
end else if ThisSize<IconSize then begin
//we're looking for the closest sized smaller icon
if BestAvailableIconSize<IconSize then begin
//we've already found one smaller
BestAvailableIconSize := Max(ThisSize, BestAvailableIconSize);
end else begin
//this is the first one that is smaller
BestAvailableIconSize := ThisSize;
end;
end;
end;
if BestAvailableIconSize<IconSize then begin
Result := CreateIconFromSmallerIcon(IconSize, LoadImage(BestAvailableIconSize));
if Result<>0 then begin
exit;
end;
end;
Finally
FreeAndNil(Stream);
End;
Except
;//swallow because this routine is contracted not to throw exceptions
End;
//final fallback: make do without
Result := 0;
end;
function LoadIconResourceMetric(const ResourceName: string; IconMetric: Integer): HICON;
begin
Result := LoadIconResourceSize(ResourceName, IconSizeFromMetric(IconMetric));
end;
end.
इन फ़ंक्शंस का उपयोग करना काफी स्पष्ट है। वे मानते हैं कि संसाधन कोड के समान मॉड्यूल में स्थित है। अगर आपको सामान्यता के उस स्तर के लिए समर्थन की आवश्यकता होती है तो कोड को आसानी से HMODULE
प्राप्त करने के लिए सामान्यीकृत किया जा सकता है।
कॉल LoadIconResourceMetric
यदि आप सिस्टम के छोटे आकार या सिस्टम बड़े आइकन के बराबर आकार के आइकन लोड करना चाहते हैं तो कॉल करें।IconMetric
पैरामीटर या तो ICON_SMALL
या ICON_BIG
होना चाहिए। टूलबार, मेनू और अधिसूचना आइकन के लिए, ICON_SMALL
का उपयोग किया जाना चाहिए।
यदि आप पूर्ण शब्दों में आइकन आकार निर्दिष्ट करना चाहते हैं तो LoadIconResourceSize
का उपयोग करें।
ये फ़ंक्शन HICON
लौटाते हैं। आप निश्चित रूप से TIcon
इंस्टेंस की संपत्ति को असाइन कर सकते हैं। अधिक संभावना है कि आप एक छवि सूची में जोड़ना चाहते हैं। ऐसा करने का सबसे आसान तरीका ImageList_AddIcon
TImageList
उदाहरण के Handle
को पार करना है।
नोट 1: डेल्फी के पुराने संस्करणों में LoadIconWithScaleDown
CommCtrl
में परिभाषित नहीं है। ऐसे डेल्फी संस्करणों के लिए आपको इसे लोड करने के लिए GetProcAddress
पर कॉल करने की आवश्यकता है। ध्यान दें कि यह एक यूनिकोड केवल एपीआई है और इसलिए आपको इसे संसाधन नाम के लिए PWideChar
भेजना होगा। इस तरह: LoadIconWithScaleDown(..., PWideChar(WideString(ResourceName)),...)
।
नोट 2:LoadIconWithScaleDown
की परिभाषा त्रुटिपूर्ण है। यदि आप सामान्य नियंत्रण पुस्तकालय शुरू करने के बाद इसे कॉल करते हैं तो आपको कोई समस्या नहीं होगी। हालांकि, अगर आप अपनी प्रक्रिया के जीवन में जल्दी ही कार्य को कॉल करते हैं तो LoadIconWithScaleDown
विफल हो सकता है। मैंने इस समस्या की रिपोर्ट करने के लिए अभी QC#101000 सबमिट कर दिया है। दोबारा, यदि आप इससे पीड़ित हैं तो आपको GetProcAddress
स्वयं को कॉल करना होगा।
यदि किसी ने इसे याद किया है, तो यह प्रश्न + उत्तर अनुरोध द्वारा किया गया था। –