Merge branch 'bug_599_picload_fd_leak' into experimental
[vuplus_dvbapp] / lib / gdi / picload.cpp
1 #include <png.h>        // must be included before Python.h because of setjmp
2 #include <fcntl.h>
3
4 #include <lib/gdi/picload.h>
5 #include <lib/gdi/picexif.h>
6
7 extern "C" {
8 #include <jpeglib.h>
9 #include <gif_lib.h>
10 }
11
12 extern const uint32_t crc32_table[256];
13
14 DEFINE_REF(ePicLoad);
15
16 static std::string getSize(const char* file)
17 {
18         struct stat64 s;
19         if (stat64(file, &s) < 0)
20                 return "";
21         char tmp[20];
22         snprintf(tmp, 20, "%ld kB",(long)s.st_size / 1024);
23         return tmp;
24 }
25
26 static unsigned char *conv24to32(unsigned char *orgin, int size, unsigned char alpha = 0xFF)
27 {
28         int s, d;
29         unsigned char *cr = new unsigned char[size * 4];
30         if (cr == NULL)
31         {
32                 eDebug("[Picload] Error malloc");
33                 return(orgin);
34         }
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 * 3];
52         if (cr == NULL)
53         {
54                 eDebug("[Picload] Error malloc");
55                 return(orgin);
56         }
57         l = cr;
58
59         for (j = 0; j < dy; j++,l += dx * 3)
60         {
61                 p = orgin + (j * oy / dy * ox * 3);
62                 for (i = 0, k = 0; i < dx; i++, k += 3)
63                 {
64                         ip = i * ox / dx * 3;
65                         l[k] = p[ip];
66                         l[k+1] = p[ip + 1];
67                         l[k+2] = p[ip + 2];
68                 }
69         }
70         delete [] orgin;
71         return(cr);
72 }
73
74 static unsigned char *color_resize(unsigned char * orgin, int ox, int oy, int dx, int dy)
75 {
76         unsigned char *cr, *p, *q;
77         int i, j, k, l, xa, xb, ya, yb;
78         int sq, r, g, b;
79         cr = new unsigned char[dx * dy * 3];
80         if (cr == NULL)
81         {
82                 eDebug("[Picload] Error malloc");
83                 return(orgin);
84         }
85         p = cr;
86
87         for (j = 0; j < dy; j++)
88         {
89                 for (i = 0; i < dx; i++, p += 3)
90                 {
91                         xa = i * ox / dx;
92                         ya = j * oy / dy;
93                         xb = (i + 1) * ox / dx; 
94                         if (xb >= ox)
95                                 xb = ox - 1;
96                         yb = (j + 1) * oy / dy; 
97                         if (yb >= oy)
98                                 yb = oy - 1;
99                         for (l = ya, r = 0, g = 0, b = 0, sq = 0; l <= yb; l++)
100                         {
101                                 q = orgin + ((l * ox + xa) * 3);
102                                 for (k = xa; k <= xb; k++, q += 3, sq++)
103                                 {
104                                         r += q[0]; g += q[1]; b += q[2];
105                                 }
106                         }
107                         p[0] = r / sq; p[1] = g / sq; p[2] = b / sq;
108                 }
109         }
110         delete [] orgin;
111         return(cr);
112 }
113
114 //---------------------------------------------------------------------------------------------
115
116 #define BMP_TORASTER_OFFSET 10
117 #define BMP_SIZE_OFFSET 18
118 #define BMP_BPP_OFFSET 28
119 #define BMP_RLE_OFFSET 30
120 #define BMP_COLOR_OFFSET 54
121
122 #define fill4B(a) ((4 - ((a) % 4 )) & 0x03)
123
124 struct color {
125         unsigned char red;
126         unsigned char green;
127         unsigned char blue;
128 };
129
130 static void fetch_pallete(int fd, struct color pallete[], int count)
131 {
132         unsigned char buff[4];
133         lseek(fd, BMP_COLOR_OFFSET, SEEK_SET);
134         for (int i = 0; i < count; i++)
135         {
136                 read(fd, buff, 4);
137                 pallete[i].red = buff[2];
138                 pallete[i].green = buff[1];
139                 pallete[i].blue = buff[0];
140         }
141 }
142
143 static unsigned char *bmp_load(const char *file,  int *x, int *y)
144 {
145         unsigned char buff[4];
146         struct color pallete[256];
147
148         int fd = open(file, O_RDONLY);
149         if (fd == -1) return NULL;
150         if (lseek(fd, BMP_SIZE_OFFSET, SEEK_SET) == -1) return NULL;
151         read(fd, buff, 4);
152         *x = buff[0] + (buff[1] << 8) + (buff[2] << 16) + (buff[3] << 24);
153         read(fd, buff, 4);
154         *y = buff[0] + (buff[1] << 8) + (buff[2] << 16) + (buff[3] << 24);
155         if (lseek(fd, BMP_TORASTER_OFFSET, SEEK_SET) == -1) return NULL;
156         read(fd, buff, 4);
157         int raster = buff[0] + (buff[1] << 8) + (buff[2] << 16) + (buff[3] << 24);
158         if (lseek(fd, BMP_BPP_OFFSET, SEEK_SET) == -1) return NULL;
159         read(fd, buff, 2);
160         int bpp = buff[0] + (buff[1] << 8);
161
162         unsigned char *pic_buffer = new unsigned char[(*x) * (*y) * 3];
163         unsigned char *wr_buffer = pic_buffer + (*x) * ((*y) - 1) * 3;
164         
165         switch (bpp)
166         {
167                 case 4:
168                 {
169                         int skip = fill4B((*x) / 2 + (*x) % 2);
170                         fetch_pallete(fd, pallete, 16);
171                         lseek(fd, raster, SEEK_SET);
172                         unsigned char * tbuffer = new unsigned char[*x / 2 + 1];
173                         if (tbuffer == NULL)
174                                 return NULL;
175                         for (int i = 0; i < *y; i++) 
176                         {
177                                 read(fd, tbuffer, (*x) / 2 + *x % 2);
178                                 int j;
179                                 for (j = 0; j < (*x) / 2; j++)
180                                 {
181                                         unsigned char c1 = tbuffer[j] >> 4;
182                                         unsigned char c2 = tbuffer[j] & 0x0f;
183                                         *wr_buffer++ = pallete[c1].red;
184                                         *wr_buffer++ = pallete[c1].green;
185                                         *wr_buffer++ = pallete[c1].blue;
186                                         *wr_buffer++ = pallete[c2].red;
187                                         *wr_buffer++ = pallete[c2].green;
188                                         *wr_buffer++ = pallete[c2].blue;
189                                 }
190                                 if ((*x) % 2)
191                                 {
192                                         unsigned char c1 = tbuffer[j] >> 4;
193                                         *wr_buffer++ = pallete[c1].red;
194                                         *wr_buffer++ = pallete[c1].green;
195                                         *wr_buffer++ = pallete[c1].blue;
196                                 }
197                                 if (skip)
198                                         read(fd, buff, skip);
199                                 wr_buffer -= (*x) * 6;
200                         }
201                         break;
202                 }
203                 case 8:
204                 {
205                         int skip = fill4B(*x);
206                         fetch_pallete(fd, pallete, 256);
207                         lseek(fd, raster, SEEK_SET);
208                         unsigned char * tbuffer = new unsigned char[*x];
209                         if (tbuffer == NULL)
210                                 return NULL;
211                         for (int i = 0; i < *y; i++)
212                         {
213                                 read(fd, tbuffer, *x);
214                                 for (int j = 0; j < *x; j++)
215                                 {
216                                         wr_buffer[j * 3] = pallete[tbuffer[j]].red;
217                                         wr_buffer[j * 3 + 1] = pallete[tbuffer[j]].green;
218                                         wr_buffer[j * 3 + 2] = pallete[tbuffer[j]].blue;
219                                 }
220                                 if (skip)
221                                         read(fd, buff, skip);
222                                 wr_buffer -= (*x) * 3;
223                         }
224                         break;
225                 }
226                 case 24:
227                 {
228                         int skip = fill4B((*x) * 3);
229                         lseek(fd, raster, SEEK_SET);
230                         for (int i = 0; i < (*y); i++)
231                         {
232                                 read(fd, wr_buffer, (*x) * 3);
233                                 for (int j = 0; j < (*x) * 3 ; j = j + 3)
234                                 {
235                                         unsigned char c = wr_buffer[j];
236                                         wr_buffer[j] = wr_buffer[j + 2];
237                                         wr_buffer[j + 2] = c;
238                                 }
239                                 if (skip)
240                                         read(fd, buff, skip);
241                                 wr_buffer -= (*x) * 3;
242                         }
243                         break;
244                 }
245                 default:
246                         return NULL;
247         }
248
249         close(fd);
250         return(pic_buffer);
251 }
252
253 //---------------------------------------------------------------------
254
255 static unsigned char *png_load(const char *file, int *ox, int *oy)
256 {
257         static const png_color_16 my_background = {0, 0, 0, 0, 0};
258
259         png_uint_32 width, height;
260         unsigned int i;
261         int bit_depth, color_type, interlace_type;
262         png_byte *fbptr;
263         FILE *fh;
264
265         if (!(fh = fopen(file, "rb")))
266                 return NULL;
267
268         png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
269         if (png_ptr == NULL)
270                 return NULL;
271         png_infop info_ptr = png_create_info_struct(png_ptr);
272         if (info_ptr == NULL)
273         {
274                 png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
275                 fclose(fh);
276                 return NULL;
277         }
278
279         if (setjmp(png_ptr->jmpbuf))
280         {
281                 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
282                 fclose(fh);
283                 return NULL;
284         }
285
286         png_init_io(png_ptr, fh);
287
288         png_read_info(png_ptr, info_ptr);
289         png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);
290
291         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)))
292                 png_set_expand(png_ptr);
293         if (bit_depth == 16)
294                 png_set_strip_16(png_ptr);
295         if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
296                 png_set_gray_to_rgb(png_ptr);
297
298         int number_passes = png_set_interlace_handling(png_ptr);
299         png_read_update_info(png_ptr, info_ptr);
300
301         if (width * 3 != png_get_rowbytes(png_ptr, info_ptr))
302         {
303                 eDebug("[Picload] Error processing");
304                 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
305                 fclose(fh);
306                 return NULL;
307         }
308
309         unsigned char *pic_buffer = new unsigned char[height * width * 3];
310         *ox=width;
311         *oy=height;
312
313         for(int pass = 0; pass < number_passes; pass++)
314         {
315                 fbptr = (png_byte *)pic_buffer;
316                 for (i = 0; i < height; i++, fbptr += width * 3)
317                         png_read_row(png_ptr, fbptr, NULL);
318         }
319         png_read_end(png_ptr, info_ptr);
320         png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
321         fclose(fh);
322         return(pic_buffer);
323 }
324
325 //-------------------------------------------------------------------
326
327 struct r_jpeg_error_mgr
328 {
329         struct jpeg_error_mgr pub;
330         jmp_buf envbuffer;
331 };
332
333 void jpeg_cb_error_exit(j_common_ptr cinfo)
334 {
335         struct r_jpeg_error_mgr *mptr;
336         mptr = (struct r_jpeg_error_mgr *) cinfo->err;
337         (*cinfo->err->output_message) (cinfo);
338         longjmp(mptr->envbuffer, 1);
339 }
340
341 static unsigned char *jpeg_load(const char *file, int *ox, int *oy)
342 {
343         struct jpeg_decompress_struct cinfo;
344         struct jpeg_decompress_struct *ciptr = &cinfo;
345         struct r_jpeg_error_mgr emgr;
346         FILE *fh;
347         unsigned char *pic_buffer=NULL;
348
349         if (!(fh = fopen(file, "rb")))
350                 return NULL;
351
352         ciptr->err = jpeg_std_error(&emgr.pub);
353         emgr.pub.error_exit = jpeg_cb_error_exit;
354         if (setjmp(emgr.envbuffer) == 1)
355         {
356                 jpeg_destroy_decompress(ciptr);
357                 fclose(fh);
358                 return NULL;
359         }
360
361         jpeg_create_decompress(ciptr);
362         jpeg_stdio_src(ciptr, fh);
363         jpeg_read_header(ciptr, TRUE);
364         ciptr->out_color_space = JCS_RGB;
365         ciptr->scale_denom = 1;
366
367         jpeg_start_decompress(ciptr);
368         
369         *ox=ciptr->output_width;
370         *oy=ciptr->output_height;
371
372         if(ciptr->output_components == 3)
373         {
374                 JSAMPLE *lb = (JSAMPLE *)(*ciptr->mem->alloc_small)((j_common_ptr) ciptr, JPOOL_PERMANENT, ciptr->output_width * ciptr->output_components);
375                 pic_buffer = new unsigned char[ciptr->output_height * ciptr->output_width * ciptr->output_components];
376                 unsigned char *bp = pic_buffer;
377
378                 while (ciptr->output_scanline < ciptr->output_height)
379                 {
380                         jpeg_read_scanlines(ciptr, &lb, 1);
381                         memcpy(bp, lb, ciptr->output_width * ciptr->output_components);
382                         bp += ciptr->output_width * ciptr->output_components;
383                 }
384         }
385         jpeg_finish_decompress(ciptr);
386         jpeg_destroy_decompress(ciptr);
387         fclose(fh);
388         return(pic_buffer);
389 }
390
391
392 static int jpeg_save(const char * filename, int ox, int oy, unsigned char *pic_buffer)
393 {
394         struct jpeg_compress_struct cinfo;
395         struct jpeg_error_mgr jerr;
396         FILE * outfile;         
397         JSAMPROW row_pointer[1];
398         int row_stride;         
399  
400         cinfo.err = jpeg_std_error(&jerr);
401         jpeg_create_compress(&cinfo);
402  
403         if ((outfile = fopen(filename, "wb")) == NULL) 
404         {
405                 eDebug("[Picload] jpeg can't open %s", filename);
406                 return 1;
407         }
408         eDebug("[Picload] save Thumbnail... %s",filename);
409
410         jpeg_stdio_dest(&cinfo, outfile);
411  
412         cinfo.image_width = ox;
413         cinfo.image_height = oy;
414         cinfo.input_components = 3;
415         cinfo.in_color_space = JCS_RGB;
416         jpeg_set_defaults(&cinfo);
417         jpeg_set_quality(&cinfo, 70, TRUE );
418         jpeg_start_compress(&cinfo, TRUE);
419         row_stride = ox * 3;
420         while (cinfo.next_scanline < cinfo.image_height) 
421         {
422                 row_pointer[0] = & pic_buffer[cinfo.next_scanline * row_stride];
423                 (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
424         }
425         jpeg_finish_compress(&cinfo);
426         fclose(outfile);
427         jpeg_destroy_compress(&cinfo);
428         return 0;
429 }
430
431 //-------------------------------------------------------------------
432
433 inline void m_rend_gif_decodecolormap(unsigned char *cmb, unsigned char *rgbb, ColorMapObject *cm, int s, int l)
434 {
435         GifColorType *cmentry;
436         int i;
437         for (i = 0; i < l; i++)
438         {
439                 cmentry = &cm->Colors[cmb[i]];
440                 *(rgbb++) = cmentry->Red;
441                 *(rgbb++) = cmentry->Green;
442                 *(rgbb++) = cmentry->Blue;
443         }
444 }
445
446 static unsigned char *gif_load(const char *file, int *ox, int *oy)
447 {
448         unsigned char *pic_buffer = NULL;
449         int px, py, i, j, ibxs;
450         unsigned char *fbptr;
451         unsigned char *lb=NULL;
452         unsigned char *slb=NULL;
453         GifFileType *gft;
454         GifRecordType rt;
455         GifByteType *extension;
456         ColorMapObject *cmap;
457         int cmaps;
458         int extcode;
459         
460         gft = DGifOpenFileName(file);
461         if (gft == NULL) 
462                 return NULL;
463         do
464         {
465                 if (DGifGetRecordType(gft, &rt) == GIF_ERROR)
466                         goto ERROR_R;
467                 switch(rt)
468                 {
469                         case IMAGE_DESC_RECORD_TYPE:
470                                 if (DGifGetImageDesc(gft) == GIF_ERROR)
471                                         goto ERROR_R;
472                                 *ox = px = gft->Image.Width;
473                                 *oy = py = gft->Image.Height;
474                                 pic_buffer = new unsigned char[px * py * 3];
475                                 lb = (unsigned char *)malloc(px * 3);
476                                 slb = (unsigned char *) malloc(px);
477
478                                 if (lb != NULL && slb != NULL)
479                                 {
480                                         cmap = (gft->Image.ColorMap ? gft->Image.ColorMap : gft->SColorMap);
481                                         cmaps = cmap->ColorCount;
482
483                                         ibxs = ibxs * 3;
484                                         fbptr = pic_buffer;
485                                         if (!(gft->Image.Interlace))
486                                         {
487                                                 for (i = 0; i < py; i++, fbptr += px * 3)
488                                                 {
489                                                         if (DGifGetLine(gft, slb, px) == GIF_ERROR)
490                                                                 goto ERROR_R;
491                                                         m_rend_gif_decodecolormap(slb, lb, cmap, cmaps, px);
492                                                         memcpy(fbptr, lb, px * 3);
493                                                 }
494                                         }
495                                         else
496                                         {
497                                                 for (j = 0; j < 4; j++)
498                                                 {
499                                                         fbptr = pic_buffer;
500                                                         for (i = 0; i < py; i++, fbptr += px * 3)
501                                                         {
502                                                                 if (DGifGetLine(gft, slb, px) == GIF_ERROR)
503                                                                         goto ERROR_R;
504                                                                 m_rend_gif_decodecolormap(slb, lb, cmap, cmaps, px);
505                                                                 memcpy(fbptr, lb, px * 3);
506                                                         }
507                                                 }
508                                         }
509                                 }
510                                 if (lb)
511                                 {
512                                         free(lb);
513                                         lb=NULL;
514                                 }
515                                 if (slb)
516                                 {
517                                         free(slb);
518                                         slb=NULL;
519                                 }
520                                 break;
521                         case EXTENSION_RECORD_TYPE:
522                                 if (DGifGetExtension(gft, &extcode, &extension) == GIF_ERROR)
523                                         goto ERROR_R;
524                                 while (extension != NULL)
525                                         if (DGifGetExtensionNext(gft, &extension) == GIF_ERROR)
526                                                 goto ERROR_R;
527                                 break;
528                         default:
529                                 break;
530                 }
531         }
532         while (rt != TERMINATE_RECORD_TYPE);
533
534         DGifCloseFile(gft);
535         return(pic_buffer);
536 ERROR_R:
537         eDebug("[Picload] <Error gif>");
538         if (lb)         free(lb);
539         if (slb)        free(slb);
540         DGifCloseFile(gft);
541         return NULL;
542 }
543
544 //---------------------------------------------------------------------------------------------
545
546 ePicLoad::ePicLoad()
547         :msg_thread(this,1), msg_main(eApp,1)
548 {
549         CONNECT(msg_thread.recv_msg, ePicLoad::gotMessage);
550         CONNECT(msg_main.recv_msg, ePicLoad::gotMessage);
551         
552         threadrunning = false;
553         m_filepara = NULL;
554         m_conf.max_x = 0;
555         m_conf.max_y = 0;
556         m_conf.aspect_ratio = 1.066400; //4:3
557         m_conf.usecache = false;
558         m_conf.resizetype = 1;
559         memset(m_conf.background,0x00,sizeof(m_conf.background));
560         m_conf.thumbnailsize = 180;
561 }
562
563 void ePicLoad::waitFinished()
564 {
565         msg_thread.send(Message(Message::quit));
566         kill();
567 }
568
569 ePicLoad::~ePicLoad()
570 {
571         if (threadrunning)
572                 waitFinished();
573         if(m_filepara != NULL)
574                 delete m_filepara;
575 }
576
577 void ePicLoad::thread_finished()
578 {
579         threadrunning=false;
580 }
581
582 void ePicLoad::thread()
583 {
584         hasStarted();
585         threadrunning=true;
586         nice(4);
587         runLoop();
588 }
589
590 void ePicLoad::decodePic()
591 {
592         eDebug("[Picload] decode picture... %s",m_filepara->file);
593         
594         switch(m_filepara->id)
595         {
596                 case F_PNG:     m_filepara->pic_buffer = png_load(m_filepara->file, &m_filepara->ox, &m_filepara->oy);  break;
597                 case F_JPEG:    m_filepara->pic_buffer = jpeg_load(m_filepara->file, &m_filepara->ox, &m_filepara->oy); break;
598                 case F_BMP:     m_filepara->pic_buffer = bmp_load(m_filepara->file, &m_filepara->ox, &m_filepara->oy);  break;
599                 case F_GIF:     m_filepara->pic_buffer = gif_load(m_filepara->file, &m_filepara->ox, &m_filepara->oy);  break;
600         }
601         
602         if(m_filepara->pic_buffer != NULL)
603         {
604                 resizePic();
605         }
606 }
607
608 void ePicLoad::decodeThumb()
609 {
610         eDebug("[Picload] get Thumbnail... %s",m_filepara->file);
611
612         bool exif_thumbnail = false;
613         bool cachefile_found = false;
614         std::string cachefile = "";
615         std::string cachedir = "/.Thumbnails";
616         
617         if(m_filepara->id == F_JPEG)
618         {
619                 Cexif *exif = new Cexif;
620                 if(exif->DecodeExif(m_filepara->file, 1))
621                 {
622                         if(exif->m_exifinfo->IsExif)
623                         {
624                                 if(exif->m_exifinfo->Thumnailstate==2)
625                                 {
626                                         m_filepara->file = strdup(THUMBNAILTMPFILE);
627                                         exif_thumbnail = true;
628                                         eDebug("[Picload] Exif Thumbnail found");
629                                 }
630                                 m_filepara->addExifInfo(exif->m_exifinfo->CameraMake);
631                                 m_filepara->addExifInfo(exif->m_exifinfo->CameraModel);
632                                 m_filepara->addExifInfo(exif->m_exifinfo->DateTime);
633                                 char buf[20];
634                                 snprintf(buf, 20, "%d x %d", exif->m_exifinfo->Width, exif->m_exifinfo->Height);
635                                 m_filepara->addExifInfo(buf);
636                         }
637                         exif->ClearExif();
638                 }
639                 delete exif;
640         }
641         
642         if((! exif_thumbnail) && m_conf.usecache)
643         {
644                 if(FILE *f=fopen(m_filepara->file, "rb"))
645                 {
646                         int c;
647                         int count = 1024*100;
648                         unsigned long crc32 = 0;
649                         char crcstr[9];*crcstr=0;
650
651                         while ((c=getc(f))!=EOF)
652                         {
653                                 crc32 = crc32_table[((crc32) ^ (c)) & 0xFF] ^ ((crc32) >> 8);
654                                 if(--count < 0) break;
655                         }
656         
657                         fclose(f);
658                         crc32 = ~crc32;
659                         sprintf(crcstr, "%08lX", crc32);
660                 
661                         cachedir = m_filepara->file;
662                         unsigned int pos = cachedir.find_last_of("/");
663                         if (pos != std::string::npos)
664                                 cachedir = cachedir.substr(0, pos) + "/.Thumbnails";
665                         
666                         cachefile = cachedir + std::string("/pc_") + crcstr;
667                         if(!access(cachefile.c_str(), R_OK))
668                         {
669                                 cachefile_found = true;
670                                 m_filepara->file = strdup(cachefile.c_str());
671                                 m_filepara->id = F_JPEG;
672                                 eDebug("[Picload] Cache File found");
673                         }
674                 }
675         }
676
677         switch(m_filepara->id)
678         {
679                 case F_PNG:     m_filepara->pic_buffer = png_load(m_filepara->file, &m_filepara->ox, &m_filepara->oy);  break;
680                 case F_JPEG:    m_filepara->pic_buffer = jpeg_load(m_filepara->file, &m_filepara->ox, &m_filepara->oy); break;
681                 case F_BMP:     m_filepara->pic_buffer = bmp_load(m_filepara->file, &m_filepara->ox, &m_filepara->oy);  break;
682                 case F_GIF:     m_filepara->pic_buffer = gif_load(m_filepara->file, &m_filepara->ox, &m_filepara->oy);  break;
683         }
684         
685         if(exif_thumbnail)
686                 ::unlink(THUMBNAILTMPFILE);
687         
688         if(m_filepara->pic_buffer != NULL)
689         {
690                 //save cachefile
691                 if(m_conf.usecache && (! exif_thumbnail) && (! cachefile_found))
692                 {
693                         if(access(cachedir.c_str(), R_OK))
694                                 ::mkdir(cachedir.c_str(), 0755);
695                         
696                         //resize for Thumbnail
697                         int imx, imy;
698                         if (m_filepara->ox <= m_filepara->oy)
699                         {
700                                 imy = m_conf.thumbnailsize;
701                                 imx = (int)( (m_conf.thumbnailsize * ((double)m_filepara->ox)) / ((double)m_filepara->oy) );
702                         }
703                         else
704                         {
705                                 imx = m_conf.thumbnailsize;
706                                 imy = (int)( (m_conf.thumbnailsize * ((double)m_filepara->oy)) / ((double)m_filepara->ox) );
707                         }
708
709                         m_filepara->pic_buffer = color_resize(m_filepara->pic_buffer, m_filepara->ox, m_filepara->oy, imx, imy);
710                         m_filepara->ox = imx;
711                         m_filepara->oy = imy;
712
713                         if(jpeg_save(cachefile.c_str(), m_filepara->ox, m_filepara->oy, m_filepara->pic_buffer))
714                                 eDebug("[Picload] error saving cachefile");
715                 }
716
717                 resizePic();
718         }
719 }
720
721 void ePicLoad::resizePic()
722 {
723         int imx, imy;
724
725         if((m_conf.aspect_ratio * m_filepara->oy * m_filepara->max_x / m_filepara->ox) <= m_filepara->max_y)
726         {
727                 imx = m_filepara->max_x;
728                 imy = (int)(m_conf.aspect_ratio * m_filepara->oy * m_filepara->max_x / m_filepara->ox);
729         }
730         else
731         {
732                 imx = (int)((1.0/m_conf.aspect_ratio) * m_filepara->ox * m_filepara->max_y / m_filepara->oy);
733                 imy = m_filepara->max_y;
734         }
735                 
736         if(m_conf.resizetype)
737                 m_filepara->pic_buffer = color_resize(m_filepara->pic_buffer, m_filepara->ox, m_filepara->oy, imx, imy);
738         else
739                 m_filepara->pic_buffer = simple_resize(m_filepara->pic_buffer, m_filepara->ox, m_filepara->oy, imx, imy);
740
741         m_filepara->ox = imx;
742         m_filepara->oy = imy;
743 }
744
745 void ePicLoad::gotMessage(const Message &msg)
746 {
747         switch (msg.type)
748         {
749                 case Message::decode_Pic:
750                         decodePic();
751                         msg_main.send(Message(Message::decode_finished));
752                         break;
753                 case Message::decode_Thumb:
754                         decodeThumb();
755                         msg_main.send(Message(Message::decode_finished));
756                         break;
757                 case Message::quit: // called from decode thread
758                         eDebug("[Picload] decode thread ... got quit msg");
759                         quit(0);
760                         break;
761                 case Message::decode_finished: // called from main thread
762                         //eDebug("[Picload] decode finished... %s", m_filepara->file);
763                         if(m_filepara->callback)
764                         {
765                                 PictureData(m_filepara->picinfo.c_str());
766                         }
767                         else
768                         {
769                                 if(m_filepara != NULL)
770                                 {
771                                         delete m_filepara;
772                                         m_filepara = NULL;
773                                 }
774                         }
775                         break;
776                 default:
777                         eDebug("unhandled thread message");
778         }
779 }
780
781 int ePicLoad::startThread(int what, const char *file, int x, int y, bool async)
782 {
783         if(async && threadrunning && m_filepara != NULL)
784         {
785                 eDebug("[Picload] thread running");
786                 m_filepara->callback = false;
787                 return 1;
788         }
789         
790         if(m_filepara != NULL)
791         {
792                 delete m_filepara;
793                 m_filepara = NULL;
794         }
795         
796         int file_id = -1;
797         unsigned char id[10];
798         int fd = ::open(file, O_RDONLY);
799         if (fd == -1) return 1;
800         ::read(fd, id, 10);
801         ::close(fd);
802
803         if(id[1] == 'P' && id[2] == 'N' && id[3] == 'G')                        file_id = F_PNG;
804         else if(id[6] == 'J' && id[7] == 'F' && id[8] == 'I' && id[9] == 'F')   file_id = F_JPEG;
805         else if(id[0] == 0xff && id[1] == 0xd8 && id[2] == 0xff)                file_id = F_JPEG;
806         else if(id[0] == 'B' && id[1] == 'M' )                                  file_id = F_BMP;
807         else if(id[0] == 'G' && id[1] == 'I' && id[2] == 'F')                   file_id = F_GIF;
808         
809         if(file_id < 0)
810         {
811                 eDebug("[Picload] <format not supportet>");
812                 return 1;
813         }
814
815         m_filepara = new Cfilepara(file, file_id, getSize(file));
816         x > 0 ? m_filepara->max_x = x : m_filepara->max_x = m_conf.max_x;
817         y > 0 ? m_filepara->max_y = y : m_filepara->max_y = m_conf.max_y;
818         
819         if(m_filepara->max_x <= 0 || m_filepara->max_y <= 0)
820         {
821                 delete m_filepara;
822                 m_filepara = NULL;
823                 eDebug("[Picload] <error in Para>");
824                 return 1;
825         }
826         
827         if (async) {
828                 if(what==1)
829                         msg_thread.send(Message(Message::decode_Pic));
830                 else
831                         msg_thread.send(Message(Message::decode_Thumb));
832                 run();
833         }
834         else if (what == 1)
835                 decodePic();
836         else
837                 decodeThumb();
838         return 0;
839 }
840
841 RESULT ePicLoad::startDecode(const char *file, int x, int y, bool async)
842 {
843         return startThread(1, file, x, y, async);
844 }
845
846 RESULT ePicLoad::getThumbnail(const char *file, int x, int y, bool async)
847 {
848         return startThread(0, file, x, y, async);
849 }
850
851 PyObject *ePicLoad::getInfo(const char *filename)
852 {
853         ePyObject list;
854         
855         Cexif *exif = new Cexif;
856         if(exif->DecodeExif(filename))
857         {
858                 if(exif->m_exifinfo->IsExif)
859                 {
860                         char tmp[256];
861                         int pos=0;
862                         list = PyList_New(23);
863                         PyList_SET_ITEM(list, pos++,  PyString_FromString(filename));
864                         PyList_SET_ITEM(list, pos++,  PyString_FromString(exif->m_exifinfo->Version));
865                         PyList_SET_ITEM(list, pos++,  PyString_FromString(exif->m_exifinfo->CameraMake));
866                         PyList_SET_ITEM(list, pos++,  PyString_FromString(exif->m_exifinfo->CameraModel));
867                         PyList_SET_ITEM(list, pos++,  PyString_FromString(exif->m_exifinfo->DateTime));
868                         PyList_SET_ITEM(list, pos++,  PyString_FromFormat("%d x %d", exif->m_exifinfo->Width, exif->m_exifinfo->Height));
869                         PyList_SET_ITEM(list, pos++,  PyString_FromString(exif->m_exifinfo->FlashUsed));
870                         PyList_SET_ITEM(list, pos++,  PyString_FromString(exif->m_exifinfo->Orientation));
871                         PyList_SET_ITEM(list, pos++,  PyString_FromString(exif->m_exifinfo->Comments));
872                         PyList_SET_ITEM(list, pos++,  PyString_FromString(exif->m_exifinfo->MeteringMode));
873                         PyList_SET_ITEM(list, pos++,  PyString_FromString(exif->m_exifinfo->ExposureProgram));
874                         PyList_SET_ITEM(list, pos++,  PyString_FromString(exif->m_exifinfo->LightSource));
875                         PyList_SET_ITEM(list, pos++,  PyString_FromFormat("%d", exif->m_exifinfo->CompressionLevel));
876                         PyList_SET_ITEM(list, pos++,  PyString_FromFormat("%d", exif->m_exifinfo->ISOequivalent));
877                         sprintf(tmp, "%.2f", exif->m_exifinfo->Xresolution);
878                         PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
879                         sprintf(tmp, "%.2f", exif->m_exifinfo->Yresolution);
880                         PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
881                         PyList_SET_ITEM(list, pos++,  PyString_FromString(exif->m_exifinfo->ResolutionUnit));
882                         sprintf(tmp, "%.2f", exif->m_exifinfo->Brightness);
883                         PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
884                         sprintf(tmp, "%.5f sec.", exif->m_exifinfo->ExposureTime);
885                         PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
886                         sprintf(tmp, "%.5f", exif->m_exifinfo->ExposureBias);
887                         PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
888                         sprintf(tmp, "%.5f", exif->m_exifinfo->Distance);
889                         PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
890                         sprintf(tmp, "%.5f", exif->m_exifinfo->CCDWidth);
891                         PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
892                         sprintf(tmp, "%.2f", exif->m_exifinfo->ApertureFNumber);
893                         PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
894                 }
895                 else
896                 {
897                         list = PyList_New(2);
898                         PyList_SET_ITEM(list, 0, PyString_FromString(filename));
899                         PyList_SET_ITEM(list, 1, PyString_FromString(exif->m_szLastError));
900                 }
901                 exif->ClearExif();
902         }
903         else
904         {
905                 list = PyList_New(2);
906                 PyList_SET_ITEM(list, 0, PyString_FromString(filename));
907                 PyList_SET_ITEM(list, 1, PyString_FromString(exif->m_szLastError));
908         }
909         delete exif;
910
911         return list ? (PyObject*)list : (PyObject*)PyList_New(0);
912 }
913
914 int ePicLoad::getData(ePtr<gPixmap> &result)
915 {
916         result = 0;
917         if(m_filepara->pic_buffer == NULL) return 0;
918         
919         m_filepara->pic_buffer = conv24to32(m_filepara->pic_buffer, m_filepara->ox * m_filepara->oy);
920         
921         result=new gPixmap(eSize(m_filepara->max_x, m_filepara->max_y), 32);
922         gSurface *surface = result->surface;
923         int a=0, b=0;
924         int nc=0, oc=0;
925         int o_y=0, u_y=0, v_x=0, h_x=0;
926
927         unsigned char *tmp_buffer=((unsigned char *)(surface->data));
928         
929         if(m_filepara->oy < m_filepara->max_y)
930         {
931                 o_y = (m_filepara->max_y - m_filepara->oy) / 2;
932                 u_y = m_filepara->max_y - m_filepara->oy - o_y;
933         }
934         if(m_filepara->ox < m_filepara->max_x)
935         {
936                 v_x = (m_filepara->max_x - m_filepara->ox) / 2;
937                 h_x = m_filepara->max_x - m_filepara->ox - v_x;
938         }
939         
940         if(m_filepara->oy < m_filepara->max_y)
941         {
942                 for(a=0; a<(o_y*m_filepara->ox); a++, nc+=4)
943                 {
944                         tmp_buffer=((unsigned char *)(surface->data)) + nc;
945                         memcpy(tmp_buffer, m_conf.background, sizeof(m_conf.background));
946                 }
947         }
948         
949         for(a=0; a<m_filepara->oy; a++)
950         {
951                 if(m_filepara->ox < m_filepara->max_x)
952                 {
953                         for(b=0; b<v_x; b++, nc+=4)
954                         {
955                                 tmp_buffer=((unsigned char *)(surface->data)) + nc;
956                                 memcpy(tmp_buffer, m_conf.background, sizeof(m_conf.background));
957                         }
958                 }
959
960                 for(b=0; b<(m_filepara->ox*4); b+=4, nc+=4)
961                 {
962                         tmp_buffer=((unsigned char *)(surface->data)) + nc;
963                         tmp_buffer[2] = m_filepara->pic_buffer[oc++];
964                         tmp_buffer[1] = m_filepara->pic_buffer[oc++];
965                         tmp_buffer[0] = m_filepara->pic_buffer[oc++];
966                         tmp_buffer[3] = m_filepara->pic_buffer[oc++];
967                 }
968                 
969                 if(m_filepara->ox < m_filepara->max_x)
970                 {
971                         for(b=0; b<h_x; b++, nc+=4)
972                         {
973                                 tmp_buffer=((unsigned char *)(surface->data)) + nc;
974                                 memcpy(tmp_buffer, m_conf.background, sizeof(m_conf.background));
975                         }
976                 }
977         }
978         
979         if(m_filepara->oy < m_filepara->max_y)
980         {
981                 for(a=0; a<(u_y*m_filepara->ox); a++, nc+=4)
982                 {
983                         tmp_buffer=((unsigned char *)(surface->data)) + nc;
984                         memcpy(tmp_buffer, m_conf.background, sizeof(m_conf.background));
985                 }
986         }
987         
988         surface->clut.data=0;
989         surface->clut.colors=0;
990         surface->clut.start=0;
991
992         delete m_filepara;
993         m_filepara = NULL;
994
995         return 0;
996 }
997
998 RESULT ePicLoad::setPara(PyObject *val)
999 {
1000         if (!PySequence_Check(val))
1001                 return 0;
1002         if (PySequence_Size(val) < 7)
1003                 return 0;
1004         else {
1005                 ePyObject fast = PySequence_Fast(val, "");
1006                 m_conf.max_x            = PyInt_AsLong( PySequence_Fast_GET_ITEM(fast, 0));
1007                 m_conf.max_y            = PyInt_AsLong( PySequence_Fast_GET_ITEM(fast, 1));
1008                 m_conf.aspect_ratio     = (double)PyInt_AsLong( PySequence_Fast_GET_ITEM(fast, 2)) / PyInt_AsLong(PySequence_Fast_GET_ITEM(fast, 3));
1009                 m_conf.usecache         = PyInt_AsLong( PySequence_Fast_GET_ITEM(fast, 4));
1010                 m_conf.resizetype       = PyInt_AsLong( PySequence_Fast_GET_ITEM(fast, 5));
1011                 const char *bg_str      = PyString_AsString( PySequence_Fast_GET_ITEM(fast, 6));
1012         
1013                 if(bg_str[0] == '#' && strlen(bg_str)==9)
1014                 {
1015                         int bg = strtoul(bg_str+1, NULL, 16);
1016                         m_conf.background[0] = bg&0xFF;         //BB
1017                         m_conf.background[1] = (bg>>8)&0xFF;    //GG
1018                         m_conf.background[2] = (bg>>16)&0xFF;   //RR
1019                         m_conf.background[3] = bg>>24;          //AA
1020                 }
1021                 eDebug("[Picload] setPara max-X=%d max-Y=%d aspect_ratio=%lf cache=%d resize=%d bg=#%02X%02X%02X%02X", m_conf.max_x, m_conf.max_y, m_conf.aspect_ratio, (int)m_conf.usecache, (int)m_conf.resizetype, m_conf.background[3], m_conf.background[2], m_conf.background[1], m_conf.background[0]);
1022         }
1023         return 1;
1024 }
1025
1026 //------------------------------------------------------------------------------------
1027
1028 //for old plugins
1029 SWIG_VOID(int) loadPic(ePtr<gPixmap> &result, std::string filename, int x, int y, int aspect, int resize_mode, int rotate, int background, std::string cachefile)
1030 {
1031         long asp1, asp2;
1032         result = 0;
1033         eDebug("deprecated loadPic function used!!! please use the non blocking version! you can see demo code in Pictureplayer plugin... this function is removed in the near future!");
1034         ePicLoad mPL;
1035
1036         switch(aspect)
1037         {
1038                 case 1:         asp1 = 16*576, asp2 = 9*720; break; //16:9
1039                 case 2:         asp1 = 16*576, asp2 = 10*720; break; //16:10
1040                 case 3:         asp1 = 5*576, asp2 = 4*720; break; //5:4
1041                 default:        asp1 = 4*576, asp2 = 3*720; break; //4:3
1042         }
1043
1044         ePyObject tuple = PyTuple_New(7);
1045         PyTuple_SET_ITEM(tuple, 0,  PyLong_FromLong(x));
1046         PyTuple_SET_ITEM(tuple, 1,  PyLong_FromLong(y));
1047         PyTuple_SET_ITEM(tuple, 2,  PyLong_FromLong(asp1));
1048         PyTuple_SET_ITEM(tuple, 3,  PyLong_FromLong(asp2));
1049         PyTuple_SET_ITEM(tuple, 4,  PyLong_FromLong(0));
1050         PyTuple_SET_ITEM(tuple, 5,  PyLong_FromLong(resize_mode));
1051         if(background)
1052                 PyTuple_SET_ITEM(tuple, 6,  PyString_FromString("#ff000000"));
1053         else
1054                 PyTuple_SET_ITEM(tuple, 6,  PyString_FromString("#00000000"));
1055
1056         mPL.setPara(tuple);
1057
1058         if(!mPL.startDecode(filename.c_str(), 0, 0, false))
1059                 mPL.getData(result);
1060
1061         return 0;
1062 }