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