]> code.delx.au - refind/blob - libeg/image.c
8b6078d5074c19444b78648431969041ffe6bc08
[refind] / libeg / image.c
1 /*
2 * libeg/image.c
3 * Image handling functions
4 *
5 * Copyright (c) 2006 Christoph Pfisterer
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * * Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the
18 * distribution.
19 *
20 * * Neither the name of Christoph Pfisterer nor the names of the
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 */
36
37 #include "libegint.h"
38 #include "../refind/global.h"
39 #include "../refind/lib.h"
40 #include "../refind/screen.h"
41 #include "../include/refit_call_wrapper.h"
42 #include "lodepng.h"
43
44 #define MAX_FILE_SIZE (1024*1024*1024)
45
46 #ifndef __MAKEWITH_GNUEFI
47 #define LibLocateHandle gBS->LocateHandleBuffer
48 #define LibOpenRoot EfiLibOpenRoot
49 #endif
50
51 //
52 // Basic image handling
53 //
54
55 EG_IMAGE * egCreateImage(IN UINTN Width, IN UINTN Height, IN BOOLEAN HasAlpha)
56 {
57 EG_IMAGE *NewImage;
58
59 NewImage = (EG_IMAGE *) AllocatePool(sizeof(EG_IMAGE));
60 if (NewImage == NULL)
61 return NULL;
62 NewImage->PixelData = (EG_PIXEL *) AllocatePool(Width * Height * sizeof(EG_PIXEL));
63 if (NewImage->PixelData == NULL) {
64 FreePool(NewImage);
65 return NULL;
66 }
67
68 NewImage->Width = Width;
69 NewImage->Height = Height;
70 NewImage->HasAlpha = HasAlpha;
71 return NewImage;
72 }
73
74 EG_IMAGE * egCreateFilledImage(IN UINTN Width, IN UINTN Height, IN BOOLEAN HasAlpha, IN EG_PIXEL *Color)
75 {
76 EG_IMAGE *NewImage;
77
78 NewImage = egCreateImage(Width, Height, HasAlpha);
79 if (NewImage == NULL)
80 return NULL;
81
82 egFillImage(NewImage, Color);
83 return NewImage;
84 }
85
86 EG_IMAGE * egCopyImage(IN EG_IMAGE *Image)
87 {
88 EG_IMAGE *NewImage = NULL;
89
90 if (Image != NULL)
91 NewImage = egCreateImage(Image->Width, Image->Height, Image->HasAlpha);
92 if (NewImage == NULL)
93 return NULL;
94
95 CopyMem(NewImage->PixelData, Image->PixelData, Image->Width * Image->Height * sizeof(EG_PIXEL));
96 return NewImage;
97 }
98
99 // Returns a smaller image composed of the specified crop area from the larger area.
100 // If the specified area is larger than is in the original, returns NULL.
101 EG_IMAGE * egCropImage(IN EG_IMAGE *Image, IN UINTN StartX, IN UINTN StartY, IN UINTN Width, IN UINTN Height) {
102 EG_IMAGE *NewImage = NULL;
103 UINTN x, y;
104
105 if (((StartX + Width) > Image->Width) || ((StartY + Height) > Image->Height))
106 return NULL;
107
108 NewImage = egCreateImage(Width, Height, Image->HasAlpha);
109 if (NewImage == NULL)
110 return NULL;
111
112 for (y = 0; y < Height; y++) {
113 for (x = 0; x < Width; x++) {
114 NewImage->PixelData[y * NewImage->Width + x] = Image->PixelData[(y + StartY) * Image->Width + x + StartX];
115 }
116 }
117 return NewImage;
118 } // EG_IMAGE * egCropImage()
119
120 VOID egFreeImage(IN EG_IMAGE *Image)
121 {
122 if (Image != NULL) {
123 if (Image->PixelData != NULL)
124 FreePool(Image->PixelData);
125 FreePool(Image);
126 }
127 }
128
129 //
130 // Basic file operations
131 //
132
133 EFI_STATUS egLoadFile(IN EFI_FILE* BaseDir, IN CHAR16 *FileName, OUT UINT8 **FileData, OUT UINTN *FileDataLength)
134 {
135 EFI_STATUS Status;
136 EFI_FILE_HANDLE FileHandle;
137 EFI_FILE_INFO *FileInfo;
138 UINT64 ReadSize;
139 UINTN BufferSize;
140 UINT8 *Buffer;
141
142 Status = refit_call5_wrapper(BaseDir->Open, BaseDir, &FileHandle, FileName, EFI_FILE_MODE_READ, 0);
143 if (EFI_ERROR(Status)) {
144 return Status;
145 }
146
147 FileInfo = LibFileInfo(FileHandle);
148 if (FileInfo == NULL) {
149 refit_call1_wrapper(FileHandle->Close, FileHandle);
150 return EFI_NOT_FOUND;
151 }
152 ReadSize = FileInfo->FileSize;
153 if (ReadSize > MAX_FILE_SIZE)
154 ReadSize = MAX_FILE_SIZE;
155 FreePool(FileInfo);
156
157 BufferSize = (UINTN)ReadSize; // was limited to 1 GB above, so this is safe
158 Buffer = (UINT8 *) AllocatePool(BufferSize);
159 if (Buffer == NULL) {
160 refit_call1_wrapper(FileHandle->Close, FileHandle);
161 return EFI_OUT_OF_RESOURCES;
162 }
163
164 Status = refit_call3_wrapper(FileHandle->Read, FileHandle, &BufferSize, Buffer);
165 refit_call1_wrapper(FileHandle->Close, FileHandle);
166 if (EFI_ERROR(Status)) {
167 FreePool(Buffer);
168 return Status;
169 }
170
171 *FileData = Buffer;
172 *FileDataLength = BufferSize;
173 return EFI_SUCCESS;
174 }
175
176 static EFI_GUID ESPGuid = { 0xc12a7328, 0xf81f, 0x11d2, { 0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b } };
177
178 EFI_STATUS egFindESP(OUT EFI_FILE_HANDLE *RootDir)
179 {
180 EFI_STATUS Status;
181 UINTN HandleCount = 0;
182 EFI_HANDLE *Handles;
183
184 Status = LibLocateHandle(ByProtocol, &ESPGuid, NULL, &HandleCount, &Handles);
185 if (!EFI_ERROR(Status) && HandleCount > 0) {
186 *RootDir = LibOpenRoot(Handles[0]);
187 if (*RootDir == NULL)
188 Status = EFI_NOT_FOUND;
189 FreePool(Handles);
190 }
191 return Status;
192 }
193
194 EFI_STATUS egSaveFile(IN EFI_FILE* BaseDir OPTIONAL, IN CHAR16 *FileName,
195 IN UINT8 *FileData, IN UINTN FileDataLength)
196 {
197 EFI_STATUS Status;
198 EFI_FILE_HANDLE FileHandle;
199 UINTN BufferSize;
200
201 if (BaseDir == NULL) {
202 Status = egFindESP(&BaseDir);
203 if (EFI_ERROR(Status))
204 return Status;
205 }
206
207 Status = refit_call5_wrapper(BaseDir->Open, BaseDir, &FileHandle, FileName,
208 EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0);
209 if (EFI_ERROR(Status))
210 return Status;
211
212 BufferSize = FileDataLength;
213 Status = refit_call3_wrapper(FileHandle->Write, FileHandle, &BufferSize, FileData);
214 refit_call1_wrapper(FileHandle->Close, FileHandle);
215
216 return Status;
217 }
218
219 //
220 // Loading images from files and embedded data
221 //
222
223 // Decode the specified image data. The IconSize parameter is relevant only
224 // for ICNS, for which it selects which ICNS sub-image is decoded.
225 // Returns a pointer to the resulting EG_IMAGE or NULL if decoding failed.
226 static EG_IMAGE * egDecodeAny(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN IconSize, IN BOOLEAN WantAlpha)
227 {
228 EG_IMAGE *NewImage = NULL;
229
230 NewImage = egDecodeICNS(FileData, FileDataLength, IconSize, WantAlpha);
231 if (NewImage == NULL)
232 NewImage = egDecodePNG(FileData, FileDataLength, IconSize, WantAlpha);
233 if (NewImage == NULL)
234 NewImage = egDecodeBMP(FileData, FileDataLength, IconSize, WantAlpha);
235
236 return NewImage;
237 }
238
239 EG_IMAGE * egLoadImage(IN EFI_FILE* BaseDir, IN CHAR16 *FileName, IN BOOLEAN WantAlpha)
240 {
241 EFI_STATUS Status;
242 UINT8 *FileData;
243 UINTN FileDataLength;
244 EG_IMAGE *NewImage;
245
246 if (BaseDir == NULL || FileName == NULL)
247 return NULL;
248
249 // load file
250 Status = egLoadFile(BaseDir, FileName, &FileData, &FileDataLength);
251 if (EFI_ERROR(Status))
252 return NULL;
253
254 // decode it
255 NewImage = egDecodeAny(FileData, FileDataLength, 128, WantAlpha);
256 FreePool(FileData);
257
258 return NewImage;
259 }
260
261 // Load an icon from (BaseDir)/Path, extracting the icon of size IconSize x IconSize.
262 // Returns a pointer to the image data, or NULL if the icon could not be loaded.
263 EG_IMAGE * egLoadIcon(IN EFI_FILE* BaseDir, IN CHAR16 *Path, IN UINTN IconSize)
264 {
265 EFI_STATUS Status;
266 UINT8 *FileData;
267 UINTN FileDataLength;
268 EG_IMAGE *NewImage;
269
270 if (BaseDir == NULL || Path == NULL)
271 return NULL;
272
273 // load file
274 Status = egLoadFile(BaseDir, Path, &FileData, &FileDataLength);
275 if (EFI_ERROR(Status))
276 return NULL;
277
278 // decode it
279 NewImage = egDecodeAny(FileData, FileDataLength, IconSize, TRUE);
280 FreePool(FileData);
281 if ((NewImage->Width != IconSize) || (NewImage->Height != IconSize)) {
282 Print(L"Warning: Attempt to load icon of the wrong size from '%s'\n", Path);
283 MyFreePool(NewImage);
284 NewImage = NULL;
285 }
286
287 return NewImage;
288 } // EG_IMAGE *egLoadIcon()
289
290 // Returns an icon of any type from the specified subdirectory using the specified
291 // base name. All directory references are relative to BaseDir. For instance, if
292 // SubdirName is "myicons" and BaseName is "os_linux", this function will return
293 // an image based on "myicons/os_linux.icns" or "myicons/os_linux.png", in that
294 // order of preference. Returns NULL if no such file is a valid icon file.
295 EG_IMAGE * egLoadIconAnyType(IN EFI_FILE *BaseDir, IN CHAR16 *SubdirName, IN CHAR16 *BaseName, IN UINTN IconSize) {
296 EG_IMAGE *Image = NULL;
297 CHAR16 *Extension;
298 CHAR16 FileName[256];
299 UINTN i = 0;
300
301 while (((Extension = FindCommaDelimited(ICON_EXTENSIONS, i++)) != NULL) && (Image == NULL)) {
302 SPrint(FileName, 255, L"%s\\%s.%s", SubdirName, BaseName, Extension);
303 Image = egLoadIcon(BaseDir, FileName, IconSize);
304 MyFreePool(Extension);
305 } // while()
306
307 return Image;
308 } // EG_IMAGE *egLoadIconAnyType()
309
310 // Returns an icon with any extension in ICON_EXTENSIONS from either the directory
311 // specified by GlobalConfig.IconsDir or DEFAULT_ICONS_DIR. The input BaseName
312 // should be the icon name without an extension. For instance, if BaseName is
313 // os_linux, GlobalConfig.IconsDir is myicons, DEFAULT_ICONS_DIR is icons, and
314 // ICON_EXTENSIONS is "icns,png", this function will return myicons/os_linux.icns,
315 // myicons/os_linux.png, icons/os_linux.icns, or icons/os_linux.png, in that
316 // order of preference. Returns NULL if no such icon can be found. All file
317 // references are relative to SelfDir.
318 EG_IMAGE * egFindIcon(IN CHAR16 *BaseName, IN UINTN IconSize) {
319 EG_IMAGE *Image = NULL;
320
321 if (GlobalConfig.IconsDir != NULL) {
322 Image = egLoadIconAnyType(SelfDir, GlobalConfig.IconsDir, BaseName, IconSize);
323 }
324
325 if (Image == NULL) {
326 Image = egLoadIconAnyType(SelfDir, DEFAULT_ICONS_DIR, BaseName, IconSize);
327 }
328
329 return Image;
330 } // EG_IMAGE * egFindIcon()
331
332 EG_IMAGE * egPrepareEmbeddedImage(IN EG_EMBEDDED_IMAGE *EmbeddedImage, IN BOOLEAN WantAlpha)
333 {
334 EG_IMAGE *NewImage;
335 UINT8 *CompData;
336 UINTN CompLen;
337 UINTN PixelCount;
338
339 // sanity check
340 if (EmbeddedImage->PixelMode > EG_MAX_EIPIXELMODE ||
341 (EmbeddedImage->CompressMode != EG_EICOMPMODE_NONE && EmbeddedImage->CompressMode != EG_EICOMPMODE_RLE))
342 return NULL;
343
344 // allocate image structure and pixel buffer
345 NewImage = egCreateImage(EmbeddedImage->Width, EmbeddedImage->Height, WantAlpha);
346 if (NewImage == NULL)
347 return NULL;
348
349 CompData = (UINT8 *)EmbeddedImage->Data; // drop const
350 CompLen = EmbeddedImage->DataLength;
351 PixelCount = EmbeddedImage->Width * EmbeddedImage->Height;
352
353 // FUTURE: for EG_EICOMPMODE_EFICOMPRESS, decompress whole data block here
354
355 if (EmbeddedImage->PixelMode == EG_EIPIXELMODE_GRAY ||
356 EmbeddedImage->PixelMode == EG_EIPIXELMODE_GRAY_ALPHA) {
357
358 // copy grayscale plane and expand
359 if (EmbeddedImage->CompressMode == EG_EICOMPMODE_RLE) {
360 egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, r), PixelCount);
361 } else {
362 egInsertPlane(CompData, PLPTR(NewImage, r), PixelCount);
363 CompData += PixelCount;
364 }
365 egCopyPlane(PLPTR(NewImage, r), PLPTR(NewImage, g), PixelCount);
366 egCopyPlane(PLPTR(NewImage, r), PLPTR(NewImage, b), PixelCount);
367
368 } else if (EmbeddedImage->PixelMode == EG_EIPIXELMODE_COLOR ||
369 EmbeddedImage->PixelMode == EG_EIPIXELMODE_COLOR_ALPHA) {
370
371 // copy color planes
372 if (EmbeddedImage->CompressMode == EG_EICOMPMODE_RLE) {
373 egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, r), PixelCount);
374 egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, g), PixelCount);
375 egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, b), PixelCount);
376 } else {
377 egInsertPlane(CompData, PLPTR(NewImage, r), PixelCount);
378 CompData += PixelCount;
379 egInsertPlane(CompData, PLPTR(NewImage, g), PixelCount);
380 CompData += PixelCount;
381 egInsertPlane(CompData, PLPTR(NewImage, b), PixelCount);
382 CompData += PixelCount;
383 }
384
385 } else {
386
387 // set color planes to black
388 egSetPlane(PLPTR(NewImage, r), 0, PixelCount);
389 egSetPlane(PLPTR(NewImage, g), 0, PixelCount);
390 egSetPlane(PLPTR(NewImage, b), 0, PixelCount);
391
392 }
393
394 if (WantAlpha && (EmbeddedImage->PixelMode == EG_EIPIXELMODE_GRAY_ALPHA ||
395 EmbeddedImage->PixelMode == EG_EIPIXELMODE_COLOR_ALPHA ||
396 EmbeddedImage->PixelMode == EG_EIPIXELMODE_ALPHA)) {
397
398 // copy alpha plane
399 if (EmbeddedImage->CompressMode == EG_EICOMPMODE_RLE) {
400 egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, a), PixelCount);
401 } else {
402 egInsertPlane(CompData, PLPTR(NewImage, a), PixelCount);
403 CompData += PixelCount;
404 }
405
406 } else {
407 egSetPlane(PLPTR(NewImage, a), WantAlpha ? 255 : 0, PixelCount);
408 }
409
410 return NewImage;
411 }
412
413 //
414 // Compositing
415 //
416
417 VOID egRestrictImageArea(IN EG_IMAGE *Image,
418 IN UINTN AreaPosX, IN UINTN AreaPosY,
419 IN OUT UINTN *AreaWidth, IN OUT UINTN *AreaHeight)
420 {
421 if (AreaPosX >= Image->Width || AreaPosY >= Image->Height) {
422 // out of bounds, operation has no effect
423 *AreaWidth = 0;
424 *AreaHeight = 0;
425 } else {
426 // calculate affected area
427 if (*AreaWidth > Image->Width - AreaPosX)
428 *AreaWidth = Image->Width - AreaPosX;
429 if (*AreaHeight > Image->Height - AreaPosY)
430 *AreaHeight = Image->Height - AreaPosY;
431 }
432 }
433
434 VOID egFillImage(IN OUT EG_IMAGE *CompImage, IN EG_PIXEL *Color)
435 {
436 UINTN i;
437 EG_PIXEL FillColor;
438 EG_PIXEL *PixelPtr;
439
440 FillColor = *Color;
441 if (!CompImage->HasAlpha)
442 FillColor.a = 0;
443
444 PixelPtr = CompImage->PixelData;
445 for (i = 0; i < CompImage->Width * CompImage->Height; i++, PixelPtr++)
446 *PixelPtr = FillColor;
447 }
448
449 VOID egFillImageArea(IN OUT EG_IMAGE *CompImage,
450 IN UINTN AreaPosX, IN UINTN AreaPosY,
451 IN UINTN AreaWidth, IN UINTN AreaHeight,
452 IN EG_PIXEL *Color)
453 {
454 UINTN x, y;
455 EG_PIXEL FillColor;
456 EG_PIXEL *PixelPtr;
457 EG_PIXEL *PixelBasePtr;
458
459 egRestrictImageArea(CompImage, AreaPosX, AreaPosY, &AreaWidth, &AreaHeight);
460
461 if (AreaWidth > 0) {
462 FillColor = *Color;
463 if (!CompImage->HasAlpha)
464 FillColor.a = 0;
465
466 PixelBasePtr = CompImage->PixelData + AreaPosY * CompImage->Width + AreaPosX;
467 for (y = 0; y < AreaHeight; y++) {
468 PixelPtr = PixelBasePtr;
469 for (x = 0; x < AreaWidth; x++, PixelPtr++)
470 *PixelPtr = FillColor;
471 PixelBasePtr += CompImage->Width;
472 }
473 }
474 }
475
476 VOID egRawCopy(IN OUT EG_PIXEL *CompBasePtr, IN EG_PIXEL *TopBasePtr,
477 IN UINTN Width, IN UINTN Height,
478 IN UINTN CompLineOffset, IN UINTN TopLineOffset)
479 {
480 UINTN x, y;
481 EG_PIXEL *TopPtr, *CompPtr;
482
483 for (y = 0; y < Height; y++) {
484 TopPtr = TopBasePtr;
485 CompPtr = CompBasePtr;
486 for (x = 0; x < Width; x++) {
487 *CompPtr = *TopPtr;
488 TopPtr++, CompPtr++;
489 }
490 TopBasePtr += TopLineOffset;
491 CompBasePtr += CompLineOffset;
492 }
493 }
494
495 VOID egRawCompose(IN OUT EG_PIXEL *CompBasePtr, IN EG_PIXEL *TopBasePtr,
496 IN UINTN Width, IN UINTN Height,
497 IN UINTN CompLineOffset, IN UINTN TopLineOffset)
498 {
499 UINTN x, y;
500 EG_PIXEL *TopPtr, *CompPtr;
501 UINTN Alpha;
502 UINTN RevAlpha;
503 UINTN Temp;
504
505 for (y = 0; y < Height; y++) {
506 TopPtr = TopBasePtr;
507 CompPtr = CompBasePtr;
508 for (x = 0; x < Width; x++) {
509 Alpha = TopPtr->a;
510 RevAlpha = 255 - Alpha;
511 Temp = (UINTN)CompPtr->b * RevAlpha + (UINTN)TopPtr->b * Alpha + 0x80;
512 CompPtr->b = (Temp + (Temp >> 8)) >> 8;
513 Temp = (UINTN)CompPtr->g * RevAlpha + (UINTN)TopPtr->g * Alpha + 0x80;
514 CompPtr->g = (Temp + (Temp >> 8)) >> 8;
515 Temp = (UINTN)CompPtr->r * RevAlpha + (UINTN)TopPtr->r * Alpha + 0x80;
516 CompPtr->r = (Temp + (Temp >> 8)) >> 8;
517 /*
518 CompPtr->b = ((UINTN)CompPtr->b * RevAlpha + (UINTN)TopPtr->b * Alpha) / 255;
519 CompPtr->g = ((UINTN)CompPtr->g * RevAlpha + (UINTN)TopPtr->g * Alpha) / 255;
520 CompPtr->r = ((UINTN)CompPtr->r * RevAlpha + (UINTN)TopPtr->r * Alpha) / 255;
521 */
522 TopPtr++, CompPtr++;
523 }
524 TopBasePtr += TopLineOffset;
525 CompBasePtr += CompLineOffset;
526 }
527 }
528
529 VOID egComposeImage(IN OUT EG_IMAGE *CompImage, IN EG_IMAGE *TopImage, IN UINTN PosX, IN UINTN PosY)
530 {
531 UINTN CompWidth, CompHeight;
532
533 CompWidth = TopImage->Width;
534 CompHeight = TopImage->Height;
535 egRestrictImageArea(CompImage, PosX, PosY, &CompWidth, &CompHeight);
536
537 // compose
538 if (CompWidth > 0) {
539 if (TopImage->HasAlpha) {
540 egRawCompose(CompImage->PixelData + PosY * CompImage->Width + PosX, TopImage->PixelData,
541 CompWidth, CompHeight, CompImage->Width, TopImage->Width);
542 } else {
543 egRawCopy(CompImage->PixelData + PosY * CompImage->Width + PosX, TopImage->PixelData,
544 CompWidth, CompHeight, CompImage->Width, TopImage->Width);
545 }
546 }
547 } /* VOID egComposeImage() */
548
549 EG_IMAGE * egEnsureImageSize(IN EG_IMAGE *Image, IN UINTN Width, IN UINTN Height, IN EG_PIXEL *Color)
550 {
551 EG_IMAGE *NewImage;
552
553 if (Image == NULL)
554 return NULL;
555 if (Image->Width == Width && Image->Height == Height)
556 return Image;
557
558 NewImage = egCreateFilledImage(Width, Height, Image->HasAlpha, Color);
559 if (NewImage == NULL) {
560 egFreeImage(Image);
561 return NULL;
562 }
563 Image->HasAlpha = FALSE;
564 egComposeImage(NewImage, Image, 0, 0);
565 egFreeImage(Image);
566
567 return NewImage;
568 }
569
570 //
571 // misc internal functions
572 //
573
574 VOID egInsertPlane(IN UINT8 *SrcDataPtr, IN UINT8 *DestPlanePtr, IN UINTN PixelCount)
575 {
576 UINTN i;
577
578 for (i = 0; i < PixelCount; i++) {
579 *DestPlanePtr = *SrcDataPtr++;
580 DestPlanePtr += 4;
581 }
582 }
583
584 VOID egSetPlane(IN UINT8 *DestPlanePtr, IN UINT8 Value, IN UINTN PixelCount)
585 {
586 UINTN i;
587
588 for (i = 0; i < PixelCount; i++) {
589 *DestPlanePtr = Value;
590 DestPlanePtr += 4;
591 }
592 }
593
594 VOID egCopyPlane(IN UINT8 *SrcPlanePtr, IN UINT8 *DestPlanePtr, IN UINTN PixelCount)
595 {
596 UINTN i;
597
598 for (i = 0; i < PixelCount; i++) {
599 *DestPlanePtr = *SrcPlanePtr;
600 DestPlanePtr += 4, SrcPlanePtr += 4;
601 }
602 }
603
604 /* EOF */