allow reading jfif embedded exif thumbnails from jpeg files and use them to speed...
[enigma2.git] / lib / gdi / picload.cpp
1 #include <png.h>        // must be included before Python.h because of setjmp
2 #include <lib/gdi/picload.h>
3 #include "picexif.h"
4 #include <lib/python/python.h>
5
6 #include <fcntl.h>
7 #include <unistd.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10
11 #include <epng.h>       // savePNG need it
12
13 #define JDCT_DEFAULT JDCT_IFAST
14
15 extern "C" {
16 #include <jpeglib.h>
17 #include <gif_lib.h>
18 //#include "transupp.h"
19 }
20
21 unsigned char *pic_buffer=NULL;
22
23 static unsigned char *conv24to32(unsigned char * orgin, int size, int background = 0)
24 {
25         int s, d;
26         unsigned char *cr = new unsigned char[size * 4];
27         if (cr == NULL)
28         {
29                 printf("[CONV32] Error: malloc\n");
30                 return(orgin);
31         }
32
33         unsigned char alpha = 0x00;
34         if(background)  alpha = 0xFF;
35
36         for (s = 0, d = 0 ; s < (size * 3); s += 3, d += 4 )
37         {
38                 cr[d] = orgin[s];
39                 cr[d+1] = orgin[s + 1];
40                 cr[d+2] = orgin[s + 2];
41                 cr[d+3] = alpha;
42         }
43         delete [] orgin;
44         return(cr);
45 }
46
47 static unsigned char *simple_resize(unsigned char * orgin, int ox, int oy, int dx, int dy)
48 {
49         unsigned char *cr, *p, *l;
50         int i, j, k, ip;
51         cr = new unsigned char[dx * dy * 4]; 
52         if (cr == NULL)
53         {
54                 printf("[RESIZE] Error: malloc\n");
55                 return(orgin);
56         }
57         l = cr;
58
59         for (j = 0; j < dy; j++,l += dx * 4)
60         {
61                 p = orgin + (j * oy / dy * ox * 4);
62                 for (i = 0, k = 0; i < dx; i++, k += 4)
63                 {
64                         ip = i * ox / dx * 4;
65                         l[k] = p[ip];
66                         l[k+1] = p[ip + 1];
67                         l[k+2] = p[ip + 2];
68                         l[k+3] = p[ip + 3];
69                 }
70         }
71         delete [] orgin;
72         return(cr);
73 }
74
75 static unsigned char *color_resize(unsigned char * orgin, int ox, int oy, int dx, int dy)
76 {
77         unsigned char *cr, *p, *q;
78         int i, j, k, l, xa, xb, ya, yb;
79         int sq, r, g, b, a;
80         cr = new unsigned char[dx * dy * 4];
81         if (cr == NULL)
82         {
83                 printf("[RESIZE] Error: malloc\n");
84                 return(orgin);
85         }
86         p = cr;
87
88         for (j = 0; j < dy; j++)
89         {
90                 for (i = 0; i < dx; i++, p += 4)
91                 {
92                         xa = i * ox / dx;
93                         ya = j * oy / dy;
94                         xb = (i + 1) * ox / dx; 
95                         if (xb >= ox)
96                                 xb = ox - 1;
97                         yb = (j + 1) * oy / dy; 
98                         if (yb >= oy)
99                                 yb = oy - 1;
100                         for (l = ya, r = 0, g = 0, b = 0, a = 0, sq = 0; l <= yb; l++)
101                         {
102                                 q = orgin + ((l * ox + xa) * 4);
103                                 for (k = xa; k <= xb; k++, q += 4, sq++)
104                                 {
105                                         r += q[0]; g += q[1]; b += q[2]; a += q[3];
106                                 }
107                         }
108                         p[0] = r / sq; p[1] = g / sq; p[2] = b / sq; p[3] = a / sq;
109                 }
110         }
111         delete [] orgin;
112         return(cr);
113 }
114
115 //-------------------------------------------------------------------
116
117 struct r_jpeg_error_mgr
118 {
119         struct jpeg_error_mgr pub;
120         jmp_buf envbuffer;
121 };
122
123 void jpeg_cb_error_exit(j_common_ptr cinfo)
124 {
125         struct r_jpeg_error_mgr *mptr;
126         mptr = (struct r_jpeg_error_mgr *) cinfo->err;
127         (*cinfo->err->output_message) (cinfo);
128         longjmp(mptr->envbuffer, 1);
129 }
130
131 static int jpeg_save(unsigned char *image_buffer, const char * filename, int quality, int image_height, int image_width)
132 {
133         struct jpeg_compress_struct cinfo;
134         struct jpeg_error_mgr jerr;
135         FILE * outfile;         /* target file */
136         JSAMPROW row_pointer[1];/* pointer to JSAMPLE row[s] */
137         int row_stride;         /* physical row width in image buffer */
138  
139         cinfo.err = jpeg_std_error(&jerr);
140         jpeg_create_compress(&cinfo);
141  
142         if ((outfile = fopen(filename, "wb")) == NULL) 
143         {
144                 eDebug("[JPEG] can't open %s", filename);
145                 return -1;
146         }
147         jpeg_stdio_dest(&cinfo, outfile);
148  
149         cinfo.image_width = image_width;
150         cinfo.image_height = image_height;
151         cinfo.input_components = 3;
152         cinfo.in_color_space = JCS_RGB;
153         jpeg_set_defaults(&cinfo);
154         jpeg_set_quality(&cinfo, quality, TRUE );
155         jpeg_start_compress(&cinfo, TRUE);
156         row_stride = image_width * 3;
157         while (cinfo.next_scanline < cinfo.image_height) 
158         {
159                 row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride];
160                 (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
161         }
162         jpeg_finish_compress(&cinfo);
163         fclose(outfile);
164         jpeg_destroy_compress(&cinfo);
165         return 0;
166 }
167
168 /* Expanded data source object for memory buffer input */
169 typedef struct
170 {
171         struct jpeg_source_mgr pub;     /* public fields */
172         FILE *infile;                   /* source stream */
173         JOCTET *buffer;         /* start of buffer */
174         boolean start_of_file;  /* have we gotten any data yet? */
175 } mem_source_mgr;
176
177 typedef mem_source_mgr *mem_src_ptr;
178
179 static void init_source (j_decompress_ptr cinfo)
180 {
181         mem_src_ptr src = (mem_src_ptr) cinfo->src;
182         src->start_of_file = TRUE;
183 }
184
185 static boolean fill_input_buffer (j_decompress_ptr cinfo)
186 {
187         /* no-op */ (void)cinfo;
188         return TRUE;
189  }
190
191 static void skip_input_data (j_decompress_ptr cinfo, long num_bytes)
192 {
193         mem_src_ptr src = (mem_src_ptr) cinfo->src;
194         
195         if (num_bytes > 0)
196         {
197                 src->pub.next_input_byte += (size_t) num_bytes;
198                 src->pub.bytes_in_buffer -= (size_t) num_bytes;
199         }
200 }
201
202 static void term_source (j_decompress_ptr cinfo)
203 {
204         /* no-op */ (void)cinfo;
205 }
206
207 static void jpeg_memory_src (j_decompress_ptr cinfo, unsigned char *inbfr, int len)
208 {
209         mem_src_ptr src;
210         if (cinfo->src == NULL)
211         {
212                 cinfo->src = (struct jpeg_source_mgr *)
213                 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, (size_t)sizeof(mem_source_mgr));
214                 src = (mem_src_ptr) cinfo->src;
215                 src->buffer = (JOCTET *) inbfr;
216         }
217         src = (mem_src_ptr) cinfo->src;
218         src->pub.init_source = init_source;
219         src->pub.fill_input_buffer = fill_input_buffer;
220         src->pub.skip_input_data = skip_input_data;
221         src->pub.resync_to_restart = jpeg_resync_to_restart;    /* use default method */
222         src->pub.term_source = term_source;
223         src->infile = 0L;
224         src->pub.bytes_in_buffer = len;                         /* sets to entire file len */
225         src->pub.next_input_byte = (JOCTET *)inbfr;             /* at start of buffer */
226 }
227
228 static int jpeg_load_thumb(const char *filename, int *x, int *y)
229 {
230         struct jpeg_decompress_struct cinfo;
231         struct jpeg_decompress_struct *ciptr = &cinfo;
232         struct r_jpeg_error_mgr emgr;
233         FILE *fh;
234
235         if (!(fh = fopen(filename, "rb")))
236                 return 0;
237
238         ciptr->err = jpeg_std_error(&emgr.pub);
239         emgr.pub.error_exit = jpeg_cb_error_exit;
240         if (setjmp(emgr.envbuffer) == 1)
241         {
242                 jpeg_destroy_decompress(ciptr);
243                 fclose(fh);
244                 return 0;
245         }
246
247         jpeg_create_decompress(ciptr);
248         jpeg_stdio_src(ciptr, fh);
249
250         jpeg_save_markers (ciptr, JPEG_APP0 + 1, 0xffff);
251
252         jpeg_read_header(ciptr, TRUE);
253
254         struct jpeg_marker_struct *m = cinfo.marker_list;
255
256         unsigned char *thumb_buf = NULL;
257         size_t bufsize;
258         
259         if ( m )
260         {
261                 unsigned char *p_data = m->data;
262                 while ( p_data < m->data+m->data_length )
263                 {
264                         if ( p_data[0] == 0xFF && p_data[1] == 0xD8 )
265                         {
266                                 bufsize = (size_t) m->data_length - (size_t) (p_data-m->data);
267                                 thumb_buf = new unsigned char[bufsize];
268                                 bufsize = 0;
269                                 do {
270                                         thumb_buf[bufsize++] = *p_data;
271                                 } while ( !(*p_data++ == 0xFF && *p_data == 0xD9) && p_data < m->data+m->data_length );
272                                 thumb_buf[bufsize++] = *p_data;
273                         }
274                         p_data++;
275                 }
276         }
277
278         if ( thumb_buf != NULL )
279         {
280                 jpeg_create_decompress(ciptr);
281                 jpeg_memory_src(ciptr, thumb_buf, bufsize-2);
282                 jpeg_read_header(ciptr, TRUE);
283         }
284         else
285                 eDebug("no exif thumbnail found! loading actual image instead");
286
287         ciptr->out_color_space = JCS_RGB;
288         ciptr->scale_denom = 1;
289
290         jpeg_start_decompress(ciptr);
291         
292         *x=ciptr->output_width;
293         *y=ciptr->output_height;
294
295         if(ciptr->output_components == 3)
296         {
297                 JSAMPLE *lb = (JSAMPLE *)(*ciptr->mem->alloc_small)((j_common_ptr) ciptr, JPOOL_PERMANENT, ciptr->output_width * ciptr->output_components);
298                 pic_buffer = new unsigned char[ciptr->output_height * ciptr->output_width * ciptr->output_components];
299                 unsigned char *bp = pic_buffer;
300
301                 while (ciptr->output_scanline < ciptr->output_height)
302                 {
303                         jpeg_read_scanlines(ciptr, &lb, 1);
304                         memcpy(bp, lb, ciptr->output_width * ciptr->output_components);
305                         bp += ciptr->output_width * ciptr->output_components;
306                 }
307         }
308         jpeg_finish_decompress(ciptr);
309         jpeg_destroy_decompress(ciptr);
310         fclose(fh);
311         return 1;
312 }
313
314 static int jpeg_load(const char *filename, int *x, int *y)
315 {
316         struct jpeg_decompress_struct cinfo;
317         struct jpeg_decompress_struct *ciptr = &cinfo;
318         struct r_jpeg_error_mgr emgr;
319         FILE *fh;
320
321         if (!(fh = fopen(filename, "rb")))
322                 return 0;
323
324         ciptr->err = jpeg_std_error(&emgr.pub);
325         emgr.pub.error_exit = jpeg_cb_error_exit;
326         if (setjmp(emgr.envbuffer) == 1)
327         {
328                 jpeg_destroy_decompress(ciptr);
329                 fclose(fh);
330                 return 0;
331         }
332
333         jpeg_create_decompress(ciptr);
334         jpeg_stdio_src(ciptr, fh);
335         jpeg_read_header(ciptr, TRUE);
336         ciptr->out_color_space = JCS_RGB;
337         ciptr->scale_denom = 1;
338
339         jpeg_start_decompress(ciptr);
340         
341         *x=ciptr->output_width;
342         *y=ciptr->output_height;
343
344         if(ciptr->output_components == 3)
345         {
346                 JSAMPLE *lb = (JSAMPLE *)(*ciptr->mem->alloc_small)((j_common_ptr) ciptr, JPOOL_PERMANENT, ciptr->output_width * ciptr->output_components);
347                 pic_buffer = new unsigned char[ciptr->output_height * ciptr->output_width * ciptr->output_components];
348                 unsigned char *bp = pic_buffer;
349
350                 while (ciptr->output_scanline < ciptr->output_height)
351                 {
352                         jpeg_read_scanlines(ciptr, &lb, 1);
353                         memcpy(bp, lb, ciptr->output_width * ciptr->output_components);
354                         bp += ciptr->output_width * ciptr->output_components;
355                 }
356         }
357         jpeg_finish_decompress(ciptr);
358         jpeg_destroy_decompress(ciptr);
359         fclose(fh);
360         return 1;
361 }
362
363 //---------------------------------------------------------------------------------------------
364
365 #define BMP_TORASTER_OFFSET 10
366 #define BMP_SIZE_OFFSET 18
367 #define BMP_BPP_OFFSET 28
368 #define BMP_RLE_OFFSET 30
369 #define BMP_COLOR_OFFSET 54
370
371 #define fill4B(a) ((4 - ((a) % 4 )) & 0x03)
372
373 struct color {
374         unsigned char red;
375         unsigned char green;
376         unsigned char blue;
377 };
378
379 static void fetch_pallete(int fd, struct color pallete[], int count)
380 {
381         unsigned char buff[4];
382         lseek(fd, BMP_COLOR_OFFSET, SEEK_SET);
383         for (int i = 0; i < count; i++)
384         {
385                 read(fd, buff, 4);
386                 pallete[i].red = buff[2];
387                 pallete[i].green = buff[1];
388                 pallete[i].blue = buff[0];
389         }
390 }
391
392 static int bmp_load(const char *filename,  int *x, int *y)
393 {
394         unsigned char buff[4];
395         struct color pallete[256];
396
397         int fd = open(filename, O_RDONLY);
398         if (fd == -1) return 0;
399         if (lseek(fd, BMP_SIZE_OFFSET, SEEK_SET) == -1) return 0;
400         read(fd, buff, 4);
401         *x = buff[0] + (buff[1] << 8) + (buff[2] << 16) + (buff[3] << 24);
402         read(fd, buff, 4);
403         *y = buff[0] + (buff[1] << 8) + (buff[2] << 16) + (buff[3] << 24);
404         if (lseek(fd, BMP_TORASTER_OFFSET, SEEK_SET) == -1) return 0;
405         read(fd, buff, 4);
406         int raster = buff[0] + (buff[1] << 8) + (buff[2] << 16) + (buff[3] << 24);
407         if (lseek(fd, BMP_BPP_OFFSET, SEEK_SET) == -1) return 0;
408         read(fd, buff, 2);
409         int bpp = buff[0] + (buff[1] << 8);
410
411         pic_buffer = new unsigned char[(*x) * (*y) * 3];
412         unsigned char *wr_buffer = pic_buffer + (*x) * ((*y) - 1) * 3;
413         
414         switch (bpp)
415         {
416                 case 4:
417                 {
418                         int skip = fill4B((*x) / 2 + (*x) % 2);
419                         fetch_pallete(fd, pallete, 16);
420                         lseek(fd, raster, SEEK_SET);
421                         unsigned char * tbuffer = new unsigned char[*x / 2 + 1];
422                         if (tbuffer == NULL)
423                                 return 0;
424                         for (int i = 0; i < *y; i++) 
425                         {
426                                 read(fd, tbuffer, (*x) / 2 + *x % 2);
427                                 int j;
428                                 for (j = 0; j < (*x) / 2; j++)
429                                 {
430                                         unsigned char c1 = tbuffer[j] >> 4;
431                                         unsigned char c2 = tbuffer[j] & 0x0f;
432                                         *wr_buffer++ = pallete[c1].red;
433                                         *wr_buffer++ = pallete[c1].green;
434                                         *wr_buffer++ = pallete[c1].blue;
435                                         *wr_buffer++ = pallete[c2].red;
436                                         *wr_buffer++ = pallete[c2].green;
437                                         *wr_buffer++ = pallete[c2].blue;
438                                 }
439                                 if ((*x) % 2)
440                                 {
441                                         unsigned char c1 = tbuffer[j] >> 4;
442                                         *wr_buffer++ = pallete[c1].red;
443                                         *wr_buffer++ = pallete[c1].green;
444                                         *wr_buffer++ = pallete[c1].blue;
445                                 }
446                                 if (skip)
447                                         read(fd, buff, skip);
448                                 wr_buffer -= (*x) * 6;
449                         }
450                         break;
451                 }
452                 case 8:
453                 {
454                         int skip = fill4B(*x);
455                         fetch_pallete(fd, pallete, 256);
456                         lseek(fd, raster, SEEK_SET);
457                         unsigned char * tbuffer = new unsigned char[*x];
458                         if (tbuffer == NULL)
459                                 return 0;
460                         for (int i = 0; i < *y; i++)
461                         {
462                                 read(fd, tbuffer, *x);
463                                 for (int j = 0; j < *x; j++)
464                                 {
465                                         wr_buffer[j * 3] = pallete[tbuffer[j]].red;
466                                         wr_buffer[j * 3 + 1] = pallete[tbuffer[j]].green;
467                                         wr_buffer[j * 3 + 2] = pallete[tbuffer[j]].blue;
468                                 }
469                                 if (skip)
470                                         read(fd, buff, skip);
471                                 wr_buffer -= (*x) * 3;
472                         }
473                         break;
474                 }
475                 case 24:
476                 {
477                         int skip = fill4B((*x) * 3);
478                         lseek(fd, raster, SEEK_SET);
479                         for (int i = 0; i < (*y); i++)
480                         {
481                                 read(fd, wr_buffer, (*x) * 3);
482                                 for (int j = 0; j < (*x) * 3 ; j = j + 3)
483                                 {
484                                         unsigned char c = wr_buffer[j];
485                                         wr_buffer[j] = wr_buffer[j + 2];
486                                         wr_buffer[j + 2] = c;
487                                 }
488                                 if (skip)
489                                         read(fd, buff, skip);
490                                 wr_buffer -= (*x) * 3;
491                         }
492                         break;
493                 }
494                 default:
495                         return 0;
496         }
497
498         close(fd);
499         return 1;
500 }
501
502 //---------------------------------------------------------------------------------------------
503 static int png_load(const char *filename,  int *x, int *y)
504 {
505         static const png_color_16 my_background = {0, 0, 0, 0, 0};
506
507         png_structp png_ptr;
508         png_infop info_ptr;
509         png_uint_32 width, height;
510         unsigned int i;
511         int bit_depth, color_type, interlace_type;
512         int number_passes, pass;
513         png_byte * fbptr;
514         FILE * fh;
515
516         if (!(fh = fopen(filename, "rb"))) return 0;
517
518         png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
519         if (png_ptr == NULL)
520                 return 0;
521         info_ptr = png_create_info_struct(png_ptr);
522         if (info_ptr == NULL)
523         {
524                 png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
525                 fclose(fh); 
526                 return 0;
527         }
528
529         if (setjmp(png_ptr->jmpbuf))
530         {
531                 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
532                 fclose(fh); 
533                 return 0;
534         }
535
536         png_init_io(png_ptr, fh);
537
538         png_read_info(png_ptr, info_ptr);
539         png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);
540
541         if ((color_type == PNG_COLOR_TYPE_PALETTE)||(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)||(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)))
542                 png_set_expand(png_ptr);
543         if (bit_depth == 16)
544                 png_set_strip_16(png_ptr);
545         if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
546                 png_set_gray_to_rgb(png_ptr);
547
548         number_passes = png_set_interlace_handling(png_ptr);
549         png_read_update_info(png_ptr, info_ptr);
550
551         int bpp =  png_get_rowbytes(png_ptr, info_ptr)/width;
552         if ((bpp !=4) && (bpp !=3))
553         {
554                 eDebug("[PNG] Error processing");
555                 return 0;
556         }
557
558         if (width * height > 1000000) // 1000x1000 or equiv.
559         {
560                 eDebug("[png_load] image size is %d x %d, which is \"too large\".", (int)width, (int)height);
561                 png_read_end(png_ptr, info_ptr);
562                 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
563                 fclose(fh);
564                 return 0;
565         }
566
567         pic_buffer = new unsigned char[width * height * bpp];
568         *x=width;
569         *y=height;
570
571         for(pass = 0; pass < number_passes; pass++)
572         {
573                 fbptr = (png_byte *)pic_buffer;
574                 for (i = 0; i < height; i++, fbptr += width * bpp)
575                         png_read_row(png_ptr, fbptr, NULL);
576         }
577         png_read_end(png_ptr, info_ptr);
578         png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
579         fclose(fh);
580         if (bpp == 3)
581                 pic_buffer = conv24to32(pic_buffer, width * height, 1);
582         return 1;
583 }
584
585 //-------------------------------------------------------------------
586
587 inline void m_rend_gif_decodecolormap(unsigned char *cmb, unsigned char *rgbb, ColorMapObject *cm, int s, int l)
588 {
589         GifColorType *cmentry;
590         int i;
591         for (i = 0; i < l; i++)
592         {
593                 cmentry = &cm->Colors[cmb[i]];
594                 *(rgbb++) = cmentry->Red;
595                 *(rgbb++) = cmentry->Green;
596                 *(rgbb++) = cmentry->Blue;
597         }
598 }
599
600 static int gif_load(const char *filename, int *x, int *y)
601 {
602         int px, py, i, j, ibxs;
603         unsigned char *fbptr;
604         unsigned char *lb=NULL;
605         unsigned char *slb=NULL;
606         GifFileType *gft;
607         GifRecordType rt;
608         GifByteType *extension;
609         ColorMapObject *cmap;
610         int cmaps;
611         int extcode;
612         
613         gft = DGifOpenFileName(filename);
614         if (gft == NULL) 
615                 return 0;
616         do
617         {
618                 if (DGifGetRecordType(gft, &rt) == GIF_ERROR)
619                         goto ERROR_R;
620                 switch(rt)
621                 {
622                         case IMAGE_DESC_RECORD_TYPE:
623                                 if (DGifGetImageDesc(gft) == GIF_ERROR)
624                                         goto ERROR_R;
625                                 *x = px = gft->Image.Width;
626                                 *y = py = gft->Image.Height;
627                                 pic_buffer = new unsigned char[px * py * 3];
628                                 lb = (unsigned char *)malloc(px * 3);
629                                 slb = (unsigned char *) malloc(px);
630
631                                 if (lb != NULL && slb != NULL)
632                                 {
633                                         cmap = (gft->Image.ColorMap ? gft->Image.ColorMap : gft->SColorMap);
634                                         cmaps = cmap->ColorCount;
635
636                                         ibxs = ibxs * 3;
637                                         fbptr = pic_buffer;
638                                         if (!(gft->Image.Interlace))
639                                         {
640                                                 for (i = 0; i < py; i++, fbptr += px * 3)
641                                                 {
642                                                         if (DGifGetLine(gft, slb, px) == GIF_ERROR)
643                                                                 goto ERROR_R;
644                                                         m_rend_gif_decodecolormap(slb, lb, cmap, cmaps, px);
645                                                         memcpy(fbptr, lb, px * 3);
646                                                 }
647                                         }
648                                         else
649                                         {
650                                                 for (j = 0; j < 4; j++)
651                                                 {
652                                                         fbptr = pic_buffer;
653                                                         for (i = 0; i < py; i++, fbptr += px * 3)
654                                                         {
655                                                                 if (DGifGetLine(gft, slb, px) == GIF_ERROR)
656                                                                         goto ERROR_R;
657                                                                 m_rend_gif_decodecolormap(slb, lb, cmap, cmaps, px);
658                                                                 memcpy(fbptr, lb, px * 3);
659                                                         }
660                                                 }
661                                         }
662                                 }
663                                 if (lb)
664                                 {
665                                         free(lb);
666                                         lb=NULL;
667                                 }
668                                 if (slb)
669                                 {
670                                         free(slb);
671                                         slb=NULL;
672                                 }
673                                 break;
674                         case EXTENSION_RECORD_TYPE:
675                                 if (DGifGetExtension(gft, &extcode, &extension) == GIF_ERROR)
676                                         goto ERROR_R;
677                                 while (extension != NULL)
678                                         if (DGifGetExtensionNext(gft, &extension) == GIF_ERROR)
679                                                 goto ERROR_R;
680                                 break;
681                         default:
682                                 break;
683                 }
684         }
685         while (rt != TERMINATE_RECORD_TYPE);
686
687         DGifCloseFile(gft);
688         return 1;
689 ERROR_R:
690         eDebug("[GIF] Error");
691         if (lb)         free(lb);
692         if (slb)        free(slb);
693         DGifCloseFile(gft);
694         return 0;
695 }
696
697 //---------------------------------------------------------------------------------------------
698
699 PyObject *getExif(const char *filename)
700 {
701         ePyObject list;
702         Cexif exif;
703         if(exif.DecodeExif(filename))
704         {
705                 if(exif.m_exifinfo->IsExif)
706                 {
707                         int pos=0;
708                         char tmp[256];
709                         list = PyList_New(22);
710                         PyList_SET_ITEM(list, pos++,  PyString_FromString(exif.m_exifinfo->Version));
711                         PyList_SET_ITEM(list, pos++,  PyString_FromString(exif.m_exifinfo->CameraMake));
712                         PyList_SET_ITEM(list, pos++,  PyString_FromString(exif.m_exifinfo->CameraModel));
713                         PyList_SET_ITEM(list, pos++,  PyString_FromString(exif.m_exifinfo->DateTime));
714                         PyList_SET_ITEM(list, pos++,  PyString_FromString(exif.m_exifinfo->Comments));
715                         PyList_SET_ITEM(list, pos++,  PyString_FromFormat("%d x %d", exif.m_exifinfo->Width, exif.m_exifinfo->Height));
716                         PyList_SET_ITEM(list, pos++,  PyString_FromString(exif.m_exifinfo->Orientation));
717                         PyList_SET_ITEM(list, pos++,  PyString_FromString(exif.m_exifinfo->MeteringMode));
718                         PyList_SET_ITEM(list, pos++,  PyString_FromString(exif.m_exifinfo->ExposureProgram));
719                         PyList_SET_ITEM(list, pos++,  PyString_FromString(exif.m_exifinfo->LightSource));
720                         PyList_SET_ITEM(list, pos++,  PyString_FromString(exif.m_exifinfo->FlashUsed));
721                         PyList_SET_ITEM(list, pos++,  PyString_FromFormat("%d", exif.m_exifinfo->CompressionLevel));
722                         PyList_SET_ITEM(list, pos++,  PyString_FromFormat("%d", exif.m_exifinfo->ISOequivalent));
723                         sprintf(tmp, "%.2f", exif.m_exifinfo->Xresolution);
724                         PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
725                         sprintf(tmp, "%.2f", exif.m_exifinfo->Yresolution);
726                         PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
727                         PyList_SET_ITEM(list, pos++,  PyString_FromString(exif.m_exifinfo->ResolutionUnit));
728                         sprintf(tmp, "%.2f", exif.m_exifinfo->Brightness);
729                         PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
730                         sprintf(tmp, "%.5f sec.", exif.m_exifinfo->ExposureTime);
731                         PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
732                         sprintf(tmp, "%.5f", exif.m_exifinfo->ExposureBias);
733                         PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
734                         sprintf(tmp, "%.5f", exif.m_exifinfo->Distance);
735                         PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
736                         sprintf(tmp, "%.5f", exif.m_exifinfo->CCDWidth);
737                         PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
738                         sprintf(tmp, "%.2f", exif.m_exifinfo->ApertureFNumber);
739                         PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
740                 }
741                 else
742                 {
743                         list = PyList_New(1);
744                         PyList_SET_ITEM(list, 0, PyString_FromString(exif.m_szLastError));
745                 }
746                 exif.ClearExif();
747         }
748         else
749         {
750                 list = PyList_New(1);
751                 PyList_SET_ITEM(list, 0, PyString_FromString(exif.m_szLastError));
752         }
753
754         return list ? (PyObject*)list : (PyObject*)PyList_New(0);
755 }
756
757 //---------------------------------------------------------------------------------------------
758 enum {F_NONE, F_PNG, F_JPEG, F_BMP, F_GIF};
759
760 static int pic_id(const char *name)
761 {
762         unsigned char id[10];
763         int fd = open(name, O_RDONLY); 
764         if (fd == -1) 
765                 return F_NONE;
766         read(fd, id, 10);
767         close(fd);
768
769         if(id[1] == 'P' && id[2] == 'N' && id[3] == 'G')
770                 return F_PNG;
771         else if(id[6] == 'J' && id[7] == 'F' && id[8] == 'I' && id[9] == 'F')
772                 return F_JPEG;
773         else if(id[0] == 0xff && id[1] == 0xd8 && id[2] == 0xff) 
774                 return F_JPEG;
775         else if(id[0] == 'B' && id[1] == 'M' )
776                 return F_BMP;
777         else if(id[0] == 'G' && id[1] == 'I' && id[2] == 'F')
778                 return F_GIF;
779         return F_NONE;
780 }
781
782 int loadPic(ePtr<gPixmap> &result, std::string filename, int w, int h, int aspect, int resize_mode, int rotate, int background, std::string cachefile, int thumbnail)
783 {
784         result = 0;
785         int ox=0, oy=0, imx, imy;
786         pic_buffer=NULL;
787         bool cache=false;
788
789         if(cachefile.length())
790         {
791                 if(png_load(cachefile.c_str(), &ox, &oy))
792                         eDebug("[CACHEPIC] x-size=%d, y-size=%d", ox, oy);
793         }
794
795         if(pic_buffer==NULL)
796         {
797                 switch(pic_id(filename.c_str()))
798                 {
799                         case F_PNG:     png_load(filename.c_str(), &ox, &oy);break;
800                         case F_JPEG:    {
801                                         if (thumbnail)
802                                                 jpeg_load_thumb(filename.c_str(), &ox, &oy);
803                                         else
804                                                 jpeg_load(filename.c_str(), &ox, &oy);
805                                         pic_buffer = conv24to32(pic_buffer, ox*oy, 1);
806                                         break; }
807                         case F_BMP:     bmp_load(filename.c_str(), &ox, &oy);pic_buffer = conv24to32(pic_buffer, ox*oy, 1); break;
808                         case F_GIF:     gif_load(filename.c_str(), &ox, &oy);pic_buffer = conv24to32(pic_buffer, ox*oy, 1); break;
809                         default:
810                                 eDebug("[PIC] <format not supportet>");
811                                 return 0;
812                 }
813         
814                 if(pic_buffer==NULL)
815                         return 0;
816
817                 double aspect_ratio;
818                 switch(aspect)
819                 {
820                         case 1:         aspect_ratio = 1.778 / ((double)720/576); break; //16:9
821                         case 2:         aspect_ratio = 1.600 / ((double)720/576); break; //16:10
822                         case 3:         aspect_ratio = 1.250 / ((double)720/576); break; //5:4
823                         default:        aspect_ratio = 1.333 / ((double)720/576); //4:3
824                 }
825
826                 if((aspect_ratio * oy * w / ox) <= h)
827                 {
828                         imx = w;
829                         imy = (int)(aspect_ratio*oy*w/ox);
830                 }
831                 else
832                 {
833                         imx = (int)((1.0/aspect_ratio)*ox*h/oy);
834                         imy = h;
835                 }
836
837                 if(resize_mode) pic_buffer = color_resize(pic_buffer, ox, oy, imx, imy);
838                 else            pic_buffer = simple_resize(pic_buffer, ox, oy, imx, imy);
839
840                 ox = imx;
841                 oy = imy;
842         }
843         else cache = true;
844         
845         result=new gPixmap(eSize(w, h), 32);
846         gSurface *surface = result->surface;
847         int a=0, b=0;
848         int nc=0, oc=0;
849         int o_y=0, u_y=0, v_x=0, h_x=0;
850         unsigned char clear[4] = {0x00,0x00,0x00,0x00};
851         if(background)  clear[3]=0xFF;
852         unsigned char *tmp_buffer=((unsigned char *)(surface->data));
853
854         if(oy < h)
855         {
856                 o_y=(h-oy)/2;
857                 u_y=h-oy-o_y;
858         }
859         if(ox < w)
860         {
861                 v_x=(w-ox)/2;
862                 h_x=w-ox-v_x;
863         }
864         
865         //eDebug("o_y=%d u_y=%d v_x=%d h_x=%d", o_y, u_y, v_x, h_x);
866
867         if(oy < h)
868                 for(a=0; a<(o_y*ox); a++, nc+=4)
869                 {
870                         tmp_buffer=((unsigned char *)(surface->data)) + nc;
871                         memcpy(tmp_buffer, clear, sizeof(clear));
872                 }
873
874         for(a=0; a<oy; a++)
875         {
876                 if(ox < w)
877                         for(b=0; b<v_x; b++, nc+=4)
878                         {
879                                 tmp_buffer=((unsigned char *)(surface->data)) + nc;
880                                 memcpy(tmp_buffer, clear, sizeof(clear));
881                         }
882
883                 for(b=0; b<(ox*4); b+=4, nc+=4)
884                 {
885                         tmp_buffer=((unsigned char *)(surface->data)) + nc;
886                         tmp_buffer[2]=pic_buffer[oc++];
887                         tmp_buffer[1]=pic_buffer[oc++];
888                         tmp_buffer[0]=pic_buffer[oc++];
889                         tmp_buffer[3]=pic_buffer[oc++];
890
891                 }
892                 
893                 if(ox < w)
894                         for(b=0; b<h_x; b++, nc+=4)
895                         {
896                                 tmp_buffer=((unsigned char *)(surface->data)) + nc;
897                                 memcpy(tmp_buffer, clear, sizeof(clear));
898                         }
899         }
900
901         if(oy < h)
902                 for(a=0; a<(u_y*ox); a++, nc+=4)
903                 {
904                         tmp_buffer=((unsigned char *)(surface->data)) + nc;
905                         memcpy(tmp_buffer, clear, sizeof(clear));
906                 }
907         
908         //eDebug("[PIC] buffer=%d, nc=%d oc=%d ox=%d, oy=%d",w*h*4, nc, oc, ox, oy);
909         
910         surface->clut.data=0;
911         surface->clut.colors=0;
912         surface->clut.start=0;
913         
914         delete [] pic_buffer;
915
916         if(cachefile.length() && !cache)
917         {
918                 savePNG( cachefile.c_str(), result);
919                 eDebug("[SAVEPIC] x-size=%d, y-size=%d", ox, oy);
920         }
921
922         return 0;
923 }