bool ZLEwlImageManager::convertImageDirect(const std::string &stringData, ZLImageData &data) const { unsigned char m0, m1; m0 = *(stringData.data()); m1 = *(stringData.data()+1); if((m0 == 0xff) && (m1 == 0xd8)) convertImageDirectJpeg(stringData, data); else if(!png_sig_cmp((unsigned char *)stringData.data(), (png_size_t)0, 4) ) convertImageDirectPng(stringData, data); else if(!strncmp(stringData.c_str(), "GIF", 3)) convertImageDirectGif(stringData, data); else if(!strncmp(stringData.c_str(), "BM", 2)) convertImageDirectBmp(stringData, data); else { /* printf("unsupported image format: %d %d\n", m0, m1); FILE *f; f = fopen("/tmp/unknown_img", "w+"); fwrite(stringData.data(), 1, stringData.length(), f); fclose(f); printf("image dumped to /tmp/unknown_img\n"); */ data.init(10, 10); bzero(((ZLEwlImageData&)data).getImageData(), 25); return false; } ZLIntegerOption myDitherAlgo(ZLCategoryKey::LOOK_AND_FEEL, "Options", "DitherAlgo", 0); if(myDitherAlgo.value() == 2) floyd_steinberg_dither(data); return true; }
void ZLEwlImageManager::convertImageDirectBmp(const std::string &stringData, ZLImageData &data) const { int xres, yres, w, h, spp, bps; const char *p = stringData.c_str(); BMPFileHeader file_hdr; BMPInfoHeader info_hdr; enum BMPType bmp_type; uint32 clr_tbl_size, n_clr_elems = 3; unsigned char *clr_tbl; uint32 row, stride; unsigned char* xdata = 0; ZLIntegerOption myDitherAlgo(ZLCategoryKey::LOOK_AND_FEEL, "Options", "DitherAlgo", 0); register int dalgo = myDitherAlgo.value(); memcpy(file_hdr.bType, p, 2); if(file_hdr.bType[0] != 'B' || file_hdr.bType[1] != 'M') { fprintf(stderr, "File is not a BMP\n"); goto bad; } /* -------------------------------------------------------------------- */ /* Read the BMPFileHeader. We need iOffBits value only */ /* -------------------------------------------------------------------- */ memcpy(&file_hdr.iOffBits, p+10, 4); file_hdr.iSize = stringData.length(); /* -------------------------------------------------------------------- */ /* Read the BMPInfoHeader. */ /* -------------------------------------------------------------------- */ memcpy(&info_hdr.iSize, p+BFH_SIZE, 4); if (info_hdr.iSize == BIH_WIN4SIZE) bmp_type = BMPT_WIN4; else if (info_hdr.iSize == BIH_OS21SIZE) bmp_type = BMPT_OS21; else if (info_hdr.iSize == BIH_OS22SIZE || info_hdr.iSize == 16) bmp_type = BMPT_OS22; else bmp_type = BMPT_WIN5; if (bmp_type == BMPT_WIN4 || bmp_type == BMPT_WIN5 || bmp_type == BMPT_OS22) { p = stringData.c_str() + BFH_SIZE + 4; memcpy(&info_hdr.iWidth, p, 4); p += 4; memcpy(&info_hdr.iHeight, p, 4); p += 4; memcpy(&info_hdr.iPlanes, p, 2); p += 2; memcpy(&info_hdr.iBitCount, p, 2); p += 2; memcpy(&info_hdr.iCompression, p, 4); p += 4; memcpy(&info_hdr.iSizeImage, p, 4); p += 4; memcpy(&info_hdr.iXPelsPerMeter, p, 4); p += 4; memcpy(&info_hdr.iYPelsPerMeter, p, 4); p += 4; memcpy(&info_hdr.iClrUsed, p, 4); p += 4; memcpy(&info_hdr.iClrImportant, p, 4); p += 4; memcpy(&info_hdr.iRedMask, p, 4); p += 4; memcpy(&info_hdr.iGreenMask, p, 4); p += 4; memcpy(&info_hdr.iBlueMask, p, 4); p += 4; memcpy(&info_hdr.iAlphaMask, p, 4); p += 4; n_clr_elems = 4; xres = ((double)info_hdr.iXPelsPerMeter * 2.54 + 0.05) / 100; yres = ((double)info_hdr.iYPelsPerMeter * 2.54 + 0.05) / 100; } if (bmp_type == BMPT_OS22) { /* * FIXME: different info in different documents * regarding this! */ n_clr_elems = 3; } if (bmp_type == BMPT_OS21) { int16 iShort; memcpy(&iShort, p, 2); p += 2; info_hdr.iWidth = iShort; memcpy(&iShort, p, 2); p += 2; info_hdr.iHeight = iShort; memcpy(&iShort, p, 2); p += 2; info_hdr.iPlanes = iShort; memcpy(&iShort, p, 2); p += 2; info_hdr.iBitCount = iShort; info_hdr.iCompression = BMPC_RGB; n_clr_elems = 3; } if (info_hdr.iBitCount != 1 && info_hdr.iBitCount != 4 && info_hdr.iBitCount != 8 && info_hdr.iBitCount != 16 && info_hdr.iBitCount != 24 && info_hdr.iBitCount != 32) { fprintf(stderr, "Cannot process BMP file with bit count %d\n", info_hdr.iBitCount); // close(fd); return; } w = info_hdr.iWidth; h = (info_hdr.iHeight > 0) ? info_hdr.iHeight : -info_hdr.iHeight; data.init(w, h); switch (info_hdr.iBitCount) { case 1: case 4: case 8: spp = 1; bps = info_hdr.iBitCount; /* Allocate memory for colour table and read it. */ if (info_hdr.iClrUsed) clr_tbl_size = ((uint32)(1 << bps) < info_hdr.iClrUsed) ? 1 << bps : info_hdr.iClrUsed; else clr_tbl_size = 1 << bps; clr_tbl = (unsigned char *) _TIFFmalloc(n_clr_elems * clr_tbl_size); if (!clr_tbl) { fprintf(stderr, "Can't allocate space for color table\n"); goto bad; } /*printf ("n_clr_elems: %d, clr_tbl_size: %d\n", n_clr_elems, clr_tbl_size); */ p = stringData.c_str() + BFH_SIZE + info_hdr.iSize; memcpy(clr_tbl, p, n_clr_elems * clr_tbl_size); /*for(clr = 0; clr < clr_tbl_size; ++clr) { printf ("%d: r: %d g: %d b: %d\n", clr, clr_tbl[clr*n_clr_elems+2], clr_tbl[clr*n_clr_elems+1], clr_tbl[clr*n_clr_elems]); }*/ break; case 16: case 24: spp = 3; bps = info_hdr.iBitCount / spp; break; case 32: spp = 3; bps = 8; break; default: break; } stride = (w * spp * bps + 7) / 8; /*printf ("w: %d, h: %d, spp: %d, bps: %d, colorspace: %d\n", *w, *h, *spp, *bps, info_hdr.iCompression); */ // detect old style bitmask images if (info_hdr.iCompression == BMPC_RGB && info_hdr.iBitCount == 16) { /*printf ("implicit non-RGB image\n"); */ info_hdr.iCompression = BMPC_BITFIELDS; info_hdr.iBlueMask = 0x1f; info_hdr.iGreenMask = 0x1f << 5; info_hdr.iRedMask = 0x1f << 10; } /* -------------------------------------------------------------------- */ /* Read uncompressed image data. */ /* -------------------------------------------------------------------- */ switch (info_hdr.iCompression) { case BMPC_BITFIELDS: // we convert those to RGB for easier use bps = 8; stride = (w * spp * bps + 7) / 8; case BMPC_RGB: { uint32 file_stride = ((w * info_hdr.iBitCount + 7) / 8 + 3) / 4 * 4; /*printf ("bitcount: %d, stride: %d, file stride: %d\n", info_hdr.iBitCount, stride, file_stride); printf ("red mask: %x, green mask: %x, blue mask: %x\n", info_hdr.iRedMask, info_hdr.iGreenMask, info_hdr.iBlueMask); */ xdata = (unsigned char*)_TIFFmalloc (stride * h); if (!xdata) { fprintf(stderr, "Can't allocate space for image buffer\n"); goto bad1; } for (row = 0; row < (unsigned)h; row++) { uint32 offset; if (info_hdr.iHeight > 0) offset = file_hdr.iOffBits + (h - row - 1) * file_stride; else offset = file_hdr.iOffBits + row * file_stride; // if (lseek(fd, offset, SEEK_SET) == (off_t)-1) { // fprintf(stderr, "scanline %lu: Seek error\n", (unsigned long) row); // } p = stringData.c_str() + offset; memcpy(xdata + stride*row, p, stride); // convert to RGB if (info_hdr.iCompression == BMPC_BITFIELDS) { unsigned char* row_ptr = xdata + stride*row; unsigned char* r16_ptr = row_ptr + file_stride - 2; unsigned char* rgb_ptr = row_ptr + stride - 3; int r_shift = last_bit_set (info_hdr.iRedMask) - 7; int g_shift = last_bit_set (info_hdr.iGreenMask) - 7; int b_shift = last_bit_set (info_hdr.iBlueMask) - 7; char *c = ((ZLEwlImageData&)data).getImageData() + w * row; for (int i=0 ; rgb_ptr >= row_ptr; r16_ptr -= 2, rgb_ptr -= 3, i++) { int val = (r16_ptr[0] << 0) + (r16_ptr[1] << 8); if (r_shift > 0) rgb_ptr[0] = (val & info_hdr.iRedMask) >> r_shift; else rgb_ptr[0] = (val & info_hdr.iRedMask) << -r_shift; if (g_shift > 0) rgb_ptr[1] = (val & info_hdr.iGreenMask) >> g_shift; else rgb_ptr[1] = (val & info_hdr.iGreenMask) << -g_shift; if (b_shift > 0) rgb_ptr[2] = (val & info_hdr.iBlueMask) >> b_shift; else rgb_ptr[2] = (val & info_hdr.iBlueMask) << -b_shift; unsigned char x = rgb_ptr[0] * 0.299 + rgb_ptr[1] * 0.587 + rgb_ptr[2] * 0.114; if(dalgo == 1) *c++ = Dither2BitColor(x, i, row); else *c++ = x; } }
void ZLEwlImageManager::convertImageDirectGif(const std::string &stringData, ZLImageData &data) const { static std::map<std::string, ImageData> imgCache; if(stringData.length() < 300) { std::map<std::string, ImageData>::const_iterator it = imgCache.find(stringData); if(it != imgCache.end()) { data.init(it->second.w, it->second.h); memcpy(((ZLEwlImageData&)data).getImageData(), it->second.d, it->second.len); return; } } GifFileType *GifFile; struct gif_info gi; gi.length = stringData.length(); gi.cpos = 0; gi.data = stringData.c_str(); if((GifFile = DGifOpen((void*)&gi, readGif)) == NULL) { data.init(10,10); bzero(((ZLEwlImageData&)data).getImageData(), 25); return; } data.init(GifFile->SWidth, GifFile->SHeight); int ColorMapSize = 0, BackGround = 0, InterlacedOffset[] = { 0, 4, 2, 1 }, /* The way Interlaced image should. */ InterlacedJumps[] = { 8, 8, 4, 2 }; /* be read - offsets and jumps... */ int i, j, Size, Row, Col, Width, Height, ExtCode, Count; GifRecordType RecordType; GifByteType *Extension; GifRowType *ScreenBuffer; ColorMapObject *ColorMap; ScreenBuffer = (GifRowType *) malloc(GifFile->SHeight * sizeof(GifRowType *)); Size = GifFile->SWidth * sizeof(GifPixelType);/* Size in bytes one row.*/ ScreenBuffer[0] = (GifRowType) malloc(Size); /* First row. */ for (i = 0; i < GifFile->SWidth; i++) /* Set its color to BackGround. */ ScreenBuffer[0][i] = GifFile->SBackGroundColor; for (i = 1; i < GifFile->SHeight; i++) { /* Allocate the other rows, and set their color to background too: */ ScreenBuffer[i] = (GifRowType) malloc(Size); memcpy(ScreenBuffer[i], ScreenBuffer[0], Size); } do { if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) { memset(((ZLEwlImageData&)data).getImageData(), 0x02, GifFile->SWidth * GifFile->SHeight / 4); DGifCloseFile(GifFile); return; } if(RecordType == EXTENSION_RECORD_TYPE) { /* Skip any extension blocks in file: */ if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR) { break; } /* printf("%d\n", *Extension); if(ExtCode == GRAPHICS_EXT_FUNC_CODE) if(Extension[0] == 4 ) { int flag = Extension[1]; transparent = (flag & 0x1) ? Extension[4] : -1; } */ while (Extension != NULL) { if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) { break; } /* printf("ExtCode: %d, %d\n", ExtCode, GRAPHICS_EXT_FUNC_CODE); if(ExtCode == GRAPHICS_EXT_FUNC_CODE) if(Extension[0] == 4 ) { int flag = Extension[1]; transparent = (flag & 0x1) ? Extension[4] : -1; } */ } } } while((RecordType != IMAGE_DESC_RECORD_TYPE) && (RecordType != TERMINATE_RECORD_TYPE)); DGifGetImageDesc(GifFile); Row = GifFile->Image.Top; /* Image Position relative to Screen. */ Col = GifFile->Image.Left; Width = GifFile->Image.Width; Height = GifFile->Image.Height; if (GifFile->Image.Interlace) { /* Need to perform 4 passes on the images: */ for (Count = i = 0; i < 4; i++) for (j = Row + InterlacedOffset[i]; j < Row + Height; j += InterlacedJumps[i]) DGifGetLine(GifFile, &ScreenBuffer[j][Col], Width); } else for (i = 0; i < Height; i++) DGifGetLine(GifFile, &ScreenBuffer[Row++][Col], Width); /* Lets display it - set the global variables required and do it: */ BackGround = GifFile->SBackGroundColor; ColorMap = (GifFile->Image.ColorMap ? GifFile->Image.ColorMap : GifFile->SColorMap); ColorMapSize = ColorMap->ColorCount; char *c; int p; GifColorType *ColorMapEntry = ColorMap->Colors; /* Let find out what are the intensities in the color map: */ /* int MinIntensity, MaxIntensity, AvgIntensity; unsigned long ValueMask; MinIntensity = 256 * 100; for (i = 0; i < ColorMapSize; i++) { p = ColorMapEntry[i].Red * 30 + ColorMapEntry[i].Green * 59 + ColorMapEntry[i].Blue * 11; if (p > MaxIntensity) MaxIntensity = p; if (p < MinIntensity) MinIntensity = p; } AvgIntensity = (MinIntensity + MaxIntensity) / 2; */ Width = GifFile->SWidth; Height = GifFile->SHeight; ZLIntegerOption myDitherAlgo(ZLCategoryKey::LOOK_AND_FEEL, "Options", "DitherAlgo", 0); register int dalgo = myDitherAlgo.value(); for (j = 0; j < Height; j++) { c = ((ZLEwlImageData&)data).getImageData() + Width * j; for (i = 0; i < Width; i++) { p = ScreenBuffer[j][i]; // p = ColorMapEntry[p].Red * 30 + // ColorMapEntry[p].Green * 59 + // ColorMapEntry[p].Blue * 11 > AvgIntensity; unsigned char x = ColorMapEntry[p].Red * 0.299 + ColorMapEntry[p].Green * 0.587 + ColorMapEntry[p].Blue * 0.114; if(dalgo == 1) *c++ = Dither2BitColor(x, i, j); else *c++ = x; } } if(stringData.length() < 300) { ImageData id; id.w = Width; id.h = Height; id.len = Width * Height; id.d = (char*)malloc(Width * Height); memcpy(id.d, ((ZLEwlImageData&)data).getImageData(), id.len); imgCache.insert(std::pair<std::string, ImageData>(stringData, id)); } for (i = GifFile->SHeight - 1 ; i >= 0 ; i--) free( ScreenBuffer[ i ] ); free( ScreenBuffer ); DGifCloseFile(GifFile); }
void ZLEwlImageManager::convertImageDirectPng(const std::string &stringData, ZLImageData &data) const { struct s_my_png my_png; my_png.p = (char*)stringData.data(); my_png.size = stringData.length(); png_structp png_ptr = NULL; png_infop info_ptr = NULL; unsigned int *row = NULL; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)&my_png, mypng_error_func, mypng_warning_func); if ( !png_ptr ) return; if (setjmp( png_ptr->jmpbuf )) { data.init(0, 0); if (png_ptr) { png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); } if ( row ) delete row; return; } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) mypng_error_func(png_ptr, "cannot create png info struct"); png_set_read_fn(png_ptr, (voidp)&my_png, mypng_read_func); png_read_info( png_ptr, info_ptr ); png_uint_32 width, height; int bit_depth, color_type, interlace_type; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); data.init(width, height); row = new unsigned int[ width ]; // SET TRANSFORMS if (color_type & PNG_COLOR_MASK_PALETTE) png_set_palette_to_rgb(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_gray_1_2_4_to_8(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); if (bit_depth == 16) png_set_strip_16(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_invert_alpha(png_ptr); } else { png_color_16 bg = {0, 0xffff, 0xffff, 0xffff, 0xffff}; png_set_background(png_ptr, &bg, PNG_BACKGROUND_GAMMA_SCREEN, 0, 0.0); png_set_strip_alpha(png_ptr); } if (bit_depth < 8) png_set_packing(png_ptr); //if (color_type == PNG_COLOR_TYPE_RGB) //png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); //if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) // png_set_swap_alpha(png_ptr); if (! (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) png_set_rgb_to_gray(png_ptr, 1, -1, -1); int number_passes = png_set_interlace_handling(png_ptr); //if (color_type == PNG_COLOR_TYPE_RGB_ALPHA || // color_type == PNG_COLOR_TYPE_GRAY_ALPHA) //if (color_type == PNG_COLOR_TYPE_RGB || // color_type == PNG_COLOR_TYPE_RGB_ALPHA) png_set_bgr(png_ptr); ZLIntegerOption myDitherAlgo(ZLCategoryKey::LOOK_AND_FEEL, "Options", "DitherAlgo", 0); register int dalgo = myDitherAlgo.value(); char *c; for(int pass = 0; pass < number_passes; pass++) { for(unsigned int y = 0; y < height; y++) { png_read_rows(png_ptr, (unsigned char **)&row, png_bytepp_NULL, 1); c = ((ZLEwlImageData&)data).getImageData() + width * y; if ((color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) { unsigned char *s = (unsigned char*)row; if(dalgo == 1) for(unsigned int i = 0; i < width; i++) *c++ = Dither2BitColor(*(++s)++, i, y); else for(unsigned int i = 0; i < width; i++) *c++ = *(++s)++; } else if(dalgo == 1) { unsigned char *s = (unsigned char*)row; for(unsigned int i = 0; i < width; i++) *c++ = Dither2BitColor(*s++, i, y); } else memcpy(c, (char*)row, width); } } png_read_end(png_ptr, info_ptr); png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); }
void ZLEwlImageManager::convertImageDirectJpeg(const std::string &stringData, ZLImageData &data) const { struct jpeg_decompress_struct cinfo; JSAMPARRAY buffer; /* Output row buffer */ int row_stride; /* physical row width in output buffer */ struct my_error_mgr jerr; jpeg_create_decompress(&cinfo); jpeg_error_mgr errmgr; cinfo.err = jpeg_std_error(&errmgr); errmgr.error_exit = my_jpeg_error; /* Establish the setjmp return context for my_error_exit to use. */ if (setjmp(jerr.setjmp_buffer)) { /* If we get here, the JPEG code has signaled an error. * We need to clean up the JPEG object, close the input file, and return. */ my_jpeg_src_free (&cinfo); jpeg_destroy_decompress(&cinfo); return; } my_jpeg_source_mgr *src; src = (my_jpeg_source_mgr *) new my_jpeg_source_mgr; cinfo.src = (struct jpeg_source_mgr *) src; src->len = stringData.length() + 2; src->buffer = new JOCTET[src->len]; memcpy(src->buffer, (const unsigned char*)stringData.data(), stringData.length()); src->buffer[stringData.length()] = (JOCTET) 0xFF; src->buffer[stringData.length() + 1] = (JOCTET) JPEG_EOI; src->pub.init_source = my_init_source; src->pub.fill_input_buffer = my_fill_input_buffer; src->pub.skip_input_data = my_skip_input_data; src->pub.resync_to_restart = my_resync_to_restart; src->pub.term_source = my_term_source; src->pub.bytes_in_buffer = src->len; src->pub.next_input_byte = src->buffer; (void) jpeg_read_header(&cinfo, true); data.init(cinfo.image_width, cinfo.image_height); cinfo.out_color_space = JCS_GRAYSCALE; (void) jpeg_start_decompress(&cinfo); row_stride = cinfo.output_width * cinfo.output_components; buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); ZLIntegerOption myDitherAlgo(ZLCategoryKey::LOOK_AND_FEEL, "Options", "DitherAlgo", 0); register int dalgo = myDitherAlgo.value(); char *c; while (cinfo.output_scanline < cinfo.output_height) { (void) jpeg_read_scanlines(&cinfo, buffer, 1); c = ((ZLEwlImageData&)data).getImageData() + cinfo.output_width * (cinfo.output_scanline - 1); if(dalgo == 1) { unsigned char *s = (unsigned char*)buffer[0]; for(unsigned int i = 0; i < cinfo.output_width; i++) *c++ = Dither2BitColor(*s++, i, cinfo.output_scanline - 1); } else memcpy(c, (char*)buffer[0], cinfo.output_width); } (void) jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); }