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