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