Bonjour à tous

Qui aurais pensé que lire un simple fichier BMP sois si compliqué ?

Alors voila après la prise en charge du 24bits je suis passé au 32bits
J'ai trouvé cette suite de test pour fichiers BMP : http://entropymine.com/jason/bmpsuite/
pour tester et prendre en charge le maximum de cas possible.

Au cas ou voici les liens sur lesquel j'essaye de m'appuyer

Informations sur le format BMP :
- https://fr.wikipedia.org/wiki/Windows_bitmap
- https://en.wikipedia.org/wiki/BMP_file_format (plus complet que la version française)
- http://www.alrj.org/docs/formats/bmp/BMP.htm
- http://netghost.narod.ru/gff/graphic...ary/os2bmp.htm
- http://www.drdobbs.com/the-bmp-file-...4409533?pgno=5

Compression/Decompression :
- http://netghost.narod.ru/gff/graphics/book/ch09_01.htm
- https://fr.wikipedia.org/wiki/Codage_de_Huffman
- http://tcharles.developpez.com/Huffman/


Et là bien ; c'est du 50% de réussite et 50% d'échec. grosso modo.

Voilà un capture d'écran des fichiers BMP 32Bits de test, vus dans l'explorateur de Windows.
Entouré en jaune ce sont les fichiers que je charge et j'affiche correctement.

Nom : apercu_fichier_test_bmp32_ex.jpg
Affichages : 889
Taille : 65,2 Ko


Je n'arrive pas à comprendre comment Lazarus affiche correctement tous les fichiers.
Les procédures et fonctions sur lesquelles je me suis basé sont celles présentes dans
la classe TLazReadDIB de l'unité IntGraphics et dans l'unité fpBMPReader.


1er cas
avec les BMP encodés à 100% correctement
- le fichier rgb32bfdef.bmp, c'est Ok

Nom : rbg32bfdef-test1.jpg
Affichages : 1138
Taille : 102,1 Ko

- le fichier rgb32bf.bmp, paf

Nom : rbg32bf-test1.jpg
Affichages : 1311
Taille : 102,1 Ko

Avez vous remarquez la valeur de "Depth" et d' "AlphaShift" pour le TBitmap ?
Il le traite comme un 24bits !! et l'alphashift est à zero. Comparez avec "TGLZBitmap" à droite.

Nb :
- regardez la version du fichier BMP dans le memo à droite et en bas.
- Les valeurs de RedMask, GreenMask, BlueMask, sont les valeurs lues dans
le fichier bmp si la version de l'en-tête > 1. sinon valeur par defaut
AlphaMask est lues dans le fichier bmp si la version de l'en-tête > 2, sinon valeur par defaut
- Les valeurs de Shift et MaskSize sont calculées

Ici je n'arrive pas à savoir comment le RawImage image du bitmap passe à 24bits ? ou plus
précisément comment il determine l'AlphaShift à zero ?

mon code de récupération des données pour le BitField:

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
 
Function TGLZBitmapBMPImage.GetHeaderRedMask: LongWord;
Begin
  if FHeaderType>= bmpht_WindowsV2 then
  begin
    Case FHeaderType Of
        bmpht_WindowsV2: Result := LEToN(FInfoHeader.WindowsV2.biRedMask);
        bmpht_WindowsV3: Result := LEToN(FInfoHeader.WindowsV3.biRedMask);
        bmpht_WindowsV4: Result := LEToN(FInfoHeader.WindowsV4.biRedMask);
        bmpht_WindowsV5: Result := LEToN(FInfoHeader.WindowsV5.biRedMask);
    End;
  end
  else
  begin
    {$ifdef ENDIAN_BIG}
      Result := $0000FF00;
    {$else}
      Result :=$00FF0000;
    {$endif}
  end;
End;
 
Function TGLZBitmapBMPImage.GetHeaderGreenMask: LongWord;
Begin
  if FHeaderType>= bmpht_WindowsV2 then
  begin
    Case FHeaderType Of
        bmpht_WindowsV2: Result := LEToN(FInfoHeader.WindowsV2.biGreenMask);
        bmpht_WindowsV3: Result := LEToN(FInfoHeader.WindowsV3.biGreenMask);
        bmpht_WindowsV4: Result := LEToN(FInfoHeader.WindowsV4.biGreenMask);
        bmpht_WindowsV5: Result := LEToN(FInfoHeader.WindowsV5.biGreenMask);
    End;
  end
  else
  begin
    {$ifdef ENDIAN_BIG}
       Result := $00FF0000;
    {$else}
       Result := $0000FF00;
    {$endif}
  end;
End;
 
