1 | /*␊ |
2 | * libeg/load_bmp.c␊ |
3 | * Loading function for BMP images␊ |
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 | ␊ |
39 | // BMP structures␊ |
40 | ␊ |
41 | #pragma pack(1)␊ |
42 | ␊ |
43 | typedef struct {␊ |
44 | UINT8 Blue;␊ |
45 | UINT8 Green;␊ |
46 | UINT8 Red;␊ |
47 | UINT8 Reserved;␊ |
48 | } BMP_COLOR_MAP;␊ |
49 | ␊ |
50 | typedef struct {␊ |
51 | CHAR8 CharB;␊ |
52 | CHAR8 CharM;␊ |
53 | UINT32 Size;␊ |
54 | UINT16 Reserved[2];␊ |
55 | UINT32 ImageOffset;␊ |
56 | UINT32 HeaderSize;␊ |
57 | UINT32 PixelWidth;␊ |
58 | UINT32 PixelHeight;␊ |
59 | UINT16 Planes; // Must be 1␊ |
60 | UINT16 BitPerPixel; // 1, 4, 8, or 24␊ |
61 | UINT32 CompressionType;␊ |
62 | UINT32 ImageSize; // Compressed image size in bytes␊ |
63 | UINT32 XPixelsPerMeter;␊ |
64 | UINT32 YPixelsPerMeter;␊ |
65 | UINT32 NumberOfColors;␊ |
66 | UINT32 ImportantColors;␊ |
67 | } BMP_IMAGE_HEADER;␊ |
68 | ␊ |
69 | #pragma pack()␊ |
70 | ␊ |
71 | //␊ |
72 | // Load BMP image␊ |
73 | //␊ |
74 | ␊ |
75 | EG_IMAGE * egDecodeBMP(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN IconSize, IN BOOLEAN WantAlpha)␊ |
76 | {␊ |
77 | EG_IMAGE *NewImage;␊ |
78 | BMP_IMAGE_HEADER *BmpHeader;␊ |
79 | BMP_COLOR_MAP *BmpColorMap;␊ |
80 | UINTN x, y;␊ |
81 | UINT8 *ImagePtr;␊ |
82 | UINT8 *ImagePtrBase;␊ |
83 | UINTN ImageLineOffset;␊ |
84 | UINT8 ImageValue = 0, AlphaValue;␊ |
85 | EG_PIXEL *PixelPtr;␊ |
86 | UINTN Index, BitIndex;␊ |
87 | ␊ |
88 | // read and check header␊ |
89 | if (FileDataLength < sizeof(BMP_IMAGE_HEADER) || FileData == NULL)␊ |
90 | return NULL;␊ |
91 | BmpHeader = (BMP_IMAGE_HEADER *) FileData;␊ |
92 | if (BmpHeader->CharB != 'B' || BmpHeader->CharM != 'M')␊ |
93 | return NULL;␊ |
94 | if (BmpHeader->CompressionType != 0)␊ |
95 | return NULL;␊ |
96 | if (BmpHeader->BitPerPixel != 1 && BmpHeader->BitPerPixel != 4 &&␊ |
97 | BmpHeader->BitPerPixel != 8 && BmpHeader->BitPerPixel != 24)␊ |
98 | return NULL;␊ |
99 | ␊ |
100 | // calculate parameters␊ |
101 | ImageLineOffset = BmpHeader->PixelWidth;␊ |
102 | if (BmpHeader->BitPerPixel == 24)␊ |
103 | ImageLineOffset *= 3;␊ |
104 | else if (BmpHeader->BitPerPixel == 1)␊ |
105 | ImageLineOffset = (ImageLineOffset + 7) >> 3;␊ |
106 | else if (BmpHeader->BitPerPixel == 4)␊ |
107 | ImageLineOffset = (ImageLineOffset + 1) >> 1;␊ |
108 | if ((ImageLineOffset % 4) != 0)␊ |
109 | ImageLineOffset = ImageLineOffset + (4 - (ImageLineOffset % 4));␊ |
110 | // check bounds␊ |
111 | if (BmpHeader->ImageOffset + ImageLineOffset * BmpHeader->PixelHeight > FileDataLength)␊ |
112 | return NULL;␊ |
113 | ␊ |
114 | // allocate image structure and buffer␊ |
115 | NewImage = egCreateImage(BmpHeader->PixelWidth, BmpHeader->PixelHeight, WantAlpha);␊ |
116 | if (NewImage == NULL)␊ |
117 | return NULL;␊ |
118 | AlphaValue = WantAlpha ? 255 : 0;␊ |
119 | ␊ |
120 | // convert image␊ |
121 | BmpColorMap = (BMP_COLOR_MAP *)(FileData + sizeof(BMP_IMAGE_HEADER));␊ |
122 | ImagePtrBase = FileData + BmpHeader->ImageOffset;␊ |
123 | for (y = 0; y < BmpHeader->PixelHeight; y++) {␊ |
124 | ImagePtr = ImagePtrBase;␊ |
125 | ImagePtrBase += ImageLineOffset;␊ |
126 | PixelPtr = NewImage->PixelData + (BmpHeader->PixelHeight - 1 - y) * BmpHeader->PixelWidth;␊ |
127 | ␊ |
128 | switch (BmpHeader->BitPerPixel) {␊ |
129 | ␊ |
130 | case 1:␊ |
131 | for (x = 0; x < BmpHeader->PixelWidth; x++) {␊ |
132 | BitIndex = x & 0x07;␊ |
133 | if (BitIndex == 0)␊ |
134 | ImageValue = *ImagePtr++;␊ |
135 | ␊ |
136 | Index = (ImageValue >> (7 - BitIndex)) & 0x01;␊ |
137 | PixelPtr->b = BmpColorMap[Index].Blue;␊ |
138 | PixelPtr->g = BmpColorMap[Index].Green;␊ |
139 | PixelPtr->r = BmpColorMap[Index].Red;␊ |
140 | PixelPtr->a = AlphaValue;␊ |
141 | PixelPtr++;␊ |
142 | }␊ |
143 | break;␊ |
144 | ␊ |
145 | case 4:␊ |
146 | for (x = 0; x <= BmpHeader->PixelWidth - 2; x += 2) {␊ |
147 | ImageValue = *ImagePtr++;␊ |
148 | ␊ |
149 | Index = ImageValue >> 4;␊ |
150 | PixelPtr->b = BmpColorMap[Index].Blue;␊ |
151 | PixelPtr->g = BmpColorMap[Index].Green;␊ |
152 | PixelPtr->r = BmpColorMap[Index].Red;␊ |
153 | PixelPtr->a = AlphaValue;␊ |
154 | PixelPtr++;␊ |
155 | ␊ |
156 | Index = ImageValue & 0x0f;␊ |
157 | PixelPtr->b = BmpColorMap[Index].Blue;␊ |
158 | PixelPtr->g = BmpColorMap[Index].Green;␊ |
159 | PixelPtr->r = BmpColorMap[Index].Red;␊ |
160 | PixelPtr->a = AlphaValue;␊ |
161 | PixelPtr++;␊ |
162 | }␊ |
163 | if (x < BmpHeader->PixelWidth) {␊ |
164 | ImageValue = *ImagePtr++;␊ |
165 | ␊ |
166 | Index = ImageValue >> 4;␊ |
167 | PixelPtr->b = BmpColorMap[Index].Blue;␊ |
168 | PixelPtr->g = BmpColorMap[Index].Green;␊ |
169 | PixelPtr->r = BmpColorMap[Index].Red;␊ |
170 | PixelPtr->a = AlphaValue;␊ |
171 | PixelPtr++;␊ |
172 | }␊ |
173 | break;␊ |
174 | ␊ |
175 | case 8:␊ |
176 | for (x = 0; x < BmpHeader->PixelWidth; x++) {␊ |
177 | Index = *ImagePtr++;␊ |
178 | PixelPtr->b = BmpColorMap[Index].Blue;␊ |
179 | PixelPtr->g = BmpColorMap[Index].Green;␊ |
180 | PixelPtr->r = BmpColorMap[Index].Red;␊ |
181 | PixelPtr->a = AlphaValue;␊ |
182 | PixelPtr++;␊ |
183 | }␊ |
184 | break;␊ |
185 | ␊ |
186 | case 24:␊ |
187 | for (x = 0; x < BmpHeader->PixelWidth; x++) {␊ |
188 | PixelPtr->b = *ImagePtr++;␊ |
189 | PixelPtr->g = *ImagePtr++;␊ |
190 | PixelPtr->r = *ImagePtr++;␊ |
191 | PixelPtr->a = AlphaValue;␊ |
192 | PixelPtr++;␊ |
193 | }␊ |
194 | break;␊ |
195 | ␊ |
196 | }␊ |
197 | }␊ |
198 | ␊ |
199 | return NewImage;␊ |
200 | }␊ |
201 | ␊ |
202 | //␊ |
203 | // Save BMP image␊ |
204 | //␊ |
205 | ␊ |
206 | VOID egEncodeBMP(IN EG_IMAGE *Image, OUT UINT8 **FileDataReturn, OUT UINTN *FileDataLengthReturn)␊ |
207 | {␊ |
208 | BMP_IMAGE_HEADER *BmpHeader;␊ |
209 | UINT8 *FileData;␊ |
210 | UINTN FileDataLength;␊ |
211 | UINT8 *ImagePtr;␊ |
212 | UINT8 *ImagePtrBase;␊ |
213 | UINTN ImageLineOffset;␊ |
214 | EG_PIXEL *PixelPtr;␊ |
215 | UINTN x, y;␊ |
216 | ␊ |
217 | ImageLineOffset = Image->Width * 3;␊ |
218 | if ((ImageLineOffset % 4) != 0)␊ |
219 | ImageLineOffset = ImageLineOffset + (4 - (ImageLineOffset % 4));␊ |
220 | ␊ |
221 | // allocate buffer for file data␊ |
222 | FileDataLength = sizeof(BMP_IMAGE_HEADER) + Image->Height * ImageLineOffset;␊ |
223 | FileData = AllocateZeroPool(FileDataLength);␊ |
224 | if (FileData == NULL) {␊ |
225 | printf("Error allocate %d bytes\n", FileDataLength);␊ |
226 | *FileDataReturn = NULL;␊ |
227 | *FileDataLengthReturn = 0;␊ |
228 | return;␊ |
229 | }␊ |
230 | ␊ |
231 | // fill header␊ |
232 | BmpHeader = (BMP_IMAGE_HEADER *)FileData;␊ |
233 | BmpHeader->CharB = 'B';␊ |
234 | BmpHeader->CharM = 'M';␊ |
235 | BmpHeader->Size = FileDataLength;␊ |
236 | BmpHeader->ImageOffset = sizeof(BMP_IMAGE_HEADER);␊ |
237 | BmpHeader->HeaderSize = 40;␊ |
238 | BmpHeader->PixelWidth = Image->Width;␊ |
239 | BmpHeader->PixelHeight = Image->Height;␊ |
240 | BmpHeader->Planes = 1;␊ |
241 | BmpHeader->BitPerPixel = 24;␊ |
242 | BmpHeader->CompressionType = 0;␊ |
243 | BmpHeader->XPixelsPerMeter = 0xb13;␊ |
244 | BmpHeader->YPixelsPerMeter = 0xb13;␊ |
245 | ␊ |
246 | // fill pixel buffer␊ |
247 | ImagePtrBase = FileData + BmpHeader->ImageOffset;␊ |
248 | for (y = 0; y < Image->Height; y++) {␊ |
249 | ImagePtr = ImagePtrBase;␊ |
250 | ImagePtrBase += ImageLineOffset;␊ |
251 | PixelPtr = Image->PixelData + (Image->Height - 1 - y) * Image->Width;␊ |
252 | ␊ |
253 | for (x = 0; x < Image->Width; x++) {␊ |
254 | *ImagePtr++ = PixelPtr->b;␊ |
255 | *ImagePtr++ = PixelPtr->g;␊ |
256 | *ImagePtr++ = PixelPtr->r;␊ |
257 | PixelPtr++;␊ |
258 | }␊ |
259 | }␊ |
260 | ␊ |
261 | *FileDataReturn = FileData;␊ |
262 | *FileDataLengthReturn = FileDataLength;␊ |
263 | }␊ |
264 | ␊ |
265 | /* EOF */␊ |
266 | |