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