1 /*
2 AllegroPNG
3
4 Copyright (c) 2006 Michal Molhanec
5
6 This software is provided 'as-is', without any express or implied
7 warranty. In no event will the authors be held liable for any damages
8 arising from the use of this software.
9
10 Permission is granted to anyone to use this software for any purpose,
11 including commercial applications, and to alter it and redistribute
12 it freely, subject to the following restrictions:
13
14 1. The origin of this software must not be misrepresented;
15 you must not claim that you wrote the original software.
16 If you use this software in a product, an acknowledgment
17 in the product documentation would be appreciated but
18 is not required.
19
20 2. Altered source versions must be plainly marked as such,
21 and must not be misrepresented as being the original software.
22
23 3. This notice may not be removed or altered from any
24 source distribution.
25 */
26
27 /*
28
29 alpng_drawer.c -- Makes Allegro BITMAPs from raw uncompressed data.
30
31 */
32
33 #include <allegro.h>
34
35 #include "alpng.h"
36 #include "alpng_internal.h"
37
38 static BITMAP* read_paletted(uint8_t* data, uint32_t data_length, struct alpng_header* header);
39 static BITMAP* read_grayscale(uint8_t* data, uint32_t data_length, struct alpng_header* header);
40 static BITMAP* read_grayscale16(uint8_t* data, uint32_t data_length, struct alpng_header* header);
41 static BITMAP* read_rgb16(uint8_t* data, uint32_t data_length, struct alpng_header* header);
42 static BITMAP* read_rgb8(uint8_t* data, uint32_t data_length, struct alpng_header* header);
43 static BITMAP* read_grayscale_with_alpha16(uint8_t* data, uint32_t data_length, struct alpng_header* header);
44 static BITMAP* read_grayscale_with_alpha8(uint8_t* data, uint32_t data_length, struct alpng_header* header);
45 static BITMAP* read_rgb_with_alpha16(uint8_t* data, uint32_t data_length, struct alpng_header* header);
46 static BITMAP* read_rgb_with_alpha8(uint8_t* data, uint32_t data_length, struct alpng_header* header);
47
alpng_draw(struct alpng_header * header,uint8_t * data,uint32_t data_length)48 BITMAP* alpng_draw(struct alpng_header* header, uint8_t* data, uint32_t data_length) {
49 BITMAP* b = 0;
50
51 if (data_length % header->height) {
52 alpng_error_msg = "Data length not divisible by picture height!";
53 return 0;
54 }
55 header->byte_width = data_length / header->height;
56
57 if (!alpng_unfilter(data, header)) {
58 return 0;
59 }
60
61 switch (header->type) {
62 case 0:
63 if (header->depth == 16) {
64 b = read_grayscale16(data, data_length, header);
65 } else {
66 b = read_grayscale(data, data_length, header);
67 }
68 break;
69 case 2:
70 if (header->depth == 16) {
71 b = read_rgb16(data, data_length, header);
72 } else {
73 b = read_rgb8(data, data_length, header);
74 }
75 break;
76 case 3:
77 b = read_paletted(data, data_length, header);
78 break;
79 case 4:
80 if (header->depth == 16) {
81 b = read_grayscale_with_alpha16(data, data_length, header);
82 } else {
83 b = read_grayscale_with_alpha8(data, data_length, header);
84 }
85 break;
86 case 6:
87 if (header->depth == 16) {
88 b = read_rgb_with_alpha16(data, data_length, header);
89 } else {
90 b = read_rgb_with_alpha8(data, data_length, header);
91 }
92 break;
93 }
94
95 return b;
96 }
97
read_rgb_with_alpha8(uint8_t * data,uint32_t data_length,struct alpng_header * header)98 static BITMAP* read_rgb_with_alpha8(uint8_t* data, uint32_t data_length, struct alpng_header* header) {
99 unsigned int x, y;
100 BITMAP* b;
101 if (header->height * (header->width * 4 + 1) != data_length) {
102 alpng_error_msg = "Bad data length!";
103 return 0;
104 }
105 b = create_bitmap_ex(32, header->width, header->height);
106 if (!b) {
107 alpng_error_msg = "Cannot allocate bitmap!";
108 return 0;
109 }
110 for (y = 0; y < header->height; y++) {
111 for (x = 0; x < header->width; x++) {
112 b->line[y][x * 4 + _rgb_r_shift_32 / 8] = data[1 + y * header->byte_width + x * 4];
113 b->line[y][x * 4 + _rgb_g_shift_32 / 8] = data[2 + y * header->byte_width + x * 4];
114 b->line[y][x * 4 + _rgb_b_shift_32 / 8] = data[3 + y * header->byte_width + x * 4];
115 b->line[y][x * 4 + _rgb_a_shift_32 / 8] = data[4 + y * header->byte_width + x * 4];
116 }
117 }
118 return b;
119 }
120
read_rgb_with_alpha16(uint8_t * data,uint32_t data_length,struct alpng_header * header)121 static BITMAP* read_rgb_with_alpha16(uint8_t* data, uint32_t data_length, struct alpng_header* header) {
122 unsigned int x, y;
123 BITMAP* b;
124 if (header->height * (header->width * 8 + 1) != data_length) {
125 alpng_error_msg = "Bad data length!";
126 return 0;
127 }
128 b = create_bitmap_ex(32, header->width, header->height);
129 if (!b) {
130 alpng_error_msg = "Cannot allocate bitmap!";
131 return 0;
132 }
133 for (y = 0; y < header->height; y++) {
134 for (x = 0; x < header->width; x++) {
135 b->line[y][x * 4 + _rgb_r_shift_32 / 8] = data[1 + y * header->byte_width + x * 8];
136 b->line[y][x * 4 + _rgb_g_shift_32 / 8] = data[3 + y * header->byte_width + x * 8];
137 b->line[y][x * 4 + _rgb_b_shift_32 / 8] = data[5 + y * header->byte_width + x * 8];
138 b->line[y][x * 4 + _rgb_a_shift_32 / 8] = data[7 + y * header->byte_width + x * 8];
139 }
140 }
141 return b;
142 }
143
read_grayscale_with_alpha8(uint8_t * data,uint32_t data_length,struct alpng_header * header)144 static BITMAP* read_grayscale_with_alpha8(uint8_t* data, uint32_t data_length, struct alpng_header* header) {
145 unsigned int x, y;
146 BITMAP* b;
147 if (header->height * (header->width * 2 + 1) != data_length) {
148 alpng_error_msg = "Bad data length!";
149 return 0;
150 }
151 b = create_bitmap_ex(32, header->width, header->height);
152 if (!b) {
153 alpng_error_msg = "Cannot allocate bitmap!";
154 return 0;
155 }
156 for (y = 0; y < header->height; y++) {
157 for (x = 0; x < header->width; x++) {
158 b->line[y][x * 4 + _rgb_r_shift_32 / 8] = data[1 + y * header->byte_width + x * 2];
159 b->line[y][x * 4 + _rgb_g_shift_32 / 8] = data[1 + y * header->byte_width + x * 2];
160 b->line[y][x * 4 + _rgb_b_shift_32 / 8] = data[1 + y * header->byte_width + x * 2];
161 b->line[y][x * 4 + _rgb_a_shift_32 / 8] = data[2 + y * header->byte_width + x * 2];
162 }
163 }
164 return b;
165 }
166
read_grayscale_with_alpha16(uint8_t * data,uint32_t data_length,struct alpng_header * header)167 static BITMAP* read_grayscale_with_alpha16(uint8_t* data, uint32_t data_length, struct alpng_header* header) {
168 unsigned int x, y;
169 BITMAP* b;
170 if (header->height * (header->width * 4 + 1) != data_length) {
171 alpng_error_msg = "Bad data length!";
172 return 0;
173 }
174 b = create_bitmap_ex(32, header->width, header->height);
175 if (!b) {
176 alpng_error_msg = "Cannot allocate bitmap!";
177 return 0;
178 }
179 for (y = 0; y < header->height; y++) {
180 for (x = 0; x < header->width; x++) {
181 b->line[y][x * 4 + _rgb_r_shift_32 / 8] = data[1 + y * header->byte_width + x * 4];
182 b->line[y][x * 4 + _rgb_g_shift_32 / 8] = data[1 + y * header->byte_width + x * 4];
183 b->line[y][x * 4 + _rgb_b_shift_32 / 8] = data[1 + y * header->byte_width + x * 4];
184 b->line[y][x * 4 + _rgb_a_shift_32 / 8] = data[3 + y * header->byte_width + x * 4];
185 }
186 }
187 return b;
188 }
189
read_rgb16(uint8_t * data,uint32_t data_length,struct alpng_header * header)190 static BITMAP* read_rgb16(uint8_t* data, uint32_t data_length, struct alpng_header* header) {
191 unsigned int x, y;
192 BITMAP* b;
193 if (header->height * (header->width * 6 + 1) != data_length) {
194 alpng_error_msg = "Bad data length!";
195 return 0;
196 }
197 b = create_bitmap_ex(24, header->width, header->height);
198 if (!b) {
199 alpng_error_msg = "Cannot allocate bitmap!";
200 return 0;
201 }
202 for (y = 0; y < header->height; y++) {
203 for (x = 0; x < header->width; x++) {
204 b->line[y][x * 3 + _rgb_r_shift_24 / 8] = data[1 + y * header->byte_width + x * 6];
205 b->line[y][x * 3 + _rgb_g_shift_24 / 8] = data[3 + y * header->byte_width + x * 6];
206 b->line[y][x * 3 + _rgb_b_shift_24 / 8] = data[5 + y * header->byte_width + x * 6];
207 }
208 }
209 return b;
210 }
211
read_rgb8(uint8_t * data,uint32_t data_length,struct alpng_header * header)212 static BITMAP* read_rgb8(uint8_t* data, uint32_t data_length, struct alpng_header* header) {
213 unsigned int x, y;
214 BITMAP* b;
215 if (header->height * (header->width * 3 + 1) != data_length) {
216 alpng_error_msg = "Bad data length!";
217 return 0;
218 }
219 b = create_bitmap_ex(24, header->width, header->height);
220 if (!b) {
221 alpng_error_msg = "Cannot allocate bitmap!";
222 return 0;
223 }
224 for (y = 0; y < header->height; y++) {
225 for (x = 0; x < header->width; x++) {
226 b->line[y][x * 3 + _rgb_r_shift_24 / 8] = data[1 + y * header->byte_width + x * 3];
227 b->line[y][x * 3 + _rgb_g_shift_24 / 8] = data[2 + y * header->byte_width + x * 3];
228 b->line[y][x * 3 + _rgb_b_shift_24 / 8] = data[3 + y * header->byte_width + x * 3];
229 }
230 }
231 return b;
232 }
233
read_grayscale16(uint8_t * data,uint32_t data_length,struct alpng_header * header)234 static BITMAP* read_grayscale16(uint8_t* data, uint32_t data_length, struct alpng_header* header) {
235 unsigned int x, y;
236 BITMAP* b;
237 if (header->height * (header->width * 2 + 1) != data_length) {
238 alpng_error_msg = "Bad data length!";
239 return 0;
240 }
241 b = create_bitmap_ex(24, header->width, header->height);
242 if (!b) {
243 alpng_error_msg = "Cannot allocate bitmap!";
244 return 0;
245 }
246 for (y = 0; y < header->height; y++) {
247 for (x = 0; x < header->width; x++) {
248 b->line[y][x * 3 + _rgb_r_shift_24 / 8] = data[1 + y * header->byte_width + x * 2];
249 b->line[y][x * 3 + _rgb_g_shift_24 / 8] = data[1 + y * header->byte_width + x * 2];
250 b->line[y][x * 3 + _rgb_b_shift_24 / 8] = data[1 + y * header->byte_width + x * 2];
251 }
252 }
253 return b;
254 }
255
read_grayscale(uint8_t * data,uint32_t data_length,struct alpng_header * header)256 static BITMAP* read_grayscale(uint8_t* data, uint32_t data_length, struct alpng_header* header) {
257 unsigned int x, y, i, j, mask = 0, width;
258 int sx;
259 BITMAP* b;
260 uint8_t sample;
261 int sample_multiple = 0;
262 switch (header->depth) {
263 case 1:
264 sample_multiple = 255;
265 break;
266 case 2:
267 sample_multiple = 85;
268 break;
269 case 4:
270 sample_multiple = 17;
271 break;
272 case 8:
273 sample_multiple = 1;
274 break;
275 }
276 j = 8 / header->depth;
277 width = (header->width + j - 1) / j;
278 if (header->height * (width + 1) != data_length) {
279 alpng_error_msg = "Bad data length!";
280 return 0;
281 }
282 b = create_bitmap_ex(24, header->width, header->height);
283 if (!b) {
284 alpng_error_msg = "Cannot allocate bitmap!";
285 return 0;
286 }
287 for (i = 0; i < header->depth; i++) {
288 mask |= 1 << i;
289 }
290 for (y = 0; y < header->height; y++) {
291 i = 0;
292 for (x = 0; x < width; x++) {
293 for (sx = j - 1; sx >= 0; sx--) {
294 if (i == header->width) {
295 break;
296 }
297 sample = (data[y * header->byte_width + x + 1] & (mask << (header->depth * sx))) >> (header->depth * sx);
298 sample *= sample_multiple;
299 b->line[y][i * 3] = sample;
300 b->line[y][i * 3 + 1] = sample;
301 b->line[y][i * 3 + 2] = sample;
302 i++;
303 }
304 }
305 }
306 return b;
307 }
308
read_paletted(uint8_t * data,uint32_t data_length,struct alpng_header * header)309 static BITMAP* read_paletted(uint8_t* data, uint32_t data_length, struct alpng_header* header) {
310 unsigned int x, y, i, j, mask = 0, width;
311 int sx;
312 BITMAP* b;
313 j = 8 / header->depth;
314 width = (header->width + j - 1) / j;
315 if (header->height * (width + 1) != data_length) {
316 alpng_error_msg = "Bad data length!";
317 return 0;
318 }
319 b = create_bitmap_ex(8, header->width, header->height);
320 if (!b) {
321 alpng_error_msg = "Cannot allocate bitmap!";
322 return 0;
323 }
324 for (i = 0; i < header->depth; i++) {
325 mask |= 1 << i;
326 }
327 for (y = 0; y < header->height; y++) {
328 i = 0;
329 for (x = 0; x < width; x++) {
330 for (sx = j - 1; sx >= 0; sx--) {
331 if (i == header->width) {
332 break;
333 }
334 b->line[y][i++] = (data[y * header->byte_width + x + 1] & (mask << (header->depth * sx))) >> (header->depth * sx);
335 }
336 }
337 }
338 return b;
339 }
340
341
342