Function TGLZBitmapBMPImage.GetHeaderBlueMask: LongWord;
Begin
  if FHeaderType>= bmpht_WindowsV2 then
  begin
    Case FHeaderType Of
        bmpht_WindowsV2: Result := LEToN(FInfoHeader.WindowsV2.biBlueMask);
        bmpht_WindowsV3: Result := LEToN(FInfoHeader.WindowsV3.biBlueMask);
        bmpht_WindowsV4: Result := LEToN(FInfoHeader.WindowsV4.biBlueMask);
        bmpht_WindowsV5: Result := LEToN(FInfoHeader.WindowsV5.biBlueMask);
    End;
  end
  else
  begin
   {$ifdef ENDIAN_BIG}
      Result := $00FF0000;
   {$else}
      Result := $000000FF;
   {$endif}
  end;
End;
 
Function TGLZBitmapBMPImage.GetHeaderAlphaMask: LongWord;
Begin
  if FHeaderType>= bmpht_WindowsV3 then
  begin
    Case FHeaderType Of
        bmpht_WindowsV3: Result := LEToN(FInfoHeader.WindowsV3.biAlphaMask);
        bmpht_WindowsV4: Result := LEToN(FInfoHeader.WindowsV4.biAlphaMask);
        bmpht_WindowsV5: Result := LEToN(FInfoHeader.WindowsV5.biAlphaMask);
      Else  Result:=0
    End;
  end
  else
  begin    
   {$ifdef ENDIAN_BIG}
       Result := $000000FF;
    {$else}
      Result := $FF000000;
    {$endif}
  end;
End;
 
...
 
function TGLZBitmapBMPImage.ReadImageProperties:Boolean; 
 
	function GetMaskShift(AMask: LongWord): ShortInt;
	begin
	  Result := 0;
	  while ((AMask and (1 shl Result)) = 0) and (Result < 32) do inc(Result);
	 // if result = 32 then result:=0;
	end;
 
	function GetMaskSize(AMask: LongWord; AShift:ShortInt): Byte;
	begin
	  Result := 0;
	  while (AShift + Result < 32) and ((AMask and (1 shl (AShift + Result))) <> 0) do Inc(Result);
	end;
 
begin
...
 
  { On a récupéré nos informations, on met à jour le  RawImage. de TGLZBitmap
     On charge la palette de couleur si besoins
     On initialise quelques variables utiles pour la lecture des données suivant
     le "PixelFormat"
   }
   With RawImage do
   begin
     UsedColors:=GetHeaderUsedColors;
     UsePalette:=False;
      With Description do
       begin
         // Le decalage par defaut pour le bitfield est le format de couleur (A)RGB
         (*RedShift := 16;
         GreenShift := 8;
         BlueShift := 24;
         AlphaShift :=0;RedMaskSize := 8;
         GreenMaskSize := 8;// Taille de valeur en Bit
         BlueMaskSize := 8;
         AlphaMaskSize := 8;*)
 
         // On Initialise le format de couleur gràce au "masque"
         // Format couleur par Defaut pour le BitField : ARGB
 
         RedMask := GetHeaderRedMask;
         GreenMask := GetHeaderGreenMask;
         BlueMask := GetHeaderBlueMask;
 
         RedShift := GetMaskShift(RedMask); //ShiftCount(RedMask);
         GreenShift := GetMaskShift(GreenMask);
         BlueShift := GetMaskShift(BlueMask);
 
         RedMaskSize :=  GetMaskSize(RedMask,RedShift);
         GreenMaskSize := GetMaskSize(GreenMask,GreenShift);
         BlueMaskSize := GetMaskSize(BlueMask,BlueShift);
 
         AlphaMask := 0; //GetMaskSize(AlphaMask);
         AlphaShift := 0;
         AlphaMaskSize :=0;
 
         if FHeaderType>bmpht_WindowsV2 then
         begin
           AlphaMask := GetHeaderAlphaMask;
           AlphaShift := GetMaskShift(AlphaMask);
           AlphaMaskSize := GetMaskSize(AlphaMask,AlphaShift);
         end
         else
         begin // En-tête Version 1, on initialise avec la valeur par defaut
          if BitCount = 32 then
          begin
          {$ifdef ENDIAN_BIG}
            AlphaMask := := $000000FF;
          {$else}
            AlphaMask := $FF000000;
          {$endif}
           AlphaShift := GetMaskShift(AlphaMask);
           AlphaMaskSize := GetMaskSize(AlphaMask,AlphaShift);
          end;
         end;
       end;
    ...
     FRowSize:=ComputeBytesPerLine(bmpWidth, bitCount, bleDWordBoundary);
     Case bitCount of  
	 ...
       32:
       begin
         Description.ColorFormat:=cfBGRA;
 
         if Not(Compression=BMP_COMPRESSION_NONE) and not(Compression=BMP_COMPRESSION_BITF) then
         begin
           ShowMessage('Bad Compression');
           Result:=False;
         end;
 
         if Description.AlphaMaskSize > 0 then
         begin
           // Le Mask Alpha cache-t-il une autre composante de la couleur
            if (Description.RedMask or Description.GreenMask or Description.BlueMask) and Description.AlphaMask <> 0 then
            begin
                Description.AlphaMask  := 0;
                Description.AlphaShift := 0;
                Description.AlphaMaskSize := 0;
            end;
        end;
		// La taille du masque alpha est 0,. C'est un format 24bits.
        if Description.AlphaMaskSize = 0 then 
        begin
          //Description.ColorFormat:=cfBGR;
          BitCount:=24;//
          Description.AlphaMask  := $FF000000;
          Description.AlphaShift := 0;//GetMaskShift(Description.AlphaMask);
         // if  Description.AlphaShift = 24 then  Description.AlphaShift := 0;
        end;
       end;
     end;     
 
