Что нового

Конвертация графических форматов в частности - PNG - в формат - ICO

assch

Новичок
Сообщения
166
Репутация
4
Здравствуйте.Не подскажете
Можно ли средствами Autoit из формата - PNG - сделать формат - ICO
Я понимаю что для этого есть другие программы
Просто нужно именно на Autoit.
Если можно пример как это делается.
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
assch [?]
пример как это делается

Код:
#include <GDIPlus.au3>

$sImageFile = FileOpenDialog('Select PNG File', '', 'Images (*.png;*.bmp;*.jpg;*.jpeg;*.gif)')
If @error Then Exit

$sIcoFile = @DesktopDir & "\" & StringRegExpReplace($sImageFile, '^.*\\|\.[^\.]*$', '') & '.ico'

_ImageConvertToIco($sImageFile, $sIcoFile, 32, 32)

Func _ImageConvertToIco($sImageFile, $sOutIconFile, $iWidth = -1, $iHeight = -1)
	Local $hImage, $HICON, $sTmp
	
	If $iWidth <> -1 And $iHeight <> -1 Then
		$sTmp = @TempDir & '\~_ImageConvertToIco.' & StringRegExpReplace($sImageFile, '^.*\.', '')
		__ImageResize($sImageFile, $sTmp, $iWidth, $iHeight)
		$sImageFile = $sTmp
	EndIf
	
	; Start GDIPlus
	_GDIPlus_Startup()
    ; Load image
	$hImage = _GDIPlus_ImageLoadFromFile($sImageFile)
	; create a HICON from the image
	$HICON = __GDIPlus_BitmapCreateHICONFromBitmap($hImage)
	;Clean up and shutdown GDIPlus
	_GDIPlus_ImageDispose($hImage)
	_GDIPlus_Shutdown()
	; create an ico file from the image
	__CreateIconFileFromHICON($HICON, $sOutIconFile)
	; Destroy the HICON now I've finished with it.
	_WinAPI_DestroyIcon($HICON)
	; Remove temporary file
	If $sTmp <> '' And FileExists($sTmp) Then
		FileDelete($sTmp)
	EndIf
EndFunc ;==>_ImageConvertToIco

Func __ImageResize($sFile, $sOutput, $iWidth, $iHeight)
    Local $hBMP, $hImage1, $hImage2, $hGraphic
    _GDIPlus_Startup()
    $hBMP = _WinAPI_CreateBitmap($iWidth, $iHeight, 1, 32) ; Create a bitmap (handle)
    $hImage1 = _GDIPlus_BitmapCreateFromHBITMAP($hBMP)  ; Create a bitmap object from a bitmap handle.
    $hGraphic = _GDIPlus_ImageGetGraphicsContext($hImage1) ; Get the graphic context of the blank bitmap.
    $hImage2 = _GDIPlus_ImageLoadFromFile($sFile)   ; Load the image you want to resize.
    _GDIPlus_GraphicsDrawImageRect($hGraphic, $hImage2, 0, 0, $iWidth, $iHeight) ;Draw the loaded image to the graphics of the blank bitmap at the size you want.
    _GDIPlus_ImageSaveToFile($hImage1, $sOutput)
    _GDIPlus_ImageDispose($hImage1)
    _GDIPlus_ImageDispose($hImage2)
    _GDIPlus_GraphicsDispose($hGraphic)
    _WinAPI_DeleteObject($hBMP)
    _GDIPlus_Shutdown()
EndFunc ;==>__ImageResize

