3 * Image handling functions
5 * Copyright (c) 2006 Christoph Pfisterer
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
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
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.
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.
37 * Modifications copyright (c) 2012-2015 Roderick W. Smith
39 * Modifications distributed under the terms of the GNU General Public
40 * License (GPL) version 3 (GPLv3), or (at your option) any later version.
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.
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.
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/>.
59 #include "../refind/global.h"
60 #include "../refind/lib.h"
61 #include "../refind/screen.h"
62 #include "../include/refit_call_wrapper.h"
65 #define MAX_FILE_SIZE (1024*1024*1024)
67 // Multiplier for pseudo-floating-point operations in egScaleImage().
68 // A value of 4096 should keep us within limits on 32-bit systems, but I've
69 // seen some minor artifacts at this level, so give it a bit more precision
70 // on 64-bit systems....
72 #define FP_MULTIPLIER (UINTN) 65536
74 #define FP_MULTIPLIER (UINTN) 4096
77 #ifndef __MAKEWITH_GNUEFI
78 #define LibLocateHandle gBS->LocateHandleBuffer
79 #define LibOpenRoot EfiLibOpenRoot
83 // Basic image handling
86 EG_IMAGE
* egCreateImage(IN UINTN Width
, IN UINTN Height
, IN BOOLEAN HasAlpha
)
90 NewImage
= (EG_IMAGE
*) AllocatePool(sizeof(EG_IMAGE
));
93 NewImage
->PixelData
= (EG_PIXEL
*) AllocatePool(Width
* Height
* sizeof(EG_PIXEL
));
94 if (NewImage
->PixelData
== NULL
) {
95 egFreeImage(NewImage
);
99 NewImage
->Width
= Width
;
100 NewImage
->Height
= Height
;
101 NewImage
->HasAlpha
= HasAlpha
;
105 EG_IMAGE
* egCreateFilledImage(IN UINTN Width
, IN UINTN Height
, IN BOOLEAN HasAlpha
, IN EG_PIXEL
*Color
)
109 NewImage
= egCreateImage(Width
, Height
, HasAlpha
);
110 if (NewImage
== NULL
)
113 egFillImage(NewImage
, Color
);
117 EG_IMAGE
* egCopyImage(IN EG_IMAGE
*Image
)
119 EG_IMAGE
*NewImage
= NULL
;
122 NewImage
= egCreateImage(Image
->Width
, Image
->Height
, Image
->HasAlpha
);
123 if (NewImage
== NULL
)
126 CopyMem(NewImage
->PixelData
, Image
->PixelData
, Image
->Width
* Image
->Height
* sizeof(EG_PIXEL
));
130 // Returns a smaller image composed of the specified crop area from the larger area.
131 // If the specified area is larger than is in the original, returns NULL.
132 EG_IMAGE
* egCropImage(IN EG_IMAGE
*Image
, IN UINTN StartX
, IN UINTN StartY
, IN UINTN Width
, IN UINTN Height
) {
133 EG_IMAGE
*NewImage
= NULL
;
136 if (((StartX
+ Width
) > Image
->Width
) || ((StartY
+ Height
) > Image
->Height
))
139 NewImage
= egCreateImage(Width
, Height
, Image
->HasAlpha
);
140 if (NewImage
== NULL
)
143 for (y
= 0; y
< Height
; y
++) {
144 for (x
= 0; x
< Width
; x
++) {
145 NewImage
->PixelData
[y
* NewImage
->Width
+ x
] = Image
->PixelData
[(y
+ StartY
) * Image
->Width
+ x
+ StartX
];
149 } // EG_IMAGE * egCropImage()
151 // The following function implements a bilinear image scaling algorithm, based on
152 // code presented at http://tech-algorithm.com/articles/bilinear-image-scaling/.
153 // Resize an image; returns pointer to resized image if successful, NULL otherwise.
154 // Calling function is responsible for freeing allocated memory.
155 // NOTE: x_ratio, y_ratio, x_diff, and y_diff should really be float values;
156 // however, I've found that my 32-bit Mac Mini has a buggy EFI (or buggy CPU?), which
157 // causes this function to hang on float-to-UINT8 conversions on some (but not all!)
158 // float values. Therefore, this function uses integer arithmetic but multiplies
159 // all values by FP_MULTIPLIER to achieve something resembling the sort of precision
160 // needed for good results.
161 EG_IMAGE
* egScaleImage(IN EG_IMAGE
*Image
, IN UINTN NewWidth
, IN UINTN NewHeight
) {
162 EG_IMAGE
*NewImage
= NULL
;
167 UINTN x_ratio
, y_ratio
, x_diff
, y_diff
;
169 if ((Image
== NULL
) || (Image
->Height
== 0) || (Image
->Width
== 0) || (NewWidth
== 0) || (NewHeight
== 0))
172 if ((Image
->Width
== NewWidth
) && (Image
->Height
== NewHeight
))
173 return (egCopyImage(Image
));
175 NewImage
= egCreateImage(NewWidth
, NewHeight
, Image
->HasAlpha
);
176 if (NewImage
== NULL
)
179 x_ratio
= ((Image
->Width
- 1) * FP_MULTIPLIER
) / NewWidth
;
180 y_ratio
= ((Image
->Height
- 1) * FP_MULTIPLIER
) / NewHeight
;
182 for (i
= 0; i
< NewHeight
; i
++) {
183 for (j
= 0; j
< NewWidth
; j
++) {
184 x
= (j
* (Image
->Width
- 1)) / NewWidth
;
185 y
= (i
* (Image
->Height
- 1)) / NewHeight
;
186 x_diff
= (x_ratio
* j
) - x
* FP_MULTIPLIER
;
187 y_diff
= (y_ratio
* i
) - y
* FP_MULTIPLIER
;
188 Index
= ((y
* Image
->Width
) + x
);
189 a
= Image
->PixelData
[Index
];
190 b
= Image
->PixelData
[Index
+ 1];
191 c
= Image
->PixelData
[Index
+ Image
->Width
];
192 d
= Image
->PixelData
[Index
+ Image
->Width
+ 1];
195 NewImage
->PixelData
[Offset
].b
= ((a
.b
) * (FP_MULTIPLIER
- x_diff
) * (FP_MULTIPLIER
- y_diff
) +
196 (b
.b
) * (x_diff
) * (FP_MULTIPLIER
- y_diff
) +
197 (c
.b
) * (y_diff
) * (FP_MULTIPLIER
- x_diff
) +
198 (d
.b
) * (x_diff
* y_diff
)) / (FP_MULTIPLIER
* FP_MULTIPLIER
);
201 NewImage
->PixelData
[Offset
].g
= ((a
.g
) * (FP_MULTIPLIER
- x_diff
) * (FP_MULTIPLIER
- y_diff
) +
202 (b
.g
) * (x_diff
) * (FP_MULTIPLIER
- y_diff
) +
203 (c
.g
) * (y_diff
) * (FP_MULTIPLIER
- x_diff
) +
204 (d
.g
) * (x_diff
* y_diff
)) / (FP_MULTIPLIER
* FP_MULTIPLIER
);
207 NewImage
->PixelData
[Offset
].r
= ((a
.r
) * (FP_MULTIPLIER
- x_diff
) * (FP_MULTIPLIER
- y_diff
) +
208 (b
.r
) * (x_diff
) * (FP_MULTIPLIER
- y_diff
) +
209 (c
.r
) * (y_diff
) * (FP_MULTIPLIER
- x_diff
) +
210 (d
.r
) * (x_diff
* y_diff
)) / (FP_MULTIPLIER
* FP_MULTIPLIER
);
213 NewImage
->PixelData
[Offset
++].a
= ((a
.a
) * (FP_MULTIPLIER
- x_diff
) * (FP_MULTIPLIER
- y_diff
) +
214 (b
.a
) * (x_diff
) * (FP_MULTIPLIER
- y_diff
) +
215 (c
.a
) * (y_diff
) * (FP_MULTIPLIER
- x_diff
) +
216 (d
.a
) * (x_diff
* y_diff
)) / (FP_MULTIPLIER
* FP_MULTIPLIER
);
220 } // EG_IMAGE * egScaleImage()
222 VOID
egFreeImage(IN EG_IMAGE
*Image
)
225 if (Image
->PixelData
!= NULL
)
226 FreePool(Image
->PixelData
);
232 // Basic file operations
235 EFI_STATUS
egLoadFile(IN EFI_FILE
*BaseDir
, IN CHAR16
*FileName
, OUT UINT8
**FileData
, OUT UINTN
*FileDataLength
)
238 EFI_FILE_HANDLE FileHandle
;
239 EFI_FILE_INFO
*FileInfo
;
244 if ((BaseDir
== NULL
) || (FileName
== NULL
))
245 return EFI_NOT_FOUND
;
247 Status
= refit_call5_wrapper(BaseDir
->Open
, BaseDir
, &FileHandle
, FileName
, EFI_FILE_MODE_READ
, 0);
248 if (EFI_ERROR(Status
)) {
252 FileInfo
= LibFileInfo(FileHandle
);
253 if (FileInfo
== NULL
) {
254 refit_call1_wrapper(FileHandle
->Close
, FileHandle
);
255 return EFI_NOT_FOUND
;
257 ReadSize
= FileInfo
->FileSize
;
258 if (ReadSize
> MAX_FILE_SIZE
)
259 ReadSize
= MAX_FILE_SIZE
;
262 BufferSize
= (UINTN
)ReadSize
; // was limited to 1 GB above, so this is safe
263 Buffer
= (UINT8
*) AllocatePool(BufferSize
);
264 if (Buffer
== NULL
) {
265 refit_call1_wrapper(FileHandle
->Close
, FileHandle
);
266 return EFI_OUT_OF_RESOURCES
;
269 Status
= refit_call3_wrapper(FileHandle
->Read
, FileHandle
, &BufferSize
, Buffer
);
270 refit_call1_wrapper(FileHandle
->Close
, FileHandle
);
271 if (EFI_ERROR(Status
)) {
277 *FileDataLength
= BufferSize
;
281 static EFI_GUID ESPGuid
= { 0xc12a7328, 0xf81f, 0x11d2, { 0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b } };
283 EFI_STATUS
egFindESP(OUT EFI_FILE_HANDLE
*RootDir
)
286 UINTN HandleCount
= 0;
289 Status
= LibLocateHandle(ByProtocol
, &ESPGuid
, NULL
, &HandleCount
, &Handles
);
290 if (!EFI_ERROR(Status
) && HandleCount
> 0) {
291 *RootDir
= LibOpenRoot(Handles
[0]);
292 if (*RootDir
== NULL
)
293 Status
= EFI_NOT_FOUND
;
299 EFI_STATUS
egSaveFile(IN EFI_FILE
* BaseDir OPTIONAL
, IN CHAR16
*FileName
,
300 IN UINT8
*FileData
, IN UINTN FileDataLength
)
303 EFI_FILE_HANDLE FileHandle
;
306 if (BaseDir
== NULL
) {
307 Status
= egFindESP(&BaseDir
);
308 if (EFI_ERROR(Status
))
312 Status
= refit_call5_wrapper(BaseDir
->Open
, BaseDir
, &FileHandle
, FileName
,
313 EFI_FILE_MODE_READ
| EFI_FILE_MODE_WRITE
| EFI_FILE_MODE_CREATE
, 0);
314 if (EFI_ERROR(Status
))
317 BufferSize
= FileDataLength
;
318 Status
= refit_call3_wrapper(FileHandle
->Write
, FileHandle
, &BufferSize
, FileData
);
319 refit_call1_wrapper(FileHandle
->Close
, FileHandle
);
325 // Loading images from files and embedded data
328 // Decode the specified image data. The IconSize parameter is relevant only
329 // for ICNS, for which it selects which ICNS sub-image is decoded.
330 // Returns a pointer to the resulting EG_IMAGE or NULL if decoding failed.
331 static EG_IMAGE
* egDecodeAny(IN UINT8
*FileData
, IN UINTN FileDataLength
, IN UINTN IconSize
, IN BOOLEAN WantAlpha
)
333 EG_IMAGE
*NewImage
= NULL
;
335 NewImage
= egDecodeICNS(FileData
, FileDataLength
, IconSize
, WantAlpha
);
336 if (NewImage
== NULL
)
337 NewImage
= egDecodePNG(FileData
, FileDataLength
, IconSize
, WantAlpha
);
338 if (NewImage
== NULL
)
339 NewImage
= egDecodeBMP(FileData
, FileDataLength
, IconSize
, WantAlpha
);
344 EG_IMAGE
* egLoadImage(IN EFI_FILE
* BaseDir
, IN CHAR16
*FileName
, IN BOOLEAN WantAlpha
)
348 UINTN FileDataLength
;
351 if (BaseDir
== NULL
|| FileName
== NULL
)
355 Status
= egLoadFile(BaseDir
, FileName
, &FileData
, &FileDataLength
);
356 if (EFI_ERROR(Status
))
360 NewImage
= egDecodeAny(FileData
, FileDataLength
, 128 /* arbitrary value */, WantAlpha
);
366 // Load an icon from (BaseDir)/Path, extracting the icon of size IconSize x IconSize.
367 // Returns a pointer to the image data, or NULL if the icon could not be loaded.
368 EG_IMAGE
* egLoadIcon(IN EFI_FILE
* BaseDir
, IN CHAR16
*Path
, IN UINTN IconSize
)
372 UINTN FileDataLength
;
373 EG_IMAGE
*Image
, *NewImage
;
375 if (BaseDir
== NULL
|| Path
== NULL
)
379 Status
= egLoadFile(BaseDir
, Path
, &FileData
, &FileDataLength
);
380 if (EFI_ERROR(Status
))
384 Image
= egDecodeAny(FileData
, FileDataLength
, IconSize
, TRUE
);
386 if ((Image
->Width
!= IconSize
) || (Image
->Height
!= IconSize
)) {
387 NewImage
= egScaleImage(Image
, IconSize
, IconSize
);
389 Print(L
"Warning: Unable to scale icon of the wrong size from '%s'\n", Path
);
395 } // EG_IMAGE *egLoadIcon()
397 // Returns an icon of any type from the specified subdirectory using the specified
398 // base name. All directory references are relative to BaseDir. For instance, if
399 // SubdirName is "myicons" and BaseName is "os_linux", this function will return
400 // an image based on "myicons/os_linux.icns" or "myicons/os_linux.png", in that
401 // order of preference. Returns NULL if no such file is a valid icon file.
402 EG_IMAGE
* egLoadIconAnyType(IN EFI_FILE
*BaseDir
, IN CHAR16
*SubdirName
, IN CHAR16
*BaseName
, IN UINTN IconSize
) {
403 EG_IMAGE
*Image
= NULL
;
405 CHAR16 FileName
[256];
408 while (((Extension
= FindCommaDelimited(ICON_EXTENSIONS
, i
++)) != NULL
) && (Image
== NULL
)) {
409 SPrint(FileName
, 255, L
"%s\\%s.%s", SubdirName
, BaseName
, Extension
);
410 Image
= egLoadIcon(BaseDir
, FileName
, IconSize
);
411 MyFreePool(Extension
);
415 } // EG_IMAGE *egLoadIconAnyType()
417 // Returns an icon with any extension in ICON_EXTENSIONS from either the directory
418 // specified by GlobalConfig.IconsDir or DEFAULT_ICONS_DIR. The input BaseName
419 // should be the icon name without an extension. For instance, if BaseName is
420 // os_linux, GlobalConfig.IconsDir is myicons, DEFAULT_ICONS_DIR is icons, and
421 // ICON_EXTENSIONS is "icns,png", this function will return myicons/os_linux.icns,
422 // myicons/os_linux.png, icons/os_linux.icns, or icons/os_linux.png, in that
423 // order of preference. Returns NULL if no such icon can be found. All file
424 // references are relative to SelfDir.
425 EG_IMAGE
* egFindIcon(IN CHAR16
*BaseName
, IN UINTN IconSize
) {
426 EG_IMAGE
*Image
= NULL
;
428 if (GlobalConfig
.IconsDir
!= NULL
) {
429 Image
= egLoadIconAnyType(SelfDir
, GlobalConfig
.IconsDir
, BaseName
, IconSize
);
433 Image
= egLoadIconAnyType(SelfDir
, DEFAULT_ICONS_DIR
, BaseName
, IconSize
);
437 } // EG_IMAGE * egFindIcon()
439 EG_IMAGE
* egPrepareEmbeddedImage(IN EG_EMBEDDED_IMAGE
*EmbeddedImage
, IN BOOLEAN WantAlpha
)
447 if (EmbeddedImage
->PixelMode
> EG_MAX_EIPIXELMODE
||
448 (EmbeddedImage
->CompressMode
!= EG_EICOMPMODE_NONE
&& EmbeddedImage
->CompressMode
!= EG_EICOMPMODE_RLE
))
451 // allocate image structure and pixel buffer
452 NewImage
= egCreateImage(EmbeddedImage
->Width
, EmbeddedImage
->Height
, WantAlpha
);
453 if (NewImage
== NULL
)
456 CompData
= (UINT8
*)EmbeddedImage
->Data
; // drop const
457 CompLen
= EmbeddedImage
->DataLength
;
458 PixelCount
= EmbeddedImage
->Width
* EmbeddedImage
->Height
;
460 // FUTURE: for EG_EICOMPMODE_EFICOMPRESS, decompress whole data block here
462 if (EmbeddedImage
->PixelMode
== EG_EIPIXELMODE_GRAY
||
463 EmbeddedImage
->PixelMode
== EG_EIPIXELMODE_GRAY_ALPHA
) {
465 // copy grayscale plane and expand
466 if (EmbeddedImage
->CompressMode
== EG_EICOMPMODE_RLE
) {
467 egDecompressIcnsRLE(&CompData
, &CompLen
, PLPTR(NewImage
, r
), PixelCount
);
469 egInsertPlane(CompData
, PLPTR(NewImage
, r
), PixelCount
);
470 CompData
+= PixelCount
;
472 egCopyPlane(PLPTR(NewImage
, r
), PLPTR(NewImage
, g
), PixelCount
);
473 egCopyPlane(PLPTR(NewImage
, r
), PLPTR(NewImage
, b
), PixelCount
);
475 } else if (EmbeddedImage
->PixelMode
== EG_EIPIXELMODE_COLOR
||
476 EmbeddedImage
->PixelMode
== EG_EIPIXELMODE_COLOR_ALPHA
) {
479 if (EmbeddedImage
->CompressMode
== EG_EICOMPMODE_RLE
) {
480 egDecompressIcnsRLE(&CompData
, &CompLen
, PLPTR(NewImage
, r
), PixelCount
);
481 egDecompressIcnsRLE(&CompData
, &CompLen
, PLPTR(NewImage
, g
), PixelCount
);
482 egDecompressIcnsRLE(&CompData
, &CompLen
, PLPTR(NewImage
, b
), PixelCount
);
484 egInsertPlane(CompData
, PLPTR(NewImage
, r
), PixelCount
);
485 CompData
+= PixelCount
;
486 egInsertPlane(CompData
, PLPTR(NewImage
, g
), PixelCount
);
487 CompData
+= PixelCount
;
488 egInsertPlane(CompData
, PLPTR(NewImage
, b
), PixelCount
);
489 CompData
+= PixelCount
;
494 // set color planes to black
495 egSetPlane(PLPTR(NewImage
, r
), 0, PixelCount
);
496 egSetPlane(PLPTR(NewImage
, g
), 0, PixelCount
);
497 egSetPlane(PLPTR(NewImage
, b
), 0, PixelCount
);
501 if (WantAlpha
&& (EmbeddedImage
->PixelMode
== EG_EIPIXELMODE_GRAY_ALPHA
||
502 EmbeddedImage
->PixelMode
== EG_EIPIXELMODE_COLOR_ALPHA
||
503 EmbeddedImage
->PixelMode
== EG_EIPIXELMODE_ALPHA
)) {
506 if (EmbeddedImage
->CompressMode
== EG_EICOMPMODE_RLE
) {
507 egDecompressIcnsRLE(&CompData
, &CompLen
, PLPTR(NewImage
, a
), PixelCount
);
509 egInsertPlane(CompData
, PLPTR(NewImage
, a
), PixelCount
);
510 CompData
+= PixelCount
;
514 egSetPlane(PLPTR(NewImage
, a
), WantAlpha
? 255 : 0, PixelCount
);
524 VOID
egRestrictImageArea(IN EG_IMAGE
*Image
,
525 IN UINTN AreaPosX
, IN UINTN AreaPosY
,
526 IN OUT UINTN
*AreaWidth
, IN OUT UINTN
*AreaHeight
)
528 if (AreaPosX
>= Image
->Width
|| AreaPosY
>= Image
->Height
) {
529 // out of bounds, operation has no effect
533 // calculate affected area
534 if (*AreaWidth
> Image
->Width
- AreaPosX
)
535 *AreaWidth
= Image
->Width
- AreaPosX
;
536 if (*AreaHeight
> Image
->Height
- AreaPosY
)
537 *AreaHeight
= Image
->Height
- AreaPosY
;
541 VOID
egFillImage(IN OUT EG_IMAGE
*CompImage
, IN EG_PIXEL
*Color
)
548 if (!CompImage
->HasAlpha
)
551 PixelPtr
= CompImage
->PixelData
;
552 for (i
= 0; i
< CompImage
->Width
* CompImage
->Height
; i
++, PixelPtr
++)
553 *PixelPtr
= FillColor
;
556 VOID
egFillImageArea(IN OUT EG_IMAGE
*CompImage
,
557 IN UINTN AreaPosX
, IN UINTN AreaPosY
,
558 IN UINTN AreaWidth
, IN UINTN AreaHeight
,
564 EG_PIXEL
*PixelBasePtr
;
566 egRestrictImageArea(CompImage
, AreaPosX
, AreaPosY
, &AreaWidth
, &AreaHeight
);
570 if (!CompImage
->HasAlpha
)
573 PixelBasePtr
= CompImage
->PixelData
+ AreaPosY
* CompImage
->Width
+ AreaPosX
;
574 for (y
= 0; y
< AreaHeight
; y
++) {
575 PixelPtr
= PixelBasePtr
;
576 for (x
= 0; x
< AreaWidth
; x
++, PixelPtr
++)
577 *PixelPtr
= FillColor
;
578 PixelBasePtr
+= CompImage
->Width
;
583 VOID
egRawCopy(IN OUT EG_PIXEL
*CompBasePtr
, IN EG_PIXEL
*TopBasePtr
,
584 IN UINTN Width
, IN UINTN Height
,
585 IN UINTN CompLineOffset
, IN UINTN TopLineOffset
)
588 EG_PIXEL
*TopPtr
, *CompPtr
;
590 for (y
= 0; y
< Height
; y
++) {
592 CompPtr
= CompBasePtr
;
593 for (x
= 0; x
< Width
; x
++) {
597 TopBasePtr
+= TopLineOffset
;
598 CompBasePtr
+= CompLineOffset
;
602 VOID
egRawCompose(IN OUT EG_PIXEL
*CompBasePtr
, IN EG_PIXEL
*TopBasePtr
,
603 IN UINTN Width
, IN UINTN Height
,
604 IN UINTN CompLineOffset
, IN UINTN TopLineOffset
)
607 EG_PIXEL
*TopPtr
, *CompPtr
;
612 for (y
= 0; y
< Height
; y
++) {
614 CompPtr
= CompBasePtr
;
615 for (x
= 0; x
< Width
; x
++) {
617 RevAlpha
= 255 - Alpha
;
618 Temp
= (UINTN
)CompPtr
->b
* RevAlpha
+ (UINTN
)TopPtr
->b
* Alpha
+ 0x80;
619 CompPtr
->b
= (Temp
+ (Temp
>> 8)) >> 8;
620 Temp
= (UINTN
)CompPtr
->g
* RevAlpha
+ (UINTN
)TopPtr
->g
* Alpha
+ 0x80;
621 CompPtr
->g
= (Temp
+ (Temp
>> 8)) >> 8;
622 Temp
= (UINTN
)CompPtr
->r
* RevAlpha
+ (UINTN
)TopPtr
->r
* Alpha
+ 0x80;
623 CompPtr
->r
= (Temp
+ (Temp
>> 8)) >> 8;
625 CompPtr->b = ((UINTN)CompPtr->b * RevAlpha + (UINTN)TopPtr->b * Alpha) / 255;
626 CompPtr->g = ((UINTN)CompPtr->g * RevAlpha + (UINTN)TopPtr->g * Alpha) / 255;
627 CompPtr->r = ((UINTN)CompPtr->r * RevAlpha + (UINTN)TopPtr->r * Alpha) / 255;
631 TopBasePtr
+= TopLineOffset
;
632 CompBasePtr
+= CompLineOffset
;
636 VOID
egComposeImage(IN OUT EG_IMAGE
*CompImage
, IN EG_IMAGE
*TopImage
, IN UINTN PosX
, IN UINTN PosY
)
638 UINTN CompWidth
, CompHeight
;
640 CompWidth
= TopImage
->Width
;
641 CompHeight
= TopImage
->Height
;
642 egRestrictImageArea(CompImage
, PosX
, PosY
, &CompWidth
, &CompHeight
);
646 if (TopImage
->HasAlpha
) {
647 egRawCompose(CompImage
->PixelData
+ PosY
* CompImage
->Width
+ PosX
, TopImage
->PixelData
,
648 CompWidth
, CompHeight
, CompImage
->Width
, TopImage
->Width
);
650 egRawCopy(CompImage
->PixelData
+ PosY
* CompImage
->Width
+ PosX
, TopImage
->PixelData
,
651 CompWidth
, CompHeight
, CompImage
->Width
, TopImage
->Width
);
654 } /* VOID egComposeImage() */
657 // misc internal functions
660 VOID
egInsertPlane(IN UINT8
*SrcDataPtr
, IN UINT8
*DestPlanePtr
, IN UINTN PixelCount
)
664 for (i
= 0; i
< PixelCount
; i
++) {
665 *DestPlanePtr
= *SrcDataPtr
++;
670 VOID
egSetPlane(IN UINT8
*DestPlanePtr
, IN UINT8 Value
, IN UINTN PixelCount
)
674 for (i
= 0; i
< PixelCount
; i
++) {
675 *DestPlanePtr
= Value
;
680 VOID
egCopyPlane(IN UINT8
*SrcPlanePtr
, IN UINT8
*DestPlanePtr
, IN UINTN PixelCount
)
684 for (i
= 0; i
< PixelCount
; i
++) {
685 *DestPlanePtr
= *SrcPlanePtr
;
686 DestPlanePtr
+= 4, SrcPlanePtr
+= 4;