X-Git-Url: http://code.vuplus.com/gitweb/?p=vuplus_dvbapp;a=blobdiff_plain;f=lib%2Fgdi%2Fpicload.cpp;h=b1dfd1a192e24ec5abb04481caeccdb5f0cd6d0b;hp=b3ffe2a8b0dfb9d1c62e2d592e822e3768dab7a3;hb=9ccb92fb3eaca35ec60c1a596db9620f9f302044;hpb=2d29b4a868272f9e844f12f571148e2d6608abe9 diff --git a/lib/gdi/picload.cpp b/lib/gdi/picload.cpp index b3ffe2a..b1dfd1a 100644 --- a/lib/gdi/picload.cpp +++ b/lib/gdi/picload.cpp @@ -1,29 +1,57 @@ -#include "picload.h" -#include "picexif.h" - -#include - +#include // must be included before Python.h because of setjmp #include -#include -#include -#include + +#include +#include extern "C" { #include -//#include "transupp.h" +#include } -#include -unsigned char *pic_buffer=NULL; +extern const uint32_t crc32_table[256]; + +DEFINE_REF(ePicLoad); -static unsigned char *simple_resize(unsigned char * orgin, int ox, int oy, int dx, int dy) +static std::string getSize(const char* file) +{ + struct stat64 s; + if (stat64(file, &s) < 0) + return ""; + char tmp[20]; + snprintf(tmp, 20, "%ld kB",(long)s.st_size / 1024); + return tmp; +} + +static unsigned char *conv24to32(unsigned char *orgin, int size, unsigned char alpha = 0xFF) +{ + int s, d; + unsigned char *cr = new unsigned char[size * 4]; + if (cr == NULL) + { + eDebug("[Picload] Error malloc"); + return(orgin); + } + + for (s = 0, d = 0 ; s < (size * 3); s += 3, d += 4 ) + { + cr[d] = orgin[s]; + cr[d+1] = orgin[s + 1]; + cr[d+2] = orgin[s + 2]; + cr[d+3] = alpha; + } + delete [] orgin; + return(cr); +} + +static unsigned char *simple_resize(unsigned char *orgin, int ox, int oy, int dx, int dy) { unsigned char *cr, *p, *l; int i, j, k, ip; - cr = new unsigned char[dx * dy * 3]; + cr = new unsigned char[dx * dy * 3]; if (cr == NULL) { - printf("[RESIZE] Error: malloc\n"); + eDebug("[Picload] Error malloc"); return(orgin); } l = cr; @@ -51,7 +79,7 @@ static unsigned char *color_resize(unsigned char * orgin, int ox, int oy, int dx cr = new unsigned char[dx * dy * 3]; if (cr == NULL) { - printf("[RESIZE] Error: malloc\n"); + eDebug("[Picload] Error malloc"); return(orgin); } p = cr; @@ -83,109 +111,6 @@ static unsigned char *color_resize(unsigned char * orgin, int ox, int oy, int dx return(cr); } -//------------------------------------------------------------------- - -struct r_jpeg_error_mgr -{ - struct jpeg_error_mgr pub; - jmp_buf envbuffer; -}; - -void jpeg_cb_error_exit(j_common_ptr cinfo) -{ - struct r_jpeg_error_mgr *mptr; - mptr = (struct r_jpeg_error_mgr *) cinfo->err; - (*cinfo->err->output_message) (cinfo); - longjmp(mptr->envbuffer, 1); -} - -static int jpeg_save(unsigned char *image_buffer, const char * filename, int quality, int image_height, int image_width) -{ - struct jpeg_compress_struct cinfo; - struct jpeg_error_mgr jerr; - FILE * outfile; /* target file */ - JSAMPROW row_pointer[1];/* pointer to JSAMPLE row[s] */ - int row_stride; /* physical row width in image buffer */ - - cinfo.err = jpeg_std_error(&jerr); - jpeg_create_compress(&cinfo); - - if ((outfile = fopen(filename, "wb")) == NULL) - { - eDebug("[JPEG] can't open %s", filename); - return -1; - } - jpeg_stdio_dest(&cinfo, outfile); - - cinfo.image_width = image_width; - cinfo.image_height = image_height; - cinfo.input_components = 3; - cinfo.in_color_space = JCS_RGB; - jpeg_set_defaults(&cinfo); - jpeg_set_quality(&cinfo, quality, TRUE ); - jpeg_start_compress(&cinfo, TRUE); - row_stride = image_width * 3; - while (cinfo.next_scanline < cinfo.image_height) - { - row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride]; - (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); - } - jpeg_finish_compress(&cinfo); - fclose(outfile); - jpeg_destroy_compress(&cinfo); - return 0; -} - - -static int jpeg_load(const char *filename, int *x, int *y) -{ - struct jpeg_decompress_struct cinfo; - struct jpeg_decompress_struct *ciptr = &cinfo; - struct r_jpeg_error_mgr emgr; - FILE *fh; - - if (!(fh = fopen(filename, "rb"))) - return 0; - - ciptr->err = jpeg_std_error(&emgr.pub); - emgr.pub.error_exit = jpeg_cb_error_exit; - if (setjmp(emgr.envbuffer) == 1) - { - jpeg_destroy_decompress(ciptr); - fclose(fh); - return 0; - } - - jpeg_create_decompress(ciptr); - jpeg_stdio_src(ciptr, fh); - jpeg_read_header(ciptr, TRUE); - ciptr->out_color_space = JCS_RGB; - ciptr->scale_denom = 1; - - jpeg_start_decompress(ciptr); - - *x=ciptr->output_width; - *y=ciptr->output_height; - - if(ciptr->output_components == 3) - { - JSAMPLE *lb = (JSAMPLE *)(*ciptr->mem->alloc_small)((j_common_ptr) ciptr, JPOOL_PERMANENT, ciptr->output_width * ciptr->output_components); - pic_buffer = new unsigned char[ciptr->output_height * ciptr->output_width * ciptr->output_components]; - unsigned char *bp = pic_buffer; - - while (ciptr->output_scanline < ciptr->output_height) - { - jpeg_read_scanlines(ciptr, &lb, 1); - memcpy(bp, lb, ciptr->output_width * ciptr->output_components); - bp += ciptr->output_width * ciptr->output_components; - } - } - jpeg_finish_decompress(ciptr); - jpeg_destroy_decompress(ciptr); - fclose(fh); - return 1; -} - //--------------------------------------------------------------------------------------------- #define BMP_TORASTER_OFFSET 10 @@ -196,41 +121,118 @@ static int jpeg_load(const char *filename, int *x, int *y) #define fill4B(a) ((4 - ((a) % 4 )) & 0x03) -static int bmp_load(const char *filename, int *x, int *y) +struct color { + unsigned char red; + unsigned char green; + unsigned char blue; +}; + +static void fetch_pallete(int fd, struct color pallete[], int count) +{ + unsigned char buff[4]; + lseek(fd, BMP_COLOR_OFFSET, SEEK_SET); + for (int i = 0; i < count; i++) + { + read(fd, buff, 4); + pallete[i].red = buff[2]; + pallete[i].green = buff[1]; + pallete[i].blue = buff[0]; + } +} + +static unsigned char *bmp_load(const char *file, int *x, int *y) { unsigned char buff[4]; + struct color pallete[256]; - int fd = open(filename, O_RDONLY); - if (fd == -1) return 0; - if (lseek(fd, BMP_SIZE_OFFSET, SEEK_SET) == -1) return 0; + int fd = open(file, O_RDONLY); + if (fd == -1) return NULL; + if (lseek(fd, BMP_SIZE_OFFSET, SEEK_SET) == -1) return NULL; read(fd, buff, 4); *x = buff[0] + (buff[1] << 8) + (buff[2] << 16) + (buff[3] << 24); read(fd, buff, 4); *y = buff[0] + (buff[1] << 8) + (buff[2] << 16) + (buff[3] << 24); - if (lseek(fd, BMP_TORASTER_OFFSET, SEEK_SET) == -1) return 0; + if (lseek(fd, BMP_TORASTER_OFFSET, SEEK_SET) == -1) return NULL; read(fd, buff, 4); int raster = buff[0] + (buff[1] << 8) + (buff[2] << 16) + (buff[3] << 24); - if (lseek(fd, BMP_BPP_OFFSET, SEEK_SET) == -1) return 0; + if (lseek(fd, BMP_BPP_OFFSET, SEEK_SET) == -1) return NULL; read(fd, buff, 2); int bpp = buff[0] + (buff[1] << 8); - //printf("x=%d, y=%d,bpp=%d\n",*x, *y, bpp); - pic_buffer = new unsigned char[(*x) * (*y) * 3]; + unsigned char *pic_buffer = new unsigned char[(*x) * (*y) * 3]; unsigned char *wr_buffer = pic_buffer + (*x) * ((*y) - 1) * 3; switch (bpp) { + case 4: + { + int skip = fill4B((*x) / 2 + (*x) % 2); + fetch_pallete(fd, pallete, 16); + lseek(fd, raster, SEEK_SET); + unsigned char * tbuffer = new unsigned char[*x / 2 + 1]; + if (tbuffer == NULL) + return NULL; + for (int i = 0; i < *y; i++) + { + read(fd, tbuffer, (*x) / 2 + *x % 2); + int j; + for (j = 0; j < (*x) / 2; j++) + { + unsigned char c1 = tbuffer[j] >> 4; + unsigned char c2 = tbuffer[j] & 0x0f; + *wr_buffer++ = pallete[c1].red; + *wr_buffer++ = pallete[c1].green; + *wr_buffer++ = pallete[c1].blue; + *wr_buffer++ = pallete[c2].red; + *wr_buffer++ = pallete[c2].green; + *wr_buffer++ = pallete[c2].blue; + } + if ((*x) % 2) + { + unsigned char c1 = tbuffer[j] >> 4; + *wr_buffer++ = pallete[c1].red; + *wr_buffer++ = pallete[c1].green; + *wr_buffer++ = pallete[c1].blue; + } + if (skip) + read(fd, buff, skip); + wr_buffer -= (*x) * 6; + } + break; + } + case 8: + { + int skip = fill4B(*x); + fetch_pallete(fd, pallete, 256); + lseek(fd, raster, SEEK_SET); + unsigned char * tbuffer = new unsigned char[*x]; + if (tbuffer == NULL) + return NULL; + for (int i = 0; i < *y; i++) + { + read(fd, tbuffer, *x); + for (int j = 0; j < *x; j++) + { + wr_buffer[j * 3] = pallete[tbuffer[j]].red; + wr_buffer[j * 3 + 1] = pallete[tbuffer[j]].green; + wr_buffer[j * 3 + 2] = pallete[tbuffer[j]].blue; + } + if (skip) + read(fd, buff, skip); + wr_buffer -= (*x) * 3; + } + break; + } case 24: { int skip = fill4B((*x) * 3); lseek(fd, raster, SEEK_SET); - unsigned char c; - for (int i = 0; i < (*y); i++) + for (int i = 0; i < (*y); i++) { read(fd, wr_buffer, (*x) * 3); for (int j = 0; j < (*x) * 3 ; j = j + 3) { - c = wr_buffer[j]; + unsigned char c = wr_buffer[j]; wr_buffer[j] = wr_buffer[j + 2]; wr_buffer[j + 2] = c; } @@ -241,19 +243,18 @@ static int bmp_load(const char *filename, int *x, int *y) break; } default: - return 0; + return NULL; } close(fd); - return 1; + return(pic_buffer); } -//--------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------- -static int png_load(const char *filename, int *x, int *y) +static unsigned char *png_load(const char *file, int *ox, int *oy) { - static const png_color_16 my_background = {0, 0, 0, 0, 0}; - + //static const png_color_16 my_background = {0, 0, 0, 0, 0}; png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; @@ -263,17 +264,17 @@ static int png_load(const char *filename, int *x, int *y) png_byte * fbptr; FILE * fh; - if (!(fh = fopen(filename, "rb"))) return 0; + if (!(fh = fopen(file, "rb"))) return NULL; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) - return 0; + return NULL; info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); fclose(fh); - return 0; + return NULL; } if (setjmp(png_ptr->jmpbuf)) @@ -288,254 +289,778 @@ static int png_load(const char *filename, int *x, int *y) png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); - if (color_type == PNG_COLOR_TYPE_PALETTE) - { - png_set_palette_to_rgb(png_ptr); - png_set_background(png_ptr, (png_color_16 *)&my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); - } - + if ((color_type == PNG_COLOR_TYPE_PALETTE)||(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)||(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))) + png_set_expand(png_ptr); + if (bit_depth == 16) + png_set_strip_16(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - { png_set_gray_to_rgb(png_ptr); - png_set_background(png_ptr, (png_color_16 *)&my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); - } - - if (color_type & PNG_COLOR_MASK_ALPHA) - png_set_strip_alpha(png_ptr); - - if (bit_depth < 8) png_set_packing(png_ptr); - if (bit_depth == 16) png_set_strip_16(png_ptr); number_passes = png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, info_ptr); - if (width * 3 != png_get_rowbytes(png_ptr, info_ptr)) + int bpp = png_get_rowbytes(png_ptr, info_ptr)/width; + if ((bpp !=4) && (bpp !=3)) { eDebug("[PNG] Error processing"); return 0; } - - pic_buffer = new unsigned char[width * height * 3]; - *x=width; - *y=height; + + if (width * height > 1000000) // 1000x1000 or equiv. + { + eDebug("[png_load] image size is %d x %d, which is \"too large\".", (int)width, (int)height); + png_read_end(png_ptr, info_ptr); + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + fclose(fh); + return 0; + } + + unsigned char *pic_buffer = new unsigned char[width * height * bpp]; + *ox=width; + *oy=height; for(pass = 0; pass < number_passes; pass++) { fbptr = (png_byte *)pic_buffer; - for (i = 0; i < height; i++, fbptr += width * 3) + for (i = 0; i < height; i++, fbptr += width * bpp) png_read_row(png_ptr, fbptr, NULL); } png_read_end(png_ptr, info_ptr); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fh); - return 1; + return(pic_buffer); } -//--------------------------------------------------------------------------------------------- +//------------------------------------------------------------------- + +struct r_jpeg_error_mgr +{ + struct jpeg_error_mgr pub; + jmp_buf envbuffer; +}; -PyObject *getExif(const char *filename) +void jpeg_cb_error_exit(j_common_ptr cinfo) { - PyObject *list = 0; - Cexif exif; - if(exif.DecodeExif(filename)) + struct r_jpeg_error_mgr *mptr; + mptr = (struct r_jpeg_error_mgr *) cinfo->err; + (*cinfo->err->output_message) (cinfo); + longjmp(mptr->envbuffer, 1); +} + +static unsigned char *jpeg_load(const char *file, int *ox, int *oy) +{ + struct jpeg_decompress_struct cinfo; + struct jpeg_decompress_struct *ciptr = &cinfo; + struct r_jpeg_error_mgr emgr; + FILE *fh; + unsigned char *pic_buffer=NULL; + + if (!(fh = fopen(file, "rb"))) + return NULL; + + ciptr->err = jpeg_std_error(&emgr.pub); + emgr.pub.error_exit = jpeg_cb_error_exit; + if (setjmp(emgr.envbuffer) == 1) { - if(exif.m_exifinfo->IsExif) - { - int pos=0; - char tmp[256]; - list = PyList_New(22); - PyList_SET_ITEM(list, pos++, PyString_FromString(exif.m_exifinfo->Version)); - PyList_SET_ITEM(list, pos++, PyString_FromString(exif.m_exifinfo->CameraMake)); - PyList_SET_ITEM(list, pos++, PyString_FromString(exif.m_exifinfo->CameraModel)); - PyList_SET_ITEM(list, pos++, PyString_FromString(exif.m_exifinfo->DateTime)); - PyList_SET_ITEM(list, pos++, PyString_FromString(exif.m_exifinfo->Comments)); - PyList_SET_ITEM(list, pos++, PyString_FromFormat("%d x %d", exif.m_exifinfo->Width, exif.m_exifinfo->Height)); - PyList_SET_ITEM(list, pos++, PyString_FromString(exif.m_exifinfo->Orientation)); - PyList_SET_ITEM(list, pos++, PyString_FromString(exif.m_exifinfo->MeteringMode)); - PyList_SET_ITEM(list, pos++, PyString_FromString(exif.m_exifinfo->ExposureProgram)); - PyList_SET_ITEM(list, pos++, PyString_FromString(exif.m_exifinfo->LightSource)); - PyList_SET_ITEM(list, pos++, PyString_FromString(exif.m_exifinfo->FlashUsed)); - PyList_SET_ITEM(list, pos++, PyString_FromFormat("%d", exif.m_exifinfo->CompressionLevel)); - PyList_SET_ITEM(list, pos++, PyString_FromFormat("%d", exif.m_exifinfo->ISOequivalent)); - sprintf(tmp, "%.2f", exif.m_exifinfo->Xresolution); - PyList_SET_ITEM(list, pos++, PyString_FromString(tmp)); - sprintf(tmp, "%.2f", exif.m_exifinfo->Yresolution); - PyList_SET_ITEM(list, pos++, PyString_FromString(tmp)); - PyList_SET_ITEM(list, pos++, PyString_FromString(exif.m_exifinfo->ResolutionUnit)); - sprintf(tmp, "%.2f", exif.m_exifinfo->Brightness); - PyList_SET_ITEM(list, pos++, PyString_FromString(tmp)); - sprintf(tmp, "%.5f sec.", exif.m_exifinfo->ExposureTime); - PyList_SET_ITEM(list, pos++, PyString_FromString(tmp)); - sprintf(tmp, "%.5f", exif.m_exifinfo->ExposureBias); - PyList_SET_ITEM(list, pos++, PyString_FromString(tmp)); - sprintf(tmp, "%.5f", exif.m_exifinfo->Distance); - PyList_SET_ITEM(list, pos++, PyString_FromString(tmp)); - sprintf(tmp, "%.5f", exif.m_exifinfo->CCDWidth); - PyList_SET_ITEM(list, pos++, PyString_FromString(tmp)); - sprintf(tmp, "%.2f", exif.m_exifinfo->ApertureFNumber); - PyList_SET_ITEM(list, pos++, PyString_FromString(tmp)); - } - else + jpeg_destroy_decompress(ciptr); + fclose(fh); + return NULL; + } + + jpeg_create_decompress(ciptr); + jpeg_stdio_src(ciptr, fh); + jpeg_read_header(ciptr, TRUE); + ciptr->out_color_space = JCS_RGB; + ciptr->scale_denom = 1; + + jpeg_start_decompress(ciptr); + + *ox=ciptr->output_width; + *oy=ciptr->output_height; + + if(ciptr->output_components == 3) + { + JSAMPLE *lb = (JSAMPLE *)(*ciptr->mem->alloc_small)((j_common_ptr) ciptr, JPOOL_PERMANENT, ciptr->output_width * ciptr->output_components); + pic_buffer = new unsigned char[ciptr->output_height * ciptr->output_width * ciptr->output_components]; + unsigned char *bp = pic_buffer; + + while (ciptr->output_scanline < ciptr->output_height) { - list = PyList_New(1); - PyList_SET_ITEM(list, 0, PyString_FromString(exif.m_szLastError)); + jpeg_read_scanlines(ciptr, &lb, 1); + memcpy(bp, lb, ciptr->output_width * ciptr->output_components); + bp += ciptr->output_width * ciptr->output_components; } - exif.ClearExif(); } - else + jpeg_finish_decompress(ciptr); + jpeg_destroy_decompress(ciptr); + fclose(fh); + return(pic_buffer); +} + + +static int jpeg_save(const char * filename, int ox, int oy, unsigned char *pic_buffer) +{ + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + FILE * outfile; + JSAMPROW row_pointer[1]; + int row_stride; + + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cinfo); + + if ((outfile = fopen(filename, "wb")) == NULL) { - list = PyList_New(1); - PyList_SET_ITEM(list, 0, PyString_FromString(exif.m_szLastError)); + eDebug("[Picload] jpeg can't open %s", filename); + return 1; } + eDebug("[Picload] save Thumbnail... %s",filename); - return list ? list : PyList_New(0); + jpeg_stdio_dest(&cinfo, outfile); + + cinfo.image_width = ox; + cinfo.image_height = oy; + cinfo.input_components = 3; + cinfo.in_color_space = JCS_RGB; + jpeg_set_defaults(&cinfo); + jpeg_set_quality(&cinfo, 70, TRUE ); + jpeg_start_compress(&cinfo, TRUE); + row_stride = ox * 3; + while (cinfo.next_scanline < cinfo.image_height) + { + row_pointer[0] = & pic_buffer[cinfo.next_scanline * row_stride]; + (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); + } + jpeg_finish_compress(&cinfo); + fclose(outfile); + jpeg_destroy_compress(&cinfo); + return 0; } -//--------------------------------------------------------------------------------------------- +//------------------------------------------------------------------- -int loadPic(ePtr &result, std::string filename, int w, int h, int aspect, int resize_mode, int rotate, int background, std::string cachefile) +inline void m_rend_gif_decodecolormap(unsigned char *cmb, unsigned char *rgbb, ColorMapObject *cm, int s, int l) { - result = 0; - int ox=0, oy=0, imx, imy; - pic_buffer=NULL; - bool cache=false; - - if(cachefile.length()) - { - cache = true; - if(jpeg_load(cachefile.c_str(), &ox, &oy)) - eDebug("[CACHEPIC] x-size=%d, y-size=%d", ox, oy); - } - - if(pic_buffer==NULL) - { - unsigned int pos = filename.find_last_of("."); - if (pos == std::string::npos) - pos = filename.length() - 1; - std::string ext = filename.substr(pos); - std::transform(ext.begin(), ext.end(), ext.begin(), (int(*)(int)) toupper); - if(ext == ".JPEG" || ext == ".JPG") - jpeg_load(filename.c_str(), &ox, &oy); - else if(ext == ".BMP") - bmp_load(filename.c_str(), &ox, &oy); - else if(ext == ".PNG") - png_load(filename.c_str(), &ox, &oy); - else + GifColorType *cmentry; + int i; + for (i = 0; i < l; i++) + { + cmentry = &cm->Colors[cmb[i]]; + *(rgbb++) = cmentry->Red; + *(rgbb++) = cmentry->Green; + *(rgbb++) = cmentry->Blue; + } +} + +static unsigned char *gif_load(const char *file, int *ox, int *oy) +{ + unsigned char *pic_buffer = NULL; + int px, py, i, j, ibxs; + unsigned char *fbptr; + unsigned char *lb=NULL; + unsigned char *slb=NULL; + GifFileType *gft; + GifRecordType rt; + GifByteType *extension; + ColorMapObject *cmap; + int cmaps; + int extcode; + + gft = DGifOpenFileName(file); + if (gft == NULL) + return NULL; + do + { + if (DGifGetRecordType(gft, &rt) == GIF_ERROR) + goto ERROR_R; + switch(rt) { - eDebug("[PIC] "); - return 0; + case IMAGE_DESC_RECORD_TYPE: + if (DGifGetImageDesc(gft) == GIF_ERROR) + goto ERROR_R; + *ox = px = gft->Image.Width; + *oy = py = gft->Image.Height; + pic_buffer = new unsigned char[px * py * 3]; + lb = (unsigned char *)malloc(px * 3); + slb = (unsigned char *) malloc(px); + + if (lb != NULL && slb != NULL) + { + cmap = (gft->Image.ColorMap ? gft->Image.ColorMap : gft->SColorMap); + cmaps = cmap->ColorCount; + + ibxs = ibxs * 3; + fbptr = pic_buffer; + if (!(gft->Image.Interlace)) + { + for (i = 0; i < py; i++, fbptr += px * 3) + { + if (DGifGetLine(gft, slb, px) == GIF_ERROR) + goto ERROR_R; + m_rend_gif_decodecolormap(slb, lb, cmap, cmaps, px); + memcpy(fbptr, lb, px * 3); + } + } + else + { + for (j = 0; j < 4; j++) + { + fbptr = pic_buffer; + for (i = 0; i < py; i++, fbptr += px * 3) + { + if (DGifGetLine(gft, slb, px) == GIF_ERROR) + goto ERROR_R; + m_rend_gif_decodecolormap(slb, lb, cmap, cmaps, px); + memcpy(fbptr, lb, px * 3); + } + } + } + } + if (lb) + { + free(lb); + lb=NULL; + } + if (slb) + { + free(slb); + slb=NULL; + } + break; + case EXTENSION_RECORD_TYPE: + if (DGifGetExtension(gft, &extcode, &extension) == GIF_ERROR) + goto ERROR_R; + while (extension != NULL) + if (DGifGetExtensionNext(gft, &extension) == GIF_ERROR) + goto ERROR_R; + break; + default: + break; } + } + while (rt != TERMINATE_RECORD_TYPE); + + DGifCloseFile(gft); + return(pic_buffer); +ERROR_R: + eDebug("[Picload] "); + if (lb) free(lb); + if (slb) free(slb); + DGifCloseFile(gft); + return NULL; +} + +//--------------------------------------------------------------------------------------------- + +ePicLoad::ePicLoad() + :msg_thread(this,1), msg_main(eApp,1) +{ + CONNECT(msg_thread.recv_msg, ePicLoad::gotMessage); + CONNECT(msg_main.recv_msg, ePicLoad::gotMessage); - eDebug("[FULLPIC] x-size=%d, y-size=%d", ox, oy); + threadrunning = false; + m_filepara = NULL; + m_conf.max_x = 0; + m_conf.max_y = 0; + m_conf.aspect_ratio = 1.066400; //4:3 + m_conf.usecache = false; + m_conf.resizetype = 1; + memset(m_conf.background,0x00,sizeof(m_conf.background)); + m_conf.thumbnailsize = 180; +} - if(pic_buffer==NULL) - return 0; +void ePicLoad::waitFinished() +{ + msg_thread.send(Message(Message::quit)); + kill(); +} - double aspect_ratio; - switch(aspect) +ePicLoad::~ePicLoad() +{ + if (threadrunning) + waitFinished(); + if(m_filepara != NULL) + delete m_filepara; +} + +void ePicLoad::thread_finished() +{ + threadrunning=false; +} + +void ePicLoad::thread() +{ + hasStarted(); + threadrunning=true; + nice(4); + runLoop(); +} + +void ePicLoad::decodePic() +{ + eDebug("[Picload] decode picture... %s",m_filepara->file); + + switch(m_filepara->id) + { + case F_PNG: m_filepara->pic_buffer = png_load(m_filepara->file, &m_filepara->ox, &m_filepara->oy); break; + case F_JPEG: m_filepara->pic_buffer = jpeg_load(m_filepara->file, &m_filepara->ox, &m_filepara->oy); break; + case F_BMP: m_filepara->pic_buffer = bmp_load(m_filepara->file, &m_filepara->ox, &m_filepara->oy); break; + case F_GIF: m_filepara->pic_buffer = gif_load(m_filepara->file, &m_filepara->ox, &m_filepara->oy); break; + } + + if(m_filepara->pic_buffer != NULL) + { + resizePic(); + } +} + +void ePicLoad::decodeThumb() +{ + eDebug("[Picload] get Thumbnail... %s",m_filepara->file); + + bool exif_thumbnail = false; + bool cachefile_found = false; + std::string cachefile = ""; + std::string cachedir = "/.Thumbnails"; + + if(m_filepara->id == F_JPEG) + { + Cexif *exif = new Cexif; + if(exif->DecodeExif(m_filepara->file, 1)) { - case 1: aspect_ratio = 1.777 / ((double)720/576); break; //16:9 - case 2: aspect_ratio = 1.600 / ((double)720/576); break; //16:10 - //case 3: aspect_ratio = 1.250 / ((double)720/576); break; //5:4 - default: aspect_ratio = 1.333 / ((double)720/576); //4:3 + if(exif->m_exifinfo->IsExif) + { + if(exif->m_exifinfo->Thumnailstate==2) + { + m_filepara->file = strdup(THUMBNAILTMPFILE); + exif_thumbnail = true; + eDebug("[Picload] Exif Thumbnail found"); + } + m_filepara->addExifInfo(exif->m_exifinfo->CameraMake); + m_filepara->addExifInfo(exif->m_exifinfo->CameraModel); + m_filepara->addExifInfo(exif->m_exifinfo->DateTime); + char buf[20]; + snprintf(buf, 20, "%d x %d", exif->m_exifinfo->Width, exif->m_exifinfo->Height); + m_filepara->addExifInfo(buf); + } + exif->ClearExif(); } - - if((aspect_ratio * oy * w / ox) <= h) + delete exif; + } + + if((! exif_thumbnail) && m_conf.usecache) + { + if(FILE *f=fopen(m_filepara->file, "rb")) { - imx = w; - imy = (int)(aspect_ratio*oy*w/ox); + int c; + int count = 1024*100; + unsigned long crc32 = 0; + char crcstr[9];*crcstr=0; + + while ((c=getc(f))!=EOF) + { + crc32 = crc32_table[((crc32) ^ (c)) & 0xFF] ^ ((crc32) >> 8); + if(--count < 0) break; + } + + fclose(f); + crc32 = ~crc32; + sprintf(crcstr, "%08lX", crc32); + + cachedir = m_filepara->file; + unsigned int pos = cachedir.find_last_of("/"); + if (pos != std::string::npos) + cachedir = cachedir.substr(0, pos) + "/.Thumbnails"; + + cachefile = cachedir + std::string("/pc_") + crcstr; + if(!access(cachefile.c_str(), R_OK)) + { + cachefile_found = true; + m_filepara->file = strdup(cachefile.c_str()); + m_filepara->id = F_JPEG; + eDebug("[Picload] Cache File found"); + } } - else + } + + switch(m_filepara->id) + { + case F_PNG: m_filepara->pic_buffer = png_load(m_filepara->file, &m_filepara->ox, &m_filepara->oy); break; + case F_JPEG: m_filepara->pic_buffer = jpeg_load(m_filepara->file, &m_filepara->ox, &m_filepara->oy); break; + case F_BMP: m_filepara->pic_buffer = bmp_load(m_filepara->file, &m_filepara->ox, &m_filepara->oy); break; + case F_GIF: m_filepara->pic_buffer = gif_load(m_filepara->file, &m_filepara->ox, &m_filepara->oy); break; + } + + if(exif_thumbnail) + ::unlink(THUMBNAILTMPFILE); + + if(m_filepara->pic_buffer != NULL) + { + //save cachefile + if(m_conf.usecache && (! exif_thumbnail) && (! cachefile_found)) { - imx = (int)((1.0/aspect_ratio)*ox*h/oy); - imy = h; + if(access(cachedir.c_str(), R_OK)) + ::mkdir(cachedir.c_str(), 0755); + + //resize for Thumbnail + int imx, imy; + if (m_filepara->ox <= m_filepara->oy) + { + imy = m_conf.thumbnailsize; + imx = (int)( (m_conf.thumbnailsize * ((double)m_filepara->ox)) / ((double)m_filepara->oy) ); + } + else + { + imx = m_conf.thumbnailsize; + imy = (int)( (m_conf.thumbnailsize * ((double)m_filepara->oy)) / ((double)m_filepara->ox) ); + } + + m_filepara->pic_buffer = color_resize(m_filepara->pic_buffer, m_filepara->ox, m_filepara->oy, imx, imy); + m_filepara->ox = imx; + m_filepara->oy = imy; + + if(jpeg_save(cachefile.c_str(), m_filepara->ox, m_filepara->oy, m_filepara->pic_buffer)) + eDebug("[Picload] error saving cachefile"); } - if(resize_mode) pic_buffer = color_resize(pic_buffer, ox, oy, imx, imy); - else pic_buffer = simple_resize(pic_buffer, ox, oy, imx, imy); + resizePic(); + } +} + +void ePicLoad::resizePic() +{ + int imx, imy; - ox = imx; - oy = imy; + if((m_conf.aspect_ratio * m_filepara->oy * m_filepara->max_x / m_filepara->ox) <= m_filepara->max_y) + { + imx = m_filepara->max_x; + imy = (int)(m_conf.aspect_ratio * m_filepara->oy * m_filepara->max_x / m_filepara->ox); + } + else + { + imx = (int)((1.0/m_conf.aspect_ratio) * m_filepara->ox * m_filepara->max_y / m_filepara->oy); + imy = m_filepara->max_y; + } - if(cache) + if(m_conf.resizetype) + m_filepara->pic_buffer = color_resize(m_filepara->pic_buffer, m_filepara->ox, m_filepara->oy, imx, imy); + else + m_filepara->pic_buffer = simple_resize(m_filepara->pic_buffer, m_filepara->ox, m_filepara->oy, imx, imy); + + m_filepara->ox = imx; + m_filepara->oy = imy; +} + +void ePicLoad::gotMessage(const Message &msg) +{ + switch (msg.type) + { + case Message::decode_Pic: + decodePic(); + msg_main.send(Message(Message::decode_finished)); + break; + case Message::decode_Thumb: + decodeThumb(); + msg_main.send(Message(Message::decode_finished)); + break; + case Message::quit: // called from decode thread + eDebug("[Picload] decode thread ... got quit msg"); + quit(0); + break; + case Message::decode_finished: // called from main thread + //eDebug("[Picload] decode finished... %s", m_filepara->file); + if(m_filepara->callback) + { + PictureData(m_filepara->picinfo.c_str()); + } + else + { + if(m_filepara != NULL) + { + delete m_filepara; + m_filepara = NULL; + } + } + break; + default: + eDebug("unhandled thread message"); + } +} + +int ePicLoad::startThread(int what, const char *file, int x, int y) +{ + if(threadrunning && m_filepara != NULL) + { + eDebug("[Picload] thread running"); + m_filepara->callback = false; + return 1; + } + + if(m_filepara != NULL) + { + delete m_filepara; + m_filepara = NULL; + } + + int file_id = -1; + unsigned char id[10]; + int fd = ::open(file, O_RDONLY); + if (fd == -1) return 1; + ::read(fd, id, 10); + ::close(fd); + + if(id[1] == 'P' && id[2] == 'N' && id[3] == 'G') file_id = F_PNG; + else if(id[6] == 'J' && id[7] == 'F' && id[8] == 'I' && id[9] == 'F') file_id = F_JPEG; + else if(id[0] == 0xff && id[1] == 0xd8 && id[2] == 0xff) file_id = F_JPEG; + else if(id[0] == 'B' && id[1] == 'M' ) file_id = F_BMP; + else if(id[0] == 'G' && id[1] == 'I' && id[2] == 'F') file_id = F_GIF; + + if(file_id < 0) + { + eDebug("[Picload] "); + return 1; + } + + m_filepara = new Cfilepara(file, file_id, getSize(file)); + x > 0 ? m_filepara->max_x = x : m_filepara->max_x = m_conf.max_x; + y > 0 ? m_filepara->max_y = y : m_filepara->max_y = m_conf.max_y; + + if(m_filepara->max_x <= 0 || m_filepara->max_y <= 0) + { + delete m_filepara; + m_filepara = NULL; + eDebug("[Picload] "); + return 1; + } + + if(what==1) + msg_thread.send(Message(Message::decode_Pic)); + else + msg_thread.send(Message(Message::decode_Thumb)); + run(); + return 0; +} + +RESULT ePicLoad::startDecode(const char *file, int x, int y) +{ + return startThread(1, file, x, y); +} + +RESULT ePicLoad::getThumbnail(const char *file, int x, int y) +{ + return startThread(0, file, x, y); +} + +PyObject *ePicLoad::getInfo(const char *filename) +{ + ePyObject list; + + Cexif *exif = new Cexif; + if(exif->DecodeExif(filename)) + { + if(exif->m_exifinfo->IsExif) + { + char tmp[256]; + int pos=0; + list = PyList_New(23); + PyList_SET_ITEM(list, pos++, PyString_FromString(filename)); + PyList_SET_ITEM(list, pos++, PyString_FromString(exif->m_exifinfo->Version)); + PyList_SET_ITEM(list, pos++, PyString_FromString(exif->m_exifinfo->CameraMake)); + PyList_SET_ITEM(list, pos++, PyString_FromString(exif->m_exifinfo->CameraModel)); + PyList_SET_ITEM(list, pos++, PyString_FromString(exif->m_exifinfo->DateTime)); + PyList_SET_ITEM(list, pos++, PyString_FromFormat("%d x %d", exif->m_exifinfo->Width, exif->m_exifinfo->Height)); + PyList_SET_ITEM(list, pos++, PyString_FromString(exif->m_exifinfo->FlashUsed)); + PyList_SET_ITEM(list, pos++, PyString_FromString(exif->m_exifinfo->Orientation)); + PyList_SET_ITEM(list, pos++, PyString_FromString(exif->m_exifinfo->Comments)); + PyList_SET_ITEM(list, pos++, PyString_FromString(exif->m_exifinfo->MeteringMode)); + PyList_SET_ITEM(list, pos++, PyString_FromString(exif->m_exifinfo->ExposureProgram)); + PyList_SET_ITEM(list, pos++, PyString_FromString(exif->m_exifinfo->LightSource)); + PyList_SET_ITEM(list, pos++, PyString_FromFormat("%d", exif->m_exifinfo->CompressionLevel)); + PyList_SET_ITEM(list, pos++, PyString_FromFormat("%d", exif->m_exifinfo->ISOequivalent)); + sprintf(tmp, "%.2f", exif->m_exifinfo->Xresolution); + PyList_SET_ITEM(list, pos++, PyString_FromString(tmp)); + sprintf(tmp, "%.2f", exif->m_exifinfo->Yresolution); + PyList_SET_ITEM(list, pos++, PyString_FromString(tmp)); + PyList_SET_ITEM(list, pos++, PyString_FromString(exif->m_exifinfo->ResolutionUnit)); + sprintf(tmp, "%.2f", exif->m_exifinfo->Brightness); + PyList_SET_ITEM(list, pos++, PyString_FromString(tmp)); + sprintf(tmp, "%.5f sec.", exif->m_exifinfo->ExposureTime); + PyList_SET_ITEM(list, pos++, PyString_FromString(tmp)); + sprintf(tmp, "%.5f", exif->m_exifinfo->ExposureBias); + PyList_SET_ITEM(list, pos++, PyString_FromString(tmp)); + sprintf(tmp, "%.5f", exif->m_exifinfo->Distance); + PyList_SET_ITEM(list, pos++, PyString_FromString(tmp)); + sprintf(tmp, "%.5f", exif->m_exifinfo->CCDWidth); + PyList_SET_ITEM(list, pos++, PyString_FromString(tmp)); + sprintf(tmp, "%.2f", exif->m_exifinfo->ApertureFNumber); + PyList_SET_ITEM(list, pos++, PyString_FromString(tmp)); + } + else { - jpeg_save(pic_buffer, cachefile.c_str(), 50, oy, ox); - eDebug("[SAVEPIC] x-size=%d, y-size=%d", ox, oy); + list = PyList_New(2); + PyList_SET_ITEM(list, 0, PyString_FromString(filename)); + PyList_SET_ITEM(list, 1, PyString_FromString(exif->m_szLastError)); } - + exif->ClearExif(); } + else + { + list = PyList_New(2); + PyList_SET_ITEM(list, 0, PyString_FromString(filename)); + PyList_SET_ITEM(list, 1, PyString_FromString(exif->m_szLastError)); + } + delete exif; + return list ? (PyObject*)list : (PyObject*)PyList_New(0); +} + +int ePicLoad::getData(ePtr &result) +{ + result = 0; + if(m_filepara->pic_buffer == NULL) return 0; - result=new gPixmap(eSize(w, h), 32); + m_filepara->pic_buffer = conv24to32(m_filepara->pic_buffer, m_filepara->ox * m_filepara->oy); + + result=new gPixmap(eSize(m_filepara->max_x, m_filepara->max_y), 32); gSurface *surface = result->surface; int a=0, b=0; int nc=0, oc=0; int o_y=0, u_y=0, v_x=0, h_x=0; - unsigned char clear[4] = {0x00,0x00,0x00,0x00}; - if(background) clear[3]=0xFF; - unsigned char *tmp_buffer = new unsigned char[4]; - if(oy < h) + unsigned char *tmp_buffer=((unsigned char *)(surface->data)); + + if(m_filepara->oy < m_filepara->max_y) { - o_y=(h-oy)/2; - u_y=h-oy-o_y; + o_y = (m_filepara->max_y - m_filepara->oy) / 2; + u_y = m_filepara->max_y - m_filepara->oy - o_y; } - if(ox < w) + if(m_filepara->ox < m_filepara->max_x) { - v_x=(w-ox)/2; - h_x=w-ox-v_x; + v_x = (m_filepara->max_x - m_filepara->ox) / 2; + h_x = m_filepara->max_x - m_filepara->ox - v_x; } - //eDebug("o_y=%d u_y=%d v_x=%d h_x=%d", o_y, u_y, v_x, h_x); - - if(oy < h) - for(a=0; a<(o_y*ox)+1; a++, nc+=4) + if(m_filepara->oy < m_filepara->max_y) + { + for(a=0; a<(o_y*m_filepara->ox); a++, nc+=4) { - memcpy(tmp_buffer, clear, sizeof(clear)); tmp_buffer=((unsigned char *)(surface->data)) + nc; + memcpy(tmp_buffer, m_conf.background, sizeof(m_conf.background)); } + } - for(a=0; aoy; a++) { - if(ox < w) + if(m_filepara->ox < m_filepara->max_x) + { for(b=0; bdata)) + nc; + memcpy(tmp_buffer, m_conf.background, sizeof(m_conf.background)); } + } - for(b=0; b<(ox*3); b+=3, nc+=4) + for(b=0; b<(m_filepara->ox*4); b+=4, nc+=4) { - tmp_buffer[3]=0xFF; - tmp_buffer[2]=pic_buffer[oc++]; - tmp_buffer[1]=pic_buffer[oc++]; - tmp_buffer[0]=pic_buffer[oc++]; - tmp_buffer=((unsigned char *)(surface->data)) + nc; + tmp_buffer[2] = m_filepara->pic_buffer[oc++]; + tmp_buffer[1] = m_filepara->pic_buffer[oc++]; + tmp_buffer[0] = m_filepara->pic_buffer[oc++]; + tmp_buffer[3] = m_filepara->pic_buffer[oc++]; } - if(ox < w) + if(m_filepara->ox < m_filepara->max_x) + { for(b=0; bdata)) + nc; + memcpy(tmp_buffer, m_conf.background, sizeof(m_conf.background)); } + } } - - if(oy < h) - for(a=0; a<(u_y*ox)+1; a++, nc+=4) + + if(m_filepara->oy < m_filepara->max_y) + { + for(a=0; a<(u_y*m_filepara->ox); a++, nc+=4) { - memcpy(tmp_buffer, clear, sizeof(clear)); tmp_buffer=((unsigned char *)(surface->data)) + nc; + memcpy(tmp_buffer, m_conf.background, sizeof(m_conf.background)); } - - //eDebug("[PIC] buffer=%d, nc=%d oc=%d ox=%d, oy=%d",w*h*4, nc, oc, ox, oy); + } surface->clut.data=0; surface->clut.colors=0; surface->clut.start=0; + + delete m_filepara; + m_filepara = NULL; + + return 0; +} + +RESULT ePicLoad::setPara(PyObject *val) +{ + if (!PyList_Check(val)) + return 0; + if (PyList_Size(val) < 6) + return 0; + + m_conf.max_x = PyInt_AsLong( PyList_GET_ITEM(val, 0)); + m_conf.max_y = PyInt_AsLong( PyList_GET_ITEM(val, 1)); + m_conf.aspect_ratio = PyFloat_AsDouble( PyList_GET_ITEM(val, 2)); + m_conf.usecache = PyInt_AsLong( PyList_GET_ITEM(val, 3)); + m_conf.resizetype = PyInt_AsLong( PyList_GET_ITEM(val, 4)); + const char *bg_str = PyString_AsString( PyList_GET_ITEM(val, 5)); + + if(bg_str[0] == '#' && strlen(bg_str)==9) + { + int bg = strtoul(bg_str+1, NULL, 16); + m_conf.background[0] = bg&0xFF; //BB + m_conf.background[1] = (bg>>8)&0xFF; //GG + m_conf.background[2] = (bg>>16)&0xFF; //RR + m_conf.background[3] = bg>>24; //AA + } + + eDebug("[Picload] setPara max-X=%d max-Y=%d aspect_ratio=%lf cache=%d resize=%d bg=#%02X%02X%02X%02X", m_conf.max_x, m_conf.max_y, m_conf.aspect_ratio, (int)m_conf.usecache, (int)m_conf.resizetype, m_conf.background[3], m_conf.background[2], m_conf.background[1], m_conf.background[0]); + return 1; +} + +//------------------------------------------------------------------------------------ + +//for old plugins +SWIG_VOID(int) loadPic(ePtr &result, std::string filename, int x, int y, int aspect, int resize_mode, int rotate, int background, std::string cachefile) +{ + result = 0; + eDebug("deprecated loadPic function used!!! please use the non blocking version! you can see demo code in Pictureplayer plugin... this function is removed in the near future!"); + ePicLoad mPL; + + double aspect_ratio; + switch(aspect) + { + case 1: aspect_ratio = 1.778 / ((double)720/576); break; //16:9 + case 2: aspect_ratio = 1.600 / ((double)720/576); break; //16:10 + case 3: aspect_ratio = 1.250 / ((double)720/576); break; //5:4 + default: aspect_ratio = 1.333 / ((double)720/576); //4:3 + } - delete [] pic_buffer; + ePyObject list = PyList_New(6); + PyList_SET_ITEM(list, 0, PyLong_FromLong(x)); + PyList_SET_ITEM(list, 1, PyLong_FromLong(y)); + PyList_SET_ITEM(list, 2, PyFloat_FromDouble(aspect_ratio)); + PyList_SET_ITEM(list, 3, PyLong_FromLong(0)); + PyList_SET_ITEM(list, 4, PyLong_FromLong(resize_mode)); + if(background) + PyList_SET_ITEM(list, 5, PyString_FromString("#ff000000")); + else + PyList_SET_ITEM(list, 5, PyString_FromString("#00000000")); + + mPL.setPara(list); + + if(!mPL.startDecode(filename.c_str())) + { + mPL.waitFinished(); // this blocks until the thread is finished + mPL.getData(result); + } return 0; }