Mam plik pojedynczej ikony o rozmiarach 128x128 pikseli w pliku. Jak ten rozmiar odczytać przy pomocy Delphi ? Chodzi mi o to, aby program przed jej wczytaniem do TImage nie akceptował innych rozmiarów oraz multiikon.
Nie wiem czy Delphi którego używasz (a którego używasz?) posiada jakiekolwiek wysokopoziomowe API do zarządzania ikonami i ich zawartością (grafikami). Jeśli takowego nie posiada i w sieci nie znajdziesz jakiejś ciekawej biblioteki, to sam system posiada zestaw funkcji służących do tego celu. Dzięki nim możesz określić liczbę grafik w pliku .ico
, ich rozmiary czy pobrać uchwyt. W Twoim przypadku wystarczy sprawdzić czy plik zawiera jedną grafikę o konkretnych rozmiarach, więc to co system oferuje powinno wystarczyć.
Pytanie zasadnicze – dlaczego akurat ikony?
Dla potrzeb tej aplikacji używam starej Delphi 6 na Windows 10, dzięki czemu uzyskuję mały plik wynikowy, co w tym przypadku jest bardzo ważne. Użycie Delphi 10.1, którą również mam odpada. Stosowanie metody opisanej przez Ciebie jest mi znane, ale z powodów podanych wcześniej też odpada. Liczyłem, że załatwię temat jakąś prostą funkcją typu GetImageSize. Jak widzę nie będzie łatwo...
Panie czego ty tu nie wiesz.
Masz nagłówek header i tam jeśli na dwu bajcie wystąpi 1, to masz ico jeśli 2 to cur.
od 6 bajtu masz szerokość w jednym bajcie podaną, a na 7 bajcie wysokość w jednym bajcie.
Na 12 bajcie jest offset do obrazu, w 4 bajtach zapisany.
W jednym takim pliku może być kilka ikon np. w różnej rozdzielczość i header nagłówek jest jeden a iconimage structure może być jeden lub więcej.
grino napisał(a):
Dla potrzeb tej aplikacji używam starej Delphi 6 na Windows 10, dzięki czemu uzyskuję mały plik wynikowy, co w tym przypadku jest bardzo ważne.
Mały rozmiar? Malware piszesz, że tak Ci na tym zależy?
Stosowanie metody opisanej przez Ciebie jest mi znane, ale z powodów podanych wcześniej też odpada.
Dlaczego odpada? Kiedy nie było krowiastych bibliotek w stylu VCL, programiści mieli do dyspozycji praktycznie wyłącznie systemowe funkcje i z ich wykorzystaniem pisali kod. Dzięki temu pliki wykonywalne ważyły nierzadko kilkadziesiąt kilobajtów, zamiast kilku megabajtów.
Liczyłem, że załatwię temat jakąś prostą funkcją typu GetImageSize. Jak widzę nie będzie łatwo...
https://msdn.microsoft.com/en-us/library/ms997538.aspx – jest tam przykład odczytu danych nagłówka i pętli iterującej po wszystkich obrazkach, na kilkanaście linijek kodu C. Wymagane typy danych znajdziesz w module Windows
.
Dzięki Panowie. Poradziłem sobie taką prostą funkcją:
function GetIconSize(Icon: TIcon; var X, Y: integer): boolean;
var
h: THandle;
IconInfo: TIconInfo;
bmpmask: TBitmap;
begin
result := Icon.Handle <> 0;
if result then
begin
bmpmask := TBitmap.Create;
try
IconInfo.fIcon := true;
try
GetIconInfo(Icon.Handle, IconInfo);
bmpmask.Handle := IconInfo.hbmMask;
bmpmask.Dormant;
finally
DeleteObject(IconInfo.hbmMask);
DeleteObject(IconInfo.hbmColor)
end;
X := bmpmask.Width;
Y := bmpmask.Height;
finally
bmpmask.Free;
end;
end;
end;
Spełnia i to doskonale. Chodziło przecież o to, by odrzucić wszystko, co nie ma rozmiarów 128x128 pix. Inne rozmiary oraz multiikony nie spełniają tego warunku (x< >128 and y< >128) i wystarczy. To naprawdę działa ! :)
W jaki sposób ten kod odrzuca multiikony? Przecież jedyne co on robi to odczytuje pośrednio te same dane, które zwracają właściwości Width
i Height
.
Sprawdź co zwróci Twój kod dla ikony z załącznika – system pokazuje, że ikona posiada rozmiary 128x128 pikseli.
Ha, tu wywala, że "Parametr jest nieprawidłowy". ale przecież to "Delfinek" 6 i on nie obsługuje ikon powyżej 128 px (resource). Obsługa tego błędu załatwia sprawę. W pozostałych przypadkach multiikon zawsze dostaję 32X32 px. Mnie interesuje, że jeśli 128X128 px to OK, wszystkie inne nie spełniają wymagań i odpadają.
Z tego co pamiętam, właściwości TIcon.Width
i TIcon.Height
zwracają rozmiar najmniejszego obrazu, więc cała Twoja funkcja staje się zbędna. No i pozostaje też jeszcze jeden przypadek – jeśli ikona zawiera np. dwa obrazy o wymaganym rozmiarze (tak, jest to możliwe). Wtedy Twój sposób też ”łyknie” taką ikonkę.
Dlatego sugerowałem skorzystanie z funkcji WinAPI, aby jasno określić ile jest obrazów w danej ikonie i jesli jest jeden, pobrać jego rozmiar już w dowolny sposób.
Jeżeli mamy dwie ikonki o tym samym rozmiarze, ale np. True Color i XP (RGB + alpha), bo o tym zapewne piszesz, to mój TImage też to łyknie i nie ma sprawy. Z drugiej strony masz rację, wystarczyło skorzystać TIcon.Width i TIcon.Height. Człowiek uczy się całe życie i zapewne wiesz jaki umiera.
grino napisał(a):
Jeżeli mamy dwie ikonki o tym samym rozmiarze, ale np. True Color i XP (RGB + alpha), bo o tym zapewne piszesz […]
W jednej ikonie może być kilka obrazów o takim samym rozmiarze i takiej samej głębi, ale o różnej zawartości. Oczywiście nikt takich ikon nie robi celowo, bo nie ma to sensu, jednak dobrze by było, gdyby Twój program prawidłowo reagował na każdą ikonkę.
Z drugiej strony masz rację, wystarczyło skorzystać TIcon.Width i TIcon.Height.
Jeśli klasa TIcon
z Delphi 6 faktycznie zawsze zwraca rozmiar najmniejszego obrazu, to w zupełności wystarczy skorzystanie z tych właściwości.