]> code.delx.au - refind/blob - libeg/image.c
New small_icon_size and big_icon_size tokens for refind.conf.
[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 egFreeImage(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 // The following function implements a bilinear image scaling algorithm, based on
129 // code presented at http://tech-algorithm.com/articles/bilinear-image-scaling/.
130 // Resize an image; returns pointer to resized image if successful, NULL otherwise.
131 // Calling function is responsible for freeing allocated memory.
132 EG_IMAGE * egScaleImage(IN EG_IMAGE *Image, IN UINTN NewWidth, IN UINTN NewHeight) {
133 EG_IMAGE *NewImage = NULL;
134 EG_PIXEL a, b, c, d;
135 UINTN x, y, Index ;
136 UINTN i, j;
137 UINTN Offset = 0;
138 float x_ratio, y_ratio, x_diff, y_diff;
139
140 if ((Image == NULL) || (Image->Height == 0) || (Image->Width == 0) || (NewWidth == 0) || (NewHeight == 0))
141 return NULL;
142
143 if ((Image->Width == NewWidth) && (Image->Height == NewHeight))
144 return (egCopyImage(Image));
145
146 NewImage = egCreateImage(NewWidth, NewHeight, Image->HasAlpha);
147 if (NewImage == NULL)
148 return NULL;
149
150 x_ratio = ((float)(Image->Width - 1)) / NewWidth;
151 y_ratio = ((float)(Image->Height - 1)) / NewHeight;
152
153 for (i = 0; i < NewHeight; i++) {
154 for (j = 0; j < NewWidth; j++) {
155 x = (UINTN)(x_ratio * j);
156 y = (UINTN)(y_ratio * i);
157 x_diff = (x_ratio * j) - x;
158 y_diff = (y_ratio * i) - y;
159 Index = ((y * Image->Width) + x);
160 a = Image->PixelData[Index];
161 b = Image->PixelData[Index + 1];
162 c = Image->PixelData[Index + Image->Width];
163 d = Image->PixelData[Index + Image->Width + 1];
164
165 // blue element
166 // Yb = Ab(1-Image->Width)(1-Image->Height) + Bb(Image->Width)(1-Image->Height) + Cb(Image->Height)(1-Image->Width) + Db(wh)
167 NewImage->PixelData[Offset].b = (a.b)*(1-x_diff)*(1-y_diff) + (b.b)*(x_diff)*(1-y_diff) +
168 (c.b)*(y_diff)*(1-x_diff) + (d.b)*(x_diff*y_diff);
169
170 // green element
171 // Yg = Ag(1-Image->Width)(1-Image->Height) + Bg(Image->Width)(1-Image->Height) + Cg(Image->Height)(1-Image->Width) + Dg(wh)
172 NewImage->PixelData[Offset].g = (a.g)*(1-x_diff)*(1-y_diff) + (b.g)*(x_diff)*(1-y_diff) +
173 (c.g)*(y_diff)*(1-x_diff) + (d.g)*(x_diff*y_diff);
174
175 // red element
176 // Yr = Ar(1-Image->Width)(1-Image->Height) + Br(Image->Width)(1-Image->Height) + Cr(Image->Height)(1-Image->Width) + Dr(wh)
177 NewImage->PixelData[Offset].r = (a.r)*(1-x_diff)*(1-y_diff) + (b.r)*(x_diff)*(1-y_diff) +
178 (c.r)*(y_diff)*(1-x_diff) + (d.r)*(x_diff*y_diff);
179
180 // alpha element
181 NewImage->PixelData[Offset++].a = (a.a)*(1-x_diff)*(1-y_diff) + (b.a)*(x_diff)*(1-y_diff) +
182 (c.a)*(y_diff)*(1-x_diff) + (d.a)*(x_diff*y_diff);
183
184 } // for (j...)
185 } // for (i...)
186 return NewImage;
187 } // EG_IMAGE * egScaleImage()
188
189 VOID egFreeImage(IN EG_IMAGE *Image)
190 {
191 if (Image != NULL) {
192 if (Image->PixelData != NULL)
193 FreePool(Image->PixelData);
194 FreePool(Image);
195 }
196 }
197
198 //
199 // Basic file operations
200 //
201
202 EFI_STATUS egLoadFile(IN EFI_FILE* BaseDir, IN CHAR16 *FileName, OUT UINT8 **FileData, OUT UINTN *FileDataLength)
203 {
204 EFI_STATUS Status;
205 EFI_FILE_HANDLE FileHandle;
206 EFI_FILE_INFO *FileInfo;
207 UINT64 ReadSize;
208 UINTN BufferSize;
209 UINT8 *Buffer;
210
211 Status = refit_call5_wrapper(BaseDir->Open, BaseDir, &FileHandle, FileName, EFI_FILE_MODE_READ, 0);
212 if (EFI_ERROR(Status)) {
213 return Status;
214 }
215
216 FileInfo = LibFileInfo(FileHandle);
217 if (FileInfo == NULL) {
218 refit_call1_wrapper(FileHandle->Close, FileHandle);
219 return EFI_NOT_FOUND;
220 }
221 ReadSize = FileInfo->FileSize;
222 if (ReadSize > MAX_FILE_SIZE)
223 ReadSize = MAX_FILE_SIZE;
224 FreePool(FileInfo);
225
226 BufferSize = (UINTN)ReadSize; // was limited to 1 GB above, so this is safe
227 Buffer = (UINT8 *) AllocatePool(BufferSize);
228 if (Buffer == NULL) {
229 refit_call1_wrapper(FileHandle->Close, FileHandle);
230 return EFI_OUT_OF_RESOURCES;
231 }
232
233 Status = refit_call3_wrapper(FileHandle->Read, FileHandle, &BufferSize, Buffer);
234 refit_call1_wrapper(FileHandle->Close, FileHandle);
235 if (EFI_ERROR(Status)) {
236 FreePool(Buffer);
237 return Status;
238 }
239
240 *FileData = Buffer;
241 *FileDataLength = BufferSize;
242 return EFI_SUCCESS;
243 }
244
245 static EFI_GUID ESPGuid = { 0xc12a7328, 0xf81f, 0x11d2, { 0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b } };
246
247 EFI_STATUS egFindESP(OUT EFI_FILE_HANDLE *RootDir)
248 {
249 EFI_STATUS Status;
250 UINTN HandleCount = 0;
251 EFI_HANDLE *Handles;
252
253 Status = LibLocateHandle(ByProtocol, &ESPGuid, NULL, &HandleCount, &Handles);
254 if (!EFI_ERROR(Status) && HandleCount > 0) {
255 *RootDir = LibOpenRoot(Handles[0]);
256 if (*RootDir == NULL)
257 Status = EFI_NOT_FOUND;
258 FreePool(Handles);
259 }
260 return Status;
261 }
262
263 EFI_STATUS egSaveFile(IN EFI_FILE* BaseDir OPTIONAL, IN CHAR16 *FileName,
264 IN UINT8 *FileData, IN UINTN FileDataLength)
265 {
266 EFI_STATUS Status;
267 EFI_FILE_HANDLE FileHandle;
268 UINTN BufferSize;
269
270 if (BaseDir == NULL) {
271 Status = egFindESP(&BaseDir);
272 if (EFI_ERROR(Status))
273 return Status;
274 }
275
276 Status = refit_call5_wrapper(BaseDir->Open, BaseDir, &FileHandle, FileName,
277 EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0);
278 if (EFI_ERROR(Status))
279 return Status;
280
281 BufferSize = FileDataLength;
282 Status = refit_call3_wrapper(FileHandle->Write, FileHandle, &BufferSize, FileData);
283 refit_call1_wrapper(FileHandle->Close, FileHandle);
284
285 return Status;
286 }
287
288 //
289 // Loading images from files and embedded data
290 //
291
292 // Decode the specified image data. The IconSize parameter is relevant only
293 // for ICNS, for which it selects which ICNS sub-image is decoded.
294 // Returns a pointer to the resulting EG_IMAGE or NULL if decoding failed.
295 static EG_IMAGE * egDecodeAny(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN IconSize, IN BOOLEAN WantAlpha)
296 {
297 EG_IMAGE *NewImage = NULL;
298
299 NewImage = egDecodeICNS(FileData, FileDataLength, IconSize, WantAlpha);
300 if (NewImage == NULL)
301 NewImage = egDecodePNG(FileData, FileDataLength, IconSize, WantAlpha);
302 if (NewImage == NULL)
303 NewImage = egDecodeBMP(FileData, FileDataLength, IconSize, WantAlpha);
304
305 return NewImage;
306 }
307
308 EG_IMAGE * egLoadImage(IN EFI_FILE* BaseDir, IN CHAR16 *FileName, IN BOOLEAN WantAlpha)
309 {
310 EFI_STATUS Status;
311 UINT8 *FileData;
312 UINTN FileDataLength;
313 EG_IMAGE *NewImage;
314
315 if (BaseDir == NULL || FileName == NULL)
316 return NULL;
317
318 // load file
319 Status = egLoadFile(BaseDir, FileName, &FileData, &FileDataLength);
320 if (EFI_ERROR(Status))
321 return NULL;
322
323 // decode it
324 NewImage = egDecodeAny(FileData, FileDataLength, 128 /* arbitrary value */, WantAlpha);
325 FreePool(FileData);
326
327 return NewImage;
328 }
329
330 // Load an icon from (BaseDir)/Path, extracting the icon of size IconSize x IconSize.
331 // Returns a pointer to the image data, or NULL if the icon could not be loaded.
332 EG_IMAGE * egLoadIcon(IN EFI_FILE* BaseDir, IN CHAR16 *Path, IN UINTN IconSize)
333 {
334 EFI_STATUS Status;
335 UINT8 *FileData;
336 UINTN FileDataLength;
337 EG_IMAGE *Image, *NewImage;
338
339 if (BaseDir == NULL || Path == NULL)
340 return NULL;
341
342 // load file
343 Status = egLoadFile(BaseDir, Path, &FileData, &FileDataLength);
344 if (EFI_ERROR(Status))
345 return NULL;
346
347 // decode it
348 Image = egDecodeAny(FileData, FileDataLength, IconSize, TRUE);
349 FreePool(FileData);
350 if ((Image->Width != IconSize) || (Image->Height != IconSize)) {
351 NewImage = egScaleImage(Image, IconSize, IconSize);
352 if (!NewImage)
353 Print(L"Warning: Unable to scale icon of the wrong size from '%s'\n", Path);
354 egFreeImage(Image);
355 Image = NewImage;
356 }
357
358 return Image;
359 } // EG_IMAGE *egLoadIcon()
360
361 // Returns an icon of any type from the specified subdirectory using the specified
362 // base name. All directory references are relative to BaseDir. For instance, if
363 // SubdirName is "myicons" and BaseName is "os_linux", this function will return
364 // an image based on "myicons/os_linux.icns" or "myicons/os_linux.png", in that
365 // order of preference. Returns NULL if no such file is a valid icon file.
366 EG_IMAGE * egLoadIconAnyType(IN EFI_FILE *BaseDir, IN CHAR16 *SubdirName, IN CHAR16 *BaseName, IN UINTN IconSize) {
367 EG_IMAGE *Image = NULL;
368 CHAR16 *Extension;
369 CHAR16 FileName[256];
370 UINTN i = 0;
371
372 while (((Extension = FindCommaDelimited(ICON_EXTENSIONS, i++)) != NULL) && (Image == NULL)) {
373 SPrint(FileName, 255, L"%s\\%s.%s", SubdirName, BaseName, Extension);
374 Image = egLoadIcon(BaseDir, FileName, IconSize);
375 MyFreePool(Extension);
376 } // while()
377
378 return Image;
379 } // EG_IMAGE *egLoadIconAnyType()
380
381 // Returns an icon with any extension in ICON_EXTENSIONS from either the directory
382 // specified by GlobalConfig.IconsDir or DEFAULT_ICONS_DIR. The input BaseName
383 // should be the icon name without an extension. For instance, if BaseName is
384 // os_linux, GlobalConfig.IconsDir is myicons, DEFAULT_ICONS_DIR is icons, and
385 // ICON_EXTENSIONS is "icns,png", this function will return myicons/os_linux.icns,
386 // myicons/os_linux.png, icons/os_linux.icns, or icons/os_linux.png, in that
387 // order of preference. Returns NULL if no such icon can be found. All file
388 // references are relative to SelfDir.
389 EG_IMAGE * egFindIcon(IN CHAR16 *BaseName, IN UINTN IconSize) {
390 EG_IMAGE *Image = NULL;
391
392 if (GlobalConfig.IconsDir != NULL) {
393 Image = egLoadIconAnyType(SelfDir, GlobalConfig.IconsDir, BaseName, IconSize);
394 }
395
396 if (Image == NULL) {
397 Image = egLoadIconAnyType(SelfDir, DEFAULT_ICONS_DIR, BaseName, IconSize);
398 }
399
400 return Image;
401 } // EG_IMAGE * egFindIcon()
402
403 EG_IMAGE * egPrepareEmbeddedImage(IN EG_EMBEDDED_IMAGE *EmbeddedImage, IN BOOLEAN WantAlpha)
404 {
405 EG_IMAGE *NewImage;
406 UINT8 *CompData;
407 UINTN CompLen;
408 UINTN PixelCount;
409
410 // sanity check
411 if (EmbeddedImage->PixelMode > EG_MAX_EIPIXELMODE ||
412 (EmbeddedImage->CompressMode != EG_EICOMPMODE_NONE && EmbeddedImage->CompressMode != EG_EICOMPMODE_RLE))
413 return NULL;
414
415 // allocate image structure and pixel buffer
416 NewImage = egCreateImage(EmbeddedImage->Width, EmbeddedImage->Height, WantAlpha);
417 if (NewImage == NULL)
418 return NULL;
419
420 CompData = (UINT8 *)EmbeddedImage->Data; // drop const
421 CompLen = EmbeddedImage->DataLength;
422 PixelCount = EmbeddedImage->Width * EmbeddedImage->Height;
423
424 // FUTURE: for EG_EICOMPMODE_EFICOMPRESS, decompress whole data block here
425
426 if (EmbeddedImage->PixelMode == EG_EIPIXELMODE_GRAY ||
427 EmbeddedImage->PixelMode == EG_EIPIXELMODE_GRAY_ALPHA) {
428
429 // copy grayscale plane and expand
430 if (EmbeddedImage->CompressMode == EG_EICOMPMODE_RLE) {
431 egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, r), PixelCount);
432 } else {
433 egInsertPlane(CompData, PLPTR(NewImage, r), PixelCount);
434 CompData += PixelCount;
435 }
436 egCopyPlane(PLPTR(NewImage, r), PLPTR(NewImage, g), PixelCount);
437 egCopyPlane(PLPTR(NewImage, r), PLPTR(NewImage, b), PixelCount);
438
439 } else if (EmbeddedImage->PixelMode == EG_EIPIXELMODE_COLOR ||
440 EmbeddedImage->PixelMode == EG_EIPIXELMODE_COLOR_ALPHA) {
441
442 // copy color planes
443 if (EmbeddedImage->CompressMode == EG_EICOMPMODE_RLE) {
444 egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, r), PixelCount);
445 egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, g), PixelCount);
446 egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, b), PixelCount);
447 } else {
448 egInsertPlane(CompData, PLPTR(NewImage, r), PixelCount);
449 CompData += PixelCount;
450 egInsertPlane(CompData, PLPTR(NewImage, g), PixelCount);
451 CompData += PixelCount;
452 egInsertPlane(CompData, PLPTR(NewImage, b), PixelCount);
453 CompData += PixelCount;
454 }
455
456 } else {
457
458 // set color planes to black
459 egSetPlane(PLPTR(NewImage, r), 0, PixelCount);
460 egSetPlane(PLPTR(NewImage, g), 0, PixelCount);
461 egSetPlane(PLPTR(NewImage, b), 0, PixelCount);
462
463 }
464
465 if (WantAlpha && (EmbeddedImage->PixelMode == EG_EIPIXELMODE_GRAY_ALPHA ||
466 EmbeddedImage->PixelMode == EG_EIPIXELMODE_COLOR_ALPHA ||
467 EmbeddedImage->PixelMode == EG_EIPIXELMODE_ALPHA)) {
468
469 // copy alpha plane
470 if (EmbeddedImage->CompressMode == EG_EICOMPMODE_RLE) {
471 egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, a), PixelCount);
472 } else {
473 egInsertPlane(CompData, PLPTR(NewImage, a), PixelCount);
474 CompData += PixelCount;
475 }
476
477 } else {
478 egSetPlane(PLPTR(NewImage, a), WantAlpha ? 255 : 0, PixelCount);
479 }
480
481 return NewImage;
482 }
483
484 //
485 // Compositing
486 //
487
488 VOID egRestrictImageArea(IN EG_IMAGE *Image,
489 IN UINTN AreaPosX, IN UINTN AreaPosY,
490 IN OUT UINTN *AreaWidth, IN OUT UINTN *AreaHeight)
491 {
492 if (AreaPosX >= Image->Width || AreaPosY >= Image->Height) {
493 // out of bounds, operation has no effect
494 *AreaWidth = 0;
495 *AreaHeight = 0;
496 } else {
497 // calculate affected area
498 if (*AreaWidth > Image->Width - AreaPosX)
499 *AreaWidth = Image->Width - AreaPosX;
500 if (*AreaHeight > Image->Height - AreaPosY)
501 *AreaHeight = Image->Height - AreaPosY;
502 }
503 }
504
505 VOID egFillImage(IN OUT EG_IMAGE *CompImage, IN EG_PIXEL *Color)
506 {
507 UINTN i;
508 EG_PIXEL FillColor;
509 EG_PIXEL *PixelPtr;
510
511 FillColor = *Color;
512 if (!CompImage->HasAlpha)
513 FillColor.a = 0;
514
515 PixelPtr = CompImage->PixelData;
516 for (i = 0; i < CompImage->Width * CompImage->Height; i++, PixelPtr++)
517 *PixelPtr = FillColor;
518 }
519
520 VOID egFillImageArea(IN OUT EG_IMAGE *CompImage,
521 IN UINTN AreaPosX, IN UINTN AreaPosY,
522 IN UINTN AreaWidth, IN UINTN AreaHeight,
523 IN EG_PIXEL *Color)
524 {
525 UINTN x, y;
526 EG_PIXEL FillColor;
527 EG_PIXEL *PixelPtr;
528 EG_PIXEL *PixelBasePtr;
529
530 egRestrictImageArea(CompImage, AreaPosX, AreaPosY, &AreaWidth, &AreaHeight);
531
532 if (AreaWidth > 0) {
533 FillColor = *Color;
534 if (!CompImage->HasAlpha)
535 FillColor.a = 0;
536
537 PixelBasePtr = CompImage->PixelData + AreaPosY * CompImage->Width + AreaPosX;
538 for (y = 0; y < AreaHeight; y++) {
539 PixelPtr = PixelBasePtr;
540 for (x = 0; x < AreaWidth; x++, PixelPtr++)
541 *PixelPtr = FillColor;
542 PixelBasePtr += CompImage->Width;
543 }
544 }
545 }
546
547 VOID egRawCopy(IN OUT EG_PIXEL *CompBasePtr, IN EG_PIXEL *TopBasePtr,
548 IN UINTN Width, IN UINTN Height,
549 IN UINTN CompLineOffset, IN UINTN TopLineOffset)
550 {
551 UINTN x, y;
552 EG_PIXEL *TopPtr, *CompPtr;
553
554 for (y = 0; y < Height; y++) {
555 TopPtr = TopBasePtr;
556 CompPtr = CompBasePtr;
557 for (x = 0; x < Width; x++) {
558 *CompPtr = *TopPtr;
559 TopPtr++, CompPtr++;
560 }
561 TopBasePtr += TopLineOffset;
562 CompBasePtr += CompLineOffset;
563 }
564 }
565
566 VOID egRawCompose(IN OUT EG_PIXEL *CompBasePtr, IN EG_PIXEL *TopBasePtr,
567 IN UINTN Width, IN UINTN Height,
568 IN UINTN CompLineOffset, IN UINTN TopLineOffset)
569 {
570 UINTN x, y;
571 EG_PIXEL *TopPtr, *CompPtr;
572 UINTN Alpha;
573 UINTN RevAlpha;
574 UINTN Temp;
575
576 for (y = 0; y < Height; y++) {
577 TopPtr = TopBasePtr;
578 CompPtr = CompBasePtr;
579 for (x = 0; x < Width; x++) {
580 Alpha = TopPtr->a;
581 RevAlpha = 255 - Alpha;
582 Temp = (UINTN)CompPtr->b * RevAlpha + (UINTN)TopPtr->b * Alpha + 0x80;
583 CompPtr->b = (Temp + (Temp >> 8)) >> 8;
584 Temp = (UINTN)CompPtr->g * RevAlpha + (UINTN)TopPtr->g * Alpha + 0x80;
585 CompPtr->g = (Temp + (Temp >> 8)) >> 8;
586 Temp = (UINTN)CompPtr->r * RevAlpha + (UINTN)TopPtr->r * Alpha + 0x80;
587 CompPtr->r = (Temp + (Temp >> 8)) >> 8;
588 /*
589 CompPtr->b = ((UINTN)CompPtr->b * RevAlpha + (UINTN)TopPtr->b * Alpha) / 255;
590 CompPtr->g = ((UINTN)CompPtr->g * RevAlpha + (UINTN)TopPtr->g * Alpha) / 255;
591 CompPtr->r = ((UINTN)CompPtr->r * RevAlpha + (UINTN)TopPtr->r * Alpha) / 255;
592 */
593 TopPtr++, CompPtr++;
594 }
595 TopBasePtr += TopLineOffset;
596 CompBasePtr += CompLineOffset;
597 }
598 }
599
600 VOID egComposeImage(IN OUT EG_IMAGE *CompImage, IN EG_IMAGE *TopImage, IN UINTN PosX, IN UINTN PosY)
601 {
602 UINTN CompWidth, CompHeight;
603
604 CompWidth = TopImage->Width;
605 CompHeight = TopImage->Height;
606 egRestrictImageArea(CompImage, PosX, PosY, &CompWidth, &CompHeight);
607
608 // compose
609 if (CompWidth > 0) {
610 if (TopImage->HasAlpha) {
611 egRawCompose(CompImage->PixelData + PosY * CompImage->Width + PosX, TopImage->PixelData,
612 CompWidth, CompHeight, CompImage->Width, TopImage->Width);
613 } else {
614 egRawCopy(CompImage->PixelData + PosY * CompImage->Width + PosX, TopImage->PixelData,
615 CompWidth, CompHeight, CompImage->Width, TopImage->Width);
616 }
617 }
618 } /* VOID egComposeImage() */
619
620 // EG_IMAGE * egEnsureImageSize(IN EG_IMAGE *Image, IN UINTN Width, IN UINTN Height, IN EG_PIXEL *Color)
621 // {
622 // EG_IMAGE *NewImage;
623 //
624 // if (Image == NULL)
625 // return NULL;
626 // if (Image->Width == Width && Image->Height == Height)
627 // return Image;
628 //
629 // NewImage = egCreateFilledImage(Width, Height, Image->HasAlpha, Color);
630 // if (NewImage == NULL) {
631 // egFreeImage(Image);
632 // return NULL;
633 // }
634 // Image->HasAlpha = FALSE;
635 // egComposeImage(NewImage, Image, 0, 0);
636 // egFreeImage(Image);
637 //
638 // return NewImage;
639 // }
640
641 //
642 // misc internal functions
643 //
644
645 VOID egInsertPlane(IN UINT8 *SrcDataPtr, IN UINT8 *DestPlanePtr, IN UINTN PixelCount)
646 {
647 UINTN i;
648
649 for (i = 0; i < PixelCount; i++) {
650 *DestPlanePtr = *SrcDataPtr++;
651 DestPlanePtr += 4;
652 }
653 }
654
655 VOID egSetPlane(IN UINT8 *DestPlanePtr, IN UINT8 Value, IN UINTN PixelCount)
656 {
657 UINTN i;
658
659 for (i = 0; i < PixelCount; i++) {
660 *DestPlanePtr = Value;
661 DestPlanePtr += 4;
662 }
663 }
664
665 VOID egCopyPlane(IN UINT8 *SrcPlanePtr, IN UINT8 *DestPlanePtr, IN UINTN PixelCount)
666 {
667 UINTN i;
668
669 for (i = 0; i < PixelCount; i++) {
670 *DestPlanePtr = *SrcPlanePtr;
671 DestPlanePtr += 4, SrcPlanePtr += 4;
672 }
673 }
674
675 /* EOF */