Voici du code pour créer une icône compressée à partir d'un png puique le principe de microsoft est d'avoir l'entête de l'icône suivi par la png en entier.
Le code fonctionne pour des png en RVB + alpha, j'ai pas cherché pour les autres formats, c'est juste les valeurs de l'en-tête à modifier, ces données se trouvent dans le chunk IHDR du png juste après les dimensions.
ici pour les explication en anglais
http://libpng.org/pub/png/spec/1.2/PNG-Chunks.html
Le code charge le fichier png (256x256) ces valeurs peuvent être modifiées dans le code.
Je teste certaines valeurs, je crée l'entête du fichier ico suivi du png.
J'ai mis la procédure de conversion Reverse_endian_format et une copie avec 3 lignes en asm pour faire la même chose.
Le code qui suit utilise celle qui n'a pas d'assembleur, celle en assembleur, je l'utilise depuis des années avec PureIconManger sans avoir eu de soucis. Faites comme bon vous semble
Cest juste pour que Falsam puisse ajouter la compression, mais je répète, pour des formats d'images par exemple 16 couleurs, je ne sais pas ce que ça donne.
Après, en utilisant une image en 32 bits et en copiant celle à 16 couleurs, cela devrait fonctionner tout en sachant que le png sera plus grand.
Code : Tout sélectionner
;// signature du png compressé pour icone Vista
#Compression_Segment_IHDR = $A1A0A0D474E5089
;// identifiant fichiers
#Fichier_Png = 100
#Fichier_Ico = 101
;- Structures IconDirEntry
;// les structures IconDirEntry et IconDir sont utilisées pour stocker les icônes en fichier .ico
Structure IconDirEntry
;// largeur de l'icône en pixels
bWidth.a
;// hauteur de l'icône en pixels (x 2)
bHeight.a
;// Ce champ permet d'indiquer le nombre de couleurs que prend en charge l'icône: 2, 4, 8 ou 16. Si la valeur est 0, il s'agit d'une icône de 256 couleurs ou plus.
bColorCount.a ; nombre de couleurs de l'icône (0 si >=8bpp)
;// Ce champ est réservé, et il doit toujours contenir la valeur 0.
bReserved.a
;// Ce champ permet d'indiquer le nombre de plages de couleurs que contient l'icône. (Color Planes)
wPlanes.u
;// Ce champ permet d'indiquer le nombre de bits par pixel que contient l'icône. (Bits per pixel)
wBitCount.u
;// Taille en octets de l'icône
dwBytesInRes.l
;// Ce champ permet d'indiquer la position de déplacement (Offset), en octets, du début du fichiers jusqu'à l'icône.
dwImageOffset.l
EndStructure
;- Structures IconDir
Structure IconDir
idReserved.u ; réservé, toujours à 0
idType.u ; resource type, à 1 pour les icônes
idCount.u ; nombre d'image dans le fichier icônes
idEntries.IconDirEntry[1] ; l'entrée de chaque image
EndStructure
Procedure.i Reverse_endian_format(valeur)
;// /////////////////////////////////////////////////////////////////////////////////////////////////
;//
;// FONCTION: Reverse_endian_format()
;//
;// BUT: inverser les octets (inverse les formats little/big endian)
;//
;// PARAMS: valeur - la valeur à convertir
;//
;// RETOURNE: un long qui est la valeur convertie
;//
;// /////////////////////////////////////////////////////////////////////////////////////////////////
ProcedureReturn ((valeur & $FF)<<24) | ((valeur & $FF00)<<8) | ((valeur & $FF0000)>>8) | ((valeur & $FF000000)>>24)
EndProcedure
Procedure.i Reverse_endian_format_Fast(valeur)
;// /////////////////////////////////////////////////////////////////////////////////////////////////
;//
;// FONCTION: Reverse_endian_format()
;//
;// BUT: inverser les octets (inverse les formats little/big endian)
;//
;// PARAMS: valeur - la valeur à convertir
;//
;// RETOURNE: un long qui est la valeur convertie
;//
;// /////////////////////////////////////////////////////////////////////////////////////////////////
;// c'est équivalent à l'instruction asm BSWAP dont le code asm est le suivant
;// supprimer le point virgule devant les instrustions asm et mettez un point virgule
;// devant la ligne ProcedureReturn, ç'est optimisé de cette façon
;// exemple : $12345678 devient $78563412
EnableASM
CompilerSelect #PB_Compiler_Processor
CompilerCase #PB_Processor_x86
! MOV eax, dword [p.v_valeur]
! BSWAP eax
ProcedureReturn
CompilerCase #PB_Processor_x64
! MOV rax, qword [p.v_valeur]
! BSWAP eax
ProcedureReturn
CompilerEndSelect
DisableASM
; ProcedureReturn ((valeur & $FF)<<24) | ((valeur & $FF00)<<8) | ((valeur & $FF0000)>>8) | ((valeur & $FF000000)>>24)
EndProcedure
Procedure SavePngToICO_C(PngFile$)
;// *********************************************************
;// PngFile$ avec chemin complet
;//
;// Retoune #True en cas de succès, sinon -1
;//
;// Le fichier ico est créé dans le même dossier que le png
;//
;// *********************************************************
;// adresse du fichier png en mémoire
Protected *MemoryAdd
;// mémorise la taille du fichier
Protected Filesize_q.q
;// variable d'écriture des ico
Protected ico.IconDir
;// fichier ico
Protected FichierIco$ = ""
Filesize_q = FileSize(PngFile$)
If Filesize_q < 0
ProcedureReturn -1 ; erreur
EndIf
;// Teste si fichier Png
If LCase(GetExtensionPart(PngFile$)) <> "png"
ProcedureReturn -1 ; erreur
EndIf
;// allocation mémoire pour le fichier
*MemoryAdd = AllocateMemory(Filesize_q)
If *MemoryAdd = 0
ProcedureReturn -1 ; erreur
EndIf
If ReadFile(#Fichier_Png, PngFile$) = #Null
FreeMemory(*MemoryAdd)
ProcedureReturn -1 ; erreur
EndIf
;// lecture et écriture du fichier en mémoire
If ReadData(#Fichier_Png, *MemoryAdd, Filesize_q) <> Filesize_q
FreeMemory(*MemoryAdd)
CloseFile(#Fichier_Png)
ProcedureReturn -1 ; erreur
EndIf
;// teste les valeurs du PNG
Select PeekQ(*MemoryAdd)
Case #Compression_Segment_IHDR
;// c'est un png
Default
FreeMemory(*MemoryAdd)
CloseFile(#Fichier_Png)
ProcedureReturn -1 ; erreur
EndSelect
;// on retrouve les dimensions depuis le segment IHDR de l'image PNG
;// 8 octets de signature PNG compressé
;// 4 octets donnant la longueur du segment qui suit qui est IHDR
;// 4 octets codant les lettres du segment IHDR 'IHDR'
;// 4 octets donnant la largeur de l'image
;// 4 octets donnant la hauteur de l'image
largeur = Reverse_endian_format(PeekL(*MemoryAdd + 8 + 4 + 4))
hauteur = Reverse_endian_format(PeekL(*MemoryAdd + 8 + 4 + 4 + 4))
If (largeur <> 256 ) Or (hauteur <> 256)
FreeMemory(*MemoryAdd)
CloseFile(#Fichier_Png)
ProcedureReturn -1 ; erreur
EndIf
;// création de l'icône
;// Le début de la Structure IconDir
ico\idReserved = 0 ; toujours à 0
ico\idType= 1 ; 1 --> ico
ico\idCount= 1 ; 1 seule icône
;// la structure IconDirEntry de la structure IconDir
ico\idEntries[0]\bWidth = 0
ico\idEntries[0]\bHeight = 0
ico\idEntries[0]\bColorCount = 0
ico\idEntries[0]\bReserved = 0
ico\idEntries[0]\wPlanes= 1
ico\idEntries[0]\wBitCount= 32
ico\idEntries[0]\dwBytesInRes= Filesize_q
ico\idEntries[0]\dwImageOffset= 22
;// le nom du fichier ico
FichierIco$ = GetPathPart(PngFile$) + StringField(GetFilePart(PngFile$), 1, ".") + ".ico"
;// création du fichier ico, aucun test si fichier existe déjà
If CreateFile(#Fichier_Ico, FichierIco$) = 0
FreeMemory(*MemoryAdd)
CloseFile(#Fichier_Png)
ProcedureReturn -1 ; erreur
EndIf
;// écriture des données de l'en-tête
If WriteData(#Fichier_Ico, @ico, SizeOf(IconDir)) <> SizeOf(IconDir)
FreeMemory(*MemoryAdd)
CloseFile(#Fichier_Ico)
CloseFile(#Fichier_Png)
DeleteFile(FichierIco$)
ProcedureReturn -1 ; erreur
EndIf
;// écriture du fichier png
If WriteData(#Fichier_Ico, *MemoryAdd, MemorySize(*MemoryAdd)) <> MemorySize(*MemoryAdd)
FreeMemory(*MemoryAdd)
CloseFile(#Fichier_Ico)
CloseFile(#Fichier_Png)
DeleteFile(FichierIco$)
ProcedureReturn -1 ; erreur
EndIf
;// termine
FreeMemory(*MemoryAdd)
CloseFile(#Fichier_Ico)
CloseFile(#Fichier_Png)
ProcedureReturn #True
EndProcedure
SavePngToICO_C("G:\Icones\Png\wyvern-jabba-the-tux.png")