procedure TGLZBitmapBMPImage.LoadFromMemory();
var
	YY,Y : Integer;
	X:Integer;
	DstColor: TGLZColor;
	SrcPtr : PLongWord;
	DstLine : PGLZColor;
	SrcColor :LongWord;
	LineBuffer : PByte;
 
	function ExpandColor(Value: LongWord): TGLZColor;
	var
	tmpr, tmpg, tmpb, tmpa: LongWord;
	begin
		tmpr := value and RawImage.Description.RedMask;
		tmpg := value and RawImage.Description.GreenMask;
		tmpb := value and RawImage.Description.BlueMask;
		tmpa := value and RawImage.Description.AlphaMask;
 
		Result.Alpha := 255;
 
		if RawImage.Description.RedShift < 0 then
		  Result.Red := byte(tmpr shl (-RawImage.Description.RedShift))
		else
		  Result.Red := byte(tmpr shr RawImage.Description.RedbitShift);
 
		if RawImage.Description.GreenShift < 0 then
		  Result.Green := byte(tmpg shl (-RawImage.Description.GreenShift))
		else
		  Result.Green := byte(tmpg shr RawImage.Description.GreenShift);
 
		if RawImage.Description.BluebitShift < 0 then
		  Result.Blue := byte(tmpb shl (-RawImage.Description.BlueShift))
		else
		  Result.Blue := byte(tmpb shr RawImage.Description.BlueShift);
 
		if  RawImage.Description.AlphaMaskSize>0 then
		begin
		  if RawImage.Description.AlphaShift < 0 then
			Result.Alpha := byte(tmpa shl (-RawImage.Description.AlphaShift))
		  else
			Result.Alpha := byte(tmpa shr RawImage.Description.AlphaShift);
		end; 
  end;
 
begin
  // On initialise les dimensions de notre bitmap
  SetSize(bmpWidth, bmpHeight);
  Case RawImage.Description.PixelFormat of     
  ...
      pf32Bits:  // Pas de compression, formats couleurs suivant "BitField" sinon RGBA
      begin
        LineBuffer:=nil;
        ReallocMem(LineBuffer,FRowSize);
        Y:=0;
 
        repeat
          Memory.Read(LineBuffer^,FRowSize);
          if TopDown then YY:=Y else  YY:=MaxHeight-Y;
          if (Compression = BMP_COMPRESSION_BITF) then //LineDecodeBITFIELD32
          begin
            DstLine:=GetScanLine(YY);
 
            SrcPtr := PLongWord(LineBuffer);
            For X:=0 to MaxWidth do
            begin
              SrcColor:=(SrcPtr+X)^;
              DstColor := ExpandColor(SrcColor);
              if (FHeaderType<bmpht_WindowsV3) then DstColor.Alpha:=255;
              DstLine^:=DstColor;
              Inc(DstLine);
             end;
          end else LineDecodeBGRA32(LineBuffer,YY,false);
 
          Inc(Y);
        Until (Y>MaxHeight);
 
        ReAllocMem(LineBuffer, 0);
        FreeMem(LineBuffer);
        LineBuffer:=nil;
      end;
  end;
end;

2eme Cas avec les BMP encodés non standard et ou avec des erreurs d'encodage

Exemples avec les fichiers BMP : rgb32h56.bmp et rbg32-xbgr.bmp, idem c'est ok ici

Nom : rgba32h56-test1.jpg
Affichages : 750
Taille : 102,5 Ko

Nom : rgb32-xbgr-test.jpg
Affichages : 731
Taille : 102,1 Ko

Avec le fichier rgba32-1010102.bmp, paf

Nom : rgba32-101002-test.jpg
Affichages : 737
Taille : 104,6 Ko

Ici j'ai également essayé ça sans succes

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
 
{ Counts how many bits are set }
function MyCountBits(Value : byte) : shortint;
var i,bits : shortint;
begin
  bits:=0;
  for i:=0 to 7 do
  begin
    if (value mod 2)<>0 then inc(bits);
    value:=value shr 1;
  end;
  Result:=bits;
