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