Func __CreateIconFileFromHICON($HICON, $sOutIcon)
    Local $aInfo, $sIco, $sBmp, $hCDC, $tBI, $tBits, $iSz, $sBD, $FO
    ; Start of single icon Header 3 x 2 bytes = 6 bytes: 0000 Reserved / 0100 icon / 0100 Numer of icons, total length will be 22 bytes for a single icon when finished
    $sIco = "0x000001000100"
    ; Start of the Bitmap data header 1 x 4bytes: length of the header will be 40 bytes when finished. Will be appended to the end of the icon header when finished
    $sBmp = "28000000"
    ; Get info about the HICON, this is mainly to get the pointers to the Color/Mask bitmaps data
    $aInfo = _WinAPI_GetIconInfo($HICON)
    ; create a memory Compatable DC
    $hCDC = _WinAPI_CreateCompatibleDC(0)
    ; create a BITMAPINFO Struct to store the Bitmap Info, it needs to be inilialized by setting the struct size.
    $tBI = DllStructCreate($tagBITMAPINFO)
    DllStructSetData($tBI, "Size", DllStructGetSize($tBI))
    ; Pass a bitmap data pointer to the BITMAPINFO struct so we can recieve the details of the color bitmap data, we use it to write the headers
    _WinAPI_GetDIBits($hCDC, $aInfo[5], 0, 0, 0, DllStructGetPtr($tBI), 0)
    ; Now we have some the basic info to add to the icon & Bitmap header so we'll add that to the headers.
    $sIco &= Hex(DllStructGetData($tBI, "Width"), 2) & Hex(DllStructGetData($tBI, "Height"), 2) & "00000100" & _
		__StringReverseBytes(Hex(DllStructGetData($tBI, "BitCount"), 4))
    $sBmp &= __StringReverseBytes(Hex(DllStructGetData($tBI, "Width"))) & __StringReverseBytes(Hex(DllStructGetData($tBI, "Height") * 2)) & "0100" & _
		__StringReverseBytes(Hex(DllStructGetData($tBI, "BitCount"), 4)) & "00000000"
    ; Get the size of the Bitmap data from the BITMAPINFO Struct, we'll use this in the headers further on.
    $iSz = DllStructGetData($tBI, "SizeImage")
    ; create a struct to store the Bitmap data Bits of the first bitmap, reset the BITMAPINFO struct
    $tBits = DllStructCreate("byte[" & DllStructGetData($tBI, "SizeImage") & "]")
    ; Get the color bitmap dib bits into the $tBits struct.
    DllCall('gdi32.dll', 'int', 'GetBitmapBits', 'ptr', $aInfo[5], 'int', $iSz, 'ptr', DllStructGetPtr($tBits))
    ; Get GetBitmapBits returns Bottom to Top dib, so I turn it to Top to Bottom dib ;)
    ; ATM I'm only assuming that GetBitmapBits returns a Bottom to Top dib, maybe the bitmap bits you use could be Top Down already?.
    For $i = DllStructGetData($tBI, "SizeImage") + 1 To 0 Step -(DllStructGetData($tBI, "SizeImage") / DllStructGetData($tBI, "Height"))
        $sBD &= StringTrimLeft(BinaryMid(DllStructGetData($tBits, 1), $i, (DllStructGetData($tBI, "SizeImage") / DllStructGetData($tBI, "Height"))), 2)
    Next
    ;Clear the BITMAPINFO & $tBits Struct as we'll use the same variables again for the mask bitmap data
    $tBits = 0
    $tBI = 0
    ; create a BITMAPINFO Struct to store the Bitmap Info again, it needs to be inilialized by setting the struct size.
    $tBI = DllStructCreate($tagBITMAPINFO)
    DllStructSetData($tBI, "Size", DllStructGetSize($tBI))
    ; Pass a bitmap data pointer to the BITMAPINFO struct so we can recieve the details of the bitmask bitmap data
    _WinAPI_GetDIBits($hCDC, $aInfo[4], 0, 0, 0, DllStructGetPtr($tBI), 0)
    ; We've finished with the Compatable DC, delete it.
    _WinAPI_DeleteDC($hCDC)
    ; Add the size of the of the color + bitmask bitmap data as we need this for both the icon & Bitmap header
    $iSz += DllStructGetData($tBI, "SizeImage")
    ; combine the bitmap data size with the bitmap header, I'm padding the rest of the 40 byte bitmap header with 0's., that's the Bitmap header done
    $sBmp &= __StringReverseBytes(Hex($iSz)) & "00000000000000000000000000000000"
    ; Now add the size of the Bitmap data + bitmap header size and combine the icon header together with the bitmap header and color bitmap data
    $sIco &= __StringReverseBytes(Hex($iSz + 40)) & __StringReverseBytes(Hex("22")) & $sBmp & $sBD
    ; create a struct to store the Bitmap dib Bits of the mask bitmap
    $tBits = DllStructCreate("byte[" & DllStructGetData($tBI, "SizeImage") & "]")
    ; Get the mask bitmap dib bits into the $tBits struct.
    DllCall('gdi32.dll', 'int', 'GetBitmapBits', 'ptr', $aInfo[4], 'int', DllStructGetData($tBI, "SizeImage"), 'ptr', DllStructGetPtr($tBits))
    ; Get GetBitmapBits returns Bottom to Top dib, so I turn it to a Top to Bottom dib and append the mask bitmap data to the icon
    For $i = DllStructGetData($tBI, "SizeImage") + 1 To 0 Step -(DllStructGetData($tBI, "SizeImage") / DllStructGetData($tBI, "Height"))
        $sIco &= StringTrimLeft(BinaryMid(DllStructGetData($tBits, 1), $i, (DllStructGetData($tBI, "SizeImage") / DllStructGetData($tBI, "Height"))), 2)
    Next
    ; Write the icon to a file.
    $FO = FileOpen($sOutIcon, 18)
    FileWrite($sOutIcon, Binary($sIco))
    FileClose($FO)
    ; Clear the structs
    $tBits = 0
    $tBI = 0
EndFunc   ;==>_CreateIconFileFromHICON

; Reverse Byte String
Func __StringReverseBytes($sByte)
    Local $aX = StringRegExp($sByte, "(.{2})", 3), $sX = ''
    For $i = UBound($aX) - 1 To 0 Step -1
        $sX &= $aX[$i]
    Next
    Return $sX
EndFunc   ;==>__StringReverseBytes

Func __GDIPlus_BitmapCreateHICONFromBitmap($hBitmap)
    Local $HICON

    $HICON = DllCall($ghGDIPDll, "int", "GdipCreateHICONFromBitmap", "hwnd", $hBitmap, "int*", 0)
    If @error Then Return SetError(@error, 0, -1)
    Return SetError($HICON[0], 0, $HICON[2])
EndFunc   ;==>_GDIPlus_BitmapCreateHICONFromBitmap


а вообще эта тема никак не связана с GUI, переношу...
 
Автор
A

assch

Новичок
Сообщения
166
Репутация
4
Creat0R
Большое спасибо за код.
Жалко что иконки получаются не полноценными . (Я имею ввиду формат PNG прозрачные пиксили сделать не удалось)
Может быть можно что то сделать?
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
assch [?]
Может быть можно что то сделать?
Скорее всего что можно, у меня не получилось, но я если честно особо и не вдавался, поковырял код, поискал по оф. форуму, на первые попытки ничего толком не нашёл.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
А в чем проблема? Изучаем структуру ICO файла и записываем в него битмапы...



Добавлено:
Сообщение автоматически объединено:

Для сохранения прозрачности лучше не использовать GDI, только GDI+.

_GDIPlus_ImageLoadFromFile()
_GDIPlus_BitmapLockBits()
 
