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