- Сообщения
- 7,790
- Репутация
- 2,322
Решил показать скрипт, который писал для того, чтобы выполнить просьбу CreatoR`а (читайте эту тему, начиная с Переводчик Google, Ответ #12).
Что и зачем делает скрипт:
Есть нужные иконки .ico, содержащие несколько размеров. Нам нужны на выходе иконки только одного размера в формате .ico и в формате .png, а также файл .png, содержащий все эти изображения.
Так как писал на AutoIt v3.3.8.1, то в поздних версиях надо разбираться с файлами #include. Сделал две версии.
Код для AutoIt v3.3.8.1.
Код для AutoIt v3.3.12.0.
Для примера прикрепляю архив с используемыми в скрипте файлами и папками.
Без изменения путей код будет работать только со структурой папок и файлов из архива.
Если кому-нибудь интересно применение полученной объединенной картинки (пример есть в библиотеке Yashied`а Animate.au3),могу показать, как использовать эту картинку в скрипте.
Продолжение темы Получение и использование частей картинок в оконных функциях.
Что и зачем делает скрипт:
Есть нужные иконки .ico, содержащие несколько размеров. Нам нужны на выходе иконки только одного размера в формате .ico и в формате .png, а также файл .png, содержащий все эти изображения.
Код для AutoIt v3.3.8.1.
Код:
#include <WinAPIEx.au3>
#include <GDIPlus.au3>
#include <File.au3>
Opt('MustDeclareVars', 1)
Global $iSize = 16, $iARGB = 32; размер иконок, которые будем извлекать, и их битность (32 bit RGB + Alpha)
Global $sDirSources = @ScriptDir & '\IcoSources\', $sDirResIco = @ScriptDir & '\Ico16x16\', $sDirResPng16x16 = @ScriptDir & '\Png16x16\', _
$sResPngBig = @ScriptDir & '\PngBig\PngBig.png', $aIcoFiles, $aTmp, $hIcon, $hBitmap, $tBits, $pBits, $hBigBitmap, $hGraphic, $sTxt
Global $iTimer = TimerInit()
;~ получаем в массив исходные файлы иконок
$aIcoFiles = _FileListToArray($sDirSources, '*.ico', 1)
If @error Then Exit 1
For $i = 1 To $aIcoFiles[0]
$hIcon = 1
;~ получаем информацию о размерах иконок и их битность. См. описание _EnumIconFile http://autoit-script.ru/index.php?topic=10788.0
$aTmp = _EnumIconFile($sDirSources & $aIcoFiles[$i])
If @error Then Exit 2
;~ проверяем иконки на наличие размера ($iSize х $iSize) и на битность ($iARGB) для конвертации в png
For $j = 1 To $aTmp[0][0]
If $aTmp[$j][0] = $iSize Then
$hIcon = 0
If ($aTmp[$j][1] <> $iSize) Or ($aTmp[$j][2] <> $iARGB) Then Exit 3
EndIf
Next
If $hIcon Then Exit 3
Next
$aTmp = 1
;~ инициируем GDI+
_GDIPlus_Startup()
Do
;~ Создаем прозрачный битмап с нужным размером для объединенной картинки $sResPngBig
$hBigBitmap = _GDIPlus_BitmapCreateFromScan0($iSize * $aIcoFiles[0], $iSize)
If @error Then ExitLoop
;~ Получаем его контекст
$hGraphic = _GDIPlus_ImageGetGraphicsContext($hBigBitmap)
If @error Then ExitLoop
$aTmp = 0
Until 1
If $aTmp Then
;~ если ошибка, то удаляеем битмап и выход
If $hBigBitmap Then _GDIPlus_ImageDispose($hBigBitmap)
_GDIPlus_Shutdown()
Exit 4
EndIf
$tBits = DllStructCreate('byte[' & (4 * $iSize ^ 2) & ']')
$pBits = DllStructGetPtr($tBits)
;~ текст с информацией для дальнейшего использования полученных файлов
$sTxt = 'Local $a_Country[' & $aIcoFiles[0] + 1 & '][4] = [[' & $aIcoFiles[0] & '], _' & @CRLF
For $i = 1 To $aIcoFiles[0]
;~ извлекаем иконку нужного размера
$hIcon = _WinAPI_ShellExtractIcon($sDirSources & $aIcoFiles[$i], 0, $iSize, $iSize)
If @error Then Exit 5
;~ сохраняем иконку в файл с новым именем (по номеру)
_WinAPI_SaveHICONToFile($sDirResIco & $i & '.ico', $hIcon)
If @error Then ExitLoop
;~ получаем информацию об иконке
$aTmp = _WinAPI_GetIconInfo($hIcon)
If @error Then ExitLoop
;~ копируем нужную информацию в структуру $tBits
_WinAPI_GetBitmapBits($aTmp[5], 4 * $iSize ^ 2, $pBits)
If @error Then ExitLoop
;~ создаем из $tBits битмап на прозрачном фоне
$hBitmap = _GDIPlus_BitmapCreateFromScan0($iSize, $iSize, 4 * $iSize, $GDIP_PXF32ARGB, $pBits)
If @error Then ExitLoop
For $j = 4 To 5
;~ удаляеем то, что уже не нужно
If Not _WinAPI_DeleteObject($aTmp[$j]) Then ExitLoop 2
Next
;~ сохраняем битмап в файл png с новым именем (по номеру)
If Not _GDIPlus_ImageSaveToFile($hBitmap, $sDirResPng16x16 & $i & '.png') Then ExitLoop
;~ рисуем битмап иконки на прозрачном битмапе (файл png $sResPngBig)
If Not _GDIPlus_GraphicsDrawImageRect($hGraphic, $hBitmap, ($i - 1) * $iSize, 0, $iSize, $iSize) Then ExitLoop
;~ удаляеем то, что уже не нужно
If Not _GDIPlus_ImageDispose($hBitmap) Then ExitLoop
;~ удаляеем то, что уже не нужно
If Not _WinAPI_DestroyIcon($hIcon) Then ExitLoop
$aTmp = 0
$hBitmap = 0
$hIcon = 0
;~ добавляем к тексту новую строку с именем файла, удалив расширение, и его индексом
$sTxt &= '['''', ''' & _WinAPI_PathRemoveExtension($aIcoFiles[$i]) & ''', '''', ' & $i & '], _' & @CRLF
Next
$tBits = 0
$pBits = 0
;~ если ошибка, то удаляеем все
If ($hIcon) Or ($hBitmap) Or (UBound($aTmp) = 6) Then
$pBits = 1
If $hIcon Then _WinAPI_DestroyIcon($hIcon)
If $hBitmap Then _GDIPlus_ImageDispose($hBitmap)
If UBound($aTmp) Then
For $j = 4 To 5
_WinAPI_DeleteObject($aTmp[$j])
Next
EndIf
Else
;~ сохраняем результат в файл png $sResPngBig
$tBits = _GDIPlus_ImageSaveToFile($hBigBitmap, $sResPngBig)
EndIf
;~ удаляем все и освобождаем GDI+
_GDIPlus_GraphicsDispose($hGraphic)
_GDIPlus_ImageDispose($hBigBitmap)
_GDIPlus_Shutdown()
If $pBits Then
MsgBox(16, 'Error', 'Error')
Exit 13
Else
$sTxt = StringTrimRight($sTxt, 5) & ']' & @CRLF
ConsoleWrite($sTxt & @LF);текст можно сразу записать в au3 файл для дальнейшего использования
MsgBox(64, 'Info', TimerDiff($iTimer) & @LF & 'Save PngBig: ' & $tBits)
EndIf
; #FUNCTION# ====================================================================================================================
; Name...........: _EnumIconFile
; Description....: Enumerates an icons from the specified .ico file.
; Syntax.........: _EnumIconFile ( $sFile )
; Parameters.....: $sFile - The path to the .ico file whose icons are to be enumerated.
; Return values..: Success - The 2D array containing the following information:
;
; [0][0] - Number of rows in array (n)
; [0][i] - Unused
; [n][0] - The width of the icon, in pixels.
; [n][1] - The heigth of the icon, in pixels.
; [n][2] - The color depth of the icon, in bits-per-pixel.
; [n][3] - 1 (TRUE) if the icon has a PNG compression (Windows Vista+), or 0 (FALSE) otherwise.
;
; Failure - 0 and sets the @error flag to non-zero.
; Author.........: Yashied
; Modified.......:
; Remarks........: None
; Related........:
; Link...........: http://autoit-script.ru/index.php?topic=10788.0
; Example........:
; ===============================================================================================================================
Func _EnumIconFile($sFile)
Local $hFile, $tEntry, $tHeader, $tData, $pData, $pIcon, $Bytes, $Count, $Offset, $Enum = 0
$hFile = _WinAPI_CreateFileEx($sFile, 3, 0x80000000, 0x03)
If @error Then
Return SetError(1, 0, 0)
EndIf
Do
$Bytes = _WinAPI_GetFileSizeEx($hFile)
If Not $Bytes Then
ExitLoop
EndIf
$tData = DllStructCreate('byte[' & $Bytes & ']')
$pData = DllStructGetPtr($tData)
If Not _WinAPI_ReadFile($hFile, $pData, $Bytes, $Bytes) Then
ExitLoop
EndIf
$tHeader = DllStructCreate('ushort;ushort;ushort', $pData)
$Count = DllStructGetData($tHeader, 3)
If Not $Count Then
ExitLoop
EndIf
Dim $Enum[$Count + 1][4] = [[$Count]]
For $i = 1 To $Count
$tEntry = DllStructCreate('byte;byte;byte;byte;ushort;ushort;long;long', $pData + 6 + 16 * ($i - 1))
$Offset = DllStructGetData($tEntry, 8)
$pIcon = $pData + $Offset
$Enum[$i][2] = DllStructGetData($tEntry, 6)
If DllStructGetData(DllStructCreate('byte[8]', $pIcon), 1) = Binary('0x89504E470D0A1A0A') Then
; PNG => Retrieve IHDR chunk data (always first chunk, offset = 8)
$tHeader = DllStructCreate('dword;dword;byte;byte;byte;byte;byte', $pIcon + 16)
$Enum[$i][0] = _WinAPI_SwapDWord(DllStructGetData($tHeader, 1))
$Enum[$i][1] = _WinAPI_SwapDWord(DllStructGetData($tHeader, 2))
$Enum[$i][3] = 1
Else
; ICO => Retrieve BITMAPINFOHEADER structure
$tHeader = DllStructCreate($tagBITMAPINFOHEADER, $pIcon)
$Enum[$i][0] = DllStructGetData($tHeader, 2)
$Enum[$i][1] = DllStructGetData($tHeader, 3) / 2
$Enum[$i][3] = 0
EndIf
Next
Until 1
_WinAPI_CloseHandle($hFile)
If Not IsArray($Enum) Then
Return SetError(1, 0, 0)
EndIf
Return $Enum
EndFunc ;==>_EnumIconFile
;~ функция из GDIP.au3
Func _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight, $iStride = 0, $iPixelFormat = 0x0026200A, $pScan0 = 0)
Local $aResult = DllCall($ghGDIPDll, 'uint', 'GdipCreateBitmapFromScan0', 'int', $iWidth, 'int', $iHeight, 'int', $iStride, 'int', $iPixelFormat, 'ptr', $pScan0, '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[6]
EndFunc ;==>_GDIPlus_BitmapCreateFromScan0
Код:
#include <WinAPIShellEx.au3>
#include <WinAPIGdi.au3>
#include <WinAPIFiles.au3>
#include <WinAPI.au3>
#include <GDIPlus.au3>
#include <File.au3>
Opt('MustDeclareVars', 1)
Global $iSize = 16, $iARGB = 32; размер иконок, которые будем извлекать, и их битность (32 bit RGB + Alpha)
Global $sDirSources = @ScriptDir & '\IcoSources\', $sDirResIco = @ScriptDir & '\Ico16x16\', $sDirResPng16x16 = @ScriptDir & '\Png16x16\', _
$sResPngBig = @ScriptDir & '\PngBig\PngBig.png', $aIcoFiles, $aTmp, $hIcon, $hBitmap, $tBits, $pBits, $hBigBitmap, $hGraphic, $sTxt
Global $iTimer = TimerInit()
;~ получаем в массив исходные файлы иконок
$aIcoFiles = _FileListToArray($sDirSources, '*.ico', 1)
If @error Then Exit 1
For $i = 1 To $aIcoFiles[0]
;~ получаем информацию о размерах иконок и их битность. См. описание _EnumIconFile http://autoit-script.ru/index.php?topic=10788.0
$aTmp = _EnumIconFile($sDirSources & $aIcoFiles[$i])
If @error Then Exit 2
;~ проверяем иконки на наличие размера ($iSize х $iSize) и на битность ($iARGB) для конвертации в png
For $j = 1 To $aTmp[0][0]
If $aTmp[$j][0] = $iSize Then
$hIcon = 0
If ($aTmp[$j][1] <> $iSize) Or ($aTmp[$j][2] <> $iARGB) Then Exit 3
EndIf
Next
If $hIcon Then Exit 3
Next
$aTmp = 1
;~ инициируем GDI+
_GDIPlus_Startup()
Do
;~ Создаем прозрачный битмап с нужным размером для объединенной картинки $sResPngBig
$hBigBitmap = _GDIPlus_BitmapCreateFromScan0($iSize * $aIcoFiles[0], $iSize)
If @error Then ExitLoop
;~ Получаем его контекст
$hGraphic = _GDIPlus_ImageGetGraphicsContext($hBigBitmap)
If @error Then ExitLoop
$aTmp = 0
Until 1
If $aTmp Then
;~ если ошибка, то удаляеем битмап и выход
If $hBigBitmap Then _GDIPlus_ImageDispose($hBigBitmap)
_GDIPlus_Shutdown()
Exit 4
EndIf
$tBits = DllStructCreate('byte[' & (4 * $iSize ^ 2) & ']')
$pBits = DllStructGetPtr($tBits)
;~ текст с информацией для дальнейшего использования полученных файлов
$sTxt = 'Local $a_Country[' & $aIcoFiles[0] + 1 & '][4] = [[' & $aIcoFiles[0] & '], _' & @CRLF
For $i = 1 To $aIcoFiles[0]
;~ извлекаем иконку нужного размера
$hIcon = _WinAPI_ShellExtractIcon($sDirSources & $aIcoFiles[$i], 0, $iSize, $iSize)
If @error Then Exit 5
;~ сохраняем иконку в файл с новым именем (по номеру)
_WinAPI_SaveHICONToFile($sDirResIco & $i & '.ico', $hIcon)
If @error Then ExitLoop
;~ получаем информацию об иконке
$aTmp = _WinAPI_GetIconInfo($hIcon)
If @error Then ExitLoop
;~ копируем нужную информацию в структуру $tBits
_WinAPI_GetBitmapBits($aTmp[5], 4 * $iSize ^ 2, $pBits)
If @error Then ExitLoop
;~ создаем из $tBits битмап на прозрачном фоне
$hBitmap = _GDIPlus_BitmapCreateFromScan0($iSize, $iSize, $GDIP_PXF32ARGB, 4 * $iSize, $pBits)
If @error Then ExitLoop
For $j = 4 To 5
;~ удаляеем то, что уже не нужно
If Not _WinAPI_DeleteObject($aTmp[$j]) Then ExitLoop 2
Next
;~ сохраняем битмап в файл png с новым именем (по номеру)
If Not _GDIPlus_ImageSaveToFile($hBitmap, $sDirResPng16x16 & $i & '.png') Then ExitLoop
;~ рисуем битмап иконки на прозрачном битмапе (файл png $sResPngBig)
If Not _GDIPlus_GraphicsDrawImageRect($hGraphic, $hBitmap, ($i - 1) * $iSize, 0, $iSize, $iSize) Then ExitLoop
;~ удаляеем то, что уже не нужно
If Not _GDIPlus_ImageDispose($hBitmap) Then ExitLoop
;~ удаляеем то, что уже не нужно
If Not _WinAPI_DestroyIcon($hIcon) Then ExitLoop
$aTmp = 0
$hBitmap = 0
$hIcon = 0
;~ добавляем к тексту новую строку с именем файла, удалив расширение, и его индексом
$sTxt &= '['''', ''' & _WinAPI_PathRemoveExtension($aIcoFiles[$i]) & ''', '''', ' & $i & '], _' & @CRLF
Next
$tBits = 0
$pBits = 0
;~ если ошибка, то удаляеем все
If ($hIcon) Or ($hBitmap) Or (UBound($aTmp) = 6) Then
$pBits = 1
If $hIcon Then _WinAPI_DestroyIcon($hIcon)
If $hBitmap Then _GDIPlus_ImageDispose($hBitmap)
If UBound($aTmp) Then
For $j = 4 To 5
_WinAPI_DeleteObject($aTmp[$j])
Next
EndIf
Else
;~ сохраняем результат в файл png $sResPngBig
$tBits = _GDIPlus_ImageSaveToFile($hBigBitmap, $sResPngBig)
EndIf
;~ удаляем все и освобождаем GDI+
_GDIPlus_GraphicsDispose($hGraphic)
_GDIPlus_ImageDispose($hBigBitmap)
_GDIPlus_Shutdown()
If $pBits Then
MsgBox(16, 'Error', 'Error')
Exit 13
Else
$sTxt = StringTrimRight($sTxt, 5) & ']' & @CRLF
ConsoleWrite($sTxt & @LF);текст можно сразу записать в au3 файл для дальнейшего использования
MsgBox(64, 'Info', TimerDiff($iTimer) & @LF & 'Save PngBig: ' & $tBits)
EndIf
; #FUNCTION# ====================================================================================================================
; Name...........: _EnumIconFile
; Description....: Enumerates an icons from the specified .ico file.
; Syntax.........: _EnumIconFile ( $sFile )
; Parameters.....: $sFile - The path to the .ico file whose icons are to be enumerated.
; Return values..: Success - The 2D array containing the following information:
;
; [0][0] - Number of rows in array (n)
; [0][i] - Unused
; [n][0] - The width of the icon, in pixels.
; [n][1] - The heigth of the icon, in pixels.
; [n][2] - The color depth of the icon, in bits-per-pixel.
; [n][3] - 1 (TRUE) if the icon has a PNG compression (Windows Vista+), or 0 (FALSE) otherwise.
;
; Failure - 0 and sets the @error flag to non-zero.
; Author.........: Yashied
; Modified.......:
; Remarks........: None
; Related........:
; Link...........: http://autoit-script.ru/index.php?topic=10788.0
; Example........:
; ===============================================================================================================================
Func _EnumIconFile($sFile)
Local $hFile, $tEntry, $tHeader, $tData, $pData, $pIcon, $Bytes, $Count, $Offset, $Enum = 0
$hFile = _WinAPI_CreateFileEx($sFile, 3, 0x80000000, 0x03)
If @error Then
Return SetError(1, 0, 0)
EndIf
Do
$Bytes = _WinAPI_GetFileSizeEx($hFile)
If Not $Bytes Then
ExitLoop
EndIf
$tData = DllStructCreate('byte[' & $Bytes & ']')
$pData = DllStructGetPtr($tData)
If Not _WinAPI_ReadFile($hFile, $pData, $Bytes, $Bytes) Then
ExitLoop
EndIf
$tHeader = DllStructCreate('ushort;ushort;ushort', $pData)
$Count = DllStructGetData($tHeader, 3)
If Not $Count Then
ExitLoop
EndIf
Dim $Enum[$Count + 1][4] = [[$Count]]
For $i = 1 To $Count
$tEntry = DllStructCreate('byte;byte;byte;byte;ushort;ushort;long;long', $pData + 6 + 16 * ($i - 1))
$Offset = DllStructGetData($tEntry, 8)
$pIcon = $pData + $Offset
$Enum[$i][2] = DllStructGetData($tEntry, 6)
If DllStructGetData(DllStructCreate('byte[8]', $pIcon), 1) = Binary('0x89504E470D0A1A0A') Then
; PNG => Retrieve IHDR chunk data (always first chunk, offset = 8)
$tHeader = DllStructCreate('dword;dword;byte;byte;byte;byte;byte', $pIcon + 16)
$Enum[$i][0] = _WinAPI_SwapDWord(DllStructGetData($tHeader, 1))
$Enum[$i][1] = _WinAPI_SwapDWord(DllStructGetData($tHeader, 2))
$Enum[$i][3] = 1
Else
; ICO => Retrieve BITMAPINFOHEADER structure
$tHeader = DllStructCreate($tagBITMAPINFOHEADER, $pIcon)
$Enum[$i][0] = DllStructGetData($tHeader, 2)
$Enum[$i][1] = DllStructGetData($tHeader, 3) / 2
$Enum[$i][3] = 0
EndIf
Next
Until 1
_WinAPI_CloseHandle($hFile)
If Not IsArray($Enum) Then
Return SetError(1, 0, 0)
EndIf
Return $Enum
EndFunc ;==>_EnumIconFile
Без изменения путей код будет работать только со структурой папок и файлов из архива.
Если кому-нибудь интересно применение полученной объединенной картинки (пример есть в библиотеке Yashied`а Animate.au3),
Продолжение темы Получение и использование частей картинок в оконных функциях.