Автор
A

assch

Новичок
Сообщения
166
Репутация
4
Иконки не прозрачные были от того наверное, что перед конвертацией стояла функция которая обрезала файл под классические размеры иконки,
в данном случае 32 на 32.Она и гасила прозрачные пиксилы. Я попробывал убрать этот участок кода подставив файл PNG уже обрезанный правда под размер 48 на 48
Эта иконка просто так лучше смотрится и вроде получилось. Можно файл и не обрезать оставить его как есть например 256 на 256
(У меня был именно такой размер файла PNG ) Система его всё равно сделает стандартно маленьким(Правда есть одно но если эту иконку стандартно поставить
например в кнопку она будет отображаться на все свои размеры )Короче я отвлёкся.
Нужен другой код в начале этой основной функции (Большое спасибо за неё Креатору ) Чтобы он обрезал под предложенные размеры и чтобы он не гасил прозрачные пиксилы.
Попробую покапать дальше но, и не откажусь от советов.
Код:
#include <GDIPlus.au3>

$sIcoFile = @DesktopDir & '\Test.ico'


    _GDIPlus_Startup()
    ; Load image
    $hImage = _GDIPlus_ImageLoadFromFile("48.png")
    ; create a HICON from the image
    $HICON = __GDIPlus_BitmapCreateHICONFromBitmap($hImage)
    ;Clean up and shutdown GDIPlus
    _GDIPlus_ImageDispose($hImage)
    _GDIPlus_Shutdown()
    ; create an ico file from the image
    __CreateIconFileFromHICON($HICON, $sIcoFile)
    ; Destroy the HICON now I've finished with it.
    _WinAPI_DestroyIcon($HICON)
    
Func __CreateIconFileFromHICON($HICON, $sOutIcon)
    Local $aInfo, $sIco, $sBmp, $hCDC, $tBI, $tBits, $iSz, $sBD, $FO
    ; Start of single icon Header 3 x 2 bytes = 6 bytes: 0000 Reserved / 0100 icon / 0100 Numer of icons, total length will be 22 bytes for a single icon when finished
    $sIco = "0x000001000100"
    ; Start of the Bitmap data header 1 x 4bytes: length of the header will be 40 bytes when finished. Will be appended to the end of the icon header when finished
    $sBmp = "28000000"
    ; Get info about the HICON, this is mainly to get the pointers to the Color/Mask bitmaps data
    $aInfo = _WinAPI_GetIconInfo($HICON)
    ; create a memory Compatable DC
    $hCDC = _WinAPI_CreateCompatibleDC(0)
    ; create a BITMAPINFO Struct to store the Bitmap Info, it needs to be inilialized by setting the struct size.
    $tBI = DllStructCreate($tagBITMAPINFO)
    DllStructSetData($tBI, "Size", DllStructGetSize($tBI))
    ; Pass a bitmap data pointer to the BITMAPINFO struct so we can recieve the details of the color bitmap data, we use it to write the headers
    _WinAPI_GetDIBits($hCDC, $aInfo[5], 0, 0, 0, DllStructGetPtr($tBI), 0)
    ; Now we have some the basic info to add to the icon & Bitmap header so we'll add that to the headers.
    $sIco &= Hex(DllStructGetData($tBI, "Width"), 2) & Hex(DllStructGetData($tBI, "Height"), 2) & "00000100" & _
        __StringReverseBytes(Hex(DllStructGetData($tBI, "BitCount"), 4))
    $sBmp &= __StringReverseBytes(Hex(DllStructGetData($tBI, "Width"))) & __StringReverseBytes(Hex(DllStructGetData($tBI, "Height") * 2)) & "0100" & _
        __StringReverseBytes(Hex(DllStructGetData($tBI, "BitCount"), 4)) & "00000000"
    ; Get the size of the Bitmap data from the BITMAPINFO Struct, we'll use this in the headers further on.
    $iSz = DllStructGetData($tBI, "SizeImage")
    ; create a struct to store the Bitmap data Bits of the first bitmap, reset the BITMAPINFO struct
    $tBits = DllStructCreate("byte[" & DllStructGetData($tBI, "SizeImage") & "]")
    ; Get the color bitmap dib bits into the $tBits struct.
    DllCall('gdi32.dll', 'int', 'GetBitmapBits', 'ptr', $aInfo[5], 'int', $iSz, 'ptr', DllStructGetPtr($tBits))
    ; Get GetBitmapBits returns Bottom to Top dib, so I turn it to Top to Bottom dib ;)
    ; ATM I'm only assuming that GetBitmapBits returns a Bottom to Top dib, maybe the bitmap bits you use could be Top Down already?.
    For $i = DllStructGetData($tBI, "SizeImage") + 1 To 0 Step -(DllStructGetData($tBI, "SizeImage") / DllStructGetData($tBI, "Height"))
        $sBD &= StringTrimLeft(BinaryMid(DllStructGetData($tBits, 1), $i, (DllStructGetData($tBI, "SizeImage") / DllStructGetData($tBI, "Height"))), 2)
    Next
    ;Clear the BITMAPINFO & $tBits Struct as we'll use the same variables again for the mask bitmap data
    $tBits = 0
    $tBI = 0
    ; create a BITMAPINFO Struct to store the Bitmap Info again, it needs to be inilialized by setting the struct size.
    $tBI = DllStructCreate($tagBITMAPINFO)
    DllStructSetData($tBI, "Size", DllStructGetSize($tBI))
    ; Pass a bitmap data pointer to the BITMAPINFO struct so we can recieve the details of the bitmask bitmap data
    _WinAPI_GetDIBits($hCDC, $aInfo[4], 0, 0, 0, DllStructGetPtr($tBI), 0)
    ; We've finished with the Compatable DC, delete it.
    _WinAPI_DeleteDC($hCDC)
    ; Add the size of the of the color + bitmask bitmap data as we need this for both the icon & Bitmap header
    $iSz += DllStructGetData($tBI, "SizeImage")
    ; combine the bitmap data size with the bitmap header, I'm padding the rest of the 40 byte bitmap header with 0's., that's the Bitmap header done
    $sBmp &= __StringReverseBytes(Hex($iSz)) & "00000000000000000000000000000000"
    ; Now add the size of the Bitmap data + bitmap header size and combine the icon header together with the bitmap header and color bitmap data
    $sIco &= __StringReverseBytes(Hex($iSz + 40)) & __StringReverseBytes(Hex("22")) & $sBmp & $sBD
    ; create a struct to store the Bitmap dib Bits of the mask bitmap
    $tBits = DllStructCreate("byte[" & DllStructGetData($tBI, "SizeImage") & "]")
    ; Get the mask bitmap dib bits into the $tBits struct.
    DllCall('gdi32.dll', 'int', 'GetBitmapBits', 'ptr', $aInfo[4], 'int', DllStructGetData($tBI, "SizeImage"), 'ptr', DllStructGetPtr($tBits))
    ; Get GetBitmapBits returns Bottom to Top dib, so I turn it to a Top to Bottom dib and append the mask bitmap data to the icon
    For $i = DllStructGetData($tBI, "SizeImage") + 1 To 0 Step -(DllStructGetData($tBI, "SizeImage") / DllStructGetData($tBI, "Height"))
        $sIco &= StringTrimLeft(BinaryMid(DllStructGetData($tBits, 1), $i, (DllStructGetData($tBI, "SizeImage") / DllStructGetData($tBI, "Height"))), 2)
    Next
    ; Write the icon to a file.
    $FO = FileOpen($sOutIcon, 18)
    FileWrite($sOutIcon, Binary($sIco))
    FileClose($FO)
    ; Clear the structs
    $tBits = 0
    $tBI = 0
