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