[Tuto] Enregistrer une image en format bmp 256 couleur
Publié : ven. 09/déc./2005 1:39
Voici un petit bout de code que j'ai créé mardi pour mon éditeur graphique GGraphEditor, commenté aujourd'hui spécialement pour vous bande de veinard. Soyez indulgents c'est mon premier tutorial !
Qu'en pensez-vous ?
Code : Tout sélectionner
; ********************************************************************************************
; ********************************** Tutorial par Gratteur **********************************
; ****** Comment sauvegarder une image en format bmp 256 couleurs avec palette indexée ******
; *** N'oubliez pas de désactiver le débogueur pour tester la performance d'un algorithme ***
; ******************************** Version du 9 décembre 2005 ********************************
; ********************************************************************************************
; On définit la largeur et la hauteur de l'image
#largeur = 800
#hauteur = 600
repertoire.s = "imagetest.bmp" ; Le répertoire de l'image
; On crée un tableau dans lequel on stock les 256 couleurs de la palette (ici aléatoires)
Dim palette.l(255)
For y=0 To 15
For x=0 To 15
palette(i) = RGB(Random(255), Random(255), Random(255))
i+1
Next x
Next y
; On crée une image avec des valeures prises dans la palette
imageID = CreateImage(#PB_Any, #largeur, #hauteur)
StartDrawing(ImageOutput())
For y=0 To #hauteur-1
For x=0 To #largeur-1
Plot(x, y, palette(Random(255)))
Next x
Next y
StopDrawing()
; Procedure d'encodage de l'image (fichier.s doit se terminer par .bmp)
; Tout ce qui prend comme valeur $00 comme les champs réservés et autres octets pour le codage RLE et dont on ne se sert pas ne sont pas détaillés pour simplifier
Procedure SaveBmp8bit(ImageID, largeur, hauteur, fichier.s)
fileID = CreateFile(#PB_Any, fichier.s) ; On crée le fichier dans lequel seront stockées les données
If fileID
While (largeur+d)%4 > 0 ; Dans la zone des donnees, la largeur de chaque ligne en octet doit être un multiple de 4
d+1
Wend
; Premiere entete (BITMAPFILEHEADER)
*MemoryID = AllocateMemory(112) ; On alloue une zone mémoire de 14*8 bit pour le premier entête
If *MemoryID
PokeB(*MemoryID, $42) ; $424D est le code d'un Bitmap Windows (2 octets)
PokeB(*MemoryID+1, $4D)
PokeL(*MemoryID+2, 54+((largeur+d)*hauteur)) ; Taille totale du fichier (4 octets)
PokeL(*MemoryID+10, 54+1024) ; Offset de l'image (4 octets)
WriteData(*MemoryID, 14) ; On écrit dans le fichier les 14 octets du premier entête
FreeMemory(*MemoryID) ; On libère la zone mémoire pour ne pas l'encombrer
EndIf
; Deuxieme entete (BITMAPINFOHEADER)
*MemoryID = AllocateMemory(320) ; On alloue une zone mémoire de 40*8 bit pour le second entête
If *MemoryID
PokeL(*MemoryID, $28) ; $28 pour Windows, ($0C pour OS/2 1.x, $F0 pour OS/2 2.x) (1 octet)
PokeL(*MemoryID+4, largeur) ; La largeur de l'image (4 octets)
PokeL(*MemoryID+8, hauteur) ; La hauteur de l'image (4 octets)
PokeW(*MemoryID+12, 1) ; Le nombre de plans (1 dans tous les cas) (1 octet)
PokeW(*MemoryID+14, 8) ; La profondeur des couleurs, ici 8 pour 8bit soit 256 couleurs (2 octets)
WriteData(*MemoryID, 40) ; On écrit dans le fichier les 40 octets du second entête
FreeMemory(*MemoryID) ; On libère la zone mémoire pour ne pas l'encombrer
EndIf
; Palette (RGBQUAD)
*MemoryID = AllocateMemory(8192) ; On alloue une zone mémoire de 1024*8 bit pour la palette indexée
If *MemoryID
For i=0 To 255 ; On fait défiler les 256 couleurs contenues dans notre tableau
PokeB(*MemoryID+(i*4), Blue(palette(i))) ; On écrit la composante "blue" de la couleur (1 octet)
PokeB(*MemoryID+1+(i*4), Green(palette(i))) ; On écrit la composante "green" de la couleur (1 octet)
PokeB(*MemoryID+2+(i*4), Red(palette(i))) ; On écrit la composante "red" de la couleur (1 octet)
Next i
WriteData(*MemoryID, 1024) ; On écrit dans le fichier les 1024 octets de la palette
FreeMemory(*MemoryID) ; On libère la zone mémoire pour ne pas l'encombrer
EndIf
; Zone de donnees
UseImage(ImageID) ; On utilise la bonne image (on ne sait jamais)
StartDrawing(ImageOutput()) ; On commence le dessin
For y=hauteur-1 To 0 Step -1 ; On écrit les données de l'image de bas en haut
*MemoryID = AllocateMemory((largeur+d)*8) ; On alloue une zone mémoire de (largeur+d)*8 bit (cf plus haut pour le d)
If *MemoryID
For x=0 To largeur-1 ; On écrit ensuite les données de l'image de gauche à droite
c = Point(x, y) ; On récupère la couleur du point de coordonnées (x,y) de l'image
For i=0 To 255 ; On cherche la couleur de ce point parmis les 256 possibilités de la palette
If c = palette(i) ; Si on trouve la couleur (attention la réduction d'une image en 24 bit n'est pas traitée dans ce tutorial)
PokeB(*MemoryID+x, i) ; On écrit l'index de la couleur correspondante (1 octet)
Break ; On casse la boucle pas la peine de tester des valeurs innutiles
EndIf
Next i
Next x
WriteData(*MemoryID, largeur+d)
FreeMemory(*MemoryID) ; On libère la zone mémoire pour ne pas l'encombrer de plus de largeur+d octets
EndIf ; (Une image 5000*5000 en 24bit prend 72Mo dans la mémoire, vous comprenez pourquoi on la vide au fur et à mesure maintenant ;p)
Next y
StopDrawing() ; On arrete le dessin
CloseFile(fileID) ; On ferme le fichier
EndIf
EndProcedure
temps1 = ElapsedMilliseconds()
SaveBmp8bit(imageID, #largeur, #hauteur, repertoire.s) ; Ne pas oublier de créer une palette dans le tableau palette(255)
temps2 = ElapsedMilliseconds()
;N'oubliez pas de désactiver le débogueur pour tester la vitesse réelle
MessageRequester("N'oubliez pas de désactiver le débogueur", "L'image en format bmp 8bit (256 couleurs) à été codé en "+Str(temps2-temps1)+" ms", #PB_MessageRequester_Ok)