EndFunc   ;==>_CreateIconFileFromHICON

; Reverse Byte String
Func __StringReverseBytes($sByte)
    Local $aX = StringRegExp($sByte, "(.{2})", 3), $sX = ''
    For $i = UBound($aX) - 1 To 0 Step -1
        $sX &= $aX[$i]
    Next
    Return $sX
EndFunc   ;==>__StringReverseBytes

Func __GDIPlus_BitmapCreateHICONFromBitmap($hBitmap)
    Local $HICON

    $HICON = DllCall($ghGDIPDll, "int", "GdipCreateHICONFromBitmap", "hwnd", $hBitmap, "int*", 0)
    If @error Then Return SetError(@error, 0, -1)
    Return SetError($HICON[0], 0, $HICON[2])
EndFunc   ;==>_GDIPlus_BitmapCreateHICONFromBitmap
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Написать универсальную (иконки ведь бывают не только 32-битные) функцию для конвертирования довольно сложно. Я советую использовать FreeImage.au3.

Код:
#Include <FreeImage.au3>

_FreeImage_LoadDLL(@ScriptDir & '\FreeImage.dll')
_FreeImage_Initialise()
$hImage = _FreeImage_LoadU($FIF_PNG, @ScriptDir & '\48.png')
_FreeImage_SaveU($FIF_ICO, $hImage, @ScriptDir & '\48.ico')
_FreeImage_Unload($hImage)
_FreeImage_DeInitialise()
_FreeImage_UnLoadDLL()


Вот и все!

:smile:
 
Автор
A

assch

Новичок
Сообщения
166
Репутация
4
Спасибо Yashied
Интересная дЭлка.

Я не собираюсь делать иконки разных мастей и размеров.
Мне в принципи это надо было для небольшой програмки которая меняет вид папки на ту иконку которую можно выбрать.
Ну а так как в PNG сейчас много разных рисунков и для иконок они подходят хорошо, я и начал эту тему с конвертацией.
Програмка конечно чистое баловство, просто это ради интереса.

И всё же вопрос на последок какой функцией лучше обрезать размеры изображения(Восновном нужен для Png)
Чтобы не гасились прозрачные пиксилы.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
assch сказал(а):
И всё же вопрос на последок какой функцией лучше обрезать размеры изображения(Восновном нужен для Png)
Чтобы не гасились прозрачные пиксилы.

Встречные вопросы:

  • Обрезать (Crop) или изменять размеры (Resize)?
  • В пределах FreeImage.au3 или вообще?
 
Автор
A

assch

Новичок
Сообщения
166
Репутация
4
Ну теоретически выбираешь например файл PNG с размерами 256 на 256 или больше не важно.
Выставляешь ему параметры скажем 48 на 48 ну и чтобы он его обрезал под эти размеры только чтобы не загасил прозрачные пиксилы и всё.
Дальше как говорится по этапу. Желательно голой функцией не хочется в такую маленькую програмку зашивать дЭлку.
Но как говорится чёрт его знает может быть придётся.

Обрезать (Crop) или изменять размеры (Resize) Честно говоря не понял.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Не обрезал, а уменьшил!

;)

Код:
#Include <GDIPlus.au3>

_GDIPlus_Startup()
$hImage = _GDIPlus_ImageLoadFromFile(@ScriptDir & '\48.png')
$hThumb = _GDIPlus_ImageGetThumbnail($hImage, 32, 32) ; <= Это уменьшенное изображение (32x32)
_GDIPlus_ImageSaveToFile($hThumb, @ScriptDir & '\32.png')
_GDIPlus_ImageDispose($hThumb)
_GDIPlus_ImageDispose($hImage)
_GDIPlus_ShutDown()

