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