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