Func _GDIPlus_ImageGetThumbnail($hImage, $iWidth, $iHeight)

	Local $aResult = DllCall($ghGDIPDll, 'uint', 'GdipGetImageThumbnail', 'ptr', $hImage, 'uint', $iWidth, 'uint', $iHeight, 'ptr*', 0, 'ptr', 0, 'ptr', 0)

	If @error Then
		Return SetError(1, 0, 0)
	Else
		If $aResult[0] Then
			Return SetError($aResult[0], 0, 0)
		EndIf
	EndIf
	Return $aResult[4]
EndFunc   ;==>_GDIPlus_ImageGetThumbnail
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
У меня вот так вышло:

Код:
#include <GDIPlus.au3>

$sImageFile = FileOpenDialog('Select PNG File', '', 'Images (*.png;*.bmp;*.jpg;*.jpeg;*.gif)')
If @error Then Exit

$sIcoFile = @DesktopDir & "\" & StringRegExpReplace($sImageFile, '^.*\\|\.[^\.]*$', '') & '.ico'

_ImageConvertToIco($sImageFile, $sIcoFile, 24, 24)
ShellExecute($sIcoFile)

Func _ImageConvertToIco($sImageFile, $sOutIconFile, $iWidth = -1, $iHeight = -1)
	Local $sTmp, $hImage, $hGC, $hBmp, $hBmpGC, $HICON
	; Start GDIPlus
	_GDIPlus_Startup()
	If $iWidth <> -1 And $iHeight <> -1 Then
		$sTmp = @TempDir & '\~_ImageConvertToIco.' & StringRegExpReplace($sImageFile, '^.*\.', '')
		; Load Image
		$hImage = _GDIPlus_ImageLoadFromFile($sImageFile)
		;Create New image
		$hGC = _GDIPlus_ImageGetGraphicsContext($hImage)
		$hBmp = _GDIPlus_BitmapCreateFromGraphics($iWidth, $iHeight, $hGC)
		$hBmpGC = _GDIPlus_ImageGetGraphicsContext($hBmp)
		;Draw
		_GDIPlus_GraphicsDrawImageRect($hBmpGC, $hImage, 0, 0, $iWidth, $iHeight)
		_GDIPlus_ImageSaveToFile($hBmp, $sTmp)
		;Clenaup
		_GDIPlus_GraphicsDispose($hGC)
		_GDIPlus_GraphicsDispose($hBmpGC)
		_GDIPlus_BitmapDispose($hBmp)
		_GDIPlus_ImageDispose($hImage)
		$sImageFile = $sTmp
	EndIf
    ; Load image
	$hImage = _GDIPlus_ImageLoadFromFile($sImageFile)
	; create a HICON from the image
	$HICON = __GDIPlus_BitmapCreateHICONFromBitmap($hImage)
	;Clean up and shutdown GDIPlus
	_GDIPlus_ImageDispose($hImage)
	_GDIPlus_Shutdown()
	; create an ico file from the image
	__CreateIconFileFromHICON($HICON, $sOutIconFile)
	; Destroy the HICON now I've finished with it.
	_WinAPI_DestroyIcon($HICON)
	; Remove temporary file
	If $sTmp <> '' And FileExists($sTmp) Then
		FileDelete($sTmp)
	EndIf
EndFunc ;==>_ImageConvertToIco