end;
 
{ If compression is bi_bitfields, there could be arbitrary masks for colors.
  Although this is not compatible with windows9x it's better to know how to read these bitmaps
  We must determine how to switch the value once masked
  Example: 0000 0111 1110 0000, if we shr 5 we have 00XX XXXX for the color, but these bits must be the
  highest in the color, so we must shr (5-(8-6))=3, and we have XXXX XX00.
  A negative value means "shift left"  }
 
  /// ! \\\\ Provient de fpBMPReader que j'ai modifié
function ShiftCountEx(Mask : longword; MaskSize:Byte) : shortint;
var tmp : shortint;
begin
  tmp:=0;
  if Mask=0 then
  begin
    Result:=0;
    exit;
  end;
 
  while (Mask mod 2)=0 do { rightmost bit is 0 }
  begin
    inc(tmp);
    Mask:= Mask shr 1;
  end;
  tmp:=tmp-(MaskSize-MyCountBits(Mask and $FF));
 // tmp:=tmp-(8-MyCountBits(Mask and $FF)); // CODE ORIGINAL
  Result:=tmp;
end;  
 
...
RedBitShift:=ShiftCountEx(RedMask,RedMaskSize);
GreenBitShift:=ShiftCountEx(GreenMask,GreenMaskSize);
BlueBitShift:=ShiftCountEx(BlueMask,BlueMaskSize);
 
...
 
 function ExpandColor(Value: LongWord): TGLZColor;
  var
    tmpr, tmpg, tmpb, tmpa: LongWord;
  begin
    tmpr := value and RawImage.Description.RedMask;
    tmpg := value and RawImage.Description.GreenMask;
    tmpb := value and RawImage.Description.BlueMask;
    tmpa := value and RawImage.Description.AlphaMask;
 
    Result.Alpha := 255; 
	if RedbitShift < 0 then
			 Result.Red := byte(tmpr shl (-RedbitShift))
		   else
			 Result.Red := byte(tmpr shr RedbitShift);
 
		   if GreenbitShift < 0 then
			 Result.Green := byte(tmpg shl (-GreenbitShift))
		   else
			 Result.Green := byte(tmpg shr GreenbitShift);
 
		   if BluebitShift < 0 then
			 Result.Blue := byte(tmpb shl (-BluebitShift))
		   else
			 Result.Blue := byte(tmpb shr BluebitShift);
 
		  if  RawImage.Description.AlphaMaskSize>0 then
		   begin
			 if AlphabitShift < 0 then
			   Result.Alpha := byte(tmpa shl (-AlphabitShift))
			 else
			   Result.Alpha := byte(tmpa shr AlphabitShift);
		   end;
 
	  end;
idem resultat foireux

Nom : rgba32-101002-test2.jpg
Affichages : 713
Taille : 104,6 Ko

Valeurs des "BitShifts"
Pour le fichier rgb32-xbgr.bmp

[STATUS] Blue Mask = $FF000000
[STATUS] Blue Mask = $00FF0000
[STATUS] Blue Mask = $0000FF00
[STATUS] Alpha Mask = $00000000

[STATUS] Red Shift = 24
[STATUS] Green Shift = 16
[STATUS] Blue Shift = 8
[STATUS] Alpha Shift = 32 //---> Ici l'alpha shift est "correct sans être juste"

[STATUS] Red Size = 8
[STATUS] Green Size = 8
[STATUS] Blue Size = 8
[STATUS] Alpha Size = 0

----> Nouvelles variable testés :

[STATUS] Red Bit Shift = 24
[STATUS] Green Bit Shift = 16
[STATUS] Blue Bit Shift = 8
[STATUS] Alpha Bit Shift = 0 //---> Ici l'alpha shift est correct

[STATUS] BitCount = 24

et celle de rgba32-1010102.bmp

[STATUS] Blue Mask = $3FF00000
[STATUS] Blue Mask = $000FFC00
[STATUS] Blue Mask = $000003FF
[STATUS] Alpha Mask = $C0000000

[STATUS] Red Shift = 20
[STATUS] Green Shift = 10
[STATUS] Blue Shift = 0
[STATUS] Alpha Shift = 30

[STATUS] Red Size = 10
[STATUS] Green Size = 10
[STATUS] Blue Size = 10
[STATUS] Alpha Size = 2
[STATUS] BitCount = 32

----> Nouvelles variable testés :

[STATUS] Red Bit Shift = 18
[STATUS] Green Bit Shift = 8
[STATUS] Blue Bit Shift = -2
[STATUS] Alpha Bit Shift = 30

[STATUS] BitCount = 32

Si vous avez des idées ou une explications je suis perdu. Je suis sur que c'est tout bête mais je vois pas, je suis un peu perdu avec tous ces décalges de bits.

Merci d'avance