output used resolution
[enigma2.git] / lib / gdi / picload.cpp
1 #include <lib/gdi/picload.h>
2 #include "picexif.h"
3 #include <lib/python/python.h>
4
5 #include <png.h>
6
7 #include <fcntl.h>
8 #include <unistd.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11
12 extern "C" {
13 #include <jpeglib.h>
14 //#include "transupp.h"
15 }
16 #include <setjmp.h>
17
18 unsigned char *pic_buffer=NULL;
19
20 static unsigned char *simple_resize(unsigned char * orgin, int ox, int oy, int dx, int dy)
21 {
22         unsigned char *cr, *p, *l;
23         int i, j, k, ip;
24         cr = new unsigned char[dx * dy * 3]; 
25         if (cr == NULL)
26         {
27                 printf("[RESIZE] Error: malloc\n");
28                 return(orgin);
29         }
30         l = cr;
31
32         for (j = 0; j < dy; j++,l += dx * 3)
33         {
34                 p = orgin + (j * oy / dy * ox * 3);
35                 for (i = 0, k = 0; i < dx; i++, k += 3)
36                 {
37                         ip = i * ox / dx * 3;
38                         l[k] = p[ip];
39                         l[k+1] = p[ip + 1];
40                         l[k+2] = p[ip + 2];
41                 }
42         }
43         delete [] orgin;
44         return(cr);
45 }
46
47 static unsigned char *color_resize(unsigned char * orgin, int ox, int oy, int dx, int dy)
48 {
49         unsigned char *cr, *p, *q;
50         int i, j, k, l, xa, xb, ya, yb;
51         int sq, r, g, b;
52         cr = new unsigned char[dx * dy * 3];
53         if (cr == NULL)
54         {
55                 printf("[RESIZE] Error: malloc\n");
56                 return(orgin);
57         }
58         p = cr;
59
60         for (j = 0; j < dy; j++)
61         {
62                 for (i = 0; i < dx; i++, p += 3)
63                 {
64                         xa = i * ox / dx;
65                         ya = j * oy / dy;
66                         xb = (i + 1) * ox / dx; 
67                         if (xb >= ox)
68                                 xb = ox - 1;
69                         yb = (j + 1) * oy / dy; 
70                         if (yb >= oy)
71                                 yb = oy - 1;
72                         for (l = ya, r = 0, g = 0, b = 0, sq = 0; l <= yb; l++)
73                         {
74                                 q = orgin + ((l * ox + xa) * 3);
75                                 for (k = xa; k <= xb; k++, q += 3, sq++)
76                                 {
77                                         r += q[0]; g += q[1]; b += q[2];
78                                 }
79                         }
80                         p[0] = r / sq; p[1] = g / sq; p[2] = b / sq;
81                 }
82         }
83         delete [] orgin;
84         return(cr);
85 }
86
87 //-------------------------------------------------------------------
88
89 struct r_jpeg_error_mgr
90 {
91         struct jpeg_error_mgr pub;
92         jmp_buf envbuffer;
93 };
94
95 void jpeg_cb_error_exit(j_common_ptr cinfo)
96 {
97         struct r_jpeg_error_mgr *mptr;
98         mptr = (struct r_jpeg_error_mgr *) cinfo->err;
99         (*cinfo->err->output_message) (cinfo);
100         longjmp(mptr->envbuffer, 1);
101 }
102
103 static int jpeg_save(unsigned char *image_buffer, const char * filename, int quality, int image_height, int image_width)
104 {
105         struct jpeg_compress_struct cinfo;
106         struct jpeg_error_mgr jerr;
107         FILE * outfile;         /* target file */
108         JSAMPROW row_pointer[1];/* pointer to JSAMPLE row[s] */
109         int row_stride;         /* physical row width in image buffer */
110  
111         cinfo.err = jpeg_std_error(&jerr);
112         jpeg_create_compress(&cinfo);
113  
114         if ((outfile = fopen(filename, "wb")) == NULL) 
115         {
116                 eDebug("[JPEG] can't open %s", filename);
117                 return -1;
118         }
119         jpeg_stdio_dest(&cinfo, outfile);
120  
121         cinfo.image_width = image_width;
122         cinfo.image_height = image_height;
123         cinfo.input_components = 3;
124         cinfo.in_color_space = JCS_RGB;
125         jpeg_set_defaults(&cinfo);
126         jpeg_set_quality(&cinfo, quality, TRUE );
127         jpeg_start_compress(&cinfo, TRUE);
128         row_stride = image_width * 3;
129         while (cinfo.next_scanline < cinfo.image_height) 
130         {
131                 row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride];
132                 (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
133         }
134         jpeg_finish_compress(&cinfo);
135         fclose(outfile);
136         jpeg_destroy_compress(&cinfo);
137         return 0;
138 }
139
140
141 static int jpeg_load(const char *filename, int *x, int *y)
142 {
143         struct jpeg_decompress_struct cinfo;
144         struct jpeg_decompress_struct *ciptr = &cinfo;
145         struct r_jpeg_error_mgr emgr;
146         FILE *fh;
147
148         if (!(fh = fopen(filename, "rb")))
149                 return 0;
150
151         ciptr->err = jpeg_std_error(&emgr.pub);
152         emgr.pub.error_exit = jpeg_cb_error_exit;
153         if (setjmp(emgr.envbuffer) == 1)
154         {
155                 jpeg_destroy_decompress(ciptr);
156                 fclose(fh);
157                 return 0;
158         }
159
160         jpeg_create_decompress(ciptr);
161         jpeg_stdio_src(ciptr, fh);
162         jpeg_read_header(ciptr, TRUE);
163         ciptr->out_color_space = JCS_RGB;
164         ciptr->scale_denom = 1;
165
166         jpeg_start_decompress(ciptr);
167         
168         *x=ciptr->output_width;
169         *y=ciptr->output_height;
170
171         if(ciptr->output_components == 3)
172         {
173                 JSAMPLE *lb = (JSAMPLE *)(*ciptr->mem->alloc_small)((j_common_ptr) ciptr, JPOOL_PERMANENT, ciptr->output_width * ciptr->output_components);
174                 pic_buffer = new unsigned char[ciptr->output_height * ciptr->output_width * ciptr->output_components];
175                 unsigned char *bp = pic_buffer;
176
177                 while (ciptr->output_scanline < ciptr->output_height)
178                 {
179                         jpeg_read_scanlines(ciptr, &lb, 1);
180                         memcpy(bp, lb, ciptr->output_width * ciptr->output_components);
181                         bp += ciptr->output_width * ciptr->output_components;
182                 }
183         }
184         jpeg_finish_decompress(ciptr);
185         jpeg_destroy_decompress(ciptr);
186         fclose(fh);
187         return 1;
188 }
189
190 //---------------------------------------------------------------------------------------------
191
192 #define BMP_TORASTER_OFFSET 10
193 #define BMP_SIZE_OFFSET 18
194 #define BMP_BPP_OFFSET 28
195 #define BMP_RLE_OFFSET 30
196 #define BMP_COLOR_OFFSET 54
197
198 #define fill4B(a) ((4 - ((a) % 4 )) & 0x03)
199
200 static int bmp_load(const char *filename,  int *x, int *y)
201 {
202         unsigned char buff[4];
203
204         int fd = open(filename, O_RDONLY);
205         if (fd == -1) return 0;
206         if (lseek(fd, BMP_SIZE_OFFSET, SEEK_SET) == -1) return 0;
207         read(fd, buff, 4);
208         *x = buff[0] + (buff[1] << 8) + (buff[2] << 16) + (buff[3] << 24);
209         read(fd, buff, 4);
210         *y = buff[0] + (buff[1] << 8) + (buff[2] << 16) + (buff[3] << 24);
211         if (lseek(fd, BMP_TORASTER_OFFSET, SEEK_SET) == -1) return 0;
212         read(fd, buff, 4);
213         int raster = buff[0] + (buff[1] << 8) + (buff[2] << 16) + (buff[3] << 24);
214         if (lseek(fd, BMP_BPP_OFFSET, SEEK_SET) == -1) return 0;
215         read(fd, buff, 2);
216         int bpp = buff[0] + (buff[1] << 8);
217
218         //printf("x=%d, y=%d,bpp=%d\n",*x, *y, bpp);
219         pic_buffer = new unsigned char[(*x) * (*y) * 3];
220         unsigned char *wr_buffer = pic_buffer + (*x) * ((*y) - 1) * 3;
221         
222         switch (bpp)
223         {
224                 case 24:
225                 {
226                         int skip = fill4B((*x) * 3);
227                         lseek(fd, raster, SEEK_SET);
228                         unsigned char c;
229                         for (int i = 0; i < (*y); i++) 
230                         {
231                                 read(fd, wr_buffer, (*x) * 3);
232                                 for (int j = 0; j < (*x) * 3 ; j = j + 3)
233                                 {
234                                         c = wr_buffer[j];
235                                         wr_buffer[j] = wr_buffer[j + 2];
236                                         wr_buffer[j + 2] = c;
237                                 }
238                                 if (skip)
239                                         read(fd, buff, skip);
240                                 wr_buffer -= (*x) * 3;
241                         }
242                         break;
243                 }
244                 default:
245                         return 0;
246         }
247
248         close(fd);
249         return 1;
250 }
251
252 //---------------------------------------------------------------------------------------------
253
254 static int png_load(const char *filename,  int *x, int *y)
255 {
256         static const png_color_16 my_background = {0, 0, 0, 0, 0};
257
258         png_structp png_ptr;
259         png_infop info_ptr;
260         png_uint_32 width, height;
261         unsigned int i;
262         int bit_depth, color_type, interlace_type;
263         int number_passes, pass;
264         png_byte * fbptr;
265         FILE * fh;
266
267         if (!(fh = fopen(filename, "rb"))) return 0;
268
269         png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
270         if (png_ptr == NULL)
271                 return 0;
272         info_ptr = png_create_info_struct(png_ptr);
273         if (info_ptr == NULL)
274         {
275                 png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
276                 fclose(fh); 
277                 return 0;
278         }
279
280         if (setjmp(png_ptr->jmpbuf))
281         {
282                 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
283                 fclose(fh); 
284                 return 0;
285         }
286
287         png_init_io(png_ptr, fh);
288
289         png_read_info(png_ptr, info_ptr);
290         png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);
291
292         if (color_type == PNG_COLOR_TYPE_PALETTE)
293         {
294                 png_set_palette_to_rgb(png_ptr);
295                 png_set_background(png_ptr, (png_color_16 *)&my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
296         }
297
298         if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
299         {
300                 png_set_gray_to_rgb(png_ptr);
301                 png_set_background(png_ptr, (png_color_16 *)&my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
302         }
303
304         if (color_type & PNG_COLOR_MASK_ALPHA)
305                 png_set_strip_alpha(png_ptr);
306
307         if (bit_depth < 8)      png_set_packing(png_ptr);
308         if (bit_depth == 16)    png_set_strip_16(png_ptr);
309
310         number_passes = png_set_interlace_handling(png_ptr);
311         png_read_update_info(png_ptr, info_ptr);
312
313         if (width * 3 != png_get_rowbytes(png_ptr, info_ptr))
314         {
315                 eDebug("[PNG] Error processing");
316                 return 0;
317         }
318         
319         pic_buffer = new unsigned char[width * height * 3];
320         *x=width;
321         *y=height;
322
323         for(pass = 0; pass < number_passes; pass++)
324         {
325                 fbptr = (png_byte *)pic_buffer;
326                 for (i = 0; i < height; i++, fbptr += width * 3)
327                         png_read_row(png_ptr, fbptr, NULL);
328         }
329         png_read_end(png_ptr, info_ptr);
330         png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
331         fclose(fh);
332         return 1;
333 }
334
335 //---------------------------------------------------------------------------------------------
336
337 PyObject *getExif(const char *filename)
338 {
339         ePyObject list;
340         Cexif exif;
341         if(exif.DecodeExif(filename))
342         {
343                 if(exif.m_exifinfo->IsExif)
344                 {
345                         int pos=0;
346                         char tmp[256];
347                         list = PyList_New(22);
348                         PyList_SET_ITEM(list, pos++,  PyString_FromString(exif.m_exifinfo->Version));
349                         PyList_SET_ITEM(list, pos++,  PyString_FromString(exif.m_exifinfo->CameraMake));
350                         PyList_SET_ITEM(list, pos++,  PyString_FromString(exif.m_exifinfo->CameraModel));
351                         PyList_SET_ITEM(list, pos++,  PyString_FromString(exif.m_exifinfo->DateTime));
352                         PyList_SET_ITEM(list, pos++,  PyString_FromString(exif.m_exifinfo->Comments));
353                         PyList_SET_ITEM(list, pos++,  PyString_FromFormat("%d x %d", exif.m_exifinfo->Width, exif.m_exifinfo->Height));
354                         PyList_SET_ITEM(list, pos++,  PyString_FromString(exif.m_exifinfo->Orientation));
355                         PyList_SET_ITEM(list, pos++,  PyString_FromString(exif.m_exifinfo->MeteringMode));
356                         PyList_SET_ITEM(list, pos++,  PyString_FromString(exif.m_exifinfo->ExposureProgram));
357                         PyList_SET_ITEM(list, pos++,  PyString_FromString(exif.m_exifinfo->LightSource));
358                         PyList_SET_ITEM(list, pos++,  PyString_FromString(exif.m_exifinfo->FlashUsed));
359                         PyList_SET_ITEM(list, pos++,  PyString_FromFormat("%d", exif.m_exifinfo->CompressionLevel));
360                         PyList_SET_ITEM(list, pos++,  PyString_FromFormat("%d", exif.m_exifinfo->ISOequivalent));
361                         sprintf(tmp, "%.2f", exif.m_exifinfo->Xresolution);
362                         PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
363                         sprintf(tmp, "%.2f", exif.m_exifinfo->Yresolution);
364                         PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
365                         PyList_SET_ITEM(list, pos++,  PyString_FromString(exif.m_exifinfo->ResolutionUnit));
366                         sprintf(tmp, "%.2f", exif.m_exifinfo->Brightness);
367                         PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
368                         sprintf(tmp, "%.5f sec.", exif.m_exifinfo->ExposureTime);
369                         PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
370                         sprintf(tmp, "%.5f", exif.m_exifinfo->ExposureBias);
371                         PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
372                         sprintf(tmp, "%.5f", exif.m_exifinfo->Distance);
373                         PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
374                         sprintf(tmp, "%.5f", exif.m_exifinfo->CCDWidth);
375                         PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
376                         sprintf(tmp, "%.2f", exif.m_exifinfo->ApertureFNumber);
377                         PyList_SET_ITEM(list, pos++,  PyString_FromString(tmp));
378                 }
379                 else
380                 {
381                         list = PyList_New(1);
382                         PyList_SET_ITEM(list, 0, PyString_FromString(exif.m_szLastError));
383                 }
384                 exif.ClearExif();
385         }
386         else
387         {
388                 list = PyList_New(1);
389                 PyList_SET_ITEM(list, 0, PyString_FromString(exif.m_szLastError));
390         }
391
392         return list ? (PyObject*)list : (PyObject*)PyList_New(0);
393 }
394
395 //---------------------------------------------------------------------------------------------
396
397 int loadPic(ePtr<gPixmap> &result, std::string filename, int w, int h, int aspect, int resize_mode, int rotate, int background, std::string cachefile)
398 {
399         result = 0;
400         int ox=0, oy=0, imx, imy;
401         pic_buffer=NULL;
402         bool cache=false;
403
404         if(cachefile.length())
405         {
406                 cache = true;
407                 if(jpeg_load(cachefile.c_str(), &ox, &oy))
408                         eDebug("[CACHEPIC] x-size=%d, y-size=%d", ox, oy);
409         }
410
411         if(pic_buffer==NULL)
412         {
413                 unsigned int pos = filename.find_last_of(".");
414                 if (pos == std::string::npos)
415                         pos = filename.length() - 1;
416                 std::string ext = filename.substr(pos);
417                 std::transform(ext.begin(), ext.end(), ext.begin(), (int(*)(int)) toupper);
418                 if(ext == ".JPEG" || ext == ".JPG")
419                         jpeg_load(filename.c_str(), &ox, &oy);
420                 else if(ext == ".BMP")
421                         bmp_load(filename.c_str(), &ox, &oy);
422                 else if(ext == ".PNG")
423                         png_load(filename.c_str(), &ox, &oy);
424                 else
425                 {
426                         eDebug("[PIC] <format not supportet>");
427                         return 0;
428                 }
429         
430                 eDebug("[FULLPIC] x-size=%d, y-size=%d", ox, oy);
431
432                 if(pic_buffer==NULL)
433                         return 0;
434
435                 double aspect_ratio;
436                 switch(aspect)
437                 {
438                         case 1:         aspect_ratio = 1.777 / ((double)720/576); break; //16:9
439                         case 2:         aspect_ratio = 1.600 / ((double)720/576); break; //16:10
440                         //case 3:       aspect_ratio = 1.250 / ((double)720/576); break; //5:4
441                         default:        aspect_ratio = 1.333 / ((double)720/576); //4:3
442                 }
443
444                 if((aspect_ratio * oy * w / ox) <= h)
445                 {
446                         imx = w;
447                         imy = (int)(aspect_ratio*oy*w/ox);
448                 }
449                 else
450                 {
451                         imx = (int)((1.0/aspect_ratio)*ox*h/oy);
452                         imy = h;
453                 }
454
455                 if(resize_mode) pic_buffer = color_resize(pic_buffer, ox, oy, imx, imy);
456                 else            pic_buffer = simple_resize(pic_buffer, ox, oy, imx, imy);
457
458                 ox = imx;
459                 oy = imy;
460                 
461                 if(cache)
462                 {
463                         jpeg_save(pic_buffer, cachefile.c_str(), 50, oy, ox);
464                         eDebug("[SAVEPIC] x-size=%d, y-size=%d", ox, oy);
465                 }
466                 
467         }
468
469         
470         result=new gPixmap(eSize(w, h), 32);
471         gSurface *surface = result->surface;
472         int a=0, b=0;
473         int nc=0, oc=0;
474         int o_y=0, u_y=0, v_x=0, h_x=0;
475         unsigned char clear[4] = {0x00,0x00,0x00,0x00};
476         if(background)  clear[3]=0xFF;
477         unsigned char *tmp_buffer = new unsigned char[4];
478
479         if(oy < h)
480         {
481                 o_y=(h-oy)/2;
482                 u_y=h-oy-o_y;
483         }
484         if(ox < w)
485         {
486                 v_x=(w-ox)/2;
487                 h_x=w-ox-v_x;
488         }
489         
490         //eDebug("o_y=%d u_y=%d v_x=%d h_x=%d", o_y, u_y, v_x, h_x);
491
492         if(oy < h)
493                 for(a=0; a<(o_y*ox)+1; a++, nc+=4)
494                 {
495                         memcpy(tmp_buffer, clear, sizeof(clear));
496                         tmp_buffer=((unsigned char *)(surface->data)) + nc;
497                 }
498         
499         for(a=0; a<oy; a++)
500         {
501                 if(ox < w)
502                         for(b=0; b<v_x; b++, nc+=4)
503                         {
504                                 memcpy(tmp_buffer, clear, sizeof(clear));
505                                 tmp_buffer=((unsigned char *)(surface->data)) + nc;
506                         }
507
508                 for(b=0; b<(ox*3); b+=3, nc+=4)
509                 {
510                         tmp_buffer[3]=0xFF;
511                         tmp_buffer[2]=pic_buffer[oc++];
512                         tmp_buffer[1]=pic_buffer[oc++];
513                         tmp_buffer[0]=pic_buffer[oc++];
514
515                         tmp_buffer=((unsigned char *)(surface->data)) + nc;
516                 }
517                 
518                 if(ox < w)
519                         for(b=0; b<h_x; b++, nc+=4)
520                         {
521                                 memcpy(tmp_buffer, clear, sizeof(clear));
522                                 tmp_buffer=((unsigned char *)(surface->data)) + nc;
523                         }
524         }
525
526         if(oy < h)
527                 for(a=0; a<(u_y*ox)+1; a++, nc+=4)
528                 {
529                         memcpy(tmp_buffer, clear, sizeof(clear));
530                         tmp_buffer=((unsigned char *)(surface->data)) + nc;
531                 }
532         
533         //eDebug("[PIC] buffer=%d, nc=%d oc=%d ox=%d, oy=%d",w*h*4, nc, oc, ox, oy);
534         
535         surface->clut.data=0;
536         surface->clut.colors=0;
537         surface->clut.start=0;
538         
539         delete [] pic_buffer;
540
541         return 0;
542 }