Func __CreateIconFileFromHICON($HICON, $sOutIcon)
    Local $aInfo, $sIco, $sBmp, $hCDC, $tBI, $tBits, $iSz, $sBD, $FO
    ; Start of single icon Header 3 x 2 bytes = 6 bytes: 0000 Reserved / 0100 icon / 0100 Numer of icons, total length will be 22 bytes for a single icon when finished
    $sIco = "0x000001000100"
    ; Start of the Bitmap data header 1 x 4bytes: length of the header will be 40 bytes when finished. Will be appended to the end of the icon header when finished
    $sBmp = "28000000"
    ; Get info about the HICON, this is mainly to get the pointers to the Color/Mask bitmaps data
    $aInfo = _WinAPI_GetIconInfo($HICON)
    ; create a memory Compatable DC
    $hCDC = _WinAPI_CreateCompatibleDC(0)
    ; create a BITMAPINFO Struct to store the Bitmap Info, it needs to be inilialized by setting the struct size.
    $tBI = DllStructCreate($tagBITMAPINFO)
    DllStructSetData($tBI, "Size", DllStructGetSize($tBI))
    ; Pass a bitmap data pointer to the BITMAPINFO struct so we can recieve the details of the color bitmap data, we use it to write the headers
    _WinAPI_GetDIBits($hCDC, $aInfo[5], 0, 0, 0, DllStructGetPtr($tBI), 0)
    ; Now we have some the basic info to add to the icon & Bitmap header so we'll add that to the headers.
    $sIco &= Hex(DllStructGetData($tBI, "Width"), 2) & Hex(DllStructGetData($tBI, "Height"), 2) & "00000100" & _
		__StringReverseBytes(Hex(DllStructGetData($tBI, "BitCount"), 4))
    $sBmp &= __StringReverseBytes(Hex(DllStructGetData($tBI, "Width"))) & __StringReverseBytes(Hex(DllStructGetData($tBI, "Height") * 2)) & "0100" & _
		__StringReverseBytes(Hex(DllStructGetData($tBI, "BitCount"), 4)) & "00000000"
    ; Get the size of the Bitmap data from the BITMAPINFO Struct, we'll use this in the headers further on.
    $iSz = DllStructGetData($tBI, "SizeImage")
    ; create a struct to store the Bitmap data Bits of the first bitmap, reset the BITMAPINFO struct
    $tBits = DllStructCreate("byte[" & DllStructGetData($tBI, "SizeImage") & "]")
    ; Get the color bitmap dib bits into the $tBits struct.
    DllCall('gdi32.dll', 'int', 'GetBitmapBits', 'ptr', $aInfo[5], 'int', $iSz, 'ptr', DllStructGetPtr($tBits))
    ; Get GetBitmapBits returns Bottom to Top dib, so I turn it to Top to Bottom dib ;)
    ; ATM I'm only assuming that GetBitmapBits returns a Bottom to Top dib, maybe the bitmap bits you use could be Top Down already?.
    For $i = DllStructGetData($tBI, "SizeImage") + 1 To 0 Step -(DllStructGetData($tBI, "SizeImage") / DllStructGetData($tBI, "Height"))
        $sBD &= StringTrimLeft(BinaryMid(DllStructGetData($tBits, 1), $i, (DllStructGetData($tBI, "SizeImage") / DllStructGetData($tBI, "Height"))), 2)
    Next
    ;Clear the BITMAPINFO & $tBits Struct as we'll use the same variables again for the mask bitmap data
    $tBits = 0
    $tBI = 0
    ; create a BITMAPINFO Struct to store the Bitmap Info again, it needs to be inilialized by setting the struct size.
    $tBI = DllStructCreate($tagBITMAPINFO)
    DllStructSetData($tBI, "Size", DllStructGetSize($tBI))
    ; Pass a bitmap data pointer to the BITMAPINFO struct so we can recieve the details of the bitmask bitmap data
    _WinAPI_GetDIBits($hCDC, $aInfo[4], 0, 0, 0, DllStructGetPtr($tBI), 0)
    ; We've finished with the Compatable DC, delete it.
    _WinAPI_DeleteDC($hCDC)
    ; Add the size of the of the color + bitmask bitmap data as we need this for both the icon & Bitmap header
    $iSz += DllStructGetData($tBI, "SizeImage")
    ; combine the bitmap data size with the bitmap header, I'm padding the rest of the 40 byte bitmap header with 0's., that's the Bitmap header done
    $sBmp &= __StringReverseBytes(Hex($iSz)) & "00000000000000000000000000000000"
    ; Now add the size of the Bitmap data + bitmap header size and combine the icon header together with the bitmap header and color bitmap data
    $sIco &= __StringReverseBytes(Hex($iSz + 40)) & __StringReverseBytes(Hex("22")) & $sBmp & $sBD
    ; create a struct to store the Bitmap dib Bits of the mask bitmap
    $tBits = DllStructCreate("byte[" & DllStructGetData($tBI, "SizeImage") & "]")
    ; Get the mask bitmap dib bits into the $tBits struct.
    DllCall('gdi32.dll', 'int', 'GetBitmapBits', 'ptr', $aInfo[4], 'int', DllStructGetData($tBI, "SizeImage"), 'ptr', DllStructGetPtr($tBits))
    ; Get GetBitmapBits returns Bottom to Top dib, so I turn it to a Top to Bottom dib and append the mask bitmap data to the icon
    For $i = DllStructGetData($tBI, "SizeImage") + 1 To 0 Step -(DllStructGetData($tBI, "SizeImage") / DllStructGetData($tBI, "Height"))
        $sIco &= StringTrimLeft(BinaryMid(DllStructGetData($tBits, 1), $i, (DllStructGetData($tBI, "SizeImage") / DllStructGetData($tBI, "Height"))), 2)
    Next
    ; Write the icon to a file.
    $FO = FileOpen($sOutIcon, 18)
    FileWrite($sOutIcon, Binary($sIco))
    FileClose($FO)
    ; Clear the structs
    $tBits = 0
    $tBI = 0
EndFunc   ;==>_CreateIconFileFromHICON

; Reverse Byte String
Func __StringReverseBytes($sByte)
    Local $aX = StringRegExp($sByte, "(.{2})", 3), $sX = ''
    For $i = UBound($aX) - 1 To 0 Step -1
        $sX &= $aX[$i]
    Next
    Return $sX
EndFunc   ;==>__StringReverseBytes

Func __GDIPlus_BitmapCreateHICONFromBitmap($hBitmap)
    Local $HICON

    $HICON = DllCall($ghGDIPDll, "int", "GdipCreateHICONFromBitmap", "hwnd", $hBitmap, "int*", 0)
    If @error Then Return SetError(@error, 0, -1)
    Return SetError($HICON[0], 0, $HICON[2])
EndFunc   ;==>_GDIPlus_BitmapCreateHICONFromBitmap
 
Автор
A

assch

Новичок
Сообщения
166
Репутация
4
Большое всем спасибо :IL_AutoIt_1:
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
А я бы все равно использовал бы FreeImage.au3. GdipCreateHICONFromBitmap() оставляет какой-то темный "налет" на прозрачности. В большинстве случаев это несущественно, но...
 
Автор
A

assch

Новичок
Сообщения
166
Репутация
4
Попробую.
Вы правы всё познаётся в сравнении.
Большое спасибо.
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Yashied [?]

Отлично, так намного короче:

Код:
#include <GDIPlus.au3>

$sImageFile = FileOpenDialog('Select Image File', '', 'Images (*.png;*.bmp;*.jpg;*.jpeg;*.gif)')
If @error Then Exit

