Искал в интернетах утилиту и наткнулся на одну древность с полудохлого сайта sekdev.com
Запустил программу, получил приглашение к регистрации, отказался, загрузил картинку формата PNG, нажал Start Conversion и получил готовый значок. Открыл файл в проверенной программе IconXP и получил ожидаемое сообщение:
Да, исправьте:
Еще один тест - та же ситуация, к тому же конвертер не учел глубину цвета. Лучше использовать старую программу(бесплатный новогодний подарок), но мне было нужно преобразование многих файлов. К тому же я давно собирался написать конвертер.
Сначала полез в программу, чтобы отучить её от жадности. По адресу $589847 нашел очень странную проверку введенных данных на строку 53fozeraWdlOnA)-:tIkcarCtoNoDesaelPppasihtrofdrahdekrowevahIylnonoisrevlairtasisiht
Погонял программу в отладчике OllyDbg и после нескольких попыток сменить первые два числа на нужные, получил серийный номер. При запуске конвертер стал тупить, соединяться с сайтом, чтобы проверить данные, но вскоре угомонился и стал работать. Даже ограничение на количество конверсий(10 элементов) исчезло.
Вернулся к программированию, написал конвертер и надолго застрял: размер файла, создаваемый моей программой, не совпадает с размером оригинального файла, созданного в WinXP(тот же аналог ArtIcons Pro, но поглючнее).
Я уже забыл, как решил задачу, но позже вернулся к тестам, и снова нашел ошибку - размер значка 57х57 отличается от того, что выдает мой код. Какие только я не попробовал вариант - 16х16, 36х36,48х48,57х57,64х64,76х76, 114х114, 256х256, но часто стал получать сходную ошибку.
Старик Google уже не смог ответить на мои запросы, поэтому я пошел обходным путем. Формат значка несложный: пара заголовков, часть рудимента BMP - данные B,G,R,A и некая XOR-маска, которую некоторые редакторы просто игнорируют. Мне не хотелось писать программу, разбирающую значок по частям, поэтому я просто посмотрел на готовый файл:
Э? Значок 48х48, для точки относится 1 бит маски(48/8=6 байт), откуда еще пара лишних байт? Теперь я знаю, что появится в запросе поисковика. Еще один запрос, и пара строчек говорит, что в BMP размер скан-линий выравнивается до dword. Написал код, который учитывает выравнивание для XOR-маски, и получил желаемый результат - совпадение размеров файлов.
Для картинки с глубиной цветов 32 бит выравнивание не нужно - размер линии всегда будет кратным 4.
Еще один тест картинок 114х114, 36х36 и снова облом. Стал проверять, верен ли код - нет, ошибка. Переписал заново - работает. Проверил все возможные варианты - теперь отлично.
Сегодня сверил сгенерированную картинку со значком 256 цветов - снова облом, поэтому опубликованный код верно работает с картинкой глубиной 32бит цвета. Вернусь к изучению попозже.
If LoadImage(0,"apple-touch-icon-57x57.png")
iw=ImageWidth(0)
ih=ImageHeight(0)
If iw And ih
If CreateFile(0,"img.ico")
;header
WriteWord(0,0);Reserved, 2bytes
WriteWord(0,1);Type, 2bytes
WriteWord(0,1);Count, 2bytes
;rest of bmpheader
If iw=256
WriteAsciiCharacter(0,0);width 1 byte, if =256 then 0!
Else
WriteAsciiCharacter(0,iw);width 1 byte, if =256 then 0!
EndIf
If ih=256
WriteAsciiCharacter(0,0);height 1 byte
Else
WriteAsciiCharacter(0,ih);height 1 byte
EndIf
WriteAsciiCharacter(0,0) ;Num of colors 1 byte
WriteAsciiCharacter(0,0) ;reserved 1 byte =0
WriteWord(0,1) ;planes byte =1
WriteWord(0,32) ;bits per pixel
sl=Int(iw/8)
If iw-sl*8
sl+1
EndIf
If sl%4
sl=Int(sl/4)*4+4
EndIf
WriteLong(0,40+iw*ih*4+iw*sl)
;Debug 40+iw*ih*4+iw*sl
WriteLong(0,22) ;FileOffset 4 byte FilePos, where InfoHeader starts
;infoheader
WriteLong(0,40) ; size of InfoHeader structure 4 bytes
WriteLong(0,iw) ; icon width 4 bytes
WriteLong(0,ih*2) ; icon height 4 bytes Icon Height (added height of XOR-Bitmap and AND-Bitmap)
WriteWord(0,1); planes 2 bytes
WriteWord(0,32); bitcount 2 bytes
WriteLong(0,0) ;Type of Compression = 0 4 bytes
WriteLong( 0,iw*ih*4+iw*ih/8 );$1080);Size of Image in Bytes = 0 (uncompressed);4 bytes 32*32*4+128
WriteLong(0,0) ;XpixelsPerM 4 bytes unused = 0
WriteLong(0,0) ;YpixelsPerM 4 bytes unused = 0
WriteLong(0,0) ;ColorsUsed 4 bytes unused = 0 4 bytes
WriteLong(0,0) ;ColorsImportant 4 bytes unused = 0
StartDrawing(ImageOutput(0))
DrawingMode(#PB_2DDrawing_AlphaChannel)
;R,G,B,Reserved
For y=ih-1 To 0 Step -1
For x=0 To iw-1
c=Point(x,y)
WriteAsciiCharacter(0,Blue(c))
WriteAsciiCharacter(0,Green(c))
WriteAsciiCharacter(0,Red(c))
WriteAsciiCharacter(0,Alpha(c))
Next x
Next y
StopDrawing()
;AND mask,Скан-строки выровнены по 32-битной границе - dword !!!,https://www.musidora.ru/formatbmp.htm
;DWORD Alignment: Each scanline (row) of both the color data and the AND-mask must be padded to a multiple of 4 bytes (32 bits).
sl=Int(iw/8)
If iw-sl*8
sl+1
EndIf
If sl%4
sl=Int(sl/4)*4+4
EndIf
For i=1 To ih
For j=1 To sl;iw/8
WriteAsciiCharacter(0,0)
Next j
Next i
CloseFile(0)
Else
Debug ("error create file!")
EndIf;If CreateFile(0,"img.ico")
Else
Debug "width=0 or height=0"
EndIf
Else
Debug ("error loading image!")
EndIf




Комментарии
Отправить комментарий