]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/libpng/lib/l4png_wrap/l4png_wrap.c
b3ed89a80ad5f8b97294657882a089865d76b6d7
[l4.git] / l4 / pkg / libpng / lib / l4png_wrap / l4png_wrap.c
1 #include <l4/libpng/l4png_wrap.h>
2 #include <l4/sys/l4int.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <png.h>
6 #include <pngstruct.h>
7
8 #ifndef png_jmpbuf
9 #  define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
10 #endif
11
12 #ifdef DEBUG
13 enum { _DEBUG = 1 };
14 #else
15 enum { _DEBUG = 0 };
16 #endif
17
18 #define u16 unsigned short
19
20 #define PNG_BYTES_TO_CHECK 4 
21 #define PNG_ROW_MEM_SIZE 8
22
23
24 static int check_if_png(char *png_data)
25 {
26   int i;
27   char buf[PNG_BYTES_TO_CHECK];
28
29   for (i=0; i<PNG_BYTES_TO_CHECK; i++)
30     buf[i] = png_data[i];
31
32   /* Compare the first PNG_BYTES_TO_CHECK bytes of the signature.
33      Return nonzero (true) if they match */
34
35   return png_sig_cmp((unsigned char *)buf, (png_size_t)0, PNG_BYTES_TO_CHECK);
36 }
37
38
39 struct l4png_wrap_read_func_struct {
40   char *mem;
41   l4_size_t offset;
42   l4_size_t size;
43 };
44
45 void
46 l4png_wrap_read_func_from_memory(png_structp png_ptr, png_bytep data,
47                                  png_size_t length);
48
49 void
50 l4png_wrap_read_func_from_memory(png_structp png_ptr, png_bytep data,
51                                  png_size_t length)
52 {
53   struct l4png_wrap_read_func_struct *a
54     = (struct l4png_wrap_read_func_struct *)png_ptr->io_ptr;
55   if (!png_ptr)
56     return;
57
58   if (a->offset + length > a->size)
59     png_error(png_ptr, "read too much");
60
61   memcpy(data, a->mem + a->offset, length);
62   a->offset += length;
63 }
64
65 enum mode_t { M_MEMORY, M_FILE };
66
67 static int __internal_png_get_size(enum mode_t mode,
68                                    void *png_data, int png_data_size,
69                                    FILE *fp,
70                                    int *width, int *height)
71 {
72   png_structp png_ptr;
73   png_infop info_ptr;
74   struct l4png_wrap_read_func_struct memio;
75
76   /* check if png_data really contains a png image */
77   if (mode == M_MEMORY)
78     {
79       if (check_if_png(png_data))
80         return LIBPNG_ENOPNG;
81     }
82
83   /* create png read struct */
84   png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
85
86   if (!png_ptr)
87     return -1;
88
89   if (mode == M_MEMORY)
90     {
91       memio.mem = png_data;
92       memio.size = png_data_size;
93       memio.offset = 0;
94       png_set_read_fn(png_ptr, &memio, l4png_wrap_read_func_from_memory);
95     }
96
97   /* create png info struct */
98   info_ptr = png_create_info_struct(png_ptr);
99
100   if (info_ptr==NULL)
101     {
102       png_destroy_read_struct(&png_ptr, NULL, NULL);
103       return -1;
104     }
105
106   if (setjmp(png_jmpbuf(png_ptr)))
107     {
108       /* Free all of the memory associated with the png_ptr and info_ptr */
109       png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
110
111       /* If we get here, we had a problem reading the file */
112       return LIBPNG_EDAMAGEDPNG;
113     }
114
115   if (mode == M_MEMORY)
116     png_init_io(png_ptr,(png_FILE_p) &memio);
117   else
118     png_init_io(png_ptr,(png_FILE_p) fp);
119
120   /* read info struct */
121   png_read_info(png_ptr, info_ptr);
122
123   *width = png_get_image_width(png_ptr,info_ptr);
124   *height = png_get_image_height(png_ptr,info_ptr);
125
126   /* free mem of png structs */
127   png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
128
129   return 0;
130 }
131
132 int libpng_get_size_mem(void *png_data, int png_data_size,
133                         int *width, int *height)
134 {
135   return __internal_png_get_size(M_MEMORY, png_data, png_data_size, NULL,
136                                  width, height);
137 }
138
139 int libpng_get_size_file(const char *filename, int *width, int *height)
140 {
141   FILE *fp;
142   int r;
143
144   if (!(fp = fopen(filename, "rb")))
145     return -1;
146
147   r = __internal_png_get_size(M_FILE, NULL, 0, fp, width, height);
148
149   fclose(fp);
150   return r;
151 }
152
153 #define DITHER_SIZE 16
154
155 static const int dither_matrix[DITHER_SIZE][DITHER_SIZE] = {
156   {   0,192, 48,240, 12,204, 60,252,  3,195, 51,243, 15,207, 63,255 },
157   { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 },
158   {  32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 },
159   { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 },
160   {   8,200, 56,248,  4,196, 52,244, 11,203, 59,251,  7,199, 55,247 },
161   { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 },
162   {  40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 },
163   { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 },
164   {   2,194, 50,242, 14,206, 62,254,  1,193, 49,241, 13,205, 61,253 },
165   { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 },
166   {  34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 },
167   { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 },
168   {  10,202, 58,250,  6,198, 54,246,  9,201, 57,249,  5,197, 53,245 },
169   { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 },
170   {  42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 },
171   { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 }
172 };
173
174
175 static inline void
176 convert_line_24to16(unsigned char *src, short *dst, int width, int line)
177 {
178   int j, r, g, b, v;
179   int const *dm = dither_matrix[line & 0xf];
180
181   /* calculate 16bit RGB value and copy it to destination buffer */
182   for (j = 0; j < width; j++)
183     {
184       v = dm[j & 0xf];
185       r = (int)(*(src++)) + (v >> 5);
186       g = (int)(*(src++)) + (v >> 6);
187       b = (int)(*(src++)) + (v >> 5);
188       if (r > 255)
189         r = 255;
190       if (g > 255)
191         g = 255;
192       if (b > 255)
193         b = 255;
194       *(dst + j) = ((r & 0xf8) << 8) + ((g & 0xfc) << 3) + ((b & 0xf8) >> 3);
195     }
196 }
197
198
199
200
201
202 static void
203 convert_pixel_from_rgb888(unsigned srcval, void *dst, l4re_video_view_info_t *fbi)
204 {
205   unsigned v;
206
207   v  = ((srcval >> (8  - fbi->pixel_info.r.size)) & ((1 << fbi->pixel_info.r.size) - 1)) << fbi->pixel_info.r.shift;
208   v |= ((srcval >> (16 - fbi->pixel_info.g.size)) & ((1 << fbi->pixel_info.g.size) - 1)) << fbi->pixel_info.g.shift;
209   v |= ((srcval >> (24 - fbi->pixel_info.b.size)) & ((1 << fbi->pixel_info.b.size) - 1)) << fbi->pixel_info.b.shift;
210
211   //printf("srcval=%08x v=%08x dst=%p bpl=%d\n", srcval, v, dst, fbi->bytes_per_line);
212   switch (fbi->pixel_info.bytes_per_pixel)
213     {
214     case 1:
215       *(unsigned char  *)dst = v;
216       break;
217     case 2:
218       *(unsigned short *)dst = v;
219       break;
220 #if defined(ARCH_x86) || defined(ARCH_amd64)
221     case 3:
222       *(unsigned short *)(dst + 0) = v & 0xffff;
223       *(unsigned char  *)(dst + 2) = v >> 16;
224       break;
225 #endif
226     case 4:
227       *(unsigned int   *)dst = v;
228       break;
229     default:
230       printf("unhandled bitsperpixel %d\n",
231              l4re_video_bits_per_pixel(&fbi->pixel_info));
232     };
233 }
234
235
236 static int
237 internal_render(enum mode_t mode, void *png_data, char * const dst,
238                 int png_data_size, unsigned dst_buf_size,
239                 l4re_video_view_info_t *dst_descr, FILE *fp)
240 {
241   png_structp png_ptr;
242   png_infop info_ptr;
243   png_uint_32 width, height;
244   unsigned char *row_ptr;
245   unsigned row;
246   int bit_depth, color_type, interlace_type;
247   struct l4png_wrap_read_func_struct memio;
248
249   /* check if png_data really contains a png image */
250   if (mode == M_MEMORY && check_if_png((char *)png_data))
251     return LIBPNG_ENOPNG;
252
253   /* create png read struct */
254   png_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL,
255                                      NULL, NULL, NULL);
256   if (!png_ptr)
257     {
258       printf("error during creation of png read struct");
259       return -1;
260     }
261
262   if (mode == M_MEMORY)
263     {
264       memio.mem = png_data;
265       memio.size = png_data_size;
266       memio.offset = 0;
267       png_set_read_fn(png_ptr, &memio, l4png_wrap_read_func_from_memory);
268     }
269
270   /* create png info struct */
271   info_ptr = png_create_info_struct(png_ptr);
272
273   if (!info_ptr)
274     {
275       png_destroy_read_struct(&png_ptr, NULL, NULL);
276       printf("error during creation of png info struct");
277       return -1;
278     }
279
280   if (setjmp(png_jmpbuf(png_ptr)))
281     {
282       /* Free all of the memory associated with the png_ptr and info_ptr */
283       png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
284
285       /* If we are here, we had a problem reading the image */
286       return LIBPNG_EDAMAGEDPNG;
287     }
288
289   if (mode == M_MEMORY)
290     png_init_io(png_ptr,(png_FILE_p)&memio);
291   else
292     png_init_io(png_ptr,(png_FILE_p)fp);
293
294   /* read info struct */
295   png_read_info(png_ptr, info_ptr);
296
297   /* get image data chunk */
298   png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
299                &interlace_type, NULL, NULL);
300
301   if (_DEBUG)
302     printf("bit_depth: %d, color_type: %d, width: %d, height: %d",
303            bit_depth, color_type, width, height);
304
305   if (dst_buf_size < height * dst_descr->bytes_per_line)
306     {
307       png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
308       return LIBPNG_ARGB_BUF_TO_SMALL;
309     }
310
311   if (color_type == PNG_COLOR_TYPE_PALETTE)
312     png_set_palette_to_rgb(png_ptr);
313
314   if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
315     png_set_expand_gray_1_2_4_to_8(png_ptr);
316
317   if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
318     png_set_gray_to_rgb(png_ptr);
319
320   if (bit_depth < 8)
321     png_set_packing(png_ptr);
322
323   /* set down to 8bit value */
324   if (bit_depth == 16)
325     png_set_strip_16(png_ptr);
326
327   if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
328     png_set_strip_alpha(png_ptr);
329
330   row_ptr = malloc(png_get_rowbytes(png_ptr, info_ptr) * PNG_ROW_MEM_SIZE);
331
332   if (!row_ptr)
333     {
334       printf("not enough memory for a png row");
335       return -1;
336     }
337
338   if (dst_descr->pixel_info.bytes_per_pixel == 2)
339     {
340       char *_dst = dst;
341       // special case for 16bit, with dithering
342       if (interlace_type == PNG_INTERLACE_NONE)
343         for (row = 0; row < height; row++)
344           {
345             png_read_row(png_ptr, (png_bytep)row_ptr, NULL);
346             convert_line_24to16(row_ptr, (short *)_dst, width, row);
347             _dst += dst_descr->bytes_per_line;
348           }
349     }
350   else
351     {
352       png_set_filler(png_ptr, 0xff, PNG_FILLER_BEFORE);
353       char *_dst = dst;
354       for (row = 0; row < height; row++)
355         {
356           png_read_row(png_ptr, (png_bytep)row_ptr, NULL);
357           unsigned *r = (unsigned *)row_ptr;
358           unsigned o = 0;
359           for (unsigned j = 0; j < width;
360                ++j, ++r, o += dst_descr->pixel_info.bytes_per_pixel)
361             convert_pixel_from_rgb888(*r >> 8, _dst + o, dst_descr);
362
363           _dst += dst_descr->bytes_per_line;
364         }
365     }
366
367   free(row_ptr);
368
369   png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
370
371   return 0;
372 }
373
374 int libpng_render_mem(void *png_data, void *dst_buf,
375                       unsigned png_data_size, unsigned dst_size,
376                       l4re_video_view_info_t *dst_descr)
377 {
378   return internal_render(M_MEMORY, png_data, dst_buf,
379                          png_data_size, dst_size,
380                          dst_descr, NULL);
381 }
382
383 int libpng_render_file(const char *filename, void *dst_buf,
384                        unsigned dst_size,
385                        l4re_video_view_info_t *dst_descr)
386 {
387   FILE *fp;
388   int r;
389
390   if (!(fp = fopen(filename, "rb")))
391     return -1;
392
393   r = internal_render(M_MEMORY, 0, dst_buf, 0, dst_size, dst_descr, fp);
394
395   fclose(fp);
396   return r;
397 }