$sIcoFile = @DesktopDir & "\" & StringRegExpReplace($sImageFile, '^.*\\|\.[^\.]*$', '') & '.ico'

_ImageConvertToIco($sImageFile, $sIcoFile, 32, 32)
ShellExecute($sIcoFile)

Func _ImageConvertToIco($sImageFile, $sOutIconFile, $iWidth = -1, $iHeight = -1)
	Local $hImage, $hThumb, $HICON
	
	; Start GDIPlus
	_GDIPlus_Startup()
	
    ; Load image
	$hImage = _GDIPlus_ImageLoadFromFile($sImageFile)
	
	If $iWidth = -1 Then
		$iWidth = _GDIPlus_ImageGetWidth($hImage)
	EndIf
	
	If $iHeight = -1 Then
		$iHeight = _GDIPlus_ImageGetHeight($hImage)
	EndIf
	
	; Get Thumbnail (resize the image)
	$hThumb = __GDIPlus_ImageGetThumbnail($hImage, $iWidth, $iHeight)
	
	; create a HICON from the image
	$HICON = __GDIPlus_BitmapCreateHICONFromBitmap($hThumb)
	
	;Clean up and shutdown GDIPlus
	_GDIPlus_ImageDispose($hImage)
	_GDIPlus_ImageDispose($hThumb)
	_GDIPlus_Shutdown()
	
	; create an ico file from the image
	__CreateIconFileFromHICON($HICON, $sOutIconFile)
	
	; Destroy the HICON now I've finished with it.
	_WinAPI_DestroyIcon($HICON)
EndFunc ;==>_ImageConvertToIco

Func __GDIPlus_ImageGetThumbnail($hImage, $iWidth, $iHeight)
    Local $aResult = DllCall($ghGDIPDll, 'uint', 'GdipGetImageThumbnail', 'ptr', $hImage, 'uint', $iWidth, 'uint', $iHeight, 'ptr*', 0, 'ptr', 0, 'ptr', 0)
    If @error Then
        Return SetError(1, 0, 0)
    Else
        If $aResult[0] Then
            Return SetError($aResult[0], 0, 0)
        EndIf
    EndIf
    Return $aResult[4]
EndFunc   ;==>_GDIPlus_ImageGetThumbnail

Func __GDIPlus_BitmapCreateHICONFromBitmap($hBitmap)
    Local $HICON = DllCall($ghGDIPDll, "int", "GdipCreateHICONFromBitmap", "hwnd", $hBitmap, "int*", 0)
    If @error Then
		Return SetError(@error, 0, -1)
	EndIf
    Return SetError($HICON[0], 0, $HICON[2])
EndFunc   ;==>_GDIPlus_BitmapCreateHICONFromBitmap

