]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/libpng/lib/l4png_wrap/l4png_wrap.c
f71da242ee6150008e761def351829b814b48189
[l4.git] / l4 / pkg / libpng / lib / l4png_wrap / l4png_wrap.c
1 #include <l4/libpng/l4png_wrap.h>
2 #include <l4/libpng/png.h>
3 #include <stdlib.h>
4 #include <l4/sys/l4int.h>
5
6 #ifndef png_jmpbuf
7 #  define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
8 #endif
9
10 #ifdef DEBUG
11 enum { _DEBUG = 1 };
12 #else
13 enum { _DEBUG = 0 };
14 #endif
15
16 #define u16 unsigned short
17
18 #define PNG_BYTES_TO_CHECK 4 
19 #define PNG_ROW_MEM_SIZE 8
20
21
22 static int check_if_png(char *png_data)
23 {
24   int i;
25   char buf[PNG_BYTES_TO_CHECK];
26
27   for (i=0; i<PNG_BYTES_TO_CHECK; i++)
28     buf[i] = png_data[i];
29
30   /* Compare the first PNG_BYTES_TO_CHECK bytes of the signature.
31      Return nonzero (true) if they match */
32
33   return png_sig_cmp((unsigned char *)buf, (png_size_t)0, PNG_BYTES_TO_CHECK);
34 }
35
36
37 struct l4png_wrap_read_func_struct {
38   char *mem;
39   l4_size_t offset;
40   l4_size_t size;
41 };
42
43 void
44 l4png_wrap_read_func_from_memory(png_structp png_ptr, png_bytep data,
45                                  png_size_t length);
46
47 void
48 l4png_wrap_read_func_from_memory(png_structp png_ptr, png_bytep data,
49                                  png_size_t length)
50 {
51   struct l4png_wrap_read_func_struct *a
52     = (struct l4png_wrap_read_func_struct *)png_ptr->io_ptr;
53   if (!png_ptr)
54     return;
55
56   if (a->offset + length > a->size)
57     png_error(png_ptr, "read too much");
58
59   memcpy(data, a->mem + a->offset, length);
60   a->offset += length;
61 }
62
63 enum mode_t { M_MEMORY, M_FILE };
64
65 static int __internal_png_get_size(enum mode_t mode,
66                                    void *png_data, int png_data_size,
67                                    FILE *fp,
68                                    int *width, int *height)
69 {
70   png_structp png_ptr;
71   png_infop info_ptr;
72   struct l4png_wrap_read_func_struct memio;
73
74   /* check if png_data really contains a png image */
75   if (mode == M_MEMORY)
76     {
77       if (check_if_png(png_data))
78         return ENOPNG;
79     }
80
81   /* create png read struct */
82   png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
83
84   if (!png_ptr)
85     return -1;
86
87   if (mode == M_MEMORY)
88     {
89       memio.mem = png_data;
90       memio.size = png_data_size;
91       memio.offset = 0;
92       png_set_read_fn(png_ptr, &memio, l4png_wrap_read_func_from_memory);
93     }
94
95   /* create png info struct */
96   info_ptr = png_create_info_struct(png_ptr);
97
98   if (info_ptr==NULL)
99     {
100       png_destroy_read_struct(&png_ptr, NULL, NULL);
101       return -1;
102     }
103
104   if (setjmp(png_jmpbuf(png_ptr)))
105     {
106       /* Free all of the memory associated with the png_ptr and info_ptr */
107       png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
108
109       /* If we get here, we had a problem reading the file */
110       return EDAMAGEDPNG;
111     }
112
113   if (mode == M_MEMORY)
114     png_init_io(png_ptr,(png_FILE_p) &memio);
115   else
116     png_init_io(png_ptr,(png_FILE_p) fp);
117
118   /* read info struct */
119   png_read_info(png_ptr, info_ptr);
120
121   *width = png_get_image_width(png_ptr,info_ptr);
122   *height = png_get_image_height(png_ptr,info_ptr);
123
124   /* free mem of png structs */
125   png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
126
127   return 0;
128 }
129
130 int png_get_size_mem(void *png_data, int png_data_size,
131                      int *width, int *height)
132 {
133   return __internal_png_get_size(M_MEMORY, png_data, png_data_size, NULL,
134                                  width, height);
135 }
136
137 int png_get_size_file(const char *filename, int *width, int *height)
138 {
139   FILE *fp;
140   int r;
141
142   if (!(fp = fopen(filename, "rb")))
143     return -1;
144
145   r = __internal_png_get_size(M_FILE, NULL, 0, fp, width, height);
146
147   fclose(fp);
148   return r;
149 }
150
151 static int __internal_png_convert_ARGB
152    (enum mode_t mode, void *png_data, void *argb_buf,
153     int png_data_size, unsigned argb_max_size, FILE *fp)
154 {
155   png_structp png_ptr;
156   png_infop info_ptr;
157   png_uint_32 width, height;
158   char *row_ptr, *row_ptr_backup, *dst;
159   unsigned row, j;
160   int bit_depth, color_type, interlace_type, a, r, g, b, offset;
161   struct l4png_wrap_read_func_struct memio;
162
163   if (mode == M_MEMORY)
164     /* check if png_data really contains a png image */
165     if(check_if_png((char *)png_data)) return ENOPNG;
166
167   offset=4;
168
169   /* create png read struct */
170   png_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL,
171                                      NULL,NULL,NULL);
172
173   if (png_ptr==NULL)
174     return -1;
175
176   if (mode == M_MEMORY)
177     {
178       memio.mem = png_data;
179       memio.size = png_data_size;
180       memio.offset = 0;
181       png_set_read_fn(png_ptr, &memio, l4png_wrap_read_func_from_memory);
182     }
183
184   /* create png info struct */
185   info_ptr = png_create_info_struct(png_ptr);
186
187   if (info_ptr==NULL) {
188       png_destroy_read_struct(&png_ptr, NULL, NULL);
189       return -1;
190   }
191
192   if (setjmp(png_jmpbuf(png_ptr)))
193     {
194       /* Free all of the memory associated with the png_ptr and info_ptr */
195       png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
196
197       /* If we get here, we had a problem reading the file */
198       return EDAMAGEDPNG;
199     }
200
201   dst = (char *) argb_buf;
202
203   if (mode == M_MEMORY)
204     png_init_io(png_ptr,(png_FILE_p) &memio);
205   else
206     png_init_io(png_ptr,(png_FILE_p) fp);
207
208   /* read info struct */
209   png_read_info(png_ptr, info_ptr);
210
211   /* get image data chunk */
212   png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
213       &interlace_type, NULL, NULL);
214
215   if (argb_max_size < height*width*offset) {
216       png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
217       return ARGB_BUF_TO_SMALL;
218   }
219
220   if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr);
221
222   /* set down to 8bit value */
223   if (bit_depth == 16) png_set_strip_16(png_ptr);
224
225   /* normally png files have rgba format now swap it into argb */
226   if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) png_set_swap_alpha(png_ptr);
227   else png_set_filler(png_ptr, 0xff, PNG_FILLER_BEFORE);
228
229   row_ptr = malloc(png_get_rowbytes(png_ptr,info_ptr)*PNG_ROW_MEM_SIZE);
230
231   if (row_ptr == NULL) {
232       printf("not enough memory for a png row");
233       return -1;
234   }
235
236   row_ptr_backup = row_ptr;
237
238   for (row = 0;row<height-1;row++) {
239
240       /* backup row pointer to start address */
241       row_ptr = row_ptr_backup;
242
243       /* read a single row */
244       png_read_row(png_ptr, (png_bytep)row_ptr, NULL);
245
246       /* calculate ARGB value and copy it to destination buffer */
247       for (j=0;j<width;j++) {
248           a=*(row_ptr++);
249           r=*(row_ptr++);
250           g=*(row_ptr++);
251           b=*(row_ptr++);
252           *(dst+j*offset) = a;
253           *(dst+j*offset+1) = r;
254           *(dst+j*offset+2) = g;
255           *(dst+j*offset+3) = b;
256       }
257       dst+=width*offset;                
258   }
259
260   /* free mem of png structs */
261   png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
262
263
264   return 0;
265 }
266
267 int png_convert_ARGB_mem(void *png_data, void *argb_buf,
268                          int png_data_size, unsigned argb_max_size)
269 {
270   return __internal_png_convert_ARGB(M_MEMORY, png_data, argb_buf,
271                                      png_data_size, argb_max_size, NULL);
272 }
273
274 int png_convert_ARGB_file(const char *filename, void *argb_buf,
275                           unsigned argb_max_size)
276 {
277   FILE *fp;
278   int r;
279
280   if (!(fp = fopen(filename, "rb")))
281     return -1;
282
283   r = __internal_png_convert_ARGB(M_FILE, 0, argb_buf,
284                                   0, argb_max_size, fp);
285
286   fclose(fp);
287   return r;
288 }
289
290
291 #define DITHER_SIZE 16
292
293 static const int dither_matrix[DITHER_SIZE][DITHER_SIZE] = {
294   {   0,192, 48,240, 12,204, 60,252,  3,195, 51,243, 15,207, 63,255 },
295   { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 },
296   {  32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 },
297   { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 },
298   {   8,200, 56,248,  4,196, 52,244, 11,203, 59,251,  7,199, 55,247 },
299   { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 },
300   {  40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 },
301   { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 },
302   {   2,194, 50,242, 14,206, 62,254,  1,193, 49,241, 13,205, 61,253 },
303   { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 },
304   {  34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 },
305   { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 },
306   {  10,202, 58,250,  6,198, 54,246,  9,201, 57,249,  5,197, 53,245 },
307   { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 },
308   {  42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 },
309   { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 }
310 };
311
312
313 static inline void convert_24to16(unsigned char *src, short *dst, int width, int line)
314 {
315   int j,r,g,b,v;
316   int const *dm = dither_matrix[line & 0xf];
317
318   /* calculate 16bit RGB value and copy it to destination buffer */
319   for (j=0;j<width;j++) {
320       v = dm[j & 0xf];
321       r = (int)(*(src++)) + (v>>5);
322       g = (int)(*(src++)) + (v>>6);
323       b = (int)(*(src++)) + (v>>5);
324       if (r>255) r=255;
325       if (g>255) g=255;
326       if (b>255) b=255;
327       *(dst+j) = ((r&0xf8)<<8) + ((g&0xfc)<<3) + ((b&0xf8)>>3);
328   }
329 }
330
331
332 static int __internal_png_convert_RGB16bit
333     (enum mode_t mode, void *png_data, void *argb_buf, int png_data_size,
334      unsigned argb_max_size, int line_offset, FILE *fp)
335 {
336   png_structp png_ptr;
337   png_infop info_ptr;
338   png_uint_32 width, height;
339   unsigned char *row_ptr, *row_ptr_backup;
340   unsigned row;
341   int bit_depth, color_type, interlace_type;
342   unsigned short *dst;
343   struct l4png_wrap_read_func_struct memio;
344
345   /* check if png_data really contains a png image */
346   if (mode == M_MEMORY)
347     if(check_if_png((char *)png_data)) return ENOPNG;
348
349   /* create png read struct */
350   png_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL,
351                                      NULL,NULL,NULL);
352
353   if (png_ptr==NULL) {
354       printf("error during creation of png read struct");
355       return -1;
356   }
357
358   if (mode == M_MEMORY)
359     {
360       memio.mem = png_data;
361       memio.size = png_data_size;
362       memio.offset = 0;
363       png_set_read_fn(png_ptr, &memio, l4png_wrap_read_func_from_memory);
364     }
365
366
367   /* create png info struct */
368   info_ptr = png_create_info_struct(png_ptr);
369
370   if (info_ptr==NULL) {
371       png_destroy_read_struct(&png_ptr, NULL, NULL);
372       printf("error during creation of png info struct");
373       return -1;
374   }
375
376   if (setjmp(png_jmpbuf(png_ptr)))
377     {
378       /* Free all of the memory associated with the png_ptr and info_ptr */
379       png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
380
381       /* If we are here, we had a problem reading the image */
382       return EDAMAGEDPNG;
383     }
384
385   dst = (unsigned short *) argb_buf;
386
387   if (mode == M_MEMORY)
388     png_init_io(png_ptr,(png_FILE_p)&memio);
389   else
390     png_init_io(png_ptr,(png_FILE_p)fp);
391
392   /* read info struct */
393   png_read_info(png_ptr, info_ptr);
394
395   /* get image data chunk */
396   png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
397       &interlace_type, NULL, NULL);
398
399   if (_DEBUG)
400     printf("bit_depth: %d, color_type: %d, width: %d, height: %d",
401            bit_depth, color_type, width, height);
402
403   if (argb_max_size < height*width*sizeof(u16)) {
404
405       /* Free all of the memory associated with the png_ptr and info_ptr */
406       png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
407
408       return ARGB_BUF_TO_SMALL;
409   }
410
411   if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr);
412
413   if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
414     png_set_expand_gray_1_2_4_to_8(png_ptr);
415
416   if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
417     png_set_gray_to_rgb(png_ptr);
418
419   if (bit_depth < 8) png_set_packing(png_ptr);
420
421   /* set down to 8bit value */
422   if (bit_depth == 16) png_set_strip_16(png_ptr);
423
424   if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) png_set_strip_alpha(png_ptr);
425
426   row_ptr = malloc(png_get_rowbytes(png_ptr,info_ptr)*PNG_ROW_MEM_SIZE);
427
428   if (row_ptr == NULL) {
429       printf("not enough memory for a png row");
430       return -1;
431   }
432
433   row_ptr_backup = row_ptr;
434
435   if (interlace_type == PNG_INTERLACE_NONE) {
436
437       for (row = 0;row<height-1;row++) {
438
439           /* backup row pointer to start address */
440           row_ptr = row_ptr_backup;
441
442           /* read a single row */
443           png_read_row(png_ptr, (png_bytep)row_ptr, NULL);
444
445           convert_24to16(row_ptr, (short *)dst, width, row);
446           //                        /* calculate 16bit RGB value and copy it to destination buffer */
447           //                        for (j=0;j<width;j++) {
448           //                                r=*(row_ptr++);
449           //                                g=*(row_ptr++);
450           //                                b=*(row_ptr++);
451           //                                *(dst+j) = ((r&0xf8)<<8) + ((g&0xfc)<<3) + ((b&0xf8)>>3);
452           //                        }
453           dst+=line_offset;
454
455       }
456
457       /* free old row pointer */
458       free(row_ptr_backup);
459
460   }
461
462   /* free mem of png structs */
463   png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
464
465   return 0;
466 }
467
468 int png_convert_RGB16bit_mem(void *png_data, void *argb_buf, int png_data_size,
469                              unsigned argb_max_size, int line_offset)
470 {
471   return __internal_png_convert_RGB16bit(M_MEMORY, png_data, argb_buf,
472                                          png_data_size, argb_max_size,
473                                          line_offset, NULL);
474 }
475
476 int png_convert_RGB16bit_file(const char *filename, void *argb_buf,
477                               unsigned argb_max_size, int line_offset)
478 {
479   FILE *fp;
480   int r;
481
482   if (!(fp = fopen(filename, "rb")))
483     return -1;
484
485   r = __internal_png_convert_RGB16bit(M_FILE, 0, argb_buf,
486                                       0, argb_max_size, line_offset, fp);
487
488   fclose(fp);
489   return r;
490 }