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 <sys/stat.h>␊ |
39 | #include <pexpert/i386/boot.h>␊ |
40 | #include "memcpy.h" // a fast memcpy␊ |
41 | ␊ |
42 | #define MAX_FILE_SIZE (1024*1024*1024)␊ |
43 | ␊ |
44 | ␊ |
45 | //␊ |
46 | // Basic image handling␊ |
47 | //␊ |
48 | ␊ |
49 | EG_IMAGE * egCreateImage(IN UINTN Width, IN UINTN Height, IN BOOLEAN HasAlpha)␊ |
50 | {␊ |
51 | EG_IMAGE *NewImage;␊ |
52 | ␊ |
53 | NewImage = (EG_IMAGE *) AllocateZeroPool(sizeof(EG_IMAGE));␊ |
54 | if (NewImage == NULL)␊ |
55 | return NULL;␊ |
56 | NewImage->PixelData = (EG_PIXEL *) AllocateZeroPool(Width * Height * sizeof(EG_PIXEL));␊ |
57 | if (NewImage->PixelData == NULL) {␊ |
58 | FreePool(NewImage);␊ |
59 | return NULL;␊ |
60 | }␊ |
61 | ␊ |
62 | NewImage->Width = Width;␊ |
63 | NewImage->Height = Height;␊ |
64 | NewImage->HasAlpha = HasAlpha;␊ |
65 | NewImage->NeedFlip = TRUE;␊ |
66 | return NewImage;␊ |
67 | }␊ |
68 | ␊ |
69 | EG_IMAGE * egCreateFilledImage(IN UINTN Width, IN UINTN Height, IN BOOLEAN HasAlpha, IN EG_PIXEL *Color)␊ |
70 | {␊ |
71 | EG_IMAGE *NewImage;␊ |
72 | ␊ |
73 | NewImage = egCreateImage(Width, Height, HasAlpha);␊ |
74 | if (NewImage == NULL)␊ |
75 | return NULL;␊ |
76 | ␊ |
77 | egFillImage(NewImage, Color);␊ |
78 | return NewImage;␊ |
79 | }␊ |
80 | ␊ |
81 | VOID egCopyImage(IN OUT EG_IMAGE *Image1, IN EG_IMAGE *Image2)␊ |
82 | { ␊ |
83 | if (Image1 == NULL || Image2 == NULL)␊ |
84 | return ;␊ |
85 | ␊ |
86 | CopyMem(Image1->PixelData, Image2->PixelData, Image2->Width * Image2->Height * sizeof(EG_PIXEL));␊ |
87 | ␊ |
88 | Image1->Width = Image2->Width;␊ |
89 | Image1->Height = Image2->Height;␊ |
90 | Image1->HasAlpha = Image2->HasAlpha;␊ |
91 | Image1->NeedFlip = Image2->NeedFlip;␊ |
92 | ␊ |
93 | return ;␊ |
94 | }␊ |
95 | ␊ |
96 | EG_IMAGE * egNewImageFromImage(IN EG_IMAGE *Image)␊ |
97 | {␊ |
98 | EG_IMAGE *NewImage;␊ |
99 | ␊ |
100 | NewImage = egCreateImage(Image->Width, Image->Height, Image->HasAlpha);␊ |
101 | if (NewImage == NULL)␊ |
102 | return NULL;␊ |
103 | ␊ |
104 | egCopyImage(NewImage, Image);␊ |
105 | ␊ |
106 | return NewImage;␊ |
107 | }␊ |
108 | ␊ |
109 | EG_IMAGE * egCreateImageFromData(IN EG_PIXEL *PixelData, IN UINTN Width, IN UINTN Height, IN BOOLEAN HasAlpha, BOOLEAN NeedFlip)␊ |
110 | {␊ |
111 | EG_IMAGE *NewImage;␊ |
112 | ␊ |
113 | NewImage = egCreateImage(Width, Height, HasAlpha);␊ |
114 | if (NewImage == NULL)␊ |
115 | return NULL;␊ |
116 | ␊ |
117 | CopyMem(NewImage->PixelData, PixelData, Width * Height * sizeof(EG_PIXEL));␊ |
118 | ␊ |
119 | NewImage->NeedFlip = NeedFlip;␊ |
120 | ␊ |
121 | return NewImage;␊ |
122 | }␊ |
123 | ␊ |
124 | VOID egCopyScaledImage(IN OUT EG_IMAGE *CompImage, IN EG_IMAGE *Image)␊ |
125 | {␊ |
126 | #ifndef MAX␊ |
127 | #define MAX(x, y) ((x) > (y) ? (x) : (y))␊ |
128 | #endif␊ |
129 | INTN x, x1, y, y1;␊ |
130 | #if UNUSED␊ |
131 | ␉INTN x0, x2;␊ |
132 | ␉INTN y0, y2;␊ |
133 | #endif␊ |
134 | UINTN RatioH, RatioW, Ratio;␊ |
135 | EG_PIXEL *Dest;␊ |
136 | ␊ |
137 | RatioW = (CompImage->Width << 4) / Image->Width;␊ |
138 | RatioH = (CompImage->Height << 4) / Image->Height;␊ |
139 | ␊ |
140 | Ratio = MAX(RatioH,RatioW);␊ |
141 | ␊ |
142 | Dest = CompImage->PixelData;␊ |
143 | for (y = 0; y < CompImage->Height; y++) {␊ |
144 | y1 = (y<<4) / Ratio;␊ |
145 | #if UNUSED␊ |
146 | y0 = ((y1 > 0)?(y1-1):y1)*Image->Width;␊ |
147 | y2 = ((y1 < Image->Height)?(y1+1):y1)*Image->Width;␊ |
148 | #endif␊ |
149 | y1 *= Image->Width;␊ |
150 | for (x = 0; x < CompImage->Width; x++) {␊ |
151 | x1 = (x<<4) / Ratio;␊ |
152 | #if UNUSED␊ |
153 | x0 = (x1 > 0)?(x1-1):x1;␊ |
154 | x2 = (x1 < Image->Width)?(x1+1):x1;␊ |
155 | #endif␊ |
156 | //TODO - make sum of 5 points␊ |
157 | *Dest++ = Image->PixelData[x1+y1];␊ |
158 | }␊ |
159 | } ␊ |
160 | }␊ |
161 | ␊ |
162 | ␊ |
163 | EG_IMAGE * egNewScaledImage(IN EG_IMAGE *Image, IN UINTN NewW, IN UINTN NewH)␊ |
164 | {␊ |
165 | ␊ |
166 | EG_IMAGE *NewImage;␊ |
167 | ␊ |
168 | NewImage = egCreateImage(NewW, NewH, Image->HasAlpha);␊ |
169 | if (NewImage == NULL)␊ |
170 | return NULL;␊ |
171 | ␊ |
172 | egCopyScaledImage(NewImage,Image); ␊ |
173 | ␊ |
174 | return NewImage;␊ |
175 | }␊ |
176 | ␊ |
177 | VOID egFreeImage(IN EG_IMAGE *Image)␊ |
178 | {␊ |
179 | if (Image != NULL) {␊ |
180 | if (Image->PixelData != NULL)␊ |
181 | FreePool(Image->PixelData);␊ |
182 | FreePool(Image);␊ |
183 | }␊ |
184 | }␊ |
185 | ␊ |
186 | //␊ |
187 | // Basic file operations␊ |
188 | //␊ |
189 | ␊ |
190 | EFI_STATUS egLoadFile(IN CHAR16 *FileName,␊ |
191 | OUT UINT8 **FileData, OUT UINTN *FileDataLength)␊ |
192 | {␊ |
193 | FILE␉␉␉␉*FileHandle;␊ |
194 | UINT64 ReadSize;␊ |
195 | UINTN BufferSize;␊ |
196 | UINT8 *Buffer;␊ |
197 | ␉CHAR8␉␉␉␉FileName8[1024];␊ |
198 | ␉struct␉␉␉␉stat buf;␊ |
199 | ␊ |
200 | ␉UnicodeStrToAsciiStr(FileName, FileName8);␊ |
201 | ␊ |
202 | FileHandle = fopen(FileName8, "rb");␊ |
203 | if (!FileHandle)␊ |
204 | return EFI_NOT_FOUND; ␊ |
205 | ␉printf("file opened\n");␊ |
206 | ␊ |
207 | fstat(fileno(FileHandle), &buf);␉␊ |
208 | ReadSize = buf.st_size;␉␊ |
209 | ␉if (!ReadSize)␊ |
210 | ␉{␊ |
211 | ␉␉fclose(FileHandle);␊ |
212 | ␉␉return EFI_LOAD_ERROR;␊ |
213 | ␉} ␊ |
214 | ␉else if (ReadSize > MAX_FILE_SIZE)␊ |
215 | ReadSize = MAX_FILE_SIZE;␊ |
216 | ␉printf("file size = %d\n", (INTN)ReadSize);␊ |
217 | ␊ |
218 | BufferSize = (UINTN)ReadSize; // was limited to 1 GB above, so this is safe␊ |
219 | Buffer = (UINT8 *) AllocatePool(BufferSize);␊ |
220 | if (Buffer == NULL) {␊ |
221 | fclose(FileHandle);␊ |
222 | return EFI_OUT_OF_RESOURCES;␊ |
223 | }␊ |
224 | ␉printf("AllocatePool = %p\n", (VOID*)Buffer);␊ |
225 | ␊ |
226 | ␉ReadSize = fread(Buffer, 1, BufferSize, FileHandle);␊ |
227 | fclose(FileHandle);␊ |
228 | if (BufferSize != ReadSize) {␊ |
229 | FreePool(Buffer);␊ |
230 | return EFI_BAD_BUFFER_SIZE;␊ |
231 | }␊ |
232 | ␉printf("Buffer read successfuly\n");␊ |
233 | ␊ |
234 | *FileData = Buffer;␊ |
235 | *FileDataLength = BufferSize;␊ |
236 | return EFI_SUCCESS;␊ |
237 | }␊ |
238 | ␊ |
239 | //␊ |
240 | // Loading images from files and embedded data␊ |
241 | //␊ |
242 | ␊ |
243 | static CHAR16 * egFindExtension(IN CHAR16 *FileName)␊ |
244 | {␊ |
245 | INTN i;␊ |
246 | ␊ |
247 | for (i = StrLen(FileName); i >= 0; i--) {␊ |
248 | if (FileName[i] == '.')␊ |
249 | return FileName + i + 1;␊ |
250 | if (FileName[i] == '/' || FileName[i] == '\\')␊ |
251 | break;␊ |
252 | }␊ |
253 | return FileName + StrLen(FileName);␊ |
254 | }␊ |
255 | ␊ |
256 | static EG_IMAGE * egDecodeAny(IN UINT8 *FileData, IN UINTN FileDataLength,␊ |
257 | IN CHAR16 *Format, IN UINTN IconSize, IN BOOLEAN WantAlpha)␊ |
258 | {␊ |
259 | EG_DECODE_FUNC DecodeFunc;␊ |
260 | EG_IMAGE *NewImage;␊ |
261 | ␊ |
262 | // dispatch by extension␊ |
263 | DecodeFunc = NULL;␊ |
264 | if (StrCmp(Format, L"BMP") == 0)␊ |
265 | DecodeFunc = egDecodeBMP;␊ |
266 | else if (StrCmp(Format, L"ICNS") == 0)␊ |
267 | DecodeFunc = egDecodeICNS;␊ |
268 | else if (StrCmp(Format, L"PNG" ) == 0)␊ |
269 | DecodeFunc = egDecodePNG;␊ |
270 | ␊ |
271 | if (DecodeFunc == NULL)␊ |
272 | return NULL;␊ |
273 | ␊ |
274 | // decode it␊ |
275 | NewImage = DecodeFunc(FileData, FileDataLength, IconSize, WantAlpha);␊ |
276 | ␊ |
277 | return NewImage;␊ |
278 | }␊ |
279 | ␊ |
280 | EG_IMAGE * egLoadImage(IN CHAR16 *FilePath, IN BOOLEAN WantAlpha)␊ |
281 | {␊ |
282 | EFI_STATUS Status;␊ |
283 | UINT8 *FileData;␊ |
284 | UINTN FileDataLength;␊ |
285 | EG_IMAGE *NewImage;␊ |
286 | ␊ |
287 | if (FilePath == NULL)␊ |
288 | return NULL;␊ |
289 | ␊ |
290 | // load file␊ |
291 | ␉printf("load file\n");␊ |
292 | Status = egLoadFile(FilePath, &FileData, &FileDataLength);␊ |
293 | if (EFI_ERROR(Status))␊ |
294 | return NULL;␊ |
295 | ␊ |
296 | // decode it␊ |
297 | ␉printf("decode it\n");␊ |
298 | NewImage = egDecodeAny(FileData, FileDataLength, egFindExtension(FilePath), 128, WantAlpha);␊ |
299 | FreePool(FileData);␊ |
300 | ␊ |
301 | return NewImage;␊ |
302 | }␊ |
303 | ␊ |
304 | EG_IMAGE * egLoadIcon(IN CHAR16 *FilePath, IN UINTN IconSize)␊ |
305 | {␊ |
306 | EFI_STATUS Status;␊ |
307 | UINT8 *FileData;␊ |
308 | UINTN FileDataLength;␊ |
309 | EG_IMAGE *NewImage;␊ |
310 | ␊ |
311 | if (FilePath == NULL)␊ |
312 | return NULL;␊ |
313 | ␊ |
314 | // load file␊ |
315 | Status = egLoadFile(FilePath, &FileData, &FileDataLength);␊ |
316 | if (EFI_ERROR(Status))␊ |
317 | return NULL;␊ |
318 | ␊ |
319 | // decode it␊ |
320 | NewImage = egDecodeAny(FileData, FileDataLength, egFindExtension(FilePath), IconSize, TRUE);␊ |
321 | FreePool(FileData);␊ |
322 | ␊ |
323 | return NewImage;␊ |
324 | }␊ |
325 | ␊ |
326 | EG_IMAGE * egDecodeImage(IN UINT8 *FileData, IN UINTN FileDataLength, IN CHAR16 *Format, IN BOOLEAN WantAlpha)␊ |
327 | {␊ |
328 | return egDecodeAny(FileData, FileDataLength, Format, 128, WantAlpha);␊ |
329 | }␊ |
330 | ␊ |
331 | EG_IMAGE * egPrepareEmbeddedImage(IN EG_EMBEDDED_IMAGE *EmbeddedImage, IN BOOLEAN WantAlpha)␊ |
332 | {␊ |
333 | EG_IMAGE *NewImage;␊ |
334 | UINT8 *CompData;␊ |
335 | UINTN CompLen;␊ |
336 | UINTN PixelCount;␊ |
337 | ␊ |
338 | // sanity check␊ |
339 | if (EmbeddedImage->PixelMode > EG_MAX_EIPIXELMODE ||␊ |
340 | (EmbeddedImage->CompressMode != EG_EICOMPMODE_NONE && EmbeddedImage->CompressMode != EG_EICOMPMODE_RLE))␊ |
341 | return NULL;␊ |
342 | ␊ |
343 | // allocate image structure and pixel buffer␊ |
344 | NewImage = egCreateImage(EmbeddedImage->Width, EmbeddedImage->Height, WantAlpha);␊ |
345 | if (NewImage == NULL)␊ |
346 | return NULL;␊ |
347 | ␊ |
348 | CompData = (UINT8 *)EmbeddedImage->Data; // drop const␊ |
349 | CompLen = EmbeddedImage->DataLength;␊ |
350 | PixelCount = EmbeddedImage->Width * EmbeddedImage->Height;␊ |
351 | ␊ |
352 | // FUTURE: for EG_EICOMPMODE_EFICOMPRESS, decompress whole data block here␊ |
353 | ␊ |
354 | if (EmbeddedImage->PixelMode == EG_EIPIXELMODE_GRAY ||␊ |
355 | EmbeddedImage->PixelMode == EG_EIPIXELMODE_GRAY_ALPHA) {␊ |
356 | ␊ |
357 | // copy grayscale plane and expand␊ |
358 | if (EmbeddedImage->CompressMode == EG_EICOMPMODE_RLE) {␊ |
359 | egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, r), PixelCount);␊ |
360 | } else {␊ |
361 | egInsertPlane(CompData, PLPTR(NewImage, r), PixelCount);␊ |
362 | CompData += PixelCount;␊ |
363 | }␊ |
364 | egCopyPlane(PLPTR(NewImage, r), PLPTR(NewImage, g), PixelCount);␊ |
365 | egCopyPlane(PLPTR(NewImage, r), PLPTR(NewImage, b), PixelCount);␊ |
366 | ␊ |
367 | } else if (EmbeddedImage->PixelMode == EG_EIPIXELMODE_COLOR ||␊ |
368 | EmbeddedImage->PixelMode == EG_EIPIXELMODE_COLOR_ALPHA) {␊ |
369 | ␊ |
370 | // copy color planes␊ |
371 | if (EmbeddedImage->CompressMode == EG_EICOMPMODE_RLE) {␊ |
372 | egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, r), PixelCount);␊ |
373 | egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, g), PixelCount);␊ |
374 | egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, b), PixelCount);␊ |
375 | } else {␊ |
376 | egInsertPlane(CompData, PLPTR(NewImage, r), PixelCount);␊ |
377 | CompData += PixelCount;␊ |
378 | egInsertPlane(CompData, PLPTR(NewImage, g), PixelCount);␊ |
379 | CompData += PixelCount;␊ |
380 | egInsertPlane(CompData, PLPTR(NewImage, b), PixelCount);␊ |
381 | CompData += PixelCount;␊ |
382 | }␊ |
383 | ␊ |
384 | } else {␊ |
385 | ␊ |
386 | // set color planes to black␊ |
387 | egSetPlane(PLPTR(NewImage, r), 0, PixelCount);␊ |
388 | egSetPlane(PLPTR(NewImage, g), 0, PixelCount);␊ |
389 | egSetPlane(PLPTR(NewImage, b), 0, PixelCount);␊ |
390 | ␊ |
391 | }␊ |
392 | ␊ |
393 | if (WantAlpha && (EmbeddedImage->PixelMode == EG_EIPIXELMODE_GRAY_ALPHA ||␊ |
394 | EmbeddedImage->PixelMode == EG_EIPIXELMODE_COLOR_ALPHA ||␊ |
395 | EmbeddedImage->PixelMode == EG_EIPIXELMODE_ALPHA)) {␊ |
396 | ␊ |
397 | // copy alpha plane␊ |
398 | if (EmbeddedImage->CompressMode == EG_EICOMPMODE_RLE) {␊ |
399 | egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, a), PixelCount);␊ |
400 | } else {␊ |
401 | egInsertPlane(CompData, PLPTR(NewImage, a), PixelCount);␊ |
402 | CompData += PixelCount;␊ |
403 | }␊ |
404 | ␊ |
405 | } else {␊ |
406 | egSetPlane(PLPTR(NewImage, a), WantAlpha ? 255 : 0, PixelCount);␊ |
407 | }␊ |
408 | ␊ |
409 | return NewImage;␊ |
410 | }␊ |
411 | ␊ |
412 | //␊ |
413 | // Compositing␊ |
414 | //␊ |
415 | ␊ |
416 | VOID egRestrictImageArea(IN EG_IMAGE *Image,␊ |
417 | ␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉ IN UINTN AreaPosX, IN UINTN AreaPosY,␊ |
418 | ␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉ IN OUT UINTN *AreaWidth, IN OUT UINTN *AreaHeight)␊ |
419 | {␊ |
420 | if (AreaPosX >= Image->Width || AreaPosY >= Image->Height) {␊ |
421 | // out of bounds, operation has no effect␊ |
422 | *AreaWidth = 0;␊ |
423 | *AreaHeight = 0;␊ |
424 | } else {␊ |
425 | // calculate affected area␊ |
426 | if (*AreaWidth > Image->Width - AreaPosX)␊ |
427 | *AreaWidth = Image->Width - AreaPosX;␊ |
428 | if (*AreaHeight > Image->Height - AreaPosY)␊ |
429 | *AreaHeight = Image->Height - AreaPosY;␊ |
430 | }␊ |
431 | }␊ |
432 | ␊ |
433 | VOID egFillImage(IN OUT EG_IMAGE *CompImage, IN EG_PIXEL *Color)␊ |
434 | {␊ |
435 | UINTN i;␊ |
436 | EG_PIXEL FillColor;␊ |
437 | EG_PIXEL *PixelPtr;␊ |
438 | ␊ |
439 | FillColor = *Color;␊ |
440 | if (!CompImage->HasAlpha)␊ |
441 | FillColor.a = 0;␊ |
442 | ␊ |
443 | PixelPtr = CompImage->PixelData;␊ |
444 | for (i = 0; i < CompImage->Width * CompImage->Height; i++, PixelPtr++)␊ |
445 | *PixelPtr = FillColor;␊ |
446 | }␊ |
447 | ␊ |
448 | VOID egFillImageArea(IN OUT EG_IMAGE *CompImage,␊ |
449 | ␉␉␉␉␉␉␉␉␉␉␉␉␉␉ IN UINTN AreaPosX, IN UINTN AreaPosY,␊ |
450 | ␉␉␉␉␉␉␉␉␉␉␉␉␉␉ IN UINTN AreaWidth, IN UINTN AreaHeight,␊ |
451 | ␉␉␉␉␉␉␉␉␉␉␉␉␉␉ IN EG_PIXEL *Color)␊ |
452 | {␊ |
453 | UINTN x, y;␊ |
454 | EG_PIXEL FillColor;␊ |
455 | EG_PIXEL *PixelPtr;␊ |
456 | EG_PIXEL *PixelBasePtr;␊ |
457 | ␊ |
458 | egRestrictImageArea(CompImage, AreaPosX, AreaPosY, &AreaWidth, &AreaHeight);␊ |
459 | ␊ |
460 | if (AreaWidth > 0) {␊ |
461 | FillColor = *Color;␊ |
462 | if (!CompImage->HasAlpha)␊ |
463 | FillColor.a = 0;␊ |
464 | ␊ |
465 | PixelBasePtr = CompImage->PixelData + AreaPosY * CompImage->Width + AreaPosX;␊ |
466 | for (y = 0; y < AreaHeight; y++) {␊ |
467 | PixelPtr = PixelBasePtr;␊ |
468 | for (x = 0; x < AreaWidth; x++, PixelPtr++)␊ |
469 | *PixelPtr = FillColor;␊ |
470 | PixelBasePtr += CompImage->Width;␊ |
471 | }␊ |
472 | }␊ |
473 | }␊ |
474 | ␊ |
475 | VOID egRawCopy(IN OUT EG_PIXEL *CompBasePtr, IN EG_PIXEL *TopBasePtr,␊ |
476 | ␉␉␉␉␉␉␉␉␉␉␉␉ IN UINTN Width, IN UINTN Height,␊ |
477 | ␉␉␉␉␉␉␉␉␉␉␉␉ IN UINTN CompLineOffset, IN UINTN TopLineOffset)␊ |
478 | {␊ |
479 | UINTN x, y;␊ |
480 | EG_PIXEL *TopPtr, *CompPtr;␊ |
481 | ␊ |
482 | for (y = 0; y < Height; y++) {␊ |
483 | TopPtr = TopBasePtr;␊ |
484 | CompPtr = CompBasePtr;␊ |
485 | for (x = 0; x < Width; x++) {␊ |
486 | *CompPtr = *TopPtr;␊ |
487 | TopPtr++, CompPtr++;␊ |
488 | }␊ |
489 | TopBasePtr += TopLineOffset;␊ |
490 | CompBasePtr += CompLineOffset;␊ |
491 | }␊ |
492 | }␊ |
493 | ␊ |
494 | VOID egRawCompose(IN OUT EG_PIXEL *CompBasePtr, IN EG_PIXEL *TopBasePtr,␊ |
495 | ␉␉␉␉␉␉␉␉␉␉␉␉␉ IN UINTN Width, IN UINTN Height,␊ |
496 | ␉␉␉␉␉␉␉␉␉␉␉␉␉ IN UINTN CompLineOffset, IN UINTN TopLineOffset)␊ |
497 | {␊ |
498 | UINTN x, y;␊ |
499 | EG_PIXEL *TopPtr, *CompPtr;␊ |
500 | UINTN Alpha;␊ |
501 | UINTN RevAlpha;␊ |
502 | UINTN Temp;␊ |
503 | ␊ |
504 | for (y = 0; y < Height; y++) {␊ |
505 | TopPtr = TopBasePtr;␊ |
506 | CompPtr = CompBasePtr;␊ |
507 | for (x = 0; x < Width; x++) {␊ |
508 | Alpha = TopPtr->a;␊ |
509 | RevAlpha = 255 - Alpha;␊ |
510 | Temp = (UINTN)CompPtr->b * RevAlpha + (UINTN)TopPtr->b * Alpha + 0x80;␊ |
511 | CompPtr->b = (Temp + (Temp >> 8)) >> 8;␊ |
512 | Temp = (UINTN)CompPtr->g * RevAlpha + (UINTN)TopPtr->g * Alpha + 0x80;␊ |
513 | CompPtr->g = (Temp + (Temp >> 8)) >> 8;␊ |
514 | Temp = (UINTN)CompPtr->r * RevAlpha + (UINTN)TopPtr->r * Alpha + 0x80;␊ |
515 | CompPtr->r = (Temp + (Temp >> 8)) >> 8;␊ |
516 | /*␊ |
517 | ␉␉␉ CompPtr->b = ((UINTN)CompPtr->b * RevAlpha + (UINTN)TopPtr->b * Alpha) / 255;␊ |
518 | ␉␉␉ CompPtr->g = ((UINTN)CompPtr->g * RevAlpha + (UINTN)TopPtr->g * Alpha) / 255;␊ |
519 | ␉␉␉ CompPtr->r = ((UINTN)CompPtr->r * RevAlpha + (UINTN)TopPtr->r * Alpha) / 255;␊ |
520 | ␉␉␉ */␊ |
521 | TopPtr++, CompPtr++;␊ |
522 | }␊ |
523 | TopBasePtr += TopLineOffset;␊ |
524 | CompBasePtr += CompLineOffset;␊ |
525 | }␊ |
526 | }␊ |
527 | ␊ |
528 | VOID egComposeImage(IN OUT EG_IMAGE *CompImage, IN EG_IMAGE *TopImage, IN UINTN PosX, IN UINTN PosY)␊ |
529 | {␊ |
530 | UINTN CompWidth, CompHeight;␊ |
531 | ␊ |
532 | CompWidth = TopImage->Width;␊ |
533 | CompHeight = TopImage->Height;␊ |
534 | egRestrictImageArea(CompImage, PosX, PosY, &CompWidth, &CompHeight);␊ |
535 | ␊ |
536 | // compose␊ |
537 | if (CompWidth > 0) {␊ |
538 | if (CompImage->HasAlpha) {␊ |
539 | CompImage->HasAlpha = FALSE;␊ |
540 | egSetPlane(PLPTR(CompImage, a), 0, CompImage->Width * CompImage->Height);␊ |
541 | }␊ |
542 | ␊ |
543 | if (TopImage->HasAlpha)␊ |
544 | egRawCompose(CompImage->PixelData + PosY * CompImage->Width + PosX, TopImage->PixelData,␊ |
545 | CompWidth, CompHeight, CompImage->Width, TopImage->Width);␊ |
546 | else␊ |
547 | egRawCopy(CompImage->PixelData + PosY * CompImage->Width + PosX, TopImage->PixelData,␊ |
548 | CompWidth, CompHeight, CompImage->Width, TopImage->Width);␊ |
549 | }␊ |
550 | }␊ |
551 | ␊ |
552 | BOOLEAN egComposeImageStretched(IN OUT EG_IMAGE *CompImage, IN EG_IMAGE *TopImage)␊ |
553 | {␊ |
554 | #define MARGIN 0␊ |
555 | UINT8␉␉*pStretchedImage;␊ |
556 | UINT8␉␉*pImg;␊ |
557 | ␉UINT8␉␉*pbImage , *pDiData;␊ |
558 | UINTN cImgChannels; ␊ |
559 | ␉UINTN␉␉deltaNewSize, deltaWinSize;␊ |
560 | ␉UINTN␉␉cxImgPos, cyImgPos;␊ |
561 | ␉UINTN␉␉xOld, yOld;␊ |
562 | UINTN␉␉xNew, yNew;␊ |
563 | ␉UINTN␉␉xImg, yImg;␊ |
564 | UINTN␉␉xWin, yWin;␊ |
565 | ␉UINT8␉␉r, g, b, a;␊ |
566 | ␉UINTN␉␉cxImgSize, cyImgSize;␊ |
567 | ␉UINT8␉␉*src, *dst;␊ |
568 | ␉const INT32 cDIChannels = 3;␊ |
569 | UINT16 wImgRowBytes;␊ |
570 | UINT16 wDIRowBytes;␊ |
571 | ␉␊ |
572 | ␉␊ |
573 | ␉deltaWinSize = MAX(CompImage->Width,CompImage->Height); ␊ |
574 | ␉cxImgSize = TopImage->Width;␊ |
575 | ␉cyImgSize = TopImage->Height;␊ |
576 | ␉pbImage␉ = (UINT8*)TopImage->PixelData;␊ |
577 | ␉pDiData = (UINT8*)CompImage->PixelData;␉␊ |
578 | ␉␊ |
579 | ␉{␊ |
580 | deltaNewSize = deltaWinSize - 2 * MARGIN;␊ |
581 | cImgChannels = (TopImage->HasAlpha) ? 4 : 3;␉␉␊ |
582 | ␊ |
583 | ␊ |
584 | // stretch the image to it's window determined size␊ |
585 | ␊ |
586 | // the following two are the same, but the first has side-effects␊ |
587 | // because of rounding␊ |
588 | // if ((deltaNewSize / deltaNewSize) > (cyImgSize / cxImgSize))␊ |
589 | if ((deltaNewSize * cxImgSize) > (cyImgSize * deltaNewSize))␊ |
590 | {␊ |
591 | deltaNewSize = deltaNewSize * cyImgSize / cxImgSize;␊ |
592 | cxImgPos = MARGIN;␊ |
593 | cyImgPos = (deltaWinSize - deltaNewSize) / 2;␊ |
594 | }␊ |
595 | else␊ |
596 | {␊ |
597 | deltaNewSize = deltaNewSize * cxImgSize / cyImgSize;␊ |
598 | cyImgPos = MARGIN;␊ |
599 | cxImgPos = (deltaWinSize - deltaNewSize) / 2;␊ |
600 | }␊ |
601 | ␊ |
602 | pStretchedImage = AllocatePool (cImgChannels * deltaNewSize * deltaNewSize);␊ |
603 | if (!pStretchedImage)␊ |
604 | {␊ |
605 | return FALSE;␊ |
606 | }␊ |
607 | ␉␉pImg = pStretchedImage;␊ |
608 | ␊ |
609 | for (yNew = 0; yNew < deltaNewSize; yNew++)␊ |
610 | {␊ |
611 | yOld = yNew * cyImgSize / deltaNewSize;␊ |
612 | for (xNew = 0; xNew < deltaNewSize; xNew++)␊ |
613 | {␊ |
614 | xOld = xNew * cxImgSize / deltaNewSize;␊ |
615 | ␊ |
616 | r = *(pbImage + cImgChannels * ((yOld * cxImgSize) + xOld) + 0);␊ |
617 | g = *(pbImage + cImgChannels * ((yOld * cxImgSize) + xOld) + 1);␊ |
618 | b = *(pbImage + cImgChannels * ((yOld * cxImgSize) + xOld) + 2);␊ |
619 | *pImg++ = r;␊ |
620 | *pImg++ = g;␊ |
621 | *pImg++ = b;␊ |
622 | if (cImgChannels == 4)␊ |
623 | {␊ |
624 | a = *(pbImage + cImgChannels * ((yOld * cxImgSize) + xOld)␊ |
625 | + 3);␊ |
626 | *pImg++ = a;␊ |
627 | }␊ |
628 | }␊ |
629 | }␊ |
630 | ␉␉␊ |
631 | ␉␉// calculate row-bytes␊ |
632 | ␊ |
633 | wImgRowBytes = cImgChannels * deltaNewSize;␊ |
634 | wDIRowBytes = (unsigned short) ((cDIChannels * deltaWinSize + 3L) >> 2) << 2;␊ |
635 | ␊ |
636 | // copy image to screen␊ |
637 | ␉␉␊ |
638 | for (yImg = 0, yWin = cyImgPos; yImg < deltaNewSize; yImg++, yWin++)␊ |
639 | {␊ |
640 | if (yWin >= CompImage->Width - cyImgPos)␊ |
641 | break;␊ |
642 | src = pStretchedImage + yImg * wImgRowBytes;␊ |
643 | dst = pDiData + yWin * wDIRowBytes + cxImgPos * cDIChannels;␊ |
644 | ␊ |
645 | for (xImg = 0, xWin = cxImgPos; xImg < deltaNewSize; xImg++, xWin++)␊ |
646 | {␊ |
647 | if (xWin >= deltaWinSize - cxImgPos)␊ |
648 | break;␊ |
649 | r = *src++;␊ |
650 | g = *src++;␊ |
651 | b = *src++;␊ |
652 | *dst++ = b; /* note the reverse order */␊ |
653 | *dst++ = g;␊ |
654 | *dst++ = r;␊ |
655 | if (cImgChannels == 4)␊ |
656 | {␊ |
657 | a = *src++;␊ |
658 | }␊ |
659 | }␊ |
660 | }␉␉␊ |
661 | ␊ |
662 | // free memory␊ |
663 | ␊ |
664 | if (pStretchedImage != NULL)␊ |
665 | {␊ |
666 | FreePool (pStretchedImage);␊ |
667 | pStretchedImage = NULL;␊ |
668 | }␉␉␊ |
669 | ␊ |
670 | }␊ |
671 | ␉return TRUE;␊ |
672 | ␊ |
673 | }␊ |
674 | ␊ |
675 | VOID egFlipRB(IN EG_IMAGE *Image)␊ |
676 | {␉␊ |
677 | ␉UINT32 x;␊ |
678 | register UINT8 tempB;␊ |
679 | if (Image->NeedFlip == TRUE)␊ |
680 | {␊ |
681 | for (x = 0; x < (unsigned long)(Image->Height) * (Image->Width) ; x++) {␊ |
682 | tempB = Image->PixelData[x].b;␊ |
683 | Image->PixelData[x].b = Image->PixelData[x].r;␊ |
684 | Image->PixelData[x].r = tempB;␊ |
685 | }␊ |
686 | Image->NeedFlip = FALSE;␊ |
687 | }␊ |
688 | }␊ |
689 | ␊ |
690 | EG_IMAGE * egEnsureImageSize(IN EG_IMAGE *Image, IN UINTN Width, IN UINTN Height, IN EG_PIXEL *Color)␊ |
691 | {␊ |
692 | EG_IMAGE *NewImage;␊ |
693 | ␉␊ |
694 | if (Image == NULL)␊ |
695 | return NULL;␊ |
696 | if (Image->Width == Width && Image->Height == Height)␊ |
697 | return Image;␊ |
698 | ␊ |
699 | NewImage = egCreateFilledImage(Width, Height, Image->HasAlpha, Color);␊ |
700 | if (NewImage == NULL) {␊ |
701 | egFreeImage(Image);␊ |
702 | return NULL;␊ |
703 | }␊ |
704 | egComposeImage(NewImage, Image, 0, 0);␊ |
705 | egFreeImage(Image);␊ |
706 | ␊ |
707 | return NewImage;␊ |
708 | }␊ |
709 | ␊ |
710 | //␊ |
711 | // misc internal functions␊ |
712 | //␊ |
713 | ␊ |
714 | VOID egInsertPlane(IN UINT8 *SrcDataPtr, IN UINT8 *DestPlanePtr, IN UINTN PixelCount)␊ |
715 | {␊ |
716 | UINTN i;␊ |
717 | ␊ |
718 | for (i = 0; i < PixelCount; i++) {␊ |
719 | *DestPlanePtr = *SrcDataPtr++;␊ |
720 | DestPlanePtr += 4;␊ |
721 | }␊ |
722 | }␊ |
723 | ␊ |
724 | VOID egSetPlane(IN UINT8 *DestPlanePtr, IN UINT8 Value, IN UINTN PixelCount)␊ |
725 | {␊ |
726 | UINTN i;␊ |
727 | ␊ |
728 | for (i = 0; i < PixelCount; i++) {␊ |
729 | *DestPlanePtr = Value;␊ |
730 | DestPlanePtr += 4;␊ |
731 | }␊ |
732 | }␊ |
733 | ␊ |
734 | VOID egCopyPlane(IN UINT8 *SrcPlanePtr, IN UINT8 *DestPlanePtr, IN UINTN PixelCount)␊ |
735 | {␊ |
736 | UINTN i;␊ |
737 | ␊ |
738 | for (i = 0; i < PixelCount; i++) {␊ |
739 | *DestPlanePtr = *SrcPlanePtr;␊ |
740 | DestPlanePtr += 4, SrcPlanePtr += 4;␊ |
741 | }␊ |
742 | }␊ |
743 | ␊ |
744 | ␊ |
745 | ␊ |
746 | ␊ |
747 | #define VIDEO(x) (((boot_args*)getBootArgs())->Video.v_ ## x)␊ |
748 | //#define vram VIDEO(baseAddr)␊ |
749 | ␊ |
750 | VOID egVramWrite (IN VOID *data, IN UINTN width, IN UINTN Height, IN UINTN PosX, IN UINTN PosY, UINTN BytesPerScanLine)␊ |
751 | {␊ |
752 | ␊ |
753 | UINT8 *vram = (UINT8 *)VIDEO(baseAddr);␊ |
754 | UINTN depth = (UINTN)VIDEO (depth);␊ |
755 | UINTN rowBytes = (UINTN)VIDEO (rowBytes);␊ |
756 | UINTN vHeight = (UINTN)VIDEO (height);␊ |
757 | UINTN vWidth ;␊ |
758 | ␊ |
759 | ␉if (depth == 0x20 && rowBytes == (UINT32)width * BytesPerScanLine)␊ |
760 | ␉␉memcpy((CHAR8 *)vram, data, rowBytes * vHeight);␊ |
761 | ␉else␊ |
762 | ␉{␊ |
763 | ␉␉UINT32 r, g, b;␊ |
764 | ␉␉UINT32 i, j;␊ |
765 | ␊ |
766 | UINT32 x, y;␊ |
767 | vWidth = (UINTN)VIDEO (width);␊ |
768 | ␊ |
769 | x = MIN(vWidth, width);␊ |
770 | y = MIN(vHeight, Height);␊ |
771 | ␊ |
772 | ␉␉for (i = PosY; i < y; i++)␊ |
773 | ␉␉␉for (j = PosX; j < x; j++)␊ |
774 | ␉␉␉{␊ |
775 | ␉␉␉␉b = ((UINT8 *) data)[4*i*width + 4*j];␊ |
776 | ␉␉␉␉g = ((UINT8 *) data)[4*i*width + 4*j + 1];␊ |
777 | ␉␉␉␉r = ((UINT8 *) data)[4*i*width + 4*j + 2];␊ |
778 | ␉␉␉␉switch (depth)␊ |
779 | ␉␉␉␉{␊ |
780 | ␉␉␉␉␉case 32:␊ |
781 | ␊ |
782 | ␉␉␉␉␉␉*(UINT32 *)(((UINT8 *)vram)+i* x*BytesPerScanLine + j*4) = (b&0xff) | ((g&0xff)<<8) | ((r&0xff)<<16);␊ |
783 | ␉␉␉␉␉␉break;␊ |
784 | ␉␉␉␉␉case 24:␊ |
785 | *(UINT32 *)(((UINT8 *)vram)+i*x*BytesPerScanLine + j*3) = ((*(UINT32 *)(((UINT8 *)vram)+i*x*BytesPerScanLine + j*3))&0xff000000)␊ |
786 | ␉␉␉␉␉␉| (b&0xff) | ((g&0xff)<<8) | ((r&0xff)<<16);␊ |
787 | ␉␉␉␉␉␉break;␊ |
788 | ␉␉␉␉␉case 16:␊ |
789 | ␉␉␉␉␉␉// Somehow 16-bit is always 15-bits really␊ |
790 | ␉␉␉␉␉␉//␉␉␉␉␉␉*(uint16_t *)(((uint8_t *)vram)+i*VIDEO (rowBytes) + j*2) = ((b&0xf8)>>3) | ((g&0xfc)<<3) | ((r&0xf8)<<8);␊ |
791 | ␉␉␉␉␉␉//␉␉␉␉␉␉break;␊ |
792 | ␉␉␉␉␉case 15:␊ |
793 | ␊ |
794 | ␉␉␉␉␉␉*(UINT16 *)(((UINT8 *)vram)+i*x*BytesPerScanLine + j*2) = ((b&0xf8)>>3) | ((g&0xf8)<<2) | ((r&0xf8)<<7);␊ |
795 | ␉␉␉␉␉␉break;␊ |
796 | ␉␉␉␉␉default:␊ |
797 | ␉␉␉␉␉␉break;␊ |
798 | ␉␉␉␉}␊ |
799 | ␉␉␉}␊ |
800 | ␉}␊ |
801 | } |