picload: updates to thumbnail EXIF handling
[openblackhole/openblackhole-enigma2.git] / lib / gdi / picload.cpp
1 #define PNG_SKIP_SETJMP_CHECK
2 #include <png.h>
3 #include <fcntl.h>
4
5 #include <lib/base/cfile.h>
6 #include <lib/gdi/picload.h>
7 #include <lib/gdi/picexif.h>
8
9 extern "C" {
10 #define HAVE_BOOLEAN
11 #define boolean int
12 #include <jpeglib.h>
13 #include <gif_lib.h>
14 }
15
16 extern const uint32_t crc32_table[256];
17
18 DEFINE_REF(ePicLoad);
19
20 static std::string getSize(const char* file)
21 {
22         struct stat64 s;
23         if (stat64(file, &s) < 0)
24                 return "";
25         char tmp[20];
26         snprintf(tmp, 20, "%ld kB", (long)s.st_size / 1024);
27         return tmp;
28 }
29
30 static unsigned char *simple_resize_24(unsigned char *orgin, int ox, int oy, int dx, int dy)
31 {
32         unsigned char *cr = new unsigned char[dx * dy * 3];
33         if (cr == NULL)
34         {
35                 eDebug("[ePicLoad] resize24 Error malloc");
36                 return orgin;
37         }
38         const int stride = 3 * dx;
39         #pragma omp parallel for
40         for (int j = 0; j < dy; ++j)
41         {
42                 unsigned char* k = cr + (j * stride);
43                 const unsigned char* p = orgin + (j * oy / dy * ox) * 3;
44                 for (int i = 0; i < dx; i++)
45                 {
46                         const unsigned char* ip = p + (i * ox / dx) * 3;
47                         *k++ = ip[0];
48                         *k++ = ip[1];
49                         *k++ = ip[2];
50                 }
51         }
52         delete [] orgin;
53         return cr;
54 }
55
56 static unsigned char *simple_resize_8(unsigned char *orgin, int ox, int oy, int dx, int dy)
57 {
58         unsigned char* cr = new unsigned char[dx * dy];
59         if (cr == NULL)
60         {
61                 eDebug("[ePicLoad] resize8 Error malloc");
62                 return(orgin);
63         }
64         const int stride = dx;
65         #pragma omp parallel for
66         for (int j = 0; j < dy; ++j)
67         {
68                 unsigned char* k = cr + (j * stride);
69                 const unsigned char* p = orgin + (j * oy / dy * ox);
70                 for (int i = 0; i < dx; i++)
71                 {
72                         *k++ = p[i * ox / dx];
73                 }
74         }
75         delete [] orgin;
76         return cr;
77 }
78
79 static unsigned char *color_resize(unsigned char * orgin, int ox, int oy, int dx, int dy)
80 {
81         unsigned char* cr = new unsigned char[dx * dy * 3];
82         if (cr == NULL)
83         {
84                 eDebug("[ePicLoad] resize Error malloc");
85                 return orgin;
86         }
87         const int stride = 3 * dx;
88         #pragma omp parallel for
89         for (int j = 0; j < dy; j++)
90         {
91                 unsigned char* p = cr + (j * stride);
92                 int ya = j * oy / dy;
93                 int yb = (j + 1) * oy / dy;
94                 if (yb >= oy)
95                         yb = oy - 1;
96                 for (int i = 0; i < dx; i++, p += 3)
97                 {
98                         int xa = i * ox / dx;
99                         int xb = (i + 1) * ox / dx;
100                         if (xb >= ox)
101                                 xb = ox - 1;
102                         int r = 0;
103                         int g = 0;
104                         int b = 0;
105                         int sq = 0;
106                         for (int l = ya; l <= yb; l++)
107                         {
108                                 const unsigned char* q = orgin + ((l * ox + xa) * 3);
109                                 for (int k = xa; k <= xb; k++, q += 3, sq++)
110                                 {
111                                         r += q[0];
112                                         g += q[1];
113                                         b += q[2];
114                                 }
115                         }
116                         p[0] = r / sq;
117                         p[1] = g / sq;
118                         p[2] = b / sq;
119                 }
120         }
121         delete [] orgin;
122         return cr;
123 }
124
125 //---------------------------------------------------------------------------------------------
126
127 #define BMP_TORASTER_OFFSET 10
128 #define BMP_SIZE_OFFSET 18
129 #define BMP_BPP_OFFSET 28
130 #define BMP_RLE_OFFSET 30
131 #define BMP_COLOR_OFFSET 54
132
133 #define fill4B(a) ((4 - ((a) % 4 )) & 0x03)
134
135 struct color {
136         unsigned char red;
137         unsigned char green;
138         unsigned char blue;
139 };
140
141 static void fetch_pallete(int fd, struct color pallete[], int count)
142 {
143         unsigned char buff[4];
144         lseek(fd, BMP_COLOR_OFFSET, SEEK_SET);
145         for (int i = 0; i < count; i++)
146         {
147                 read(fd, buff, 4);
148                 pallete[i].red = buff[2];
149                 pallete[i].green = buff[1];
150                 pallete[i].blue = buff[0];
151         }
152 }
153
154 static unsigned char *bmp_load(const char *file,  int *x, int *y)
155 {
156         unsigned char buff[4];
157         struct color pallete[256];
158
159         int fd = open(file, O_RDONLY);
160         if (fd == -1) return NULL;
161         if (lseek(fd, BMP_SIZE_OFFSET, SEEK_SET) == -1) return NULL;
162         read(fd, buff, 4);
163         *x = buff[0] + (buff[1] << 8) + (buff[2] << 16) + (buff[3] << 24);
164         read(fd, buff, 4);
165         *y = buff[0] + (buff[1] << 8) + (buff[2] << 16) + (buff[3] << 24);
166         if (lseek(fd, BMP_TORASTER_OFFSET, SEEK_SET) == -1) return NULL;
167         read(fd, buff, 4);
168         int raster = buff[0] + (buff[1] << 8) + (buff[2] << 16) + (buff[3] << 24);
169         if (lseek(fd, BMP_BPP_OFFSET, SEEK_SET) == -1) return NULL;
170         read(fd, buff, 2);
171         int bpp = buff[0] + (buff[1] << 8);
172
173         unsigned char *pic_buffer = new unsigned char[(*x) * (*y) * 3];
174         unsigned char *wr_buffer = pic_buffer + (*x) * ((*y) - 1) * 3;
175
176         switch (bpp)
177         {
178                 case 4:
179                 {
180                         int skip = fill4B((*x) / 2 + (*x) % 2);
181                         fetch_pallete(fd, pallete, 16);
182                         lseek(fd, raster, SEEK_SET);
183                         unsigned char * tbuffer = new unsigned char[*x / 2 + 1];
184                         if (tbuffer == NULL)
185                                 return NULL;
186                         for (int i = 0; i < *y; i++)
187                         {
188                                 read(fd, tbuffer, (*x) / 2 + *x % 2);
189                                 int j;
190                                 for (j = 0; j < (*x) / 2; j++)
191                                 {
192                                         unsigned char c1 = tbuffer[j] >> 4;
193                                         unsigned char c2 = tbuffer[j] & 0x0f;
194                                         *wr_buffer++ = pallete[c1].red;
195                                         *wr_buffer++ = pallete[c1].green;
196                                         *wr_buffer++ = pallete[c1].blue;
197                                         *wr_buffer++ = pallete[c2].red;
198                                         *wr_buffer++ = pallete[c2].green;
199                                         *wr_buffer++ = pallete[c2].blue;
200                                 }
201                                 if ((*x) % 2)
202                                 {
203                                         unsigned char c1 = tbuffer[j] >> 4;
204                                         *wr_buffer++ = pallete[c1].red;
205                                         *wr_buffer++ = pallete[c1].green;
206                                         *wr_buffer++ = pallete[c1].blue;
207                                 }
208                                 if (skip)
209                                         read(fd, buff, skip);
210                                 wr_buffer -= (*x) * 6;
211                         }
212                         delete [] tbuffer;
213                         break;
214                 }
215                 case 8:
216                 {
217                         int skip = fill4B(*x);
218                         fetch_pallete(fd, pallete, 256);
219                         lseek(fd, raster, SEEK_SET);
220                         unsigned char * tbuffer = new unsigned char[*x];
221                         if (tbuffer == NULL)
222                                 return NULL;
223                         for (int i = 0; i < *y; i++)
224                         {
225                                 read(fd, tbuffer, *x);
226                                 for (int j = 0; j < *x; j++)
227                                 {
228                                         wr_buffer[j * 3] = pallete[tbuffer[j]].red;
229                                         wr_buffer[j * 3 + 1] = pallete[tbuffer[j]].green;
230                                         wr_buffer[j * 3 + 2] = pallete[tbuffer[j]].blue;
231                                 }
232                                 if (skip)
233                                         read(fd, buff, skip);
234                                 wr_buffer -= (*x) * 3;
235                         }
236                         delete [] tbuffer;
237                         break;
238                 }
239                 case 24:
240                 {
241                         int skip = fill4B((*x) * 3);
242                         lseek(fd, raster, SEEK_SET);
243                         for (int i = 0; i < (*y); i++)
244                         {
245                                 read(fd, wr_buffer, (*x) * 3);
246                                 for (int j = 0; j < (*x) * 3 ; j = j + 3)
247                                 {
248                                         unsigned char c = wr_buffer[j];
249                                         wr_buffer[j] = wr_buffer[j + 2];
250                                         wr_buffer[j + 2] = c;
251                                 }
252                                 if (skip)
253                                         read(fd, buff, skip);
254                                 wr_buffer -= (*x) * 3;
255                         }
256                         break;
257                 }
258                 default:
259                         close(fd);
260                         return NULL;
261         }
262
263         close(fd);
264         return(pic_buffer);
265 }
266
267 //---------------------------------------------------------------------
268
269 static void png_load(Cfilepara* filepara, int background, bool forceRGB = false)
270 {
271         png_uint_32 width, height;
272         unsigned int i;
273         int bit_depth, color_type, interlace_type;
274         png_byte *fbptr;
275         CFile fh(filepara->file, "rb");
276         if (!fh)
277                 return;
278
279         png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
280         if (png_ptr == NULL)
281                 return;
282         png_infop info_ptr = png_create_info_struct(png_ptr);
283         if (info_ptr == NULL)
284         {
285                 png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
286                 return;
287         }
288
289         if (setjmp(png_jmpbuf(png_ptr)))
290         {
291                 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
292                 return;
293         }
294
295         png_init_io(png_ptr, fh);
296
297         png_read_info(png_ptr, info_ptr);
298         png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);
299
300         if (!forceRGB && (color_type == PNG_COLOR_TYPE_GRAY || color_type & PNG_COLOR_MASK_PALETTE))
301         {
302                 if (bit_depth < 8)
303                 {
304                         png_set_packing(png_ptr);
305                         bit_depth = 8;
306                 }
307                 unsigned char *pic_buffer = new unsigned char[height * width];
308                 filepara->ox = width;
309                 filepara->oy = height;
310                 filepara->pic_buffer = pic_buffer;
311                 filepara->bits = 8;
312
313                 png_bytep *rowptr=new png_bytep[height];
314                 for (unsigned int i=0; i!=height; i++)
315                 {
316                         rowptr[i]=(png_byte*)pic_buffer;
317                         pic_buffer += width;
318                 }
319                 png_read_rows(png_ptr, rowptr, 0, height);
320                 delete [] rowptr;
321
322                 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE))
323                 {
324                         png_color *palette;
325                         int num_palette;
326                         png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
327                         filepara->palette_size = num_palette;
328                         if (num_palette)
329                                 filepara->palette = new gRGB[num_palette];
330                         for (int i=0; i<num_palette; i++)
331                         {
332                                 filepara->palette[i].a=0;
333                                 filepara->palette[i].r=palette[i].red;
334                                 filepara->palette[i].g=palette[i].green;
335                                 filepara->palette[i].b=palette[i].blue;
336                         }
337                         if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
338                         {
339                                 png_byte *trans;
340                                 png_get_tRNS(png_ptr, info_ptr, &trans, &num_palette, 0);
341                                 for (int i=0; i<num_palette; i++)
342                                         filepara->palette[i].a=255-trans[i];
343                         }
344                 }
345         }
346         else
347         {
348                 if (bit_depth == 16)
349                         png_set_strip_16(png_ptr);
350                 if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
351                         png_set_gray_to_rgb(png_ptr);
352                 if (color_type & PNG_COLOR_MASK_PALETTE)
353                         png_set_palette_to_rgb(png_ptr);
354                 if (color_type & PNG_COLOR_MASK_ALPHA || png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
355                 {
356                         png_set_strip_alpha(png_ptr);
357                         png_color_16 bg;
358                         bg.red = (background >> 16) & 0xFF;
359                         bg.green = (background >> 8) & 0xFF;
360                         bg.blue = (background) & 0xFF;
361                         bg.gray = bg.green;
362                         bg.index = 0;
363                         png_set_background(png_ptr, &bg, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
364                 }
365                 png_read_update_info(png_ptr, info_ptr);
366
367                 if (width * 3 != png_get_rowbytes(png_ptr, info_ptr))
368                 {
369                         eDebug("[ePicLoad] Error processing (did not get RGB data from PNG file)");
370                         png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
371                         return;
372                 }
373
374                 unsigned char *pic_buffer = new unsigned char[height * width * 3];
375                 filepara->ox = width;
376                 filepara->oy = height;
377                 filepara->pic_buffer = pic_buffer;
378
379                 int number_passes = png_set_interlace_handling(png_ptr);
380                 for(int pass = 0; pass < number_passes; pass++)
381                 {
382                         fbptr = (png_byte *)pic_buffer;
383                         for (i = 0; i < height; i++, fbptr += width * 3)
384                                 png_read_row(png_ptr, fbptr, NULL);
385                 }
386                 png_read_end(png_ptr, info_ptr);
387         }
388         png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
389 }
390
391 //-------------------------------------------------------------------
392
393 struct r_jpeg_error_mgr
394 {
395         struct jpeg_error_mgr pub;
396         jmp_buf envbuffer;
397 };
398
399 void jpeg_cb_error_exit(j_common_ptr cinfo)
400 {
401         struct r_jpeg_error_mgr *mptr;
402         mptr = (struct r_jpeg_error_mgr *) cinfo->err;
403         (*cinfo->err->output_message) (cinfo);
404         longjmp(mptr->envbuffer, 1);
405 }
406
407 static unsigned char *jpeg_load(const char *file, int *ox, int *oy, unsigned int max_x, unsigned int max_y)
408 {
409         struct jpeg_decompress_struct cinfo;
410         struct jpeg_decompress_struct *ciptr = &cinfo;
411         struct r_jpeg_error_mgr emgr;
412         unsigned char *pic_buffer=NULL;
413         CFile fh(file, "rb");
414
415         if (!fh)
416                 return NULL;
417
418         ciptr->err = jpeg_std_error(&emgr.pub);
419         emgr.pub.error_exit = jpeg_cb_error_exit;
420         if (setjmp(emgr.envbuffer) == 1)
421         {
422                 jpeg_destroy_decompress(ciptr);
423                 return NULL;
424         }
425
426         jpeg_create_decompress(ciptr);
427         jpeg_stdio_src(ciptr, fh);
428         jpeg_read_header(ciptr, TRUE);
429         ciptr->out_color_space = JCS_RGB;
430
431         if (max_x == 0) max_x = 1280; // sensible default
432         if (max_y == 0) max_y = 720;
433         // define scale to always fit vertically or horizontally in all orientations
434         ciptr->scale_denom = 8;
435         unsigned int screenmax = max_x > max_y ? max_x : max_y;
436         unsigned int imagemin  = ciptr->image_width < ciptr->image_height ? ciptr->image_width : ciptr->image_height;
437         ciptr->scale_num = (ciptr->scale_denom * screenmax + imagemin -1) / imagemin;
438         if (ciptr->scale_num < 1)  ciptr->scale_num = 1;
439         if (ciptr->scale_num > 16) ciptr->scale_num = 16;
440
441         jpeg_start_decompress(ciptr);
442
443         *ox=ciptr->output_width;
444         *oy=ciptr->output_height;
445         //eDebug("[jpeg_load] ox=%d oy=%d w=%d (%d), h=%d (%d) scale=%d rec_outbuf_height=%d", ciptr->output_width, ciptr->output_height, ciptr->image_width, max_x, ciptr->image_height, max_y, ciptr->scale_num, ciptr->rec_outbuf_height);
446
447         if(ciptr->output_components == 3)
448         {
449                 unsigned int stride = ciptr->output_width * ciptr->output_components;
450                 pic_buffer = new unsigned char[ciptr->output_height * stride];
451                 unsigned char *bp = pic_buffer;
452
453                 while (ciptr->output_scanline < ciptr->output_height)
454                 {
455                         JDIMENSION lines = jpeg_read_scanlines(ciptr, &bp, ciptr->rec_outbuf_height);
456                         bp += stride * lines;
457                 }
458         }
459         jpeg_finish_decompress(ciptr);
460         jpeg_destroy_decompress(ciptr);
461         return(pic_buffer);
462 }
463
464
465 static int jpeg_save(const char * filename, int ox, int oy, unsigned char *pic_buffer)
466 {
467         struct jpeg_compress_struct cinfo;
468         struct jpeg_error_mgr jerr;
469         JSAMPROW row_pointer[1];
470         int row_stride;
471         CFile outfile(filename, "wb");
472
473         if (!outfile)
474         {
475                 eDebug("[ePicLoad] jpeg can't write %s: %m", filename);
476                 return 1;
477         }
478
479         cinfo.err = jpeg_std_error(&jerr);
480         jpeg_create_compress(&cinfo);
481
482         eDebug("[ePicLoad] save Thumbnail... %s",filename);
483
484         jpeg_stdio_dest(&cinfo, outfile);
485
486         cinfo.image_width = ox;
487         cinfo.image_height = oy;
488         cinfo.input_components = 3;
489         cinfo.in_color_space = JCS_RGB;
490         jpeg_set_defaults(&cinfo);
491         jpeg_set_quality(&cinfo, 70, TRUE );
492         jpeg_start_compress(&cinfo, TRUE);
493         row_stride = ox * 3;
494         while (cinfo.next_scanline < cinfo.image_height)
495         {
496                 row_pointer[0] = & pic_buffer[cinfo.next_scanline * row_stride];
497                 (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
498         }
499         jpeg_finish_compress(&cinfo);
500         jpeg_destroy_compress(&cinfo);
501         return 0;
502 }
503
504 //-------------------------------------------------------------------
505
506 inline void m_rend_gif_decodecolormap(unsigned char *cmb, unsigned char *rgbb, ColorMapObject *cm, int s, int l)
507 {
508         GifColorType *cmentry;
509         int i;
510         for (i = 0; i < l; i++)
511         {
512                 cmentry = &cm->Colors[cmb[i]];
513                 *(rgbb++) = cmentry->Red;
514                 *(rgbb++) = cmentry->Green;
515                 *(rgbb++) = cmentry->Blue;
516         }
517 }
518
519 static void gif_load(Cfilepara* filepara, bool forceRGB = false)
520 {
521         unsigned char *pic_buffer = NULL;
522         int px, py, i, j;
523         unsigned char *slb=NULL;
524         GifFileType *gft;
525         GifRecordType rt;
526         GifByteType *extension;
527         ColorMapObject *cmap;
528         int cmaps;
529         int extcode;
530
531         gft = DGifOpenFileName(filepara->file);
532         if (gft == NULL)
533                 return;
534         do
535         {
536                 if (DGifGetRecordType(gft, &rt) == GIF_ERROR)
537                         goto ERROR_R;
538                 switch(rt)
539                 {
540                         case IMAGE_DESC_RECORD_TYPE:
541                                 if (DGifGetImageDesc(gft) == GIF_ERROR)
542                                         goto ERROR_R;
543                                 filepara->ox = px = gft->Image.Width;
544                                 filepara->oy = py = gft->Image.Height;
545                                 pic_buffer = new unsigned char[px * py];
546                                 filepara->pic_buffer = pic_buffer;
547                                 filepara->bits = 8;
548                                 slb = pic_buffer;
549
550                                 if (pic_buffer != NULL)
551                                 {
552                                         cmap = (gft->Image.ColorMap ? gft->Image.ColorMap : gft->SColorMap);
553                                         cmaps = cmap->ColorCount;
554                                         filepara->palette_size = cmaps;
555                                         filepara->palette = new gRGB[cmaps];
556                                         for (i = 0; i != cmaps; ++i)
557                                         {
558                                                 filepara->palette[i].a = 0;
559                                                 filepara->palette[i].r = cmap->Colors[i].Red;
560                                                 filepara->palette[i].g = cmap->Colors[i].Green;
561                                                 filepara->palette[i].b = cmap->Colors[i].Blue;
562                                         }
563
564                                         if (!(gft->Image.Interlace))
565                                         {
566                                                 for (i = 0; i < py; i++)
567                                                 {
568                                                         if (DGifGetLine(gft, slb, px) == GIF_ERROR)
569                                                                 goto ERROR_R;
570                                                         slb += px;
571                                                 }
572                                         }
573                                         else
574                                         {
575                                                 int IOffset[] = { 0, 4, 2, 1 }; // The way Interlaced image should.
576                                                 int IJumps[] = { 8, 8, 4, 2 };  // be read - offsets and jumps...
577                                                 for (j = 0; j < 4; j++)
578                                                 {
579                                                         for (i = IOffset[j]; i < py; i += IJumps[j])
580                                                         {
581                                                                 if (DGifGetLine(gft, pic_buffer + i*px, px) == GIF_ERROR)
582                                                                         goto ERROR_R;
583                                                         }
584                                                 }
585                                         }
586                                         if (forceRGB) {
587                                                 unsigned char *pic_buffer2 = new unsigned char[px * py * 3];
588                                                 if (pic_buffer2 != NULL) {
589                                                         unsigned char *slb2 = pic_buffer2;
590                                                         slb = pic_buffer;
591                                                         for (j = 0; j < py; j++) {
592                                                                 for (i = 0; i < px; i++) {
593                                                                         int c = *slb++;
594                                                                         *slb2++ = filepara->palette[c].r;
595                                                                         *slb2++ = filepara->palette[c].g;
596                                                                         *slb2++ = filepara->palette[c].b;
597                                                                 }
598                                                         }
599                                                         filepara->bits = 24;
600                                                         filepara->pic_buffer = pic_buffer2;
601                                                         delete [] pic_buffer;
602                                                         delete filepara->palette;
603                                                         filepara->palette = NULL;
604                                                 }
605                                         }
606                                 }
607                                 break;
608                         case EXTENSION_RECORD_TYPE:
609                                 if (DGifGetExtension(gft, &extcode, &extension) == GIF_ERROR)
610                                         goto ERROR_R;
611                                 while (extension != NULL)
612                                         if (DGifGetExtensionNext(gft, &extension) == GIF_ERROR)
613                                                 goto ERROR_R;
614                                 break;
615                         default:
616                                 break;
617                 }
618         }
619         while (rt != TERMINATE_RECORD_TYPE);
620
621         DGifCloseFile(gft);
622         return;
623 ERROR_R:
624         eDebug("[ePicLoad] <Error gif>");
625         DGifCloseFile(gft);
626 }
627
628 //---------------------------------------------------------------------------------------------
629
630 ePicLoad::ePicLoad():
631         m_filepara(NULL),
632         m_exif(NULL),
633         threadrunning(false),
634         m_conf(),
635         msg_thread(this,1),
636         msg_main(eApp,1)
637 {
638         CONNECT(msg_thread.recv_msg, ePicLoad::gotMessage);
639         CONNECT(msg_main.recv_msg, ePicLoad::gotMessage);
640 }
641
642 ePicLoad::PConf::PConf():
643         max_x(0),
644         max_y(0),
645         aspect_ratio(1.066400), //4:3
646         background(0),
647         resizetype(1),
648         usecache(false),
649         auto_orientation(false),
650         thumbnailsize(180)
651 {
652 }
653
654 void ePicLoad::waitFinished()
655 {
656         msg_thread.send(Message(Message::quit));
657         kill();
658 }
659
660 ePicLoad::~ePicLoad()
661 {
662         if (threadrunning)
663                 waitFinished();
664         if (m_filepara != NULL)
665                 delete m_filepara;
666         if (m_exif != NULL) {
667                 m_exif->ClearExif();
668                 delete m_exif;
669         }
670 }
671
672 void ePicLoad::thread_finished()
673 {
674         threadrunning = false;
675 }
676
677 void ePicLoad::thread()
678 {
679         threadrunning = true;
680         hasStarted();
681         nice(4);
682         runLoop();
683 }
684
685 void ePicLoad::decodePic()
686 {
687         eDebug("[ePicLoad] decode picture... %s", m_filepara->file);
688
689         getExif(m_filepara->file);
690         switch(m_filepara->id)
691         {
692                 case F_PNG:     png_load(m_filepara, m_conf.background);
693                                 break;
694                 case F_JPEG:    m_filepara->pic_buffer = jpeg_load(m_filepara->file, &m_filepara->ox, &m_filepara->oy, m_filepara->max_x, m_filepara->max_y);
695                                 break;
696                 case F_BMP:     m_filepara->pic_buffer = bmp_load(m_filepara->file, &m_filepara->ox, &m_filepara->oy);
697                                 break;
698                 case F_GIF:     gif_load(m_filepara);
699                                 break;
700         }
701 }
702
703 void ePicLoad::decodeThumb()
704 {
705         eDebug("[ePicLoad] get Thumbnail... %s", m_filepara->file);
706
707         bool exif_thumbnail = false;
708         bool cachefile_found = false;
709         std::string cachefile = "";
710         std::string cachedir = "/.Thumbnails";
711
712         getExif(m_filepara->file, 1);
713         if (m_exif && m_exif->m_exifinfo->IsExif)
714         {
715                 if (m_exif->m_exifinfo->Thumnailstate == 2)
716                 {
717                         free(m_filepara->file);
718                         m_filepara->file = strdup(THUMBNAILTMPFILE);
719                         exif_thumbnail = true;
720                         eDebug("[ePicLoad] Exif Thumbnail found");
721                 }
722                 m_filepara->addExifInfo(m_exif->m_exifinfo->CameraMake);
723                 m_filepara->addExifInfo(m_exif->m_exifinfo->CameraModel);
724                 m_filepara->addExifInfo(m_exif->m_exifinfo->DateTime);
725                 char buf[20];
726                 snprintf(buf, 20, "%d x %d", m_exif->m_exifinfo->Width, m_exif->m_exifinfo->Height);
727                 m_filepara->addExifInfo(buf);
728         }
729
730         if (!exif_thumbnail && m_conf.usecache)
731         {
732                 if (FILE *f = fopen(m_filepara->file, "rb"))
733                 {
734                         int c;
735                         int count = 1024*100; // get checksum data out of max 100kB
736                         unsigned long crc32 = 0;
737                         char crcstr[9];
738                         *crcstr = 0;
739
740                         while (count-- > 0 && (c = getc(f)) != EOF)
741                                 crc32 = crc32_table[((crc32) ^ (c)) & 0xFF] ^ ((crc32) >> 8);
742
743                         fclose(f);
744                         crc32 = ~crc32;
745                         sprintf(crcstr, "%08lX", crc32);
746
747                         cachedir = m_filepara->file;
748                         unsigned int pos = cachedir.find_last_of("/");
749                         if (pos != std::string::npos)
750                                 cachedir = cachedir.substr(0, pos) + "/.Thumbnails";
751
752                         cachefile = cachedir + std::string("/pc_") + crcstr;
753                         if (!access(cachefile.c_str(), R_OK))
754                         {
755                                 cachefile_found = true;
756                                 free(m_filepara->file);
757                                 m_filepara->file = strdup(cachefile.c_str());
758                                 m_filepara->id = F_JPEG;
759                                 eDebug("[ePicLoad] Cache File found");
760                         }
761                 }
762         }
763
764         switch (m_filepara->id)
765         {
766                 case F_PNG:     png_load(m_filepara, m_conf.background, true);
767                                 break;
768                 case F_JPEG:    m_filepara->pic_buffer = jpeg_load(m_filepara->file, &m_filepara->ox, &m_filepara->oy, m_filepara->max_x, m_filepara->max_y);
769                                 break;
770                 case F_BMP:     m_filepara->pic_buffer = bmp_load(m_filepara->file, &m_filepara->ox, &m_filepara->oy);
771                                 break;
772                 case F_GIF:     gif_load(m_filepara, true);
773                                 break;
774         }
775
776         if (exif_thumbnail)
777                 ::unlink(THUMBNAILTMPFILE);
778
779         if (m_filepara->pic_buffer != NULL)
780         {
781                 // Save cachefile
782                 if (m_conf.usecache && !exif_thumbnail && !cachefile_found)
783                 {
784                         if (access(cachedir.c_str(), R_OK))
785                                 ::mkdir(cachedir.c_str(), 0755);
786
787                         // Resize for Thumbnail
788                         int imx, imy;
789                         if (m_filepara->ox <= m_filepara->oy)
790                         {
791                                 imy = m_conf.thumbnailsize;
792                                 imx = (int)( (m_conf.thumbnailsize * ((double)m_filepara->ox)) / ((double)m_filepara->oy) );
793                         }
794                         else
795                         {
796                                 imx = m_conf.thumbnailsize;
797                                 imy = (int)( (m_conf.thumbnailsize * ((double)m_filepara->oy)) / ((double)m_filepara->ox) );
798                         }
799
800                         if (m_filepara->bits == 8)
801                                 m_filepara->pic_buffer = simple_resize_8(m_filepara->pic_buffer, m_filepara->ox, m_filepara->oy, imx, imy);
802                         else
803                                 m_filepara->pic_buffer = color_resize(m_filepara->pic_buffer, m_filepara->ox, m_filepara->oy, imx, imy);
804                         m_filepara->ox = imx;
805                         m_filepara->oy = imy;
806
807                         if (jpeg_save(cachefile.c_str(), m_filepara->ox, m_filepara->oy, m_filepara->pic_buffer))
808                                 eDebug("[ePicLoad] error saving cachefile");
809                 }
810         }
811 }
812
813 void ePicLoad::resizePic()
814 {
815         int imx, imy;
816
817         if (m_conf.aspect_ratio == 0)  // do not keep aspect ratio but just fill the destination area
818         {
819                 imx = m_filepara->max_x;
820                 imy = m_filepara->max_y;
821         }
822         else if ((m_conf.aspect_ratio * m_filepara->oy * m_filepara->max_x / m_filepara->ox) <= m_filepara->max_y)
823         {
824                 imx = m_filepara->max_x;
825                 imy = (int)(m_conf.aspect_ratio * m_filepara->oy * m_filepara->max_x / m_filepara->ox);
826         }
827         else
828         {
829                 imx = (int)((1.0/m_conf.aspect_ratio) * m_filepara->ox * m_filepara->max_y / m_filepara->oy);
830                 imy = m_filepara->max_y;
831         }
832
833         if (m_filepara->bits == 8)
834                 m_filepara->pic_buffer = simple_resize_8(m_filepara->pic_buffer, m_filepara->ox, m_filepara->oy, imx, imy);
835         else if (m_conf.resizetype)
836                 m_filepara->pic_buffer = color_resize(m_filepara->pic_buffer, m_filepara->ox, m_filepara->oy, imx, imy);
837         else
838                 m_filepara->pic_buffer = simple_resize_24(m_filepara->pic_buffer, m_filepara->ox, m_filepara->oy, imx, imy);
839
840         m_filepara->ox = imx;
841         m_filepara->oy = imy;
842 }
843
844 void ePicLoad::gotMessage(const Message &msg)
845 {
846         switch (msg.type)
847         {
848                 case Message::decode_Pic:
849                         decodePic();
850                         msg_main.send(Message(Message::decode_finished));
851                         break;
852                 case Message::decode_Thumb:
853                         decodeThumb();
854                         msg_main.send(Message(Message::decode_finished));
855                         break;
856                 case Message::quit: // called from decode thread
857                         eDebug("[ePicLoad] decode thread ... got quit msg");
858                         quit(0);
859                         break;
860                 case Message::decode_finished: // called from main thread
861                         //eDebug("[ePicLoad] decode finished... %s", m_filepara->file);
862                         if(m_filepara->callback)
863                                 PictureData(m_filepara->picinfo.c_str());
864                         else
865                         {
866                                 if(m_filepara != NULL)
867                                 {
868                                         delete m_filepara;
869                                         m_filepara = NULL;
870                                 }
871                                 if (m_exif != NULL) {
872                                         m_exif->ClearExif();
873                                         delete m_exif;
874                                         m_exif = NULL;
875                                 }
876                         }
877                         break;
878                 default:
879                         eDebug("[ePicLoad] unhandled thread message");
880         }
881 }
882
883 int ePicLoad::startThread(int what, const char *file, int x, int y, bool async)
884 {
885         if(async && threadrunning && m_filepara != NULL)
886         {
887                 eDebug("[ePicLoad] thread running");
888                 m_filepara->callback = false;
889                 return 1;
890         }
891
892         if(m_filepara != NULL)
893         {
894                 delete m_filepara;
895                 m_filepara = NULL;
896         }
897         if (m_exif != NULL) {
898                 m_exif->ClearExif();
899                 delete m_exif;
900                 m_exif = NULL;
901         }
902
903         int file_id = -1;
904         unsigned char id[10];
905         int fd = ::open(file, O_RDONLY);
906         if (fd == -1) return 1;
907         ::read(fd, id, 10);
908         ::close(fd);
909
910         if      (id[1] == 'P'  && id[2] == 'N'  && id[3] == 'G')                        file_id = F_PNG;
911         else if (id[6] == 'J'  && id[7] == 'F'  && id[8] == 'I' && id[9] == 'F')        file_id = F_JPEG;
912         else if (id[0] == 0xff && id[1] == 0xd8 && id[2] == 0xff)                       file_id = F_JPEG;
913         else if (id[0] == 'B'  && id[1] == 'M' )                                        file_id = F_BMP;
914         else if (id[0] == 'G'  && id[1] == 'I'  && id[2] == 'F')                        file_id = F_GIF;
915
916         if(file_id < 0)
917         {
918                 eDebug("[ePicLoad] <format not supported>");
919                 return 1;
920         }
921
922         m_filepara = new Cfilepara(file, file_id, getSize(file));
923         m_filepara->max_x = x > 0 ? x : m_conf.max_x;
924         m_filepara->max_y = x > 0 ? y : m_conf.max_y;
925
926         if(m_filepara->max_x <= 0 || m_filepara->max_y <= 0)
927         {
928                 delete m_filepara;
929                 m_filepara = NULL;
930                 eDebug("[ePicLoad] <error in Para>");
931                 return 1;
932         }
933
934         if (async) {
935                 if(what == 1)
936                         msg_thread.send(Message(Message::decode_Pic));
937                 else
938                         msg_thread.send(Message(Message::decode_Thumb));
939                 run();
940         }
941         else if (what == 1)
942                 decodePic();
943         else
944                 decodeThumb();
945         return 0;
946 }
947
948 RESULT ePicLoad::startDecode(const char *file, int x, int y, bool async)
949 {
950         return startThread(1, file, x, y, async);
951 }
952
953 RESULT ePicLoad::getThumbnail(const char *file, int x, int y, bool async)
954 {
955         return startThread(0, file, x, y, async);
956 }
957
958 PyObject *ePicLoad::getInfo(const char *filename)
959 {
960         ePyObject list;
961
962         getExif(filename);
963         if(m_exif && m_exif->m_exifinfo->IsExif)
964         {
965                 char tmp[256];
966                 int pos = 0;
967                 list = PyList_New(23);
968                 PyList_SET_ITEM(list, pos++,  PyString_FromString(filename));
969                 PyList_SET_ITEM(list, pos++,  PyString_FromString(m_exif->m_exifinfo->Version));
970                 PyList_SET_ITEM(list, pos++,  PyString_FromString(m_exif->m_exifinfo->CameraMake));
971                 PyList_SET_ITEM(list, pos++,  PyString_FromString(m_exif->m_exifinfo->CameraModel));
972                 PyList_SET_ITEM(list, pos++,  PyString_FromString(m_exif->m_exifinfo->DateTime));
973                 PyList_SET_ITEM(list, pos++,  PyString_FromFormat("%d x %d", m_exif->m_exifinfo->Width, m_exif->m_exifinfo->Height));
974                 PyList_SET_ITEM(list, pos++,  PyString_FromString(m_exif->m_exifinfo->FlashUsed));
975                 PyList_SET_ITEM(list, pos++,  PyString_FromString(m_exif->m_exifinfo->Orientation));
976                 PyList_SET_ITEM(list, pos++,  PyString_FromString(m_exif->m_exifinfo->Comments));
977                 PyList_SET_ITEM(list, pos++,  PyString_FromString(m_exif->m_exifinfo->MeteringMode));
978                 PyList_SET_ITEM(list, pos++,  PyString_FromString(m_exif->m_exifinfo->ExposureProgram));
979                 PyList_SET_ITEM(list, pos++,  PyString_FromString(m_exif->m_exifinfo->LightSource));
980                 PyList_SET_ITEM(list, pos++,  PyString_FromFormat("%d", m_exif->m_exifinfo->CompressionLevel));
981                 PyList_SET_ITEM(list, pos++,  PyString_FromFormat("%d", m_exif->m_exifinfo->ISOequivalent));
982                 sprintf(tmp, "%.2f", m_exif->m_exifinfo->Xresolution);
983                 PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
984                 sprintf(tmp, "%.2f", m_exif->m_exifinfo->Yresolution);
985                 PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
986                 PyList_SET_ITEM(list, pos++,  PyString_FromString(m_exif->m_exifinfo->ResolutionUnit));
987                 sprintf(tmp, "%.2f", m_exif->m_exifinfo->Brightness);
988                 PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
989                 sprintf(tmp, "%.5f sec.", m_exif->m_exifinfo->ExposureTime);
990                 PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
991                 sprintf(tmp, "%.5f", m_exif->m_exifinfo->ExposureBias);
992                 PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
993                 sprintf(tmp, "%.5f", m_exif->m_exifinfo->Distance);
994                 PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
995                 sprintf(tmp, "%.5f", m_exif->m_exifinfo->CCDWidth);
996                 PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
997                 sprintf(tmp, "%.2f", m_exif->m_exifinfo->ApertureFNumber);
998                 PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
999         }
1000         else
1001         {
1002                 list = PyList_New(2);
1003                 PyList_SET_ITEM(list, 0, PyString_FromString(filename));
1004                 PyList_SET_ITEM(list, 1, PyString_FromString(m_exif->m_szLastError));
1005         }
1006
1007         return list ? (PyObject*)list : (PyObject*)PyList_New(0);
1008 }
1009
1010 bool ePicLoad::getExif(const char *filename, int Thumb)
1011 {
1012         if (!m_exif) {
1013                 m_exif = new Cexif;
1014                 return m_exif->DecodeExif(filename, Thumb);
1015         }
1016         return true;
1017 }
1018
1019 int ePicLoad::getData(ePtr<gPixmap> &result)
1020 {
1021         result = 0;
1022         if (m_filepara == NULL)
1023         {
1024                 eDebug("[ePicLoad] Weird situation, was not decoding anything!");
1025                 return 1;
1026         }
1027         if(m_filepara->pic_buffer == NULL)
1028         {
1029                 delete m_filepara;
1030                 m_filepara = NULL;
1031                 if (m_exif != NULL) {
1032                         m_exif->ClearExif();
1033                         delete m_exif;
1034                         m_exif = NULL;
1035                 }
1036                 return 0;
1037         }
1038
1039         result = new gPixmap(m_filepara->max_x, m_filepara->max_y, m_filepara->bits == 8 ? 8 : 32,
1040                                 NULL, m_filepara->bits == 8 ? gPixmap::accelAlways : gPixmap::accelAuto);
1041         gUnmanagedSurface *surface = result->surface;
1042
1043         // original image    : ox, oy
1044         // surface size      : max_x, max_y
1045         // after aspect calc : scrx, scry
1046         // center image      : xoff, yoff
1047         int scrx, scry; // Aspect ratio calculation
1048         int orientation = m_conf.auto_orientation ? (m_exif && m_exif->m_exifinfo->Orient ? m_exif->m_exifinfo->Orient : 1) : 1;
1049         if (m_conf.aspect_ratio == 0)  // do not keep aspect ratio but just fill the destination area
1050         {
1051                 scrx = m_filepara->max_x;
1052                 scry = m_filepara->max_y;
1053         }
1054         else if (orientation < 5) {
1055                 if ((m_conf.aspect_ratio * m_filepara->oy * m_filepara->max_x / m_filepara->ox) <= m_filepara->max_y)
1056                 {
1057                         scrx = m_filepara->max_x;
1058                         scry = (int)(m_conf.aspect_ratio * m_filepara->oy * m_filepara->max_x / m_filepara->ox);
1059                 }
1060                 else
1061                 {
1062                         scrx = (int)((1.0/m_conf.aspect_ratio) * m_filepara->ox * m_filepara->max_y / m_filepara->oy);
1063                         scry = m_filepara->max_y;
1064                 }
1065         }
1066         else {
1067                 if ((m_conf.aspect_ratio * m_filepara->ox * m_filepara->max_x / m_filepara->oy) <= m_filepara->max_y)
1068                 {
1069                         scrx = m_filepara->max_x;
1070                         scry = (int)(m_conf.aspect_ratio * m_filepara->ox * m_filepara->max_x / m_filepara->oy);
1071                 }
1072                 else
1073                 {
1074                         scrx = (int)((1.0/m_conf.aspect_ratio) * m_filepara->oy * m_filepara->max_y / m_filepara->ox);
1075                         scry = m_filepara->max_y;
1076                 }
1077         }
1078         float xscale = (float)(orientation < 5 ? m_filepara->ox : m_filepara->oy) / (float)scrx; // scale factor as result of screen and image size
1079         float yscale = (float)(orientation < 5 ? m_filepara->oy : m_filepara->ox) / (float)scry;
1080         int xoff = (m_filepara->max_x - scrx) / 2;  // borders as result of screen and image aspect
1081         int yoff = (m_filepara->max_y - scry) / 2;
1082         //eDebug("[getData] ox=%d oy=%d max_x=%d max_y=%d scrx=%d scry=%d xoff=%d yoff=%d xscale=%f yscale=%f aspect=%f bits=%d orientation=%d", m_filepara->ox, m_filepara->oy, m_filepara->max_x, m_filepara->max_y, scrx, scry, xoff, yoff, xscale, yscale, m_conf.aspect_ratio, m_filepara->bits, orientation);
1083
1084         unsigned char *tmp_buffer = ((unsigned char *)(surface->data));
1085         unsigned char *origin = m_filepara->pic_buffer;
1086         // fill borders with background color
1087         if (xoff != 0 || yoff != 0) {
1088                 unsigned int background;
1089                 if (m_filepara->bits == 8) {
1090                         surface->clut.data = m_filepara->palette;
1091                         surface->clut.colors = m_filepara->palette_size;
1092                         m_filepara->palette = NULL; // transfer ownership
1093
1094                         gRGB bg(m_conf.background);
1095                         background = surface->clut.findColor(bg);
1096
1097                         if (yoff != 0) {
1098                                 memset(tmp_buffer, background, yoff * surface->stride);
1099                                 memset(tmp_buffer + (yoff + scry) * surface->stride, background,
1100                                         (m_filepara->max_y - scry - yoff) * surface->stride);
1101                         }
1102
1103                         if (xoff != 0) {
1104                                 #pragma omp parallel for
1105                                 for(int y = yoff; y < scry; ++y) {
1106                                         memset(tmp_buffer + y * surface->stride, background, xoff);
1107                                         memset(tmp_buffer + y * surface->stride + xoff + scrx, background,
1108                                                 (m_filepara->max_x - scrx - xoff));
1109                                 }
1110                         }
1111                 }
1112                 else {
1113                         background = m_conf.background;
1114                         unsigned int* row_buffer;
1115                         if (yoff != 0) {
1116                                 row_buffer = (unsigned int *) tmp_buffer;
1117                                 for (int x = 0; x < m_filepara->max_x; ++x) // fill first line
1118                                         *row_buffer++ = background;
1119                                 int y;
1120                                 #pragma omp parallel for
1121                                 for (y = 1; y < yoff; ++y) // copy from first line
1122                                         memcpy(tmp_buffer + y*surface->stride, tmp_buffer,
1123                                                 m_filepara->max_x * surface->bypp);
1124                                 #pragma omp parallel for
1125                                 for (y = yoff + scry; y < m_filepara->max_y; ++y)
1126                                         memcpy(tmp_buffer + y * surface->stride, tmp_buffer,
1127                                                 m_filepara->max_x * surface->bypp);
1128                         }
1129                         if (xoff != 0) {
1130                                 row_buffer = (unsigned int *) (tmp_buffer + yoff * surface->stride);
1131                                 int x;
1132                                 for (x = 0; x < xoff; ++x) // fill left side of first line
1133                                         *row_buffer++ = background;
1134                                 row_buffer += scrx;
1135                                 for (x = xoff + scrx; x < m_filepara->max_x; ++x) // fill right side of first line
1136                                         *row_buffer++ = background;
1137                                 #pragma omp parallel for
1138                                 for (int y = yoff + 1; y < scry; ++y) { // copy from first line
1139                                         memcpy(tmp_buffer + y*surface->stride,
1140                                                 tmp_buffer + yoff * surface->stride,
1141                                                 xoff * surface->bypp);
1142                                         memcpy(tmp_buffer + y*surface->stride + (xoff + scrx) * surface->bypp,
1143                                                 tmp_buffer + yoff * surface->stride + (xoff + scrx) * surface->bypp,
1144                                                 (m_filepara->max_x - scrx - xoff) * surface->bypp);
1145                                 }
1146                         }
1147                 }
1148                 tmp_buffer += yoff * surface->stride + xoff * surface->bypp;
1149         }
1150
1151         // Setup input image base pointers and x/y increment factors according to orientation
1152         //     1        2       3      4         5            6           7          8
1153         //
1154         //   888888  888888      88  88      8888888888  88                  88  8888888888
1155         //   88          88      88  88      88  88      88  88          88  88      88  88
1156         //   8888      8888    8888  8888    88          8888888888  8888888888          88
1157         //   88          88      88  88
1158         //   88          88  888888  888888
1159         //
1160         // ori  ori-1   yfax    xfac    origin
1161         // 0001 000      b * x   b      0
1162         // 0010 001      b * x  -b                                    b * (x - 1)
1163         // 0011 010     -b * x  -b      b * yscale * (sy - 1) * x  +  b * (x - 1)
1164         // 0100 011     -b * x   b      b * yscale * (sy - 1) * x
1165         // 0101 100      b       b * x  0
1166         // 0110 101      b      -b * x                              b * (y - 1) * x
1167         // 0111 110     -b      -b * x  b * yscale * (sy - 1)   +   b * (y - 1) * x
1168         // 1000 111     -b       b * x  b * yscale * (sy - 1)
1169         int bpp = m_filepara->bits / 8;
1170 #if 0
1171         int iyfac = ((orientation-1) & 0x2) ? -bpp : bpp;
1172         int ixfac = (orientation & 0x2) ? -bpp : bpp;
1173         if (orientation < 5)
1174                 iyfac *= m_filepara->ox;
1175         else
1176                 ixfac *= m_filepara->ox;
1177         if (((orientation-1) & 0x6) == 2)
1178                 origin += bpp * (int)(yscale * (scry - 1)) * m_filepara->ox;
1179         if (((orientation-1) & 0x6) == 6)
1180                 origin += bpp * (int)(yscale * (scry - 1));
1181         if (((orientation) & 0x6) == 2)
1182                 origin += bpp * (m_filepara->ox - 1);
1183         if (((orientation) & 0x6) == 6)
1184                 origin += bpp * (m_filepara->oy - 1) * m_filepara->ox;
1185 #else
1186         int ixfac;
1187         int iyfac;
1188         if (orientation < 5) {
1189                 if (orientation == 1 || orientation == 2)
1190                         iyfac = bpp * m_filepara->ox; // run y across rows
1191                 else {
1192                         origin += bpp * (int)(yscale * (scry - 1)) * m_filepara->ox;
1193                         iyfac = -bpp * m_filepara->ox;
1194                 }
1195                 if (orientation == 2 || orientation == 3) {
1196                         origin += bpp * (m_filepara->ox - 1);
1197                         ixfac = -bpp;
1198                 }
1199                 else
1200                         ixfac = bpp;
1201         }
1202         else {
1203                 if (orientation == 5 || orientation == 6)
1204                         iyfac = bpp;
1205                 else {
1206                         origin += bpp * (int)(yscale * (scry - 1));
1207                         iyfac = -bpp ;
1208                 }
1209                 if (orientation == 6 || orientation == 7) {
1210                         origin += bpp * (m_filepara->oy - 1) * m_filepara->ox;
1211                         ixfac = -bpp * m_filepara->ox;
1212                 }
1213                 else
1214                         ixfac = bpp * m_filepara->ox;
1215         }
1216 #endif
1217         // Build output according to screen y by x loops
1218         // Fill surface with image data, resize and correct for orientation on the fly
1219         if (m_filepara->bits == 8)
1220         {
1221                 #pragma omp parallel for
1222                 for (int y = 0; y < scry; ++y) {
1223                         const unsigned char *irow, *irowy = origin + iyfac * (int)(y * yscale);
1224                         unsigned char *srow = tmp_buffer + surface->stride * y;
1225                         float xind = 0.0;
1226                         for (int x = 0; x < scrx; ++x) {
1227                                 irow = irowy + ixfac * (int)xind;
1228                                 *srow++ = *irow;
1229                                 xind += xscale;
1230                         }
1231                 }
1232         }
1233         else // 24-bit images
1234         {
1235                 #pragma omp parallel for
1236                 for (int y = 0; y < scry; ++y) {
1237                         const unsigned char *irow, *irowy = origin + iyfac * (int)(yscale * y);
1238                         unsigned char *srow = tmp_buffer + surface->stride * y;
1239                         float xind = 0.0;
1240
1241                         if (m_conf.resizetype != 1) {
1242                                 // simple resizing
1243                                 for (int x = 0; x < scrx; ++x) {
1244                                         irow = irowy + ixfac * (int)xind;
1245                                         srow[2] = irow[0];
1246                                         srow[1] = irow[1];
1247                                         srow[0] = irow[2];
1248                                         srow[3] = 0xFF; // alpha
1249                                         srow += 4;
1250                                         xind += xscale;
1251                                 }
1252                         }
1253                         else {
1254                                 // color average resizing
1255                                 // determine block range for resize
1256                                 int yr = (int)((y+1) * yscale) - (int) (y * yscale);
1257                                 if (y + yr >= scry)
1258                                         yr = scry - y - 1;
1259                                 for (int x = 0; x < scrx; x++) {
1260                                         // determine x range for resize
1261                                         int xr = (int)(xind + xscale) - (int) xind;
1262                                         if (x + xr >= scrx)
1263                                                 xr = scrx - x - 1;
1264                                         int r = 0;
1265                                         int g = 0;
1266                                         int b = 0;
1267                                         int sq = 0;
1268                                         irow = irowy + ixfac * (int)xind;
1269                                         // average over all pixels in x by y block
1270                                         for (int l = 0; l <= yr; l++) {
1271                                                 for (int k = 0; k <= xr; k++) {
1272                                                         r += irow[0];
1273                                                         g += irow[1];
1274                                                         b += irow[2];
1275                                                         sq++;
1276                                                         irow += ixfac;
1277                                                 }
1278                                                 irow -= (xr + 1) * ixfac; // go back to starting point of this subrow
1279                                                 irow += iyfac;
1280                                         }
1281                                         srow[2] = r / sq;
1282                                         srow[1] = g / sq;
1283                                         srow[0] = b / sq;
1284                                         srow[3] = 0xFF; // alpha
1285                                         srow += 4;
1286                                         xind += xscale;
1287                                 }
1288                         }
1289                 }
1290         }
1291
1292         delete m_filepara; // so caller can start a new decode in background
1293         m_filepara = NULL;
1294         if (m_exif) {
1295                 m_exif->ClearExif();
1296                 delete m_exif;
1297                 m_exif = NULL;
1298         }
1299
1300         return 0;
1301 }
1302
1303 RESULT ePicLoad::setPara(PyObject *val)
1304 {
1305         if (!PySequence_Check(val))
1306                 return 0;
1307         if (PySequence_Size(val) < 7)
1308                 return 0;
1309         else {
1310                 ePyObject fast          = PySequence_Fast(val, "");
1311                 int width               = PyInt_AsLong(PySequence_Fast_GET_ITEM(fast, 0));
1312                 int height              = PyInt_AsLong(PySequence_Fast_GET_ITEM(fast, 1));
1313                 double aspectRatio      = PyInt_AsLong(PySequence_Fast_GET_ITEM(fast, 2));
1314                 int as                  = PyInt_AsLong(PySequence_Fast_GET_ITEM(fast, 3));
1315                 bool useCache           = PyInt_AsLong(PySequence_Fast_GET_ITEM(fast, 4));
1316                 int resizeType          = PyInt_AsLong(PySequence_Fast_GET_ITEM(fast, 5));
1317                 const char *bg_str      = PyString_AsString(PySequence_Fast_GET_ITEM(fast, 6));
1318                 bool auto_orientation   = (PySequence_Size(val) > 7) ?
1319                                                 PyInt_AsLong(PySequence_Fast_GET_ITEM(fast, 7)) :
1320                                                 0;
1321
1322                 return setPara(width, height, aspectRatio, as, useCache, resizeType, bg_str, auto_orientation);
1323         }
1324         return 1;
1325 }
1326
1327 RESULT ePicLoad::setPara(int width, int height, double aspectRatio, int as, bool useCache, int resizeType, const char *bg_str, bool auto_orientation)
1328 {
1329         m_conf.max_x = width;
1330         m_conf.max_y = height;
1331         m_conf.aspect_ratio = as == 0 ? 0.0 : aspectRatio / as;
1332         m_conf.usecache = useCache;
1333         m_conf.auto_orientation = auto_orientation;
1334         m_conf.resizetype = resizeType;
1335
1336         if(bg_str[0] == '#' && strlen(bg_str)==9)
1337                 m_conf.background = strtoul(bg_str+1, NULL, 16);
1338         eDebug("[ePicLoad] setPara max-X=%d max-Y=%d aspect_ratio=%lf cache=%d resize=%d bg=#%08X auto_orient=%d",
1339                         m_conf.max_x, m_conf.max_y, m_conf.aspect_ratio,
1340                         (int)m_conf.usecache, (int)m_conf.resizetype, m_conf.background, m_conf.auto_orientation);
1341         return 1;
1342 }
1343
1344 //------------------------------------------------------------------------------------
1345
1346 //for old plugins
1347 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)
1348 {
1349         long asp1, asp2;
1350         result = 0;
1351         eDebug("[loadPic] 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!");
1352         ePicLoad mPL;
1353
1354         switch(aspect)
1355         {
1356                 case 1:         asp1 = 16*576, asp2 = 9*720; break; //16:9
1357                 case 2:         asp1 = 16*576, asp2 = 10*720; break; //16:10
1358                 case 3:         asp1 = 5*576, asp2 = 4*720; break; //5:4
1359                 default:        asp1 = 4*576, asp2 = 3*720; break; //4:3
1360         }
1361
1362         ePyObject tuple = PyTuple_New(7);
1363         PyTuple_SET_ITEM(tuple, 0,  PyLong_FromLong(x));
1364         PyTuple_SET_ITEM(tuple, 1,  PyLong_FromLong(y));
1365         PyTuple_SET_ITEM(tuple, 2,  PyLong_FromLong(asp1));
1366         PyTuple_SET_ITEM(tuple, 3,  PyLong_FromLong(asp2));
1367         PyTuple_SET_ITEM(tuple, 4,  PyLong_FromLong(0));
1368         PyTuple_SET_ITEM(tuple, 5,  PyLong_FromLong(resize_mode));
1369         if(background)
1370                 PyTuple_SET_ITEM(tuple, 6,  PyString_FromString("#ff000000"));
1371         else
1372                 PyTuple_SET_ITEM(tuple, 6,  PyString_FromString("#00000000"));
1373
1374         mPL.setPara(tuple);
1375
1376         if(!mPL.startDecode(filename.c_str(), 0, 0, false))
1377                 mPL.getData(result);
1378
1379         return 0;
1380 }