Формат ICO

Программирование на Visual Basic, главный форум. Обсуждение тем программирования на VB 1—6.
Даже если вы плохо разбираетесь в VB и программировании вообще — тут вам помогут. В разумных пределах, конечно.
Правила форума
Темы, в которых будет сначала написано «что нужно сделать», а затем просьба «помогите», будут закрыты.
Читайте требования к создаваемым темам.
arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Формат ICO

Сообщение arthur2 » 05.06.2019 (Ср) 6:58

Итак, читаю файл иконки.

Сначала ICONDIR, потом массив ICONDIRENTRY, перебираю его, нахожу подходящий мне по параметрам значок, загружаю саму картинку в массив байтов.

Теперь всё это мне нужно скормить CreateIcon.

У меня есть один массив байтов, в нём сначала идёт маска, а затем сама картинка. Я так понимаю, что по тем сведениям, которые у меня уже есть, я могу узнать, начиная с какого байта заканчивается маска и начинается картинка. Правильно? Если да, то как? А маска вообще есть, если иконка 32-битная?

Код: Выделить всё
With IcItm(i)
     'Как получить offSetBmp, если я вообще туда рою?
      hIco = CreateIcon(App.hInstance, .bWidth, .bHeight, .wPlanes, .wBitCount, b(0), b(offSetBmp))
End With

Артур
 
   

Admiralisimys
Постоялец
Постоялец
 
Сообщения: 318
Зарегистрирован: 01.06.2009 (Пн) 10:26

Re: Формат ICO

Сообщение Admiralisimys » 06.06.2019 (Чт) 18:18

arthur2 да такое можно узнать. Сразу за BITMAPINFOHEADER, если изображение не содержит цветовой палитры, находятся байты маски.
Их количество в документации мной обнаружено не было, но эмпирическим путём бразильский программист Gustavo Franco вывел такой подход (там C#).
Код: Выделить всё
            //IconLib_src.zip -> IconLib/System/Drawing/IconLib/EncodingFormats/BMPEncoder.cs
            // XOR Image
            int stride = (int) ((mHeader.biWidth * mHeader.biBitCount + 31) & ~31) >> 3;
            mXOR = new byte[stride * (mHeader.biHeight / 2)];
            stream.Read(mXOR, 0, mXOR.Length);

            // AND Image
            stride = (int) ((mHeader.biWidth * 1 + 31) & ~31) >> 3;
            mAND = new byte[stride * (mHeader.biHeight / 2)];
            stream.Read(mAND, 0, mAND.Length);

XOR это маска, AND изображение сложив с которым получается результирующая иконка.
В BITMAPINFOHEADER высота двойного размера - о чём указано в документации.

Маска есть всегда для BMP данных, а для PNG нет, так как там она высчитывается операционной системой налету из альфа канал.
PNG данные могут быть только разрешением 256 на 256, в этом случаи соответствующие поля в ICONDIRENTRY заполняют нулями.

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Re: Формат ICO

Сообщение arthur2 » 07.06.2019 (Пт) 21:11

Admiralisimys писал(а): (там C#)
Код: Выделить всё
& ~31) >> 3

Блин, а как это "на русский" переводится?

Я тоже имперически поковырялся - получил такой подход:
Код: Выделить всё
   
'В маске по биту на пиксель, значит в строке байтов
'в восемь раз меньше, округляем в большую сторону:
         cntB = -Int((-.bWidth * 1) / 8)

'Теперь нужно строку выровнять по слову, значит байтов
'должно быть чётное количество:
         cntB = cntB + (cntB Mod 2)
         
'умножаем на количество строк
         cntB = cntB * .bHeight
         
'сюрприз: маска идёт-таки после картинки:
         offSetMask = .dwBytesInRes - cntB
   
Видимо, подход не правильный - некоторые маски читаются не правильно. Думал, что правильно читаются те, где выравнивание не нужно и мой код ничего не меняет, но нет - некоторые маски, вроде бы, с одинаковыми габаритами, читаются по-разному.

А ещё - значки почему-то рисуются кверх ногами :shock:

Похоже, прежде чем скармливать байты CreateIcon, их нужно ещё преобразовывать.

Маски рисуются у крупных значков, а у мелких читаются неправильно.

Картинки рисуются только 32 битные и, видимо, 24 битные.

У 32-битных маска есть, но картинка рисуется без её учёта - потому что есть значки, где маска прочитана правильно, а картинка - со сдвигом. Изображение

А в некоторых 32-битных значках маски вообще нет.
Вложения
ico.zip
(856.56 Кб) Скачиваний: 139
Артур
 
   

The trick
Постоялец
Постоялец
 
Сообщения: 774
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: Формат ICO

Сообщение The trick » 07.06.2019 (Пт) 21:23

Код: Выделить всё
typedef struct {
   long fIcon;
   long xHotspot;
   long yHotspot;
   long hbmMask;
   long hbmColor;
} ICONINFO;

typedef struct {
   unsigned char bWidth;
   unsigned char bHeight;
   unsigned char bColorCount;
   unsigned char bReserved;
   short wPlanes;
   short wBitCount;
   long dwBytesInRes;
   long dwImageOffset;
} ICONDIRENTRY;

typedef struct {
   short idReserved;
   short idType;
   short idCount;
} ICONDIR;


Код: Выделить всё
Public Function CreateIconFromMemory( _
                ByVal pData As Long, _
                ByVal lSize As Long, _
                ByVal lIndex As Long) As Long
    Dim hIcon           As Long
    Dim tDir            As ICONDIR
    Dim tEntry          As ICONDIRENTRY
    Dim tIcon           As ICONIMAGE
    Dim lOffset         As Long
   
    If lSize < Len(tDir) Then Exit Function
   
    memcpy tDir, ByVal pData, Len(tDir)
   
    If lIndex < 0 Or lIndex >= tDir.idCount Then Exit Function
   
    lOffset = Len(tDir) + Len(tEntry) * lIndex
   
    If lOffset + Len(tEntry) >= lSize Then Exit Function
       
    memcpy tEntry, ByVal pData + lOffset, Len(tEntry)
   
    If tEntry.dwImageOffset + tEntry.dwBytesInRes > lSize Or _
        tEntry.dwBytesInRes < Len(tIcon) Then Exit Function
   
    memcpy tIcon, ByVal pData + tEntry.dwImageOffset, Len(tIcon)
   
    hIcon = CreateIconFromResourceEx(ByVal pData + tEntry.dwImageOffset, tEntry.dwBytesInRes, 1, &H30000, _
                                     tIcon.icHeader.biWidth, tIcon.icHeader.biHeight \ 2, 0)

    CreateIconFromMemory = hIcon

End Function
UA6527P

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Re: Формат ICO

Сообщение arthur2 » 08.06.2019 (Сб) 0:09

The trick
Ура!!! Огромное спасибо! Всё заработало. И пинги в иконках тоже читает на раз! Причем, без всякого дополнительного кода. А всего-то и нужно было заменить CreateIcon на CreateIconFromResourceEx
Вложения
ico.zip
(856.19 Кб) Скачиваний: 159
Артур
 
   


Вернуться в Visual Basic 1–6

Кто сейчас на конференции

Сейчас этот форум просматривают: Yandex-бот и гости: 14

    TopList