J'ai travaillé en C++ avec la VCL/ Embarcadero Xe et c'est la même chose.
Le problème du truc c'est que le format BMP a été inventé dans les années 90 avec la notion de palette de couleurs sur des systèmes 16 bits, pour évoluer avec un canal de transparence, abandon des palettes, un rien de compression etc.
Il me semble aussi que le stockage de l'image est inversé avec des lignes multiples de 4 : il est unique ce format
Et au passage, on remercie Microsoft d'avoir fournit/ autorisé des outils qui sont tolérants aux erreurs
Si la version 5 n'est pas utilisée c'est parce qu'elle ne sert à rien (ajout des profils ICC) .. si à augmenter le nombre de fonctionnalités et la complexité des "compatibles/ incompatibles"
Et pour revenir au bgr cela vient des processeurs Intel qui lisent les mots de 16 bits poids faible/poids fort (little endian)
Bonjour,
Désolé, j'avais donc prévu de travailler sur les différents BitmapInfoHeaders et j'ai fait complètement autre chose : j'ai creusé en profondeur dans les entrailles du Vampyre , et je commence à cerner le bug...
D'abord, dans ImagingCanvases, tout en bas, on peut lire :
et dans le Main.LoadFile de VCLimageBrowser on trouve
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 class function TFastARGB32Canvas.GetSupportedFormats: TImageFormats; begin Result := [ifA8R8G8B8]; end;
Est-ce qu'il n'aurait pas été plus simple d'écrire
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 // Convert image to 32bit ARGB format if current format is not supported by canvas class if not (FImage.Format in TImagingCanvas.GetSupportedFormats) then FImage.Format := ifA8R8G8B8;
et basta ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2// Convert image to 32bit ARGB format FImage.Format := ifA8R8G8B8;
Puisqu'in fine c'est ce qu'on retrouve tout au long du pas-à-pas à cause de ImagingBitmap ligne 431 :
Ayant constaté ligne 493
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 case BI.BitCount of ... 32: Format := ifA8R8G8B8; // As with R5G5B5 there is alpha check later <<< ici avec fichier xrgb end;
puis découvert ça ligne 513 :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 case BI.Compression of BI_RGB : LoadRGB; BI_RLE4: LoadRLE4; BI_RLE8: LoadRLE8; BI_BITFIELDS: LoadRGB; // <<< on passe ici avec fichier xrgb end;
Je trouve cette première ligne de commentaire un peu idiote puisque, par définition et par construction, le format A8R8G8B8 inclut un canal alpha.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 // Check if there is alpha channel present in A8R8G8B8 images, if it is not // change format to X8R8G8B8 if not Has32BitImageAlpha(Width * Height, Bits) then Format := ifX8R8G8B8;
Tests avec Gimp : image 1x1 à 100% de transparence, les 4 bytes sont à 0, le viewer affiche un carré noir ; image à 99% de transparence, le pixel est à 08 45 CA 02, limite invisible dans le viewer.
Le test pour les curieux, ligne 2180 :
en français : si on décale le pixel 0845CAFF de 24 bits vers la gauche on va se retrouver avec FFxxxxxxxx, correct ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 function Has32BitImageAlpha(NumPixels: LongInt; Data: PLongWord): Boolean; var I: LongInt; begin Result := False; for I := 0 to NumPixels - 1 do begin if Data^ >= 1 shl 24 then begin Result := True; <<< ici dès I = 0 Exit; end; Inc(Data); end; end;
Et donc Data^ sera > à 1, on est d'accord.
Sauf que c'est idiot car si fichier xrgb, les 32 bits sont 000845CA et donc le décalage de 24 bits vers la gauche donne CAxxxxxx et Data^ est encore > à 1,
j'ai tenté un truc de malade, pour voir :
et là ça l'inscrit dans les infos de l'ihm :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 //jpt if not Has32BitImageAlpha(Width * Height, Bits) then if BI.Compression = BI_BITFIELDS then Format := ifX8R8G8B8;
Mais la couleur c'est toujours pas ça...
Je vous passe les recherches dans les tréfonds d'Imaging, ImagingComponents, ImagingFormats, etc, force est de constater qu'il doit y avoir une conversion quelque part car quand on voit ça, ligne 485 dans imagingComponents :
on se dit que ça ne peut pas être au top !
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 function PixelFormatToDataFormat(Format: TPixelFormat): TImageFormat; begin case Format of pf8bit: Result := ifIndex8; pf15bit: Result := ifA1R5G5B5; pf16bit: Result := ifR5G6B5; pf24bit: Result := ifR8G8B8; pf32bit: Result := ifA8R8G8B8; // et le ifX8... alors !? else Result := ifUnknown; end; end;
La solution a l'air de se cacher dans Main.TMainForm.PaintBoxPaint, dans les commentaires tout en bas :
Alors j'ai tenté, dans le Main.LoadFile,
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 // Draw image to canvas (without conversion) using OS drawing functions. // Note that DisplayImage only supports images in ifA8R8G8B8 format so // if you have image in different format you must convert it or // create standard TBitmap by calling ImagingComponents.ConvertImageToBitmap ImagingComponents.DisplayImage(PaintBox.Canvas, PaintBox.BoundsRect, FBack);
car la conversion se résume, dans ImagingFormats ligne 2914, à
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 // Activate first image and update UI FImage.ActiveImage := 0; SetSupported; FImage.ConvertImages(ifX8R8G8B8);// jpt pour voir mais pas mieux // pas-à-pas montre que l'image est déjà au format X8... // En enlevant le hack ligne 515 de ImagingBitmap, // le test montre que src et dst sont différents, ok, mais couleur pas bonne // j'ai peur que ce format X8 ne soit pas bon en mémoire... PaintBox.Repaint;
et il n'y a rien pour prendre en compte la promenade du canal Alpha de la dernière place dans les pixels ifA8R8G8B8 à la première place dans les pixels ifX8R8G8B8,
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8 for I := 0 to NumPixels - 1 do begin // general ARGB conversion ChannelGetSrcPixel(Src, SrcInfo, Pix64); ChannelSetDstPixel(Dst, DstInfo, Pix64); Inc(Src, SrcInfo.BytesPerPixel); Inc(Dst, DstInfo.BytesPerPixel); end;
Terminé
Salut,
Une belle prise de tête se format BMP comme l'a dit foetus. L'introduction de l'encodage avec "BitField" c'est une misère à gérer. Imagine qu'il existe des fichier BMP 32 bits décris comme cela A2R10G10B10, A4R8G12B8, ou encore A0R11G11B10 (cf BMP-TestSuite dossier Q) En gros tu peux choisir le nombre de bit que tu veux utilisé par canal à l'enregistrement. Merci Microsoft
Pour ma part pour différencié un "XRGB / BGRX" a un "ARGB / BGRA" je lis les données normalement. Je teste juste si toute l'image est transparente ou pas pour des raisons d'affichage évidente
Ensuite pour différencier un format "XRGB / BGRX" du "ARGB / BGRA" je me base sur les valeurs du "BitField" dans ma description de l'image
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 pf32Bits: // Pas de compression, formats couleurs suivant "BitField" sinon format couleur par defaut BGRA Begin LineBuffer := nil; GetMem(LineBuffer, FRowSize); Try Y := 0; Repeat Memory.Read(LineBuffer^, FRowSize); If TopDown Then YY := Y Else YY := MaxHeight - Y; DstLine := GetScanLine(YY); SrcPtr := PLongWord(LineBuffer); X:= Width; While (X>0) Do Begin SrcColor := SrcPtr^; DstColor := ConvertBitFieldsToBZColor(ImageDescription.BitFields, SrcColor); //---> Note : Avec un format XRGB la valeur alpha sera toujours égale à FF FIgnoreAlpha := FIgnoreAlpha and (DstColor.alpha = 0); // ----> On teste tous les pixels sont 100% transparent DstLine^ := DstColor; Inc(SrcPtr); Inc(DstLine); Dec(X); End; Inc(Y); AdvanceProgress(Delta,0,1,False); Until (Y > MaxHeight); Finally FreeMem(LineBuffer); LineBuffer := nil; End; // Si tous les pixels sont transparent, on ignore la transparence pour l'affichage car si non, rien ne serait affiché If FIgnoreAlpha Then Begin ImageDescription.HasAlpha := False; With ImageDescription.BitFields Do Begin AlphaSize := 0; End; End;
EDIT : Par contre là j'ai un bug d'affichage de la valeur des masques
Au secours ! Non mais allô quoi
Ben moi je vais sans doute écrire à l'auteur de Vampyre car mettre les mains dedans, c'est un coup à y laisser les doigts et tout le bras ! Dis-toi que dans ses conversions il passe par du 64 bits, si si !
Bon, bref, j'ai trouvé une manière extrêmement bourrin de récupérer la bonne couleur d'un xrgb, attention, à ne pas mettre en prod, c'est juste pour vérifier qu'en lui passant un bel orange je récupère bien enfin un bel orange :
Dans ImagingFormats, ligne 2517, ChannelSetDstPixel :
Bon, là je plie la machine, il fait trop chaud et j'ai une bouillie de pixels dans les neurones,
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14 case DstInfo.BytesPerPixel of 4: with PColor32Rec(Dst)^ do begin {en faisant ça la couleur est enfin ok ! A := MulDiv(PixW.A, 255, 65535); R := MulDiv(PixW.R, 255, 65535); G := MulDiv(PixW.G, 255, 65535); B := MulDiv(PixW.B, 255, 65535); } R := MulDiv(PixW.A, 255, 65535); G := MulDiv(PixW.R, 255, 65535); B := MulDiv(PixW.G, 255, 65535); A := MulDiv(PixW.B, 255, 65535); end;
EDIT : Euh, t'es sûr de toi, là ?
Regarde mes images, chez moi la valeur "x" (il n'y a pas de valeur "alpha" dans un xrgb ) est égale à 00 !
Oui je suis sûre de ma fonction. le format est 32bits mais seul les canaux RGB sont utilisés. Ma valeur de sortie est un pixel en 32 bits donc oui la valeur alpha est bien définie à FF (255)
Dans function ConvertBitFieldsToBZColorEDIT : En plus j'ai une double vérification au cas ou suivant le "bitfield"
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 if (AlphaSize=0) then Result.Alpha:=255 else Result.Alpha:=GetBitFieldValue(SrcColor,AlphaMask, AlphaShift, AlphaSize);
Code : Sélectionner tout - Visualiser dans une fenêtre à part FIgnoreAlpha := FIgnoreAlpha and (DstColor.alpha = 0); // ----> On teste tous les pixels sont 100% transparent
Alors comment expliques-tu le fait que j'aie 00 avant les canaux BGR dans mon fichier xrgb ?
J'aimerais bien voir une copie d'écran de l'afficheur hexa montrant la fin du fichier (un peu comme ci-dessus), merci...
Pi là aussi va falloir m'expliquer comment tu peux rentrer 11111111bin dans un canal dont la taille est à 0
Le File Header et le Bitmap Info Header nous disent :Alors comment expliques-tu le fait que j'aie 00 avant les canaux BGR dans mon fichier xrgb ?
- en 0Ah que ton image XRGB commence en 8Ah (pas en 8Bh !)
- en 1Eh qu'elle est composée de pixels non compressés = BitFields (03h)
- dont le codage indiqué en 1Ch est sur 32 bits (20h)
- les positions des canaux possibles (au maximum 4) sont données par les masques de lecture sur 4 octets à appliquer à un pixel lu pour trouver chaque canal, à partir de 36h, dans l'ordre RGBA selon le schéma
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 // en appliquant les masques au pixel 00 08 45 CA : . pour le canal Red, en 36h -> 00 00 00 FF => R = CAh . pour celui Green, en 3Ah -> 00 00 FF 00 => G = 45h . pour le Blue, en 3Eh -> 00 FF 00 00 => B = 08h . pour le Alpha, en 42h -> 00 00 00 00 => A = 00h // non considéré dans le xrgb
Yep !
on est bien d'accord ! Les datas (1 seul pixel de 4 bytes) commencent à 8Ahex par un 00.
Confirmé par ce petit calcul sur les doigts : Le 7Chex en 0Ehex (le biSize, number of bytes required by the bih structure) correspond à 124dec, soit partir de 0Ehex et aller jusqu'à 89hex, donc les datas commencent bien à 8Ahex par 00, na !
et la coïncidence (j'adoooore les coïncidences) fait que la valeur 8Ahex dans l'adresse 0Ahex génère une colonne visuelle qui fait que tout en bas de cette colonne passant par 01, 13, une tripotée de 00, et 02, se trouve l'adresse 8Ahex, lol !
on est toujours d'accord.
on ne change pas une équipe qui gagne (en plus je suis d'actualité, même si je ne la suis pas : je la subis ).
Merci pour cette explication qui me manquait, mais d'où vient-elle ? Surtout ce "(au maximum 4)".
Juste un point de français pour lequel je ne suis pas d'accord :
"non considéré", j'aurais dit "non utilisé pour la représentation de l'image".
Et donc tu me cites et tu réponds dessous, mais ta réponse n'explique pas pourquoi j'ai 00 en 8Ahex quand Jérome dit qu'il a FF.
Ta réponse a cependant le mérite de préciser/confirmer mes déductions,mon seul regret c'est de ne pas trouver d'où vient cette adresse 36hex où commencent les masques.
J'ai trouvé : les masques se trouvent juste après la structure BitmatInfoHeader (https://docs.microsoft.com/en-us/win...-tagbitmapinfo), mais la quantité de masques est pifométrique :car dans le fichier qui m'intéresse biBitCount vaut 32 et biClrUsed 0 et qu'est-ce que je fais avec ces deux valeurs ? Nobody knows...Envoyé par msdn
Alors j'ai cherché, je suis retourné aux sources (https://msdn.microsoft.com/en-us/lib...=vs.85%29.aspx) et là, je suis un peu tombé par terre :
- je découvre l'apparition des flags de compression BI_JPEG et BI_PNG ;
- le discours sur le format 32 bits par pixel ne dit pas un mot du canal alpha, on dirait qu'il est là (bien obligé, on a 32 bits) mais non utilisé : The bitmap has a maximum of 2^32 colors. If the biCompression member of the BITMAPINFOHEADER is BI_RGB, the bmiColors member of BITMAPINFO is NULL. Each DWORD [A DWORD is a 32-bit unsigned integer, un cardinal, quoi, ou mieux : un RGBQuad] in the bitmap array represents the relative intensities of blue, green, and red for a pixel. The value for blue is in the least [à gauche] significant 8 bits, followed [vers la droite] by 8 bits each for green and red. The high byte in each DWORD is not used [et deviendra le canal Alpha] ;
- tu nous parles de 4 masques sur 4 octets, msdn parle de 3 masques : If the biCompression member of the BITMAPINFOHEADER is BI_BITFIELDS, the bmiColors member contains three DWORD color masks that specify the red, green, and blue components, respectively, of each pixel. Each DWORD in the bitmap array represents a single pixel.
Bon, soyons clair, tout ça est très compliqué alors on va ralentir un peu, je n'ai pas l'intention de refaire une librairie à la Vampyre, je vais me contenter d'essayer de faire en sorte que cette chose ouvre correctement les fichiers xrgb que je lui passe.
Et ça sera déjà pas mal, j'y vois beaucoup plus clair.
La structure BitmapInfoHeader présente dans le fichier peut être une version étendue. Dans ton xbgr, elle est de version 5 (https://docs.microsoft.com/fr-fr/win...bitmapv5header), plus longue que dans tes 2 autres exemples qui ne sont qu'en version 4.
Euh ? Non, la phrase de la msdn est relative au nombre de couleurs utilisées pour une palette. Si biClrUsed = 0, ce qui est ton cas, pas de palette et "True Colors" sur l'étendue de la taille de biBitCount (il y a plus de couleurs quand on attribue 8 bits par canal que 2 !)la quantité de masques est pifométrique
Dans la V1 du BMI, oui, sûrement créée à une époque où la transparence n'avait pas été imaginée, à la différence de l'intérêt d'aligner les données sur un nombre pair d'octets. Mais ton BMI est en version 5 et indique bien les 4 masques (pas un de plus) des 4 canaux (en fait, il y a un "canal" X qui est ignoré, composé des bits non codants R, G, B ou A :le discours sur le format 32 bits par pixel ne dit pas un mot du canal alpha, on dirait qu'il est là (bien obligé, on a 32 bits) mais non utilisé
Ma réponse explique pourquoi il y a 00 en 8Ahex. Il pourrait d'ailleurs y avoir n'importe quelle valeur : avec un masque à 00 00 00 00, elle serait ignorée par le lecteur, ce qui est bien la notion du xbgr = R8G8B8A0X8 qui ne définit que 3 canaux sur 32 bits...ta réponse n'explique pas pourquoi j'ai 00 en 8Ahex quand Jérome dit qu'il a FF.
Elle n'explique pas pourquoi Jérôme trouve FF
C'est trivial pourtant
- biBitCount c'est le nombre de bits par couleurs : 8, 16, 24, 32
- biClrUsed c'est le nombre de couleurs dans ta palette (couleur indexée)
En lisant la documentation, nous avons les limitations ultra-courantes des 2 systèmes de couleurs
- Ta palette ne peut pas avoir plus de 2^16 couleurs
- Tes couleurs "vraies" c'est minimum 16 bits de couleurs (donc soit 16, 24 ou 32) plus le monochrome.
Mais Microsoft sont des "oufs guedin de la vie" : on peut utiliser les 2 systèmes de couleurs en même temps (si je comprends bien la documentation et en oubliant les détails/ "compatibles - incompatibles" )
Si tes couleurs "vraies" c'est soit 16 soit 24 bits, tu vois qu'il y a un trou avec des couleurs 32 bits. Donc tu peux mettre un index de palette dans le trou : comment que l'algo se débrouille pour savoir si tu veux la couleur vraie ou bien la couleur indexée ? mystère et boule de gomme
Bonjour,
Ou la la, bon dur d'expliquer :
// non considéré dans le xrgb Masque Alpha =00 00 00 00 donc taille taille du masque = 0
Ici ce n'est pas 11111111 mais 00111111.
Dans mon fichier j'ai bien 00
255 = FF. c'est ma fonction qui retourne FF pas le 00 présent dans le fichier
Pour ce qui est des palettes :
Normalement un fichier WINDOWS BMP VALIDE 8bits ne peut pas avoir une palette de plus de 256 couleurs., un BMP 1 bits plus de 2 couleurs, un BMP 4 bits plus de 16 couleurs.
Cependant certain logiciels peuvent avoir avec des bugs dans leurs procedures d'enregistrement du format BMP.
Certain peuvent enregistrer une palette des couleurs utilisées dans l'image avec les formats 16, 24, 32 bits en effet certains logiciels sauvegardent une palette pouvant servir de référence pour une réduction du nombre de couleur entre autres.
De même certain fichier peuvent être invalide en indiquant un mauvais nombre de couleur dans la palette.
If faut donc calculer le GapSize manuellement pour vérifier le nombre d'octets exacte la palette sans oublier de prendre en compte également les données du "bitfield".
L'algo utilise toujours les vraies couleurs. La palette comme je le dis plus haut est présente à titre indicatif (pour les BMP 16,24 et 32 bits). Ensuite pour connaitre la valeur de la couleur indexée c'est suivant le "BitField". Le masque inutilisé pour les vraies couleurs pourrai alors peut-être faire référence à l'index suivant sa valeur. J'avoue n'être pas encore tombé sur ce genre de fichier tordu lors de mes tests.
Bonjour et merci à tous pour ces explications pointues.
Ah, je n'avais pas bien capté ce point, tout s'éclaire donc !
De mon côté j'ai pas mal avancé :
La seule manière d'avoir la bonne couleur c'est de bien prendre en compte ifX8... avec, dans ImagingBitmap ligne 431
puis d'appeler la conversion vers ifA8... dans Main.TMainForm.LoadFile (rappel : dans Main.TMainForm.PaintBoxPaint on lit
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 case BI.BitCount of ... 24: Format := ifR8G8B8; //jpt 32: Format := ifA8R8G8B8; // As with R5G5B5 there is alpha check later 32: if BI.Compression = BI_BITFIELDS then Format := ifX8R8G8B8 // to deal with xrgb else Format := ifA8R8G8B8; // As with R5G5B5 there is alpha check later end;
)
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 // Note that DisplayImage only supports images in ifA8R8G8B8 format so // if you have image in different format you must convert it or // create standard TBitmap by calling ImagingComponents.ConvertImageToBitmap
avec
en ayant pris soin de rajouter un test dans ImagingFormats.ChannelGetSrcPixel pour l'adaptation des bytes :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 // Activate first image and update UI FImage.ActiveImage := 0; SetSupported; if FImage.Format = ifX8R8G8B8 then FImage.ConvertImages(ifA8R8G8B8); // jpt PaintBox.Repaint;
Et voilà :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 case SrcInfo.BytesPerPixel of 4: with Pix do if SrcInfo.Format = ifX8R8G8B8 then // jpt -- to deal with xrgb // move X_B_G_R (as recorded in file) to B_G_R_A (needed for good display) begin A := MulDiv(PColor32Rec(Src).B, 65535, 255); R := MulDiv(PColor32Rec(Src).A, 65535, 255); G := MulDiv(PColor32Rec(Src).R, 65535, 255); B := MulDiv(PColor32Rec(Src).G, 65535, 255); end else begin A := MulDiv(PColor32Rec(Src).A, 65535, 255); R := MulDiv(PColor32Rec(Src).R, 65535, 255); G := MulDiv(PColor32Rec(Src).G, 65535, 255); B := MulDiv(PColor32Rec(Src).B, 65535, 255); end;
Les valeurs des ShowMessage viennent de ImagingTypes :
Plus qu'à écrire au monsieur,
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 type TImageFormat = ( ifR8G8B8 = 87, ifA8R8G8B8 = 88, ifX8R8G8B8 = 89,
Je n'arrive pas à comprendre pourquoi tu te prends la tête c'est pourtant simple
Il faut regarder la compression. 2 valeurs sont importantes : BI_RGB et BI_BITFIELDS. De toute manière, les images 24 et 32 bits ne peuvent pas être compressées et si on oublie les valeurs spécifiques, ce sont les 2 seules possibles.
Et pire que cela, il faut avoir une version d'entête au moins égale à 3 sinon on n'a pas de transparence (je pense que le masque alpha est ignoré dans le meilleur des cas).
Et ensuite, si la compression est BI_BITFIELDS, il faut alors lire les masques (parce que sinon il ne sont pas présents dans l'entête) pour savoir s'il y a de la transparence ou pas (masque alpha == 0) et si le canal alpha est en premier ou en dernier.
La difficulté me semble que les masques sont en "big endian" et le stockage des couleurs en "little endian" (bgra donc) : rien de préciser
Ce qui est simple pour toi ne l'est pas forcément pour l'autre. Arriverais-tu as l'expliquer clairement et simplement pour que l'autre personne comprenne du premier coup ?
Et non ce ne sont pas les deux seules valeurs possibles tu peux rajouter BI_JPEG, BI_PNG et BI_ALPHABITFIELD (ce dernier n'etant dispo qu'avec des bmp sous WinCE 5.0 et .NET 4.0 et sup)
Faux un bmp version 1.0 32bits peux très bien contenir des valeurs dont l'alpha n'est pas opaque à 100%
Comme ici avec le format XRGB mais il existe d'autre cas. Comme par exemple les format 8bits dont les couleurs de la palette sont aux format BGRA. L'alpha est d'ailleurs majoritairement à ZERO (100% Transparent)
Et il ya bien sûre également les valeurs de BitFields exotiques comme je l'ai décris dans un de mes messages précédents.
Les valeurs des masques ne sont pas forcément présentes. Le format des données par défaut est alors BGR/BGRA. Pour les masques ce qui est vraiment important de calculer ce sont leur taille respective et le décalage en bit.
Les big-endian et little-endian dépendent de la plateforme ou tourne ton application. Dans le cas d'une machine non-intel les données de l'entête devront être convertit. Pour le reste cela n'a pas vraiment d'importance. Enfin presque, tout dépend de comment tu décides d'organiser les données dans "ta gestion des bitmaps".
C'est normal tu es sur une vieille version et il faut regarder la version 4 (<- lien msdn en anglais) ou la version 5
Je le redis 1 fois : une image voire même une vidéo sont assez simple à comprendre avec un peu de connaissance (même si certains algo comme la compression sont hardcore)
Mais le format BMP est un gloubi-boulga et le témoignage de l'évolution des cartes graphiques
Et pourtant à la base c'est simple : un format d'image non compressé, ou légèrement avec RLE.
BI_ALPHABITFIELD tu oublies parce que spécifique WinCE et d'après la documentation Microsoft n'existe plus (sûrement en compatibilité)
Et ensuite je me méfie des valeurs BI_JPEG et BI_PNG.
Faire un jpeg ou un png avec un format bmp quel est l'avantage du truc ?
Et je suis persuadé qu'il n'y a que la bibliothèque de Microsoft qui puisse faire des bmp valides avec un jpeg/ png.
Ce n'est pas ce qui ressort : BI_BITFIELDS -> BITMAPV2INFOHEADER: RGB bit field masks, BITMAPV3INFOHEADER+: RGBA
Et il y a ambiguïté parce qu'on peut supposer que les formats BITMAPV2INFOHEADER et antérieur ne supportent pas le masque alpha (et ce serait logique si on regarde l'histoire)
Édit : C'est Jipété qui l'a confirmé. D'après son lien vers la documentation Microsoft, une vieille version de l'entête ne contient aucun masque et n'utilise que la table des couleurs.
Seuls les outils ferment les yeux et se débrouillent comme ils peuvent lorsqu'ils rencontrent BITMAPCOREHEADER/ BITMAPV1INFOHEADER/ BITMAPV2INFOHEADER et 1 canal alpha.
Édit : Il n'y a pas ambiguïté parce que seules les versions 4 et 5 existent. Et que la version 3 est une version officieuse d'Adobe.
Les couleurs indexées sont à part. Elles sont stockées sur 32 bits, mais le canal alpha n'est pas géré (et ce serait logique si on regarde l'histoire)
Microsoft par contre l'autorise en spécifiant le drapeau "RGBQUAD.rgbReserved" pour les entêtes 4 et 5 ... et en même temps le désapprouve
The colors in the color table are usually specified in the 4-byte per entry RGBA32 format. The color table used with the OS/2 BITMAPCOREHEADER uses the 3-byte per entry RGB24 format
....
Microsoft does not disallow the presence of a valid alpha channel bit mask[13] in BITMAPV4HEADER and BITMAPV5HEADER for 1bpp, 4bpp and 8bpp indexed color images, which indicates that the color table entries can also specify an alpha component using the 8.8.8.[0-8].[0-8] format via the RGBQUAD.rgbReserved[14] member. However, some versions of Microsoft's documentation disallow this feature by stating that the RGBQUAD.rgbReserved member "must be zero".
Ce qu'il en ressort, c'est que si tu veux les masques il faut mettre la compression à BI_BITFIELDS.
Et si ton image a des couleurs 32 bits, c'est la seule valeur possible. Parce que BI_RGB ne remplit que 24 bits et le canal alpha n'existe pas.<- Microsoft supporte le canal alpha avec les images 32 bits, compression BI_RGB (format RGBA)
Seuls les outils ferment les yeux et se débrouillent comme ils peuvent lorsqu'ils rencontrent BI_RGB et 32 bits ou bien BI_BITFIELDS, 24 bits et un canal alpha non vide.
Édit : d'après Microsoft il n'est pas valide d'avoir en même temps BI_BITFIELDS et 24 bits
Et donc, c'est assez simple pour distinguer le format ARGB du format RGBA : il faut lire la valeurs des masques, et notamment celui du masque alpha.BI_BITFIELDS Specifies that the bitmap is not compressed. The members bV4RedMask, bV4GreenMask, and bV4BlueMask specify the red, green, and blue components for each pixel. This is valid when used with 16- and 32-bpp bitmaps.
Microsoft précise que les masques ne doivent pas se chevaucher (ce qui est logique)
Sauf qu'on parle d'un format de stockage et non pas d'une représentation en mémoire. Si sur ton disque dur tes images sont stockées en bgra, tu vas avoir une différence lorsque tu vas essayer de la lire en argb.
J'ai trouvé
Les compressions BI_JPEG et BI_PNG ne sont pas faites pour le stockage, mais pour gérer de grosses images couleurs sur des périphériques ayant très peu de mémoire (<- le format bmp est un format avant tout non compressé donc effectivement cela peut faire mal )
Par exemple, les imprimantes : on crée une surface DIB et on l'envoie au périphérique. Mais il faut que le périphérique supporte ces formats, le bon OS (NT tu oublies), la bonne version des DLLs et utiliser des fonctions spéciales/ spécifiques comme OleLoadPicture.
Yep !
Dans tes rêves !
D'abord il faut savoir où se trouve ce masque alpha et je n'ai pas lu grand chose l'expliquant, à part le post d'Yves hier matin, terriblement confus au demeurant, au niveau des images, où la 1re partie notée BITFIELDS laisserait supposer qu'il faut 4x32 bits pour coder ces masques quand la ligne dessous "Sample Length" montre que 1x32 suffit -- quant à la ligne RBGAX, voilà-t-y pas qu'on découvre un 5e canal !
Bref, j'essaye de rapporter sur le croquis ce qu'il y a dans mon fichier 1x1x32_xrgb :
soit 000000FF0000FF0000FF000000000000, en splittant
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 @ data 36 00 37 00 38 00 39 FF 3a 00 3b 00 3c FF 3d 00 3e 00 3f FF 40 00 41 00 42 00 43 00 44 00 45 00
et on est bien avancé...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 000 000FF 0000FF0 000FF000 000000000 none alpha green red blue
C'est peut-être à l'envers, alors ?
Bof...
Code : Sélectionner tout - Visualiser dans une fenêtre à part 000000000 000FF000 0FF0000 FF000 000
à l'envers de l'envers ?
Insoluble.
Code : Sélectionner tout - Visualiser dans une fenêtre à part 000 00000 0000FF0 000FF000 0FF000000
Yves, source du croquis please, peut-être que le texte autour expliquera des choses.
Euh, tu ne l'as pas bien lu, alors... Extrait de ton lien, rubrique BitCount chapitre "32" : If the bV4Compression member of the BITMAPV4HEADER is BI_BITFIELDS, the bmiColors member contains three DWORD color masks that specify the red, green, and blue components of each pixel.
À moins que 3 != three ?
Et si je regarde la V5, j'en conclus qu'ils ont fait un bête copier-coller de la V4 :D'autant plus amusant que la structure en début d'article montre bien DWORD bV5AlphaMask;...If the bV5Compression member of the BITMAPV5HEADER is BI_BITFIELDS, the bmiColors member contains three DWORD color masks that [...]
J'enfonce le clou : une recherche sur la page de bV5RedMask montre 4 occurrences quand bV5AlphaMask n'en montre que 2.
La conclusion de la conclusion c'est que msdn n'est pas fiable à 100 %, et là, on est très mal !
Pour en revenir à Vampyre (vous n'êtes pas assis ? Vous devriez...), je me suis amusé à prendre un fichier 1x1x32_argb et à le recopier puis lui faire subir avec l'éditeur hexa le remplacement de BI_RGB en BI_BITFIELD et le remplacement de 08 45 CA FF par 00 08 45 CA et que croyez-vous qu'il arriva ?
Vampyre (modifié par ma bidouille d'hier) l'affiche avec mon bel orange, par contre Gimp comme le viewer Linux me sortent le marron sale.
Conclusion : certains utilisent les masques (et rendent mal les couleurs s'ils sont absents) et d'autres non.
C'est vraiment une pagaille désespérante.
Pour dire la vérité profonde, je n'ai pas vu grand chose concernant les masques dans Vampyre (ou je suis passé à côté ?).
Bon, j'ai encore d'autres tests à faire avec cette librairie avant de lui écrire.
J'ai bien conscience que ma manière de faire afficher un xrgb avec Vampyre n'est qu'une grosse bidouille, c"était juste pour vérifier que l'outil est capable de me montrer mon bel orange.
L'ayant vu, je la supprime.
Je conserve cependant la détection efficace du ifX8R8G8B8 dans ImagingBitmaps ligne 431 avec
Si quelqu'un a mieux, qu'il le dise maintenant sinon
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8 case BI.BitCount of ... //jpt 32: Format := ifA8R8G8B8; // As with R5G5B5 there is alpha check later 32: if BI.Compression = BI_BITFIELDS then Format := ifX8R8G8B8 else Format := ifA8R8G8B8; // As with R5G5B5 there is alpha check later end;qu'il se taise à jamaisqu'il le dise plus tard,
Et la bidouille va devoir être remplacée par quelque chose de plus professionnel, dans ImagingFormats ligne 2491 :
Le support d'étude se résume à cette vision colorée du fichier 1x1x32_xbgr avec
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 4: with Pix do if SrcInfo.Format = ifX8R8G8B8 then // jpt -- to deal with xrgb begin // devoir de vacances : utiliser les masks... end else // Format is ifA8R8G8B8 begin A := MulDiv(PColor32Rec(Src).A, 65535, 255); R := MulDiv(PColor32Rec(Src).R, 65535, 255); G := MulDiv(PColor32Rec(Src).G, 65535, 255); B := MulDiv(PColor32Rec(Src).B, 65535, 255); end;
- en 1Ehex la valeur BI_BITFIELD ;
- de 36hex à 45hex les 16 bytes des 4 masks (msdn ) ;
- et tout en bas à partir de 8Ahex la data, dans l'ordre X, B, G, R. (smiley bidon juste pour gérer l'espacement vertical de ces trois lignes -- encore une bidouille, )
Voili voilou,
EDIT 1 : une première piste :
EDIT 2 : question liminaire : ils servent à quoi, ces masks ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 4: with Pix do begin if SrcInfo.Format = ifX8R8G8B8 then // jpt -- to deal with xrgb begin // l'idée est de convertir ifX8R8G8B8 vers ifA8R8G8B8 en utilisant les masks end; // Format ifA8R8G8B8 A := MulDiv(PColor32Rec(Src).A, 65535, 255); R := MulDiv(PColor32Rec(Src).R, 65535, 255); G := MulDiv(PColor32Rec(Src).G, 65535, 255); B := MulDiv(PColor32Rec(Src).B, 65535, 255); end;
Si on lit des pixels de 32 bits à la queue leu leu, d'accord pour retrouver les bytes des couleurs, mais si on lit directement des bytes ?
Un truc m'échappe, là...
Parce que quand on travaille avec du RGBQuad par exemple, on travaille en fait avec un uint de 32 bits et si on veut la couleur rouge on précise simplement monRGBQuad.rgbRed, et je suspecte fortement qu'en interne et à bas niveau c'est le système d'exploitation qui fait mumuse avec les masks pour me renvoyer la valeur que je demande, donc à quoi bon en rajouter une couche ?
Ils indiquent quels bits des 32 codent chaque canal, selon le schéma d'où mon image était extraite).EDIT 2 : question liminaire : ils servent à quoi, ces masks ?
Ce n'est pas parce qu'on code les pixels sur 32 bits qu'on a forcément un codage en 4 fois 8 bits... Le format permet de définir une image non compressée (BitFields) dont les pixels sont codés en True Colors sur 32 bits, mais avec des canaux inégaux (par exemple 5 bits pour le rouge et 7 pour le bleu, mais 8 pour le vert ; un canal de transparence sur 4 bits, et 8 bits qui ne servent à rien...). Je pense que la seule limitation des masques est qu'un canal doit être une succession de bits contigus (et encore...). Un canal peut être à cheval sur plusieurs octets : ce ne sont pas des RGBQuad qu'on lit, mais des pixels dont le format particulier est entièrement décrit dans l'entête.
Pour les masques, l'utilisation est simple : on lit le Cardinal représentant le pixel, on fait un and avec le masque du canal à lire, et un décalage pour le caler sur le poids faible du Cardinal. Au passage, j'imagine mal que masques et pixels aient des endianités différentes !
Il n'y a que 4 masques définis : A, R, G, B ; le X correspondant à la différence éventuelle, qui reste inexploitée (sauf en stéganographie ?).
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager