TianoCore EDK2 master
Loading...
Searching...
No Matches
BmpSupportLib.c
Go to the documentation of this file.
1
21#include <PiDxe.h>
22#include <Library/DebugLib.h>
25#include <Library/SafeIntLib.h>
27
29
30//
31// BMP Image header for an uncompressed 24-bit per pixel BMP image.
32//
33const BMP_IMAGE_HEADER mBmpImageHeaderTemplate = {
34 'B', // CharB
35 'M', // CharM
36 0, // Size will be updated at runtime
37 { 0, 0 }, // Reserved
38 sizeof (BMP_IMAGE_HEADER), // ImageOffset
39 sizeof (BMP_IMAGE_HEADER) - OFFSET_OF (BMP_IMAGE_HEADER, HeaderSize), // HeaderSize
40 0, // PixelWidth will be updated at runtime
41 0, // PixelHeight will be updated at runtime
42 1, // Planes
43 24, // BitPerPixel
44 0, // CompressionType
45 0, // ImageSize will be updated at runtime
46 0, // XPixelsPerMeter
47 0, // YPixelsPerMeter
48 0, // NumberOfColors
49 0 // ImportantColors
50};
51
78RETURN_STATUS
79EFIAPI
81 IN VOID *BmpImage,
82 IN UINTN BmpImageSize,
84 IN OUT UINTN *GopBltSize,
85 OUT UINTN *PixelHeight,
86 OUT UINTN *PixelWidth
87 )
88{
89 UINT8 *Image;
90 UINT8 *ImageHeader;
91 BMP_IMAGE_HEADER *BmpHeader;
92 BMP_COLOR_MAP *BmpColorMap;
95 UINT32 BltBufferSize;
96 UINTN Index;
97 UINTN Height;
98 UINTN Width;
99 UINTN ImageIndex;
100 UINT32 DataSizePerLine;
101 BOOLEAN IsAllocated;
102 UINT32 ColorMapNum;
103 RETURN_STATUS Status;
104 UINT32 DataSize;
105 UINT32 Temp;
106
107 if ((BmpImage == NULL) || (GopBlt == NULL) || (GopBltSize == NULL)) {
109 }
110
111 if ((PixelHeight == NULL) || (PixelWidth == NULL)) {
113 }
114
115 if (BmpImageSize < sizeof (BMP_IMAGE_HEADER)) {
116 DEBUG ((DEBUG_ERROR, "TranslateBmpToGopBlt: BmpImageSize too small\n"));
117 return RETURN_UNSUPPORTED;
118 }
119
120 BmpHeader = (BMP_IMAGE_HEADER *)BmpImage;
121
122 if ((BmpHeader->CharB != 'B') || (BmpHeader->CharM != 'M')) {
123 DEBUG ((DEBUG_ERROR, "TranslateBmpToGopBlt: BmpHeader->Char fields incorrect\n"));
124 return RETURN_UNSUPPORTED;
125 }
126
127 //
128 // Doesn't support compress.
129 //
130 if (BmpHeader->CompressionType != 0) {
131 DEBUG ((DEBUG_ERROR, "TranslateBmpToGopBlt: Compression Type unsupported.\n"));
132 return RETURN_UNSUPPORTED;
133 }
134
135 if ((BmpHeader->PixelHeight == 0) || (BmpHeader->PixelWidth == 0)) {
136 DEBUG ((DEBUG_ERROR, "TranslateBmpToGopBlt: BmpHeader->PixelHeight or BmpHeader->PixelWidth is 0.\n"));
137 return RETURN_UNSUPPORTED;
138 }
139
140 //
141 // Only support BITMAPINFOHEADER format.
142 // BITMAPFILEHEADER + BITMAPINFOHEADER = BMP_IMAGE_HEADER
143 //
144 if (BmpHeader->HeaderSize != sizeof (BMP_IMAGE_HEADER) - OFFSET_OF (BMP_IMAGE_HEADER, HeaderSize)) {
145 DEBUG ((
146 DEBUG_ERROR,
147 "TranslateBmpToGopBlt: BmpHeader->Headership is not as expected. Headersize is 0x%x\n",
148 BmpHeader->HeaderSize
149 ));
150 return RETURN_UNSUPPORTED;
151 }
152
153 //
154 // The data size in each line must be 4 byte alignment.
155 //
156 Status = SafeUint32Mult (
157 BmpHeader->PixelWidth,
158 BmpHeader->BitPerPixel,
159 &DataSizePerLine
160 );
161 if (EFI_ERROR (Status)) {
162 DEBUG ((
163 DEBUG_ERROR,
164 "TranslateBmpToGopBlt: invalid BmpImage... PixelWidth:0x%x BitPerPixel:0x%x\n",
165 BmpHeader->PixelWidth,
166 BmpHeader->BitPerPixel
167 ));
168 return RETURN_UNSUPPORTED;
169 }
170
171 Status = SafeUint32Add (DataSizePerLine, 31, &DataSizePerLine);
172 if (EFI_ERROR (Status)) {
173 DEBUG ((
174 DEBUG_ERROR,
175 "TranslateBmpToGopBlt: invalid BmpImage... DataSizePerLine:0x%x\n",
176 DataSizePerLine
177 ));
178
179 return RETURN_UNSUPPORTED;
180 }
181
182 DataSizePerLine = (DataSizePerLine >> 3) &(~0x3);
183 Status = SafeUint32Mult (
184 DataSizePerLine,
185 BmpHeader->PixelHeight,
186 &BltBufferSize
187 );
188
189 if (EFI_ERROR (Status)) {
190 DEBUG ((
191 DEBUG_ERROR,
192 "TranslateBmpToGopBlt: invalid BmpImage... DataSizePerLine:0x%x PixelHeight:0x%x\n",
193 DataSizePerLine,
194 BmpHeader->PixelHeight
195 ));
196
197 return RETURN_UNSUPPORTED;
198 }
199
200 Status = SafeUint32Mult (
201 BmpHeader->PixelHeight,
202 DataSizePerLine,
203 &DataSize
204 );
205
206 if (EFI_ERROR (Status)) {
207 DEBUG ((
208 DEBUG_ERROR,
209 "TranslateBmpToGopBlt: invalid BmpImage... PixelHeight:0x%x DataSizePerLine:0x%x\n",
210 BmpHeader->PixelHeight,
211 DataSizePerLine
212 ));
213
214 return RETURN_UNSUPPORTED;
215 }
216
217 if ((BmpHeader->Size != BmpImageSize) ||
218 (BmpHeader->Size < BmpHeader->ImageOffset) ||
219 (BmpHeader->Size - BmpHeader->ImageOffset != DataSize))
220 {
221 DEBUG ((DEBUG_ERROR, "TranslateBmpToGopBlt: invalid BmpImage... \n"));
222 DEBUG ((DEBUG_ERROR, " BmpHeader->Size: 0x%x\n", BmpHeader->Size));
223 DEBUG ((DEBUG_ERROR, " BmpHeader->ImageOffset: 0x%x\n", BmpHeader->ImageOffset));
224 DEBUG ((DEBUG_ERROR, " BmpImageSize: 0x%lx\n", (UINTN)BmpImageSize));
225 DEBUG ((DEBUG_ERROR, " DataSize: 0x%lx\n", (UINTN)DataSize));
226
227 return RETURN_UNSUPPORTED;
228 }
229
230 //
231 // Calculate Color Map offset in the image.
232 //
233 Image = BmpImage;
234 BmpColorMap = (BMP_COLOR_MAP *)(Image + sizeof (BMP_IMAGE_HEADER));
235 if (BmpHeader->ImageOffset < sizeof (BMP_IMAGE_HEADER)) {
236 return RETURN_UNSUPPORTED;
237 }
238
239 if (BmpHeader->ImageOffset > sizeof (BMP_IMAGE_HEADER)) {
240 switch (BmpHeader->BitPerPixel) {
241 case 1:
242 ColorMapNum = 2;
243 break;
244 case 4:
245 ColorMapNum = 16;
246 break;
247 case 8:
248 ColorMapNum = 256;
249 break;
250 default:
251 ColorMapNum = 0;
252 break;
253 }
254
255 //
256 // BMP file may has padding data between the bmp header section and the
257 // bmp data section.
258 //
259 if (BmpHeader->ImageOffset - sizeof (BMP_IMAGE_HEADER) < sizeof (BMP_COLOR_MAP) * ColorMapNum) {
260 return RETURN_UNSUPPORTED;
261 }
262 }
263
264 //
265 // Calculate graphics image data address in the image
266 //
267 Image = ((UINT8 *)BmpImage) + BmpHeader->ImageOffset;
268 ImageHeader = Image;
269
270 //
271 // Calculate the BltBuffer needed size.
272 //
273 Status = SafeUint32Mult (
274 BmpHeader->PixelWidth,
275 BmpHeader->PixelHeight,
276 &BltBufferSize
277 );
278
279 if (EFI_ERROR (Status)) {
280 DEBUG ((
281 DEBUG_ERROR,
282 "TranslateBmpToGopBlt: invalid BltBuffer needed size... PixelWidth:0x%x PixelHeight:0x%x\n",
283 BmpHeader->PixelWidth,
284 BmpHeader->PixelHeight
285 ));
286
287 return RETURN_UNSUPPORTED;
288 }
289
290 Temp = BltBufferSize;
291 Status = SafeUint32Mult (
292 BltBufferSize,
294 &BltBufferSize
295 );
296
297 if (EFI_ERROR (Status)) {
298 DEBUG ((
299 DEBUG_ERROR,
300 "TranslateBmpToGopBlt: invalid BltBuffer needed size... PixelWidth x PixelHeight:0x%x struct size:0x%x\n",
301 Temp,
303 ));
304
305 return RETURN_UNSUPPORTED;
306 }
307
308 IsAllocated = FALSE;
309 if (*GopBlt == NULL) {
310 //
311 // GopBlt is not allocated by caller.
312 //
313 DEBUG ((DEBUG_INFO, "Bmp Support: Allocating 0x%X bytes of memory\n", BltBufferSize));
314 *GopBltSize = (UINTN)BltBufferSize;
315 *GopBlt = AllocatePool (*GopBltSize);
316 IsAllocated = TRUE;
317 if (*GopBlt == NULL) {
319 }
320 } else {
321 //
322 // GopBlt has been allocated by caller.
323 //
324 if (*GopBltSize < (UINTN)BltBufferSize) {
325 *GopBltSize = (UINTN)BltBufferSize;
327 }
328 }
329
330 *PixelWidth = BmpHeader->PixelWidth;
331 *PixelHeight = BmpHeader->PixelHeight;
332 DEBUG ((DEBUG_INFO, "BmpHeader->ImageOffset 0x%X\n", BmpHeader->ImageOffset));
333 DEBUG ((DEBUG_INFO, "BmpHeader->PixelWidth 0x%X\n", BmpHeader->PixelWidth));
334 DEBUG ((DEBUG_INFO, "BmpHeader->PixelHeight 0x%X\n", BmpHeader->PixelHeight));
335 DEBUG ((DEBUG_INFO, "BmpHeader->BitPerPixel 0x%X\n", BmpHeader->BitPerPixel));
336 DEBUG ((DEBUG_INFO, "BmpHeader->ImageSize 0x%X\n", BmpHeader->ImageSize));
337 DEBUG ((DEBUG_INFO, "BmpHeader->HeaderSize 0x%X\n", BmpHeader->HeaderSize));
338 DEBUG ((DEBUG_INFO, "BmpHeader->Size 0x%X\n", BmpHeader->Size));
339
340 //
341 // Translate image from BMP to Blt buffer format
342 //
343 BltBuffer = *GopBlt;
344 for (Height = 0; Height < BmpHeader->PixelHeight; Height++) {
345 Blt = &BltBuffer[(BmpHeader->PixelHeight - Height - 1) * BmpHeader->PixelWidth];
346 for (Width = 0; Width < BmpHeader->PixelWidth; Width++, Image++, Blt++) {
347 switch (BmpHeader->BitPerPixel) {
348 case 1:
349 //
350 // Translate 1-bit (2 colors) BMP to 24-bit color
351 //
352 for (Index = 0; Index < 8 && Width < BmpHeader->PixelWidth; Index++) {
353 Blt->Red = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Red;
354 Blt->Green = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Green;
355 Blt->Blue = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Blue;
356 Blt++;
357 Width++;
358 }
359
360 Blt--;
361 Width--;
362 break;
363
364 case 4:
365 //
366 // Translate 4-bit (16 colors) BMP Palette to 24-bit color
367 //
368 Index = (*Image) >> 4;
369 Blt->Red = BmpColorMap[Index].Red;
370 Blt->Green = BmpColorMap[Index].Green;
371 Blt->Blue = BmpColorMap[Index].Blue;
372 if (Width < (BmpHeader->PixelWidth - 1)) {
373 Blt++;
374 Width++;
375 Index = (*Image) & 0x0f;
376 Blt->Red = BmpColorMap[Index].Red;
377 Blt->Green = BmpColorMap[Index].Green;
378 Blt->Blue = BmpColorMap[Index].Blue;
379 }
380
381 break;
382
383 case 8:
384 //
385 // Translate 8-bit (256 colors) BMP Palette to 24-bit color
386 //
387 Blt->Red = BmpColorMap[*Image].Red;
388 Blt->Green = BmpColorMap[*Image].Green;
389 Blt->Blue = BmpColorMap[*Image].Blue;
390 break;
391
392 case 24:
393 //
394 // It is 24-bit BMP.
395 //
396 Blt->Blue = *Image++;
397 Blt->Green = *Image++;
398 Blt->Red = *Image;
399 break;
400
401 case 32:
402 //
403 // Conver 32 bit to 24bit bmp - just ignore the final byte of each pixel
404 Blt->Blue = *Image++;
405 Blt->Green = *Image++;
406 Blt->Red = *Image++;
407 break;
408
409 default:
410 //
411 // Other bit format BMP is not supported.
412 //
413 if (IsAllocated) {
414 FreePool (*GopBlt);
415 *GopBlt = NULL;
416 }
417
418 DEBUG ((DEBUG_ERROR, "Bmp Bit format not supported. 0x%X\n", BmpHeader->BitPerPixel));
419 return RETURN_UNSUPPORTED;
420 break;
421 }
422 }
423
424 ImageIndex = (UINTN)Image - (UINTN)ImageHeader;
425 if ((ImageIndex % 4) != 0) {
426 //
427 // Bmp Image starts each row on a 32-bit boundary!
428 //
429 Image = Image + (4 - (ImageIndex % 4));
430 }
431 }
432
433 return RETURN_SUCCESS;
434}
435
459RETURN_STATUS
460EFIAPI
463 IN UINT32 PixelHeight,
464 IN UINT32 PixelWidth,
465 IN OUT VOID **BmpImage,
466 IN OUT UINT32 *BmpImageSize
467 )
468{
469 RETURN_STATUS Status;
470 UINT32 PaddingSize;
471 UINT32 BmpSize;
472 BMP_IMAGE_HEADER *BmpImageHeader;
473 UINT8 *Image;
474 UINTN Col;
475 UINTN Row;
477
478 if ((GopBlt == NULL) || (BmpImage == NULL) || (BmpImageSize == NULL)) {
480 }
481
482 if ((PixelHeight == 0) || (PixelWidth == 0)) {
483 return RETURN_UNSUPPORTED;
484 }
485
486 //
487 // Allocate memory for BMP file.
488 //
489 PaddingSize = PixelWidth & 0x3;
490
491 //
492 // First check PixelWidth * 3 + PaddingSize doesn't overflow
493 //
494 Status = SafeUint32Mult (PixelWidth, 3, &BmpSize);
495 if (EFI_ERROR (Status)) {
496 DEBUG ((
497 DEBUG_ERROR,
498 "TranslateGopBltToBmp: GopBlt is too large. PixelHeight:0x%x PixelWidth:0x%x\n",
499 PixelHeight,
500 PixelWidth
501 ));
502 return RETURN_UNSUPPORTED;
503 }
504
505 Status = SafeUint32Add (BmpSize, PaddingSize, &BmpSize);
506 if (EFI_ERROR (Status)) {
507 DEBUG ((
508 DEBUG_ERROR,
509 "TranslateGopBltToBmp: GopBlt is too large. PixelHeight:0x%x PixelWidth:0x%x\n",
510 PixelHeight,
511 PixelWidth
512 ));
513 return RETURN_UNSUPPORTED;
514 }
515
516 //
517 // Second check (mLogoWidth * 3 + PaddingSize) * mLogoHeight + sizeof (BMP_IMAGE_HEADER) doesn't overflow
518 //
519 Status = SafeUint32Mult (BmpSize, PixelHeight, &BmpSize);
520 if (EFI_ERROR (Status)) {
521 DEBUG ((
522 DEBUG_ERROR,
523 "TranslateGopBltToBmp: GopBlt is too large. PixelHeight:0x%x PixelWidth:0x%x\n",
524 PixelHeight,
525 PixelWidth
526 ));
527 return RETURN_UNSUPPORTED;
528 }
529
530 Status = SafeUint32Add (BmpSize, sizeof (BMP_IMAGE_HEADER), &BmpSize);
531 if (EFI_ERROR (Status)) {
532 DEBUG ((
533 DEBUG_ERROR,
534 "TranslateGopBltToBmp: GopBlt is too large. PixelHeight:0x%x PixelWidth:0x%x\n",
535 PixelHeight,
536 PixelWidth
537 ));
538 return RETURN_UNSUPPORTED;
539 }
540
541 //
542 // The image should be stored in EfiBootServicesData, allowing the system to
543 // reclaim the memory
544 //
545 if (*BmpImage == NULL) {
546 *BmpImage = AllocateZeroPool (BmpSize);
547 if (*BmpImage == NULL) {
548 return EFI_OUT_OF_RESOURCES;
549 }
550
551 *BmpImageSize = BmpSize;
552 } else if (*BmpImageSize < BmpSize) {
553 *BmpImageSize = BmpSize;
555 }
556
557 BmpImageHeader = (BMP_IMAGE_HEADER *)*BmpImage;
558 CopyMem (BmpImageHeader, &mBmpImageHeaderTemplate, sizeof (BMP_IMAGE_HEADER));
559 BmpImageHeader->Size = *BmpImageSize;
560 BmpImageHeader->ImageSize = *BmpImageSize - sizeof (BMP_IMAGE_HEADER);
561 BmpImageHeader->PixelWidth = PixelWidth;
562 BmpImageHeader->PixelHeight = PixelHeight;
563
564 //
565 // Convert BLT buffer to BMP file.
566 //
567 Image = (UINT8 *)BmpImageHeader + sizeof (BMP_IMAGE_HEADER);
568 for (Row = 0; Row < PixelHeight; Row++) {
569 BltPixel = &GopBlt[(PixelHeight - Row - 1) * PixelWidth];
570
571 for (Col = 0; Col < PixelWidth; Col++) {
572 *Image++ = BltPixel->Blue;
573 *Image++ = BltPixel->Green;
574 *Image++ = BltPixel->Red;
575 BltPixel++;
576 }
577
578 //
579 // Padding for 4 byte alignment.
580 //
581 Image += PaddingSize;
582 }
583
584 return RETURN_SUCCESS;
585}
UINT64 UINTN
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
RETURN_STATUS EFIAPI TranslateBmpToGopBlt(IN VOID *BmpImage, IN UINTN BmpImageSize, IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **GopBlt, IN OUT UINTN *GopBltSize, OUT UINTN *PixelHeight, OUT UINTN *PixelWidth)
Definition: BmpSupportLib.c:80
RETURN_STATUS EFIAPI TranslateGopBltToBmp(IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *GopBlt, IN UINT32 PixelHeight, IN UINT32 PixelWidth, IN OUT VOID **BmpImage, IN OUT UINT32 *BmpImageSize)
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
VOID EFIAPI FreePool(IN VOID *Buffer)
#define NULL
Definition: Base.h:319
#define RETURN_BUFFER_TOO_SMALL
Definition: Base.h:1093
#define RETURN_UNSUPPORTED
Definition: Base.h:1081
#define RETURN_OUT_OF_RESOURCES
Definition: Base.h:1114
#define RETURN_SUCCESS
Definition: Base.h:1066
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OFFSET_OF(TYPE, Field)
Definition: Base.h:758
#define OUT
Definition: Base.h:284
#define RETURN_INVALID_PARAMETER
Definition: Base.h:1076
#define DEBUG(Expression)
Definition: DebugLib.h:434
VOID *EFIAPI AllocatePool(IN UINTN AllocationSize)
RETURN_STATUS EFIAPI SafeUint32Add(IN UINT32 Augend, IN UINT32 Addend, OUT UINT32 *Result)
Definition: SafeIntLib.c:2927
RETURN_STATUS EFIAPI SafeUint32Mult(IN UINT32 Multiplicand, IN UINT32 Multiplier, OUT UINT32 *Result)
Definition: SafeIntLib.c:3283
UINT16 BitPerPixel
1, 4, 8, or 24
Definition: Bmp.h:31
UINT32 ImageSize
Compressed image size in bytes.
Definition: Bmp.h:33