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