Func __CreateIconFileFromHICON($HICON, $sOutIcon)
    Local $aInfo, $sIco, $sBmp, $hCDC, $tBI, $tBits, $iSz, $sBD, $FO
    ; Start of single icon Header 3 x 2 bytes = 6 bytes: 0000 Reserved / 0100 icon / 0100 Numer of icons, total length will be 22 bytes for a single icon when finished
    $sIco = "0x000001000100"
    ; Start of the Bitmap data header 1 x 4bytes: length of the header will be 40 bytes when finished. Will be appended to the end of the icon header when finished
    $sBmp = "28000000"
    ; Get info about the HICON, this is mainly to get the pointers to the Color/Mask bitmaps data
    $aInfo = _WinAPI_GetIconInfo($HICON)
    ; create a memory Compatable DC
    $hCDC = _WinAPI_CreateCompatibleDC(0)
    ; create a BITMAPINFO Struct to store the Bitmap Info, it needs to be inilialized by setting the struct size.
    $tBI = DllStructCreate($tagBITMAPINFO)
    DllStructSetData($tBI, "Size", DllStructGetSize($tBI))
    ; Pass a bitmap data pointer to the BITMAPINFO struct so we can recieve the details of the color bitmap data, we use it to write the headers
    _WinAPI_GetDIBits($hCDC, $aInfo[5], 0, 0, 0, DllStructGetPtr($tBI), 0)
    ; Now we have some the basic info to add to the icon & Bitmap header so we'll add that to the headers.
    $sIco &= Hex(DllStructGetData($tBI, "Width"), 2) & Hex(DllStructGetData($tBI, "Height"), 2) & "00000100" & _
		__StringReverseBytes(Hex(DllStructGetData($tBI, "BitCount"), 4))
    $sBmp &= __StringReverseBytes(Hex(DllStructGetData($tBI, "Width"))) & __StringReverseBytes(Hex(DllStructGetData($tBI, "Height") * 2)) & "0100" & _
		__StringReverseBytes(Hex(DllStructGetData($tBI, "BitCount"), 4)) & "00000000"
    ; Get the size of the Bitmap data from the BITMAPINFO Struct, we'll use this in the headers further on.
    $iSz = DllStructGetData($tBI, "SizeImage")
    ; create a struct to store the Bitmap data Bits of the first bitmap, reset the BITMAPINFO struct
    $tBits = DllStructCreate("byte[" & DllStructGetData($tBI, "SizeImage") & "]")
    ; Get the color bitmap dib bits into the $tBits struct.
    DllCall('gdi32.dll', 'int', 'GetBitmapBits', 'ptr', $aInfo[5], 'int', $iSz, 'ptr', DllStructGetPtr($tBits))
    ; Get GetBitmapBits returns Bottom to Top dib, so I turn it to Top to Bottom dib ;)
    ; ATM I'm only assuming that GetBitmapBits returns a Bottom to Top dib, maybe the bitmap bits you use could be Top Down already?.
    For $i = DllStructGetData($tBI, "SizeImage") + 1 To 0 Step -(DllStructGetData($tBI, "SizeImage") / DllStructGetData($tBI, "Height"))
        $sBD &= StringTrimLeft(BinaryMid(DllStructGetData($tBits, 1), $i, (DllStructGetData($tBI, "SizeImage") / DllStructGetData($tBI, "Height"))), 2)
    Next
    ;Clear the BITMAPINFO & $tBits Struct as we'll use the same variables again for the mask bitmap data
    $tBits = 0
    $tBI = 0
    ; create a BITMAPINFO Struct to store the Bitmap Info again, it needs to be inilialized by setting the struct size.
    $tBI = DllStructCreate($tagBITMAPINFO)
    DllStructSetData($tBI, "Size", DllStructGetSize($tBI))
    ; Pass a bitmap data pointer to the BITMAPINFO struct so we can recieve the details of the bitmask bitmap data
    _WinAPI_GetDIBits($hCDC, $aInfo[4], 0, 0, 0, DllStructGetPtr($tBI), 0)
    ; We've finished with the Compatable DC, delete it.
    _WinAPI_DeleteDC($hCDC)
    ; Add the size of the of the color + bitmask bitmap data as we need this for both the icon & Bitmap header
    $iSz += DllStructGetData($tBI, "SizeImage")
    ; combine the bitmap data size with the bitmap header, I'm padding the rest of the 40 byte bitmap header with 0's., that's the Bitmap header done
    $sBmp &= __StringReverseBytes(Hex($iSz)) & "00000000000000000000000000000000"
    ; Now add the size of the Bitmap data + bitmap header size and combine the icon header together with the bitmap header and color bitmap data
    $sIco &= __StringReverseBytes(Hex($iSz + 40)) & __StringReverseBytes(Hex("22")) & $sBmp & $sBD
    ; create a struct to store the Bitmap dib Bits of the mask bitmap
    $tBits = DllStructCreate("byte[" & DllStructGetData($tBI, "SizeImage") & "]")
    ; Get the mask bitmap dib bits into the $tBits struct.
    DllCall('gdi32.dll', 'int', 'GetBitmapBits', 'ptr', $aInfo[4], 'int', DllStructGetData($tBI, "SizeImage"), 'ptr', DllStructGetPtr($tBits))
    ; Get GetBitmapBits returns Bottom to Top dib, so I turn it to a Top to Bottom dib and append the mask bitmap data to the icon
    For $i = DllStructGetData($tBI, "SizeImage") + 1 To 0 Step -(DllStructGetData($tBI, "SizeImage") / DllStructGetData($tBI, "Height"))
        $sIco &= StringTrimLeft(BinaryMid(DllStructGetData($tBits, 1), $i, (DllStructGetData($tBI, "SizeImage") / DllStructGetData($tBI, "Height"))), 2)
    Next
    ; Write the icon to a file.
    $FO = FileOpen($sOutIcon, 18)
    FileWrite($sOutIcon, Binary($sIco))
    FileClose($FO)
    ; Clear the structs
    $tBits = 0
    $tBI = 0
EndFunc   ;==>_CreateIconFileFromHICON

; Reverse Byte String
Func __StringReverseBytes($sByte)
    Local $aX = StringRegExp($sByte, "(.{2})", 3), $sX = ''
    For $i = UBound($aX) - 1 To 0 Step -1
        $sX &= $aX[$i]
    Next
    Return $sX
EndFunc   ;==>__StringReverseBytes


[?]
А я бы все равно использовал бы
Сама Dll'ка “тяжёлая”, если писать мелкую утилиту, то оно будет лишним.
 
Автор
A

assch

Новичок
Сообщения
166
Репутация
4
Re: Конвертация графических форматов в частности - PNG - в формат - ICO.

Это просто рог изобилия.
Спасибо.
Только интересный эфект даёт этот код и предыдущий тоже.
Иконка конвертируется на ура но и сразу же всплывает моя программа ArtIcons Pro с этой же иконкой в ней.
Чудеса.
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
assch [?]
сразу же всплывает моя программа ArtIcons Pro с этой же иконкой в ней
Значит она установлена как редактор по умолчанию для файлов иконок. Это делает строчка с ShellExecute.
 
Автор
A

assch

Новичок
Сообщения
166
Репутация
4
То что она установлена как редактор иконок по умолчанию это понятно
Только в коде что я приводил выше где я обрезал начало без файл опен диалогов
PNG поставил прямо в начало функции Получается тажа прозрачная иконка
И ArtIcons Pro не всплывает. Как думаете в чём дело?

Кстати помните я занимался вытаскиванием иконок из экзешников.
Вы тогда предложили мне простенькую функцию:

_FileExtractIcon("shell32.dll", @DesktopDir & "\Icon.ico", -20)

Она ещё вытаскивала иконки на чёрном фоне. Потом вы дали Другую функцию которая заработала отлично.
Пока мне не попался файл crack.exe и она с ним не справилась, даже более того программа гасла.
Тогда вы внесли изменение в ту функцию чтобы при ошибке иконка вытаскивалась той первой простенькой функцией
хотя бы на чёрном фоне.

Так вот при экспериментах я обратил внимание что та иконка на чёрном фоне легко конвертируется в PNG
но уже с бесцветными пиксилами. Поэтому я и начал эту тему как из PNG сделать нормальную иконку.
Теперь надо всю эту многоходовую комбинацию попытатся реализовать.
Конечно всё это из за одного файла crack.exe
 
Верх