7cdfced3325446b30308bbfca73dd1263d561f28
[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         if(m_filepara->id == F_JPEG)
713         {
714                 Cexif *exif = new Cexif;
715                 if(exif->DecodeExif(m_filepara->file, 1))
716                 {
717                         if(exif->m_exifinfo->IsExif)
718                         {
719                                 if(exif->m_exifinfo->Thumnailstate == 2)
720                                 {
721                                         free(m_filepara->file);
722                                         m_filepara->file = strdup(THUMBNAILTMPFILE);
723                                         exif_thumbnail = true;
724                                         eDebug("[ePicLoad] Exif Thumbnail found");
725                                 }
726                                 m_filepara->addExifInfo(exif->m_exifinfo->CameraMake);
727                                 m_filepara->addExifInfo(exif->m_exifinfo->CameraModel);
728                                 m_filepara->addExifInfo(exif->m_exifinfo->DateTime);
729                                 char buf[20];
730                                 snprintf(buf, 20, "%d x %d", exif->m_exifinfo->Width, exif->m_exifinfo->Height);
731                                 m_filepara->addExifInfo(buf);
732                         }
733                         exif->ClearExif();
734                 }
735                 delete exif;
736         }
737
738         if((! exif_thumbnail) && m_conf.usecache)
739         {
740                 if(FILE *f = fopen(m_filepara->file, "rb"))
741                 {
742                         int c;
743                         int count = 1024*100; // get checksum data out of max 100kB
744                         unsigned long crc32 = 0;
745                         char crcstr[9];
746                         *crcstr = 0;
747
748                         while ((c = getc(f)) != EOF)
749                         {
750                                 crc32 = crc32_table[((crc32) ^ (c)) & 0xFF] ^ ((crc32) >> 8);
751                                 if (--count < 0) break;
752                         }
753
754                         fclose(f);
755                         crc32 = ~crc32;
756                         sprintf(crcstr, "%08lX", crc32);
757
758                         cachedir = m_filepara->file;
759                         unsigned int pos = cachedir.find_last_of("/");
760                         if (pos != std::string::npos)
761                                 cachedir = cachedir.substr(0, pos) + "/.Thumbnails";
762
763                         cachefile = cachedir + std::string("/pc_") + crcstr;
764                         if(!access(cachefile.c_str(), R_OK))
765                         {
766                                 cachefile_found = true;
767                                 free(m_filepara->file);
768                                 m_filepara->file = strdup(cachefile.c_str());
769                                 m_filepara->id = F_JPEG;
770                                 eDebug("[ePicLoad] Cache File found");
771                         }
772                 }
773         }
774
775         switch(m_filepara->id)
776         {
777                 case F_PNG:     png_load(m_filepara, m_conf.background, true);
778                                 break;
779                 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);
780                                 break;
781                 case F_BMP:     m_filepara->pic_buffer = bmp_load(m_filepara->file, &m_filepara->ox, &m_filepara->oy);
782                                 break;
783                 case F_GIF:     gif_load(m_filepara, true);
784                                 break;
785         }
786
787         if(exif_thumbnail)
788                 ::unlink(THUMBNAILTMPFILE);
789
790         if(m_filepara->pic_buffer != NULL)
791         {
792                 //save cachefile
793                 if(m_conf.usecache && (!exif_thumbnail) && (!cachefile_found))
794                 {
795                         if(access(cachedir.c_str(), R_OK))
796                                 ::mkdir(cachedir.c_str(), 0755);
797
798                         //resize for Thumbnail
799                         int imx, imy;
800                         if (m_filepara->ox <= m_filepara->oy)
801                         {
802                                 imy = m_conf.thumbnailsize;
803                                 imx = (int)( (m_conf.thumbnailsize * ((double)m_filepara->ox)) / ((double)m_filepara->oy) );
804                         }
805                         else
806                         {
807                                 imx = m_conf.thumbnailsize;
808                                 imy = (int)( (m_conf.thumbnailsize * ((double)m_filepara->oy)) / ((double)m_filepara->ox) );
809                         }
810
811                         if (m_filepara->bits == 8)
812                                 m_filepara->pic_buffer = simple_resize_8(m_filepara->pic_buffer, m_filepara->ox, m_filepara->oy, imx, imy);
813                         else
814                                 m_filepara->pic_buffer = color_resize(m_filepara->pic_buffer, m_filepara->ox, m_filepara->oy, imx, imy);
815                         m_filepara->ox = imx;
816                         m_filepara->oy = imy;
817
818                         if(jpeg_save(cachefile.c_str(), m_filepara->ox, m_filepara->oy, m_filepara->pic_buffer))
819                                 eDebug("[ePicLoad] error saving cachefile");
820                 }
821
822                 resizePic();
823         }
824 }
825
826 void ePicLoad::resizePic()
827 {
828         int imx, imy;
829
830         if (m_conf.aspect_ratio == 0)  // do not keep aspect ratio but just fill the destination area
831         {
832                 imx = m_filepara->max_x;
833                 imy = m_filepara->max_y;
834         }
835         else if ((m_conf.aspect_ratio * m_filepara->oy * m_filepara->max_x / m_filepara->ox) <= m_filepara->max_y)
836         {
837                 imx = m_filepara->max_x;
838                 imy = (int)(m_conf.aspect_ratio * m_filepara->oy * m_filepara->max_x / m_filepara->ox);
839         }
840         else
841         {
842                 imx = (int)((1.0/m_conf.aspect_ratio) * m_filepara->ox * m_filepara->max_y / m_filepara->oy);
843                 imy = m_filepara->max_y;
844         }
845
846         if (m_filepara->bits == 8)
847                 m_filepara->pic_buffer = simple_resize_8(m_filepara->pic_buffer, m_filepara->ox, m_filepara->oy, imx, imy);
848         else if (m_conf.resizetype)
849                 m_filepara->pic_buffer = color_resize(m_filepara->pic_buffer, m_filepara->ox, m_filepara->oy, imx, imy);
850         else
851                 m_filepara->pic_buffer = simple_resize_24(m_filepara->pic_buffer, m_filepara->ox, m_filepara->oy, imx, imy);
852
853         m_filepara->ox = imx;
854         m_filepara->oy = imy;
855 }
856
857 void ePicLoad::gotMessage(const Message &msg)
858 {
859         switch (msg.type)
860         {
861                 case Message::decode_Pic:
862                         decodePic();
863                         msg_main.send(Message(Message::decode_finished));
864                         break;
865                 case Message::decode_Thumb:
866                         decodeThumb();
867                         msg_main.send(Message(Message::decode_finished));
868                         break;
869                 case Message::quit: // called from decode thread
870                         eDebug("[ePicLoad] decode thread ... got quit msg");
871                         quit(0);
872                         break;
873                 case Message::decode_finished: // called from main thread
874                         //eDebug("[ePicLoad] decode finished... %s", m_filepara->file);
875                         if(m_filepara->callback)
876                                 PictureData(m_filepara->picinfo.c_str());
877                         else
878                         {
879                                 if(m_filepara != NULL)
880                                 {
881                                         delete m_filepara;
882                                         m_filepara = NULL;
883                                 }
884                                 if (m_exif != NULL) {
885                                         m_exif->ClearExif();
886                                         delete m_exif;
887                                         m_exif = NULL;
888                                 }
889                         }
890                         break;
891                 default:
892                         eDebug("[ePicLoad] unhandled thread message");
893         }
894 }
895
896 int ePicLoad::startThread(int what, const char *file, int x, int y, bool async)
897 {
898         if(async && threadrunning && m_filepara != NULL)
899         {
900                 eDebug("[ePicLoad] thread running");
901                 m_filepara->callback = false;
902                 return 1;
903         }
904
905         if(m_filepara != NULL)
906         {
907                 delete m_filepara;
908                 m_filepara = NULL;
909         }
910         if (m_exif != NULL) {
911                 m_exif->ClearExif();
912                 delete m_exif;
913                 m_exif = NULL;
914         }
915
916         int file_id = -1;
917         unsigned char id[10];
918         int fd = ::open(file, O_RDONLY);
919         if (fd == -1) return 1;
920         ::read(fd, id, 10);
921         ::close(fd);
922
923         if      (id[1] == 'P'  && id[2] == 'N'  && id[3] == 'G')                        file_id = F_PNG;
924         else if (id[6] == 'J'  && id[7] == 'F'  && id[8] == 'I' && id[9] == 'F')        file_id = F_JPEG;
925         else if (id[0] == 0xff && id[1] == 0xd8 && id[2] == 0xff)                       file_id = F_JPEG;
926         else if (id[0] == 'B'  && id[1] == 'M' )                                        file_id = F_BMP;
927         else if (id[0] == 'G'  && id[1] == 'I'  && id[2] == 'F')                        file_id = F_GIF;
928
929         if(file_id < 0)
930         {
931                 eDebug("[ePicLoad] <format not supported>");
932                 return 1;
933         }
934
935         m_filepara = new Cfilepara(file, file_id, getSize(file));
936         m_filepara->max_x = x > 0 ? x : m_conf.max_x;
937         m_filepara->max_y = x > 0 ? y : m_conf.max_y;
938
939         if(m_filepara->max_x <= 0 || m_filepara->max_y <= 0)
940         {
941                 delete m_filepara;
942                 m_filepara = NULL;
943                 eDebug("[ePicLoad] <error in Para>");
944                 return 1;
945         }
946
947         if (async) {
948                 if(what == 1)
949                         msg_thread.send(Message(Message::decode_Pic));
950                 else
951                         msg_thread.send(Message(Message::decode_Thumb));
952                 run();
953         }
954         else if (what == 1)
955                 decodePic();
956         else
957                 decodeThumb();
958         return 0;
959 }
960
961 RESULT ePicLoad::startDecode(const char *file, int x, int y, bool async)
962 {
963         return startThread(1, file, x, y, async);
964 }
965
966 RESULT ePicLoad::getThumbnail(const char *file, int x, int y, bool async)
967 {
968         return startThread(0, file, x, y, async);
969 }
970
971 PyObject *ePicLoad::getInfo(const char *filename)
972 {
973         ePyObject list;
974
975         getExif(filename);
976         if(m_exif && m_exif->m_exifinfo->IsExif)
977         {
978                 char tmp[256];
979                 int pos = 0;
980                 list = PyList_New(23);
981                 PyList_SET_ITEM(list, pos++,  PyString_FromString(filename));
982                 PyList_SET_ITEM(list, pos++,  PyString_FromString(m_exif->m_exifinfo->Version));
983                 PyList_SET_ITEM(list, pos++,  PyString_FromString(m_exif->m_exifinfo->CameraMake));
984                 PyList_SET_ITEM(list, pos++,  PyString_FromString(m_exif->m_exifinfo->CameraModel));
985                 PyList_SET_ITEM(list, pos++,  PyString_FromString(m_exif->m_exifinfo->DateTime));
986                 PyList_SET_ITEM(list, pos++,  PyString_FromFormat("%d x %d", m_exif->m_exifinfo->Width, m_exif->m_exifinfo->Height));
987                 PyList_SET_ITEM(list, pos++,  PyString_FromString(m_exif->m_exifinfo->FlashUsed));
988                 PyList_SET_ITEM(list, pos++,  PyString_FromString(m_exif->m_exifinfo->Orientation));
989                 PyList_SET_ITEM(list, pos++,  PyString_FromString(m_exif->m_exifinfo->Comments));
990                 PyList_SET_ITEM(list, pos++,  PyString_FromString(m_exif->m_exifinfo->MeteringMode));
991                 PyList_SET_ITEM(list, pos++,  PyString_FromString(m_exif->m_exifinfo->ExposureProgram));
992                 PyList_SET_ITEM(list, pos++,  PyString_FromString(m_exif->m_exifinfo->LightSource));
993                 PyList_SET_ITEM(list, pos++,  PyString_FromFormat("%d", m_exif->m_exifinfo->CompressionLevel));
994                 PyList_SET_ITEM(list, pos++,  PyString_FromFormat("%d", m_exif->m_exifinfo->ISOequivalent));
995                 sprintf(tmp, "%.2f", m_exif->m_exifinfo->Xresolution);
996                 PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
997                 sprintf(tmp, "%.2f", m_exif->m_exifinfo->Yresolution);
998                 PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
999                 PyList_SET_ITEM(list, pos++,  PyString_FromString(m_exif->m_exifinfo->ResolutionUnit));
1000                 sprintf(tmp, "%.2f", m_exif->m_exifinfo->Brightness);
1001                 PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
1002                 sprintf(tmp, "%.5f sec.", m_exif->m_exifinfo->ExposureTime);
1003                 PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
1004                 sprintf(tmp, "%.5f", m_exif->m_exifinfo->ExposureBias);
1005                 PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
1006                 sprintf(tmp, "%.5f", m_exif->m_exifinfo->Distance);
1007                 PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
1008                 sprintf(tmp, "%.5f", m_exif->m_exifinfo->CCDWidth);
1009                 PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
1010                 sprintf(tmp, "%.2f", m_exif->m_exifinfo->ApertureFNumber);
1011                 PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
1012         }
1013         else
1014         {
1015                 list = PyList_New(2);
1016                 PyList_SET_ITEM(list, 0, PyString_FromString(filename));
1017                 PyList_SET_ITEM(list, 1, PyString_FromString(m_exif->m_szLastError));
1018         }
1019
1020         return list ? (PyObject*)list : (PyObject*)PyList_New(0);
1021 }
1022
1023 bool ePicLoad::getExif(const char *filename, int Thumb)
1024 {
1025         if (!m_exif) {
1026                 m_exif = new Cexif;
1027                 return m_exif->DecodeExif(filename, Thumb);
1028         }
1029         return true;
1030 }
1031
1032 int ePicLoad::getData(ePtr<gPixmap> &result)
1033 {
1034         result = 0;
1035         if (m_filepara == NULL)
1036         {
1037                 eDebug("[ePicLoad] Weird situation, was not decoding anything!");
1038                 return 1;
1039         }
1040         if(m_filepara->pic_buffer == NULL)
1041         {
1042                 delete m_filepara;
1043                 m_filepara = NULL;
1044                 if (m_exif != NULL) {
1045                         m_exif->ClearExif();
1046                         delete m_exif;
1047                         m_exif = NULL;
1048                 }
1049                 return 0;
1050         }
1051
1052         result = new gPixmap(m_filepara->max_x, m_filepara->max_y, m_filepara->bits == 8 ? 8 : 32,
1053                                 NULL, m_filepara->bits == 8 ? gPixmap::accelAlways : gPixmap::accelAuto);
1054         gUnmanagedSurface *surface = result->surface;
1055
1056         // original image    : ox, oy
1057         // surface size      : max_x, max_y
1058         // after aspect calc : scrx, scry
1059         // center image      : xoff, yoff
1060         int scrx, scry; // Aspect ratio calculation
1061         int orientation = m_conf.auto_orientation ? (m_exif && m_exif->m_exifinfo->Orient ? m_exif->m_exifinfo->Orient : 1) : 1;
1062         if (m_conf.aspect_ratio == 0)  // do not keep aspect ratio but just fill the destination area
1063         {
1064                 scrx = m_filepara->max_x;
1065                 scry = m_filepara->max_y;
1066         }
1067         else if (orientation < 5) {
1068                 if ((m_conf.aspect_ratio * m_filepara->oy * m_filepara->max_x / m_filepara->ox) <= m_filepara->max_y)
1069                 {
1070                         scrx = m_filepara->max_x;
1071                         scry = (int)(m_conf.aspect_ratio * m_filepara->oy * m_filepara->max_x / m_filepara->ox);
1072                 }
1073                 else
1074                 {
1075                         scrx = (int)((1.0/m_conf.aspect_ratio) * m_filepara->ox * m_filepara->max_y / m_filepara->oy);
1076                         scry = m_filepara->max_y;
1077                 }
1078         }
1079         else {
1080                 if ((m_conf.aspect_ratio * m_filepara->ox * m_filepara->max_x / m_filepara->oy) <= m_filepara->max_y)
1081                 {
1082                         scrx = m_filepara->max_x;
1083                         scry = (int)(m_conf.aspect_ratio * m_filepara->ox * m_filepara->max_x / m_filepara->oy);
1084                 }
1085                 else
1086                 {
1087                         scrx = (int)((1.0/m_conf.aspect_ratio) * m_filepara->oy * m_filepara->max_y / m_filepara->ox);
1088                         scry = m_filepara->max_y;
1089                 }
1090         }
1091         float xscale = (float)(orientation < 5 ? m_filepara->ox : m_filepara->oy) / (float)scrx; // scale factor as result of screen and image size
1092         float yscale = (float)(orientation < 5 ? m_filepara->oy : m_filepara->ox) / (float)scry;
1093         int xoff = (m_filepara->max_x - scrx) / 2;  // borders as result of screen and image aspect
1094         int yoff = (m_filepara->max_y - scry) / 2;
1095         //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);
1096
1097         unsigned char *tmp_buffer = ((unsigned char *)(surface->data));
1098         unsigned char *origin = m_filepara->pic_buffer;
1099         // fill borders with background color
1100         if (xoff != 0 || yoff != 0) {
1101                 unsigned int background;
1102                 if (m_filepara->bits == 8) {
1103                         surface->clut.data = m_filepara->palette;
1104                         surface->clut.colors = m_filepara->palette_size;
1105                         m_filepara->palette = NULL; // transfer ownership
1106
1107                         gRGB bg(m_conf.background);
1108                         background = surface->clut.findColor(bg);
1109
1110                         if (yoff != 0) {
1111                                 memset(tmp_buffer, background, yoff * surface->stride);
1112                                 memset(tmp_buffer + (yoff + scry) * surface->stride, background,
1113                                         (m_filepara->max_y - scry - yoff) * surface->stride);
1114                         }
1115
1116                         if (xoff != 0) {
1117                                 #pragma omp parallel for
1118                                 for(int y = yoff; y < scry; ++y) {
1119                                         memset(tmp_buffer + y * surface->stride, background, xoff);
1120                                         memset(tmp_buffer + y * surface->stride + xoff + scrx, background,
1121                                                 (m_filepara->max_x - scrx - xoff));
1122                                 }
1123                         }
1124                 }
1125                 else {
1126                         background = m_conf.background;
1127                         unsigned int* row_buffer;
1128                         if (yoff != 0) {
1129                                 row_buffer = (unsigned int *) tmp_buffer;
1130                                 for (int x = 0; x < m_filepara->max_x; ++x) // fill first line
1131                                         *row_buffer++ = background;
1132                                 int y;
1133                                 #pragma omp parallel for
1134                                 for (y = 1; y < yoff; ++y) // copy from first line
1135                                         memcpy(tmp_buffer + y*surface->stride, tmp_buffer,
1136                                                 m_filepara->max_x * surface->bypp);
1137                                 #pragma omp parallel for
1138                                 for (y = yoff + scry; y < m_filepara->max_y; ++y)
1139                                         memcpy(tmp_buffer + y * surface->stride, tmp_buffer,
1140                                                 m_filepara->max_x * surface->bypp);
1141                         }
1142                         if (xoff != 0) {
1143                                 row_buffer = (unsigned int *) (tmp_buffer + yoff * surface->stride);
1144                                 int x;
1145                                 for (x = 0; x < xoff; ++x) // fill left side of first line
1146                                         *row_buffer++ = background;
1147                                 row_buffer += scrx;
1148                                 for (x = xoff + scrx; x < m_filepara->max_x; ++x) // fill right side of first line
1149                                         *row_buffer++ = background;
1150                                 #pragma omp parallel for
1151                                 for (int y = yoff + 1; y < scry; ++y) { // copy from first line
1152                                         memcpy(tmp_buffer + y*surface->stride,
1153                                                 tmp_buffer + yoff * surface->stride,
1154                                                 xoff * surface->bypp);
1155                                         memcpy(tmp_buffer + y*surface->stride + (xoff + scrx) * surface->bypp,
1156                                                 tmp_buffer + yoff * surface->stride + (xoff + scrx) * surface->bypp,
1157                                                 (m_filepara->max_x - scrx - xoff) * surface->bypp);
1158                                 }
1159                         }
1160                 }
1161                 tmp_buffer += yoff * surface->stride + xoff * surface->bypp;
1162         }
1163
1164         // Setup input image base pointers and x/y increment factors according to orientation
1165         //     1        2       3      4         5            6           7          8
1166         //
1167         //   888888  888888      88  88      8888888888  88                  88  8888888888
1168         //   88          88      88  88      88  88      88  88          88  88      88  88
1169         //   8888      8888    8888  8888    88          8888888888  8888888888          88
1170         //   88          88      88  88
1171         //   88          88  888888  888888
1172         //
1173         // ori  ori-1   yfax    xfac    origin
1174         // 0001 000      b * x   b      0
1175         // 0010 001      b * x  -b                                    b * (x - 1)
1176         // 0011 010     -b * x  -b      b * yscale * (sy - 1) * x  +  b * (x - 1)
1177         // 0100 011     -b * x   b      b * yscale * (sy - 1) * x
1178         // 0101 100      b       b * x  0
1179         // 0110 101      b      -b * x                              b * (y - 1) * x
1180         // 0111 110     -b      -b * x  b * yscale * (sy - 1)   +   b * (y - 1) * x
1181         // 1000 111     -b       b * x  b * yscale * (sy - 1)
1182         int bpp = m_filepara->bits / 8;
1183 #if 0
1184         int iyfac = ((orientation-1) & 0x2) ? -bpp : bpp;
1185         int ixfac = (orientation & 0x2) ? -bpp : bpp;
1186         if (orientation < 5)
1187                 iyfac *= m_filepara->ox;
1188         else
1189                 ixfac *= m_filepara->ox;
1190         if (((orientation-1) & 0x6) == 2)
1191                 origin += bpp * (int)(yscale * (scry - 1)) * m_filepara->ox;
1192         if (((orientation-1) & 0x6) == 6)
1193                 origin += bpp * (int)(yscale * (scry - 1));
1194         if (((orientation) & 0x6) == 2)
1195                 origin += bpp * (m_filepara->ox - 1);
1196         if (((orientation) & 0x6) == 6)
1197                 origin += bpp * (m_filepara->oy - 1) * m_filepara->ox;
1198 #else
1199         int ixfac;
1200         int iyfac;
1201         if (orientation < 5) {
1202                 if (orientation == 1 || orientation == 2)
1203                         iyfac = bpp * m_filepara->ox; // run y across rows
1204                 else {
1205                         origin += bpp * (int)(yscale * (scry - 1)) * m_filepara->ox;
1206                         iyfac = -bpp * m_filepara->ox;
1207                 }
1208                 if (orientation == 2 || orientation == 3) {
1209                         origin += bpp * (m_filepara->ox - 1);
1210                         ixfac = -bpp;
1211                 }
1212                 else
1213                         ixfac = bpp;
1214         }
1215         else {
1216                 if (orientation == 5 || orientation == 6)
1217                         iyfac = bpp;
1218                 else {
1219                         origin += bpp * (int)(yscale * (scry - 1));
1220                         iyfac = -bpp ;
1221                 }
1222                 if (orientation == 6 || orientation == 7) {
1223                         origin += bpp * (m_filepara->oy - 1) * m_filepara->ox;
1224                         ixfac = -bpp * m_filepara->ox;
1225                 }
1226                 else
1227                         ixfac = bpp * m_filepara->ox;
1228         }
1229 #endif
1230         // Build output according to screen y by x loops
1231         // Fill surface with image data, resize and correct for orientation on the fly
1232         if (m_filepara->bits == 8)
1233         {
1234                 #pragma omp parallel for
1235                 for (int y = 0; y < scry; ++y) {
1236                         const unsigned char *irow, *irowy = origin + iyfac * (int)(y * yscale);
1237                         unsigned char *srow = tmp_buffer + surface->stride * y;
1238                         float xind = 0.0;
1239                         for (int x = 0; x < scrx; ++x) {
1240                                 irow = irowy + ixfac * (int)xind;
1241                                 *srow++ = *irow;
1242                                 xind += xscale;
1243                         }
1244                 }
1245         }
1246         else // 24-bit images
1247         {
1248                 #pragma omp parallel for
1249                 for (int y = 0; y < scry; ++y) {
1250                         const unsigned char *irow, *irowy = origin + iyfac * (int)(yscale * y);
1251                         unsigned char *srow = tmp_buffer + surface->stride * y;
1252                         float xind = 0.0;
1253
1254                         if (m_conf.resizetype != 1) {
1255                                 // simple resizing
1256                                 for (int x = 0; x < scrx; ++x) {
1257                                         irow = irowy + ixfac * (int)xind;
1258                                         srow[2] = irow[0];
1259                                         srow[1] = irow[1];
1260                                         srow[0] = irow[2];
1261                                         srow[3] = 0xFF; // alpha
1262                                         srow += 4;
1263                                         xind += xscale;
1264                                 }
1265                         }
1266                         else {
1267                                 // color average resizing
1268                                 // determine block range for resize
1269                                 int yr = (int)((y+1) * yscale) - (int) (y * yscale);
1270                                 if (y + yr >= scry)
1271                                         yr = scry - y - 1;
1272                                 for (int x = 0; x < scrx; x++) {
1273                                         // determine x range for resize
1274                                         int xr = (int)(xind + xscale) - (int) xind;
1275                                         if (x + xr >= scrx)
1276                                                 xr = scrx - x - 1;
1277                                         int r = 0;
1278                                         int g = 0;
1279                                         int b = 0;
1280                                         int sq = 0;
1281                                         irow = irowy + ixfac * (int)xind;
1282                                         // average over all pixels in x by y block
1283                                         for (int l = 0; l <= yr; l++) {
1284                                                 for (int k = 0; k <= xr; k++) {
1285                                                         r += irow[0];
1286                                                         g += irow[1];
1287                                                         b += irow[2];
1288                                                         sq++;
1289                                                         irow += ixfac;
1290                                                 }
1291                                                 irow -= (xr + 1) * ixfac; // go back to starting point of this subrow
1292                                                 irow += iyfac;
1293                                         }
1294                                         srow[2] = r / sq;
1295                                         srow[1] = g / sq;
1296                                         srow[0] = b / sq;
1297                                         srow[3] = 0xFF; // alpha
1298                                         srow += 4;
1299                                         xind += xscale;
1300                                 }
1301                         }
1302                 }
1303         }
1304
1305         delete m_filepara; // so caller can start a new decode in background
1306         m_filepara = NULL;
1307         if (m_exif) {
1308                 m_exif->ClearExif();
1309                 delete m_exif;
1310                 m_exif = NULL;
1311         }
1312
1313         return 0;
1314 }
1315
1316 RESULT ePicLoad::setPara(PyObject *val)
1317 {
1318         if (!PySequence_Check(val))
1319                 return 0;
1320         if (PySequence_Size(val) < 7)
1321                 return 0;
1322         else {
1323                 ePyObject fast          = PySequence_Fast(val, "");
1324                 int width               = PyInt_AsLong(PySequence_Fast_GET_ITEM(fast, 0));
1325                 int height              = PyInt_AsLong(PySequence_Fast_GET_ITEM(fast, 1));
1326                 double aspectRatio      = PyInt_AsLong(PySequence_Fast_GET_ITEM(fast, 2));
1327                 int as                  = PyInt_AsLong(PySequence_Fast_GET_ITEM(fast, 3));
1328                 bool useCache           = PyInt_AsLong(PySequence_Fast_GET_ITEM(fast, 4));
1329                 int resizeType          = PyInt_AsLong(PySequence_Fast_GET_ITEM(fast, 5));
1330                 const char *bg_str      = PyString_AsString(PySequence_Fast_GET_ITEM(fast, 6));
1331                 bool auto_orientation   = (PySequence_Size(val) > 7) ?
1332                                                 PyInt_AsLong(PySequence_Fast_GET_ITEM(fast, 7)) :
1333                                                 0;
1334
1335                 return setPara(width, height, aspectRatio, as, useCache, resizeType, bg_str, auto_orientation);
1336         }
1337         return 1;
1338 }
1339
1340 RESULT ePicLoad::setPara(int width, int height, double aspectRatio, int as, bool useCache, int resizeType, const char *bg_str, bool auto_orientation)
1341 {
1342         m_conf.max_x = width;
1343         m_conf.max_y = height;
1344         m_conf.aspect_ratio = as == 0 ? 0.0 : aspectRatio / as;
1345         m_conf.usecache = useCache;
1346         m_conf.auto_orientation = auto_orientation;
1347         m_conf.resizetype = resizeType;
1348
1349         if(bg_str[0] == '#' && strlen(bg_str)==9)
1350                 m_conf.background = strtoul(bg_str+1, NULL, 16);
1351         eDebug("[ePicLoad] setPara max-X=%d max-Y=%d aspect_ratio=%lf cache=%d resize=%d bg=#%08X auto_orient=%d",
1352                         m_conf.max_x, m_conf.max_y, m_conf.aspect_ratio,
1353                         (int)m_conf.usecache, (int)m_conf.resizetype, m_conf.background, m_conf.auto_orientation);
1354         return 1;
1355 }
1356
1357 //------------------------------------------------------------------------------------
1358
1359 //for old plugins
1360 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)
1361 {
1362         long asp1, asp2;
1363         result = 0;
1364         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!");
1365         ePicLoad mPL;
1366
1367         switch(aspect)
1368         {
1369                 case 1:         asp1 = 16*576, asp2 = 9*720; break; //16:9
1370                 case 2:         asp1 = 16*576, asp2 = 10*720; break; //16:10
1371                 case 3:         asp1 = 5*576, asp2 = 4*720; break; //5:4
1372                 default:        asp1 = 4*576, asp2 = 3*720; break; //4:3
1373         }
1374
1375         ePyObject tuple = PyTuple_New(7);
1376         PyTuple_SET_ITEM(tuple, 0,  PyLong_FromLong(x));
1377         PyTuple_SET_ITEM(tuple, 1,  PyLong_FromLong(y));
1378         PyTuple_SET_ITEM(tuple, 2,  PyLong_FromLong(asp1));
1379         PyTuple_SET_ITEM(tuple, 3,  PyLong_FromLong(asp2));
1380         PyTuple_SET_ITEM(tuple, 4,  PyLong_FromLong(0));
1381         PyTuple_SET_ITEM(tuple, 5,  PyLong_FromLong(resize_mode));
1382         if(background)
1383                 PyTuple_SET_ITEM(tuple, 6,  PyString_FromString("#ff000000"));
1384         else
1385                 PyTuple_SET_ITEM(tuple, 6,  PyString_FromString("#00000000"));
1386
1387         mPL.setPara(tuple);
1388
1389         if(!mPL.startDecode(filename.c_str(), 0, 0, false))
1390                 mPL.getData(result);
1391
1392         return 0;
1393 }