void NVTTProcessor::compress(osg::Image& image, osg::Texture::InternalFormatMode compressedFormat, bool generateMipMap, bool resizeToPowerOfTwo, CompressionMethod method, CompressionQuality quality) { nvtt::Format format; switch (compressedFormat) { case osg::Texture::USE_S3TC_DXT1_COMPRESSION: if (image.getPixelFormat() == GL_RGBA) format = nvtt::Format_DXT1a; else format = nvtt::Format_DXT1; break; case osg::Texture::USE_S3TC_DXT1c_COMPRESSION: format = nvtt::Format_DXT1; break; case osg::Texture::USE_S3TC_DXT1a_COMPRESSION: format = nvtt::Format_DXT1a; break; case osg::Texture::USE_S3TC_DXT3_COMPRESSION: format = nvtt::Format_DXT3; break; case osg::Texture::USE_S3TC_DXT5_COMPRESSION: format = nvtt::Format_DXT5; break; default: OSG_WARN<<" Invalid or not supported compress format"<<std::endl; return; } process( image, format, generateMipMap, resizeToPowerOfTwo, method, quality ); }
void operator()(const osg::Image& image, const unsigned int) { frame_id++; QImage::Format qtFormat; if (image.getPixelFormat() == GL_BGR) qtFormat = QImage::Format_RGB888; else if (image.getPixelFormat() == GL_BGRA) qtFormat = QImage::Format_ARGB32; else if (image.getPixelFormat() == GL_RGB) qtFormat = QImage::Format_RGB888; else if (image.getPixelFormat() == GL_RGBA) qtFormat = QImage::Format_ARGB32; else throw std::runtime_error("cannot interpret osg-provided image format " + boost::lexical_cast<std::string>(image.getPixelFormat())); this->image = QImage(image.data(), image.s(), image.t(), qtFormat); }
virtual WriteResult writeImage(const osg::Image& image,const std::string& fileName, const osgDB::ReaderWriter::Options* options) const { // Only ppm format output supported std::string ext = osgDB::getFileExtension(fileName); if ( !osgDB::equalCaseInsensitive(ext, "ppm") ) return WriteResult::FILE_NOT_HANDLED; // only support rgb images right now. if (image.getPixelFormat()!=GL_RGB || image.getDataType()!=GL_UNSIGNED_BYTE) return WriteResult("Error image pixel format not supported by pnm writer."); osgDB::ofstream fout(fileName.c_str(), std::ios::out | std::ios::binary); if(!fout) return WriteResult::ERROR_IN_WRITING_FILE; return writeImage(image,fout,options); }
virtual WriteResult writeImage(const osg::Image &img, const std::string &fileName, const osgDB::ReaderWriter::Options *options) const { std::string ext = osgDB::getFileExtension(fileName); if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED; int internalFormat = osg::Image::computeNumComponents(img.getPixelFormat()); osgDB::ofstream f(fileName.c_str(), std::ios_base::out | std::ios_base::binary | std::ios_base::trunc); if (!f) return WriteResult::ERROR_IN_WRITING_FILE; return writeImage(img, f, options); }
WriteResult writeImage(const osg::Image &img, std::ostream &fout, const Options *options) const { int internalFormat = osg::Image::computeNumComponents(img.getPixelFormat()); WebPConfig config; config.quality = 75; config.method = 2; if (options) { std::istringstream iss(options->getOptionString()); std::string opt; while (iss >> opt) { if (strcmp(opt.c_str(), "lossless") == 0) { config.lossless = 1; config.quality = 100; } else if (strcmp(opt.c_str(), "hint") == 0) { std::string v; iss >> v; if (strcmp(v.c_str(), "picture") == 0) { config.image_hint = WEBP_HINT_PICTURE; } else if (strcmp(v.c_str(), "photo") == 0) { config.image_hint = WEBP_HINT_PHOTO; } else if (strcmp(v.c_str(), "graph") == 0) { config.image_hint = WEBP_HINT_GRAPH; } } else if (strcmp(opt.c_str(), "quality") == 0) { float v; iss >> v; if (v >= 0.0 && v <= 100.0) { config.quality = v; } }
/* Create a CGImageRef from osg::Image. * Code adapted from * http://developer.apple.com/samplecode/OpenGLScreenSnapshot/listing2.html */ CGImageRef CreateCGImageFromOSGData(const osg::Image& osg_image) { size_t image_width = osg_image.s(); size_t image_height = osg_image.t(); /* From Apple's header for CGBitmapContextCreate() * Each row of the bitmap consists of `bytesPerRow' bytes, which must be at * least `(width * bitsPerComponent * number of components + 7)/8' bytes. */ size_t target_bytes_per_row; CGColorSpaceRef color_space; CGBitmapInfo bitmap_info; /* From what I can figure out so far... * We need to create a CGContext connected to the data we want to save * and then call CGBitmapContextCreateImage() on that context to get * a CGImageRef. * However, OS X only allows 4-component image formats (e.g. RGBA) and not * just RGB for the RGB-based CGContext. So for a 24-bit image coming in, * we need to expand the data to 32-bit. * The easiest and fastest way to do that is through the vImage framework * which is part of the Accelerate framework. * Also, the osg::Image data coming in is inverted from what we want, so * we need to invert the image too. Since the osg::Image is const, * we don't want to touch the data, so again we turn to the vImage framework * and invert the data. */ vImage_Buffer vimage_buffer_in = { (void*)osg_image.data(), // need to override const, but we don't modify the data so it's safe image_height, image_width, osg_image.getRowSizeInBytes() }; void* out_image_data; vImage_Buffer vimage_buffer_out = { NULL, // will fill-in in switch image_height, image_width, 0 // will fill-in in switch }; vImage_Error vimage_error_flag; // FIXME: Do I want to use format, type, or internalFormat? switch(osg_image.getPixelFormat()) { case GL_LUMINANCE: { bitmap_info = kCGImageAlphaNone; target_bytes_per_row = (image_width * 8 + 7)/8; //color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray); color_space = CGColorSpaceCreateDeviceGray(); if(NULL == color_space) { return NULL; } // out_image_data = calloc(target_bytes_per_row, image_height); out_image_data = malloc(target_bytes_per_row * image_height); if(NULL == out_image_data) { OSG_WARN << "In CreateCGImageFromOSGData, malloc failed" << std::endl; CGColorSpaceRelease(color_space); return NULL; } vimage_buffer_out.data = out_image_data; vimage_buffer_out.rowBytes = target_bytes_per_row; // Now invert the image vimage_error_flag = vImageVerticalReflect_Planar8( &vimage_buffer_in, // since the osg_image is const... &vimage_buffer_out, // don't reuse the buffer kvImageNoFlags ); if(vimage_error_flag != kvImageNoError) { OSG_WARN << "In CreateCGImageFromOSGData for GL_LUMINANCE, vImageVerticalReflect_Planar8 failed with vImage Error Code: " << vimage_error_flag << std::endl; free(out_image_data); CGColorSpaceRelease(color_space); return NULL; } break; } case GL_ALPHA: { bitmap_info = kCGImageAlphaOnly; target_bytes_per_row = (image_width * 8 + 7)/8; // According to: // http://developer.apple.com/qa/qa2001/qa1037.html // colorSpace=NULL is for alpha only color_space = NULL; // out_image_data = calloc(target_bytes_per_row, image_height); out_image_data = malloc(target_bytes_per_row * image_height); if(NULL == out_image_data) { OSG_WARN << "In CreateCGImageFromOSGData, malloc failed" << std::endl; return NULL; } vimage_buffer_out.data = out_image_data; vimage_buffer_out.rowBytes = target_bytes_per_row; // Now invert the image vimage_error_flag = vImageVerticalReflect_Planar8( &vimage_buffer_in, // since the osg_image is const... &vimage_buffer_out, // don't reuse the buffer kvImageNoFlags ); if(vimage_error_flag != kvImageNoError) { OSG_WARN << "In CreateCGImageFromOSGData for GL_ALPHA, vImageVerticalReflect_Planar8 failed with vImage Error Code: " << vimage_error_flag << std::endl; free(out_image_data); return NULL; } break; } /* case GL_LUMINANCE_ALPHA: { // I don't know if we can support this. // The qa1037 doesn't show both gray+alpha. break; } */ case GL_RGB: { bitmap_info = kCGImageAlphaNoneSkipFirst; target_bytes_per_row = (image_width * 8 * 4 + 7)/8; //color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); color_space = CGColorSpaceCreateDeviceRGB(); if(NULL == color_space) { OSG_WARN << "In CreateCGImageFromOSGData, CGColorSpaceCreateWithName failed" << std::endl; return NULL; } // out_image_data = calloc(target_bytes_per_row, image_height); out_image_data = malloc(target_bytes_per_row * image_height); if(NULL == out_image_data) { OSG_WARN << "In CreateCGImageFromOSGData, malloc failed" << std::endl; CGColorSpaceRelease(color_space); return NULL; } // Use vImage to get an RGB buffer into ARGB. vimage_buffer_out.data = out_image_data; vimage_buffer_out.rowBytes = target_bytes_per_row; vimage_error_flag = vImageConvert_RGB888toARGB8888( &vimage_buffer_in, NULL, // we don't have a buffer containing alpha values 255, // The alpha value we want given to all pixels since we don't have a buffer &vimage_buffer_out, 0, // premultiply? kvImageNoFlags // Only responds to kvImageDoNotTile, but I think we want tiling/threading ); if(vimage_error_flag != kvImageNoError) { OSG_WARN << "In CreateCGImageFromOSGData, vImageConvert_RGB888toARGB8888 failed with vImage Error Code: " << vimage_error_flag << std::endl; free(out_image_data); CGColorSpaceRelease(color_space); return NULL; } // Now invert the image vimage_error_flag = vImageVerticalReflect_ARGB8888( &vimage_buffer_out, &vimage_buffer_out, // reuse the same buffer kvImageNoFlags ); if(vimage_error_flag != kvImageNoError) { OSG_WARN << "In CreateCGImageFromOSGData, vImageAffineWarp_ARGB8888 failed with vImage Error Code: " << vimage_error_flag << std::endl; free(out_image_data); CGColorSpaceRelease(color_space); return NULL; } break; } case GL_RGBA: { bitmap_info = kCGImageAlphaPremultipliedLast; target_bytes_per_row = osg_image.getRowSizeInBytes(); //color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); color_space = CGColorSpaceCreateDeviceRGB(); if(NULL == color_space) { OSG_WARN << "In CreateCGImageFromOSGData, CGColorSpaceCreateWithName failed" << std::endl; return NULL; } // out_image_data = calloc(target_bytes_per_row, image_height); out_image_data = malloc(target_bytes_per_row * image_height); if(NULL == out_image_data) { OSG_WARN << "In CreateCGImageFromOSGData, malloc failed" << std::endl; CGColorSpaceRelease(color_space); return NULL; } vimage_buffer_out.data = out_image_data; vimage_buffer_out.rowBytes = target_bytes_per_row; // Invert the image vimage_error_flag = vImageVerticalReflect_ARGB8888( &vimage_buffer_in, // since the osg_image is const... &vimage_buffer_out, // don't reuse the buffer kvImageNoFlags ); if(vimage_error_flag != kvImageNoError) { OSG_WARN << "In CreateCGImageFromOSGData, vImageAffineWarp_ARGB8888 failed with vImage Error Code: " << vimage_error_flag << std::endl; free(out_image_data); CGColorSpaceRelease(color_space); return NULL; } break; } case GL_BGRA: { if(GL_UNSIGNED_INT_8_8_8_8_REV == osg_image.getDataType()) { #if __BIG_ENDIAN__ bitmap_info = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big; /* XRGB Big Endian */ #else bitmap_info = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little; /* XRGB Little Endian */ #endif } else { // FIXME: Don't know how to handle this case bitmap_info = kCGImageAlphaPremultipliedLast; } target_bytes_per_row = osg_image.getRowSizeInBytes(); //color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); color_space = CGColorSpaceCreateDeviceRGB(); if(NULL == color_space) { OSG_WARN << "In CreateCGImageFromOSGData, CGColorSpaceCreateWithName failed" << std::endl; return NULL; } // out_image_data = calloc(target_bytes_per_row, image_height); out_image_data = malloc(target_bytes_per_row * image_height); if(NULL == out_image_data) { OSG_WARN << "In CreateCGImageFromOSGData, malloc failed" << std::endl; CGColorSpaceRelease(color_space); return NULL; } vimage_buffer_out.data = out_image_data; vimage_buffer_out.rowBytes = target_bytes_per_row; // Invert the image vimage_error_flag = vImageVerticalReflect_ARGB8888( &vimage_buffer_in, // since the osg_image is const... &vimage_buffer_out, // don't reuse the buffer kvImageNoFlags ); if(vimage_error_flag != kvImageNoError) { OSG_WARN << "In CreateCGImageFromOSGData, vImageAffineWarp_ARGB8888 failed with vImage Error Code: " << vimage_error_flag << std::endl; free(out_image_data); CGColorSpaceRelease(color_space); return NULL; } break; } // FIXME: Handle other cases. // Use vImagePermuteChannels_ARGB8888 to swizzle bytes default: { OSG_WARN << "In CreateCGImageFromOSGData: Sorry support for this format is not implemented." << std::endl; return NULL; break; } } CGContextRef bitmap_context = CGBitmapContextCreate( vimage_buffer_out.data, vimage_buffer_out.width, vimage_buffer_out.height, 8, vimage_buffer_out.rowBytes, color_space, bitmap_info ); /* Done with color space */ CGColorSpaceRelease(color_space); if(NULL == bitmap_context) { free(out_image_data); return NULL; } /* Make an image out of our bitmap; does a cheap vm_copy of the bitmap */ CGImageRef image_ref = CGBitmapContextCreateImage(bitmap_context); /* Done with data */ free(out_image_data); /* Done with bitmap_context */ CGContextRelease(bitmap_context); return image_ref; }
WriteResult::WriteStatus writeTIFStream(std::ostream& fout, const osg::Image& img, const osgDB::ReaderWriter::Options* options) const { int compressionType = COMPRESSION_PACKBITS; if (options) { std::istringstream iss(options->getOptionString()); std::string opt; while (iss >> opt) { opt = osgDB::convertToLowerCase(opt); std::size_t eqInd = opt.find("="); if (opt.substr(0, eqInd) == "tiff_compression") { std::string compressTypeOpt; compressTypeOpt = opt.substr(eqInd + 1); compressTypeOpt = osgDB::convertToLowerCase(compressTypeOpt); if (compressTypeOpt == "packbits") { compressionType = COMPRESSION_PACKBITS; } else if (compressTypeOpt == "lzw") { compressionType = COMPRESSION_LZW; } else if (compressTypeOpt == "jpeg") { compressionType = COMPRESSION_JPEG; } } } } //Code is based from the following article on CodeProject.com //http://www.codeproject.com/bitmap/BitmapsToTiffs.asp TIFF *image; int samplesPerPixel; int bitsPerSample; uint16 photometric; image = TIFFClientOpen("outputstream", "w", (thandle_t)&fout, libtiffOStreamReadProc, //Custom read function libtiffOStreamWriteProc, //Custom write function libtiffOStreamSeekProc, //Custom seek function libtiffStreamCloseProc, //Custom close function libtiffOStreamSizeProc, //Custom size function libtiffStreamMapProc, //Custom map function libtiffStreamUnmapProc); //Custom unmap function if(image == NULL) { return WriteResult::ERROR_IN_WRITING_FILE; } switch(img.getPixelFormat()) { case GL_DEPTH_COMPONENT: case GL_LUMINANCE: case GL_ALPHA: photometric = PHOTOMETRIC_MINISBLACK; samplesPerPixel = 1; break; case GL_LUMINANCE_ALPHA: photometric = PHOTOMETRIC_MINISBLACK; samplesPerPixel = 2; break; case GL_RGB: photometric = PHOTOMETRIC_RGB; samplesPerPixel = 3; break; case GL_RGBA: photometric = PHOTOMETRIC_RGB; samplesPerPixel = 4; break; default: return WriteResult::ERROR_IN_WRITING_FILE; break; } switch(img.getDataType()){ case GL_FLOAT: TIFFSetField(image, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP); TIFFSetField(image, TIFFTAG_ROWSPERSTRIP, 1); bitsPerSample = 32; break; case GL_SHORT: TIFFSetField(image, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_INT); bitsPerSample = 16; break; default: bitsPerSample = 8; break; } TIFFSetField(image, TIFFTAG_IMAGEWIDTH,img.s()); TIFFSetField(image, TIFFTAG_IMAGELENGTH,img.t()); TIFFSetField(image, TIFFTAG_BITSPERSAMPLE,bitsPerSample); TIFFSetField(image, TIFFTAG_SAMPLESPERPIXEL,samplesPerPixel); TIFFSetField(image, TIFFTAG_PHOTOMETRIC, photometric); TIFFSetField(image, TIFFTAG_COMPRESSION, compressionType); TIFFSetField(image, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB); TIFFSetField(image, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); //uint32 rowsperstrip = TIFFDefaultStripSize(image, -1); //TIFFSetField(image, TIFFTAG_ROWSPERSTRIP, rowsperstrip); // Write the information to the file for(int i = 0; i < img.t(); ++i) { TIFFWriteScanline(image,(tdata_t)img.data(0,img.t()-i-1),i,0); } // Close the file TIFFClose(image); return WriteResult::FILE_SAVED; }
WriteResult::WriteStatus writeTIFStream(std::ostream& fout, const osg::Image& img) const { //Code is based from the following article on CodeProject.com //http://www.codeproject.com/bitmap/BitmapsToTiffs.asp TIFF *image; int samplesPerPixel; int bitsPerSample; uint16 photometric; image = TIFFClientOpen("outputstream", "w", (thandle_t)&fout, libtiffOStreamReadProc, //Custom read function libtiffOStreamWriteProc, //Custom write function libtiffOStreamSeekProc, //Custom seek function libtiffStreamCloseProc, //Custom close function libtiffOStreamSizeProc, //Custom size function libtiffStreamMapProc, //Custom map function libtiffStreamUnmapProc); //Custom unmap function if(image == NULL) { return WriteResult::ERROR_IN_WRITING_FILE; } switch(img.getPixelFormat()) { case GL_LUMINANCE: case GL_ALPHA: photometric = PHOTOMETRIC_MINISBLACK; samplesPerPixel = 1; break; case GL_LUMINANCE_ALPHA: photometric = PHOTOMETRIC_MINISBLACK; samplesPerPixel = 2; break; case GL_RGB: photometric = PHOTOMETRIC_RGB; samplesPerPixel = 3; break; case GL_RGBA: photometric = PHOTOMETRIC_RGB; samplesPerPixel = 4; break; default: return WriteResult::ERROR_IN_WRITING_FILE; break; } switch(img.getDataType()){ case GL_FLOAT: TIFFSetField(image, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP); TIFFSetField(image, TIFFTAG_ROWSPERSTRIP, 1); bitsPerSample = 32; break; default: bitsPerSample = 8; break; } TIFFSetField(image, TIFFTAG_IMAGEWIDTH,img.s()); TIFFSetField(image, TIFFTAG_IMAGELENGTH,img.t()); TIFFSetField(image, TIFFTAG_BITSPERSAMPLE,bitsPerSample); TIFFSetField(image, TIFFTAG_SAMPLESPERPIXEL,samplesPerPixel); TIFFSetField(image, TIFFTAG_PHOTOMETRIC, photometric); TIFFSetField(image, TIFFTAG_COMPRESSION, COMPRESSION_PACKBITS); TIFFSetField(image, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB); TIFFSetField(image, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); //uint32 rowsperstrip = TIFFDefaultStripSize(image, -1); //TIFFSetField(image, TIFFTAG_ROWSPERSTRIP, rowsperstrip); // Write the information to the file for(int i = 0; i < img.t(); ++i) { TIFFWriteScanline(image,(tdata_t)img.data(0,img.t()-i-1),i,0); } // Close the file TIFFClose(image); return WriteResult::FILE_SAVED; }
// Main interface with NVTT void NVTTProcessor::process( osg::Image& image, nvtt::Format format, bool generateMipMap, bool resizeToPowerOfTwo, CompressionMethod method, CompressionQuality quality) { // Fill input options nvtt::InputOptions inputOptions; inputOptions.setTextureLayout(nvtt::TextureType_2D, image.s(), image.t() ); inputOptions.setNormalMap(false); inputOptions.setConvertToNormalMap(false); inputOptions.setGamma(2.2f, 2.2f); inputOptions.setNormalizeMipmaps(false); inputOptions.setWrapMode(nvtt::WrapMode_Clamp); if (resizeToPowerOfTwo) { inputOptions.setRoundMode(nvtt::RoundMode_ToNearestPowerOfTwo); } inputOptions.setMipmapGeneration(generateMipMap); if (image.getPixelFormat() == GL_RGBA) { inputOptions.setAlphaMode( nvtt::AlphaMode_Transparency ); } else { inputOptions.setAlphaMode( nvtt::AlphaMode_None ); } std::vector<unsigned char> imageData( image.s() * image.t() * 4 ); if (image.getPixelFormat() == GL_RGB) { convertRGBToBGRA( imageData, image ); } else { convertRGBAToBGRA( imageData, image ); } inputOptions.setMipmapData(&imageData[0],image.s(),image.t()); // Fill compression options nvtt::CompressionOptions compressionOptions; switch(quality) { case FASTEST: compressionOptions.setQuality( nvtt::Quality_Fastest ); break; case NORMAL: compressionOptions.setQuality( nvtt::Quality_Normal ); break; case PRODUCTION: compressionOptions.setQuality( nvtt::Quality_Production); break; case HIGHEST: compressionOptions.setQuality( nvtt::Quality_Highest); break; } compressionOptions.setFormat( format ); //compressionOptions.setQuantization(false,false,false); if (format == nvtt::Format_RGBA) { if (image.getPixelFormat() == GL_RGB) { compressionOptions.setPixelFormat(24,0xff,0xff00,0xff0000,0); } else { compressionOptions.setPixelFormat(32,0xff,0xff00,0xff0000,0xff000000); } } // Handler OSGImageOutputHandler outputHandler(format,image.getPixelFormat() == GL_RGB); VPBErrorHandler errorHandler; // Fill output options nvtt::OutputOptions outputOptions; outputOptions.setOutputHandler(&outputHandler); outputOptions.setErrorHandler(&errorHandler); outputOptions.setOutputHeader(false); // Process the compression now nvtt::Compressor compressor; if(method == USE_GPU) { compressor.enableCudaAcceleration(true); if(!compressor.isCudaAccelerationEnabled()) { OSG_WARN<< "CUDA acceleration was enabled but it is not available. CPU will be used."<<std::endl; } } else { compressor.enableCudaAcceleration(false); } compressor.process(inputOptions,compressionOptions,outputOptions); outputHandler.assignImage(image); }
WriteResult writeRGBStream(const osg::Image& img, std::ostream &fout, const std::string& name) const { rawImageRec raw; raw.imagic = 0732; GLenum dataType = img.getDataType(); raw.type = dataType == GL_UNSIGNED_BYTE ? 1 : dataType == GL_BYTE ? 1 : dataType == GL_BITMAP ? 1 : dataType == GL_UNSIGNED_SHORT ? 2 : dataType == GL_SHORT ? 2 : dataType == GL_UNSIGNED_INT ? 4 : dataType == GL_INT ? 4 : dataType == GL_FLOAT ? 4 : dataType == GL_UNSIGNED_BYTE_3_3_2 ? 1 : dataType == GL_UNSIGNED_BYTE_2_3_3_REV ? 1 : dataType == GL_UNSIGNED_SHORT_5_6_5 ? 2 : dataType == GL_UNSIGNED_SHORT_5_6_5_REV ? 2 : dataType == GL_UNSIGNED_SHORT_4_4_4_4 ? 2 : dataType == GL_UNSIGNED_SHORT_4_4_4_4_REV ? 2 : dataType == GL_UNSIGNED_SHORT_5_5_5_1 ? 2 : dataType == GL_UNSIGNED_SHORT_1_5_5_5_REV ? 2 : dataType == GL_UNSIGNED_INT_8_8_8_8 ? 4 : dataType == GL_UNSIGNED_INT_8_8_8_8_REV ? 4 : dataType == GL_UNSIGNED_INT_10_10_10_2 ? 4 : dataType == GL_UNSIGNED_INT_2_10_10_10_REV ? 4 : 4; GLenum pixelFormat = img.getPixelFormat(); raw.dim = 3; raw.sizeX = img.s(); raw.sizeY = img.t(); raw.sizeZ = pixelFormat == GL_COLOR_INDEX? 1 : pixelFormat == GL_RED? 1 : pixelFormat == GL_GREEN? 1 : pixelFormat == GL_BLUE? 1 : pixelFormat == GL_ALPHA? 1 : pixelFormat == GL_RGB? 3 : pixelFormat == GL_BGR ? 3 : pixelFormat == GL_RGBA? 4 : pixelFormat == GL_BGRA? 4 : pixelFormat == GL_LUMINANCE? 1 : pixelFormat == GL_LUMINANCE_ALPHA ? 2 : 1; raw.min = 0; raw.max = 0xFF; raw.wasteBytes = 0; strncpy( raw.name, name.c_str(), 80); raw.colorMap = 0; raw.bpc = (img.getPixelSizeInBits()/raw.sizeZ)/8; int isize = img.getImageSizeInBytes(); unsigned char *buffer = new unsigned char[isize]; if(raw.bpc == 1) { unsigned char *dptr = buffer; int i, j; for( i = 0; i < raw.sizeZ; ++i ) { const unsigned char *ptr = img.data(); ptr += i; for( j = 0; j < isize/raw.sizeZ; ++j ) { *(dptr++) = *ptr; ptr += raw.sizeZ; } } } else { // bpc == 2 unsigned short *dptr = reinterpret_cast<unsigned short*>(buffer); int i, j; for( i = 0; i < raw.sizeZ; ++i ) { const unsigned short *ptr = reinterpret_cast<const unsigned short*>(img.data()); ptr += i; for( j = 0; j < isize/(raw.sizeZ*2); ++j ) { *dptr = *ptr; ConvertShort(dptr++, 1); ptr += raw.sizeZ; } } } if( raw.needsBytesSwapped() ) raw.swapBytes(); /* swapBytes( raw.imagic ); swapBytes( raw.type ); swapBytes( raw.dim ); swapBytes( raw.sizeX ); swapBytes( raw.sizeY ); swapBytes( raw.sizeZ ); swapBytes( raw.min ); swapBytes( raw.max ); swapBytes( raw.colorMap ); */ char pad[512 - sizeof(rawImageRec)]; memset( pad, 0, sizeof(pad)); fout.write((const char*)&raw,sizeof(rawImageRec)); fout.write((const char*)pad,sizeof(pad)); fout.write((const char*)buffer,isize); delete [] buffer; return WriteResult::FILE_SAVED; }
WriteResult local_writeImage(std::ostream& fout,const osg::Image& img,const osgDB::ReaderWriter::Options* options) const { std::string my_errmsg; try { gta::header hdr; gta::compression compression = gta::zlib; if (options) { std::istringstream iss(options->getOptionString()); std::string opt; std::string compressionMethod; while (iss >> opt) { if (opt == "COMPRESSION") { iss >> compressionMethod; } }; if (compressionMethod == "NONE") compression = gta::none; else if (compressionMethod == "ZLIB") compression = gta::zlib; else if (compressionMethod == "ZLIB1") compression = gta::zlib1; else if (compressionMethod == "ZLIB2") compression = gta::zlib2; else if (compressionMethod == "ZLIB3") compression = gta::zlib3; else if (compressionMethod == "ZLIB4") compression = gta::zlib4; else if (compressionMethod == "ZLIB5") compression = gta::zlib5; else if (compressionMethod == "ZLIB6") compression = gta::zlib6; else if (compressionMethod == "ZLIB7") compression = gta::zlib7; else if (compressionMethod == "ZLIB8") compression = gta::zlib8; else if (compressionMethod == "ZLIB9") compression = gta::zlib9; else if (compressionMethod == "BZIP2") compression = gta::bzip2; else if (compressionMethod == "XZ") compression = gta::xz; } hdr.set_compression(compression); if (img.s() > 0 && img.t() <= 1 && img.r() <= 1) { hdr.set_dimensions(img.s()); } else if (img.s() > 0 && img.t() > 1 && img.r() <= 1) { hdr.set_dimensions(img.s(), img.t()); } else if (img.s() > 0 && img.t() > 1 && img.r() > 1) { hdr.set_dimensions(img.s(), img.t(), img.r()); } else { my_errmsg = "Image has unsupported dimensions"; throw std::exception(); } gta::type type; switch (img.getDataType()) { case GL_BYTE: type = gta::int8; break; case GL_UNSIGNED_BYTE: type = gta::uint8; break; case GL_SHORT: type = gta::int16; break; case GL_UNSIGNED_SHORT: type = gta::uint16; break; case GL_INT: type = gta::int32; break; case GL_UNSIGNED_INT: type = gta::uint32; break; case GL_FLOAT: type = gta::float32; break; default: my_errmsg = "Image has unsupported data type"; throw std::exception(); } switch (img.getPixelFormat()) { case 1: case GL_DEPTH_COMPONENT: case GL_LUMINANCE: case GL_ALPHA: hdr.set_components(type); break; case 2: case GL_LUMINANCE_ALPHA: hdr.set_components(type, type); break; case 3: case GL_RGB: hdr.set_components(type, type, type); break; case 4: case GL_RGBA: hdr.set_components(type, type, type, type); break; default: my_errmsg = "Image has unsupported pixel format"; throw std::exception(); } if (img.getPacking() != 1) { my_errmsg = "Image has unsupported packing"; throw std::exception(); } hdr.write_to(fout); #if 0 /* Does not seem to be necessary */ if (img.t() > 1 && img.getOrigin() == osg::Image::BOTTOM_LEFT) { int depth = (img.r() >= 1 ? img.r() : 1); const unsigned char* data = static_cast<const unsigned char*>(img.getDataPointer()); size_t row_size = hdr.element_size() * img.s(); gta::io_state io_state; for (int k = 0; k < depth; k++) { const unsigned char* slice = data + k * (row_size * img.t()); for (int j = 0; j < img.t(); j++) { const unsigned char* p = slice + (img.t() - 1 - j) * row_size; hdr.write_elements(io_state, fout, img.s(), p); } } } else { hdr.write_data(fout, img.getDataPointer()); } #endif hdr.write_data(fout, img.getDataPointer()); }
bool writeEXRStream(const osg::Image &img, std::ostream& fout, const std::string &fileName) const { bool writeOK = true; //Obtain data from texture int width = img.s(); int height = img.t(); unsigned int pixelFormat = img.getPixelFormat(); int numComponents = img.computeNumComponents(pixelFormat); unsigned int dataType = img.getDataType(); //Validates image data //if numbers of components matches if (!( numComponents == 3 || numComponents == 4)) { writeOK = false; return false; } if (!( dataType == GL_HALF_FLOAT_ARB || dataType == GL_FLOAT)) { writeOK = false; return false; } //Create a stream to save to C_OStream outStream(&fout); //Copy data from texture to rgba pixel format Array2D<Rgba> outPixels(height,width); //If texture is half format if (dataType == GL_HALF_FLOAT_ARB) { half* pOut = (half*) img.data(); for (long i = height-1; i >= 0; i--) { for (long j = 0 ; j < width; j++) { outPixels[i][j].r = (*pOut); pOut++; outPixels[i][j].g = (*pOut); pOut++; outPixels[i][j].b = (*pOut); pOut++; if (numComponents >= 4) { outPixels[i][j].a = (*pOut); pOut++; } else { outPixels[i][j].a = 1.0f; } } } } else if (dataType == GL_FLOAT) { float* pOut = (float*) img.data(); for (long i = height-1; i >= 0; i--) { for (long j = 0 ; j < width; j++) { outPixels[i][j].r = half(*pOut); pOut++; outPixels[i][j].g = half(*pOut); pOut++; outPixels[i][j].b = half(*pOut); pOut++; if (numComponents >= 4) { outPixels[i][j].a = half(*pOut); pOut++; } else { outPixels[i][j].a = 1.0f; } } } } else { //If texture format not supported return false; } try { //Write to stream Header outHeader(width, height); RgbaOutputFile rgbaFile (outStream, outHeader, WRITE_RGBA); rgbaFile.setFrameBuffer ((&outPixels)[0][0], 1, width); rgbaFile.writePixels (height); } catch( char * str ) { writeOK = false; } return writeOK; }
WriteResult writeImage(const osg::Image& img, std::ostream& fout, const Options* options) const { if (!img.isDataContiguous()) { OSG_WARN<<"Warning: Writing of image data, that is non contiguous, is not supported by JPEG2000 plugin."<<std::endl; return WriteResult::ERROR_IN_WRITING_FILE; } jas_image_cmptparm_t cmptparms[4]; jas_image_cmptparm_t *cmptparm; int internalFormat = osg::Image::computeNumComponents(img.getPixelFormat()); jas_stream_t* mem = jas_stream_memopen((char*)img.data(), internalFormat*img.s()*img.t()); /* Create an image of the correct size. */ jas_image_t* jimage; int i; for (i = 0, cmptparm = cmptparms; i < internalFormat; ++i, ++cmptparm) { cmptparm->tlx = 0; cmptparm->tly = 0; cmptparm->hstep = 1; cmptparm->vstep = 1; cmptparm->width = img.s(); cmptparm->height = img.t(); cmptparm->prec = 8; cmptparm->sgnd = 0; } if (!(jimage = jas_image_create(internalFormat, cmptparms, JAS_CLRSPC_UNKNOWN))) { return WriteResult::ERROR_IN_WRITING_FILE; } if(internalFormat == 1) { jas_image_setclrspc(jimage, JAS_CLRSPC_SGRAY); jas_image_setcmpttype(jimage, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y)); } else if(internalFormat == 2) { jas_image_setclrspc(jimage, JAS_CLRSPC_SGRAY); jas_image_setcmpttype(jimage, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y)); jas_image_setcmpttype(jimage, 1, JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_OPACITY)); } else if(internalFormat == 3) { jas_image_setclrspc(jimage, JAS_CLRSPC_SRGB); jas_image_setcmpttype(jimage, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R)); jas_image_setcmpttype(jimage, 1, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G)); jas_image_setcmpttype(jimage, 2, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B)); } else if(internalFormat == 4) { jas_image_setclrspc(jimage, JAS_CLRSPC_SRGB); jas_image_setcmpttype(jimage, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R)); jas_image_setcmpttype(jimage, 1, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G)); jas_image_setcmpttype(jimage, 2, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B)); jas_image_setcmpttype(jimage, 3, JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_OPACITY)); } getdata(mem, jimage); jas_stream_t* out = jas_stream_memopen(0, 0); if (!out) return WriteResult::ERROR_IN_WRITING_FILE; char* opt = 0; if(options) { opt = new char[options->getOptionString().size() + 1]; strcpy(opt, options->getOptionString().c_str()); } jas_image_encode(jimage, out, _fmt_jp2, opt); if(opt) delete[] opt; jas_stream_flush(out); // now the encoded jp2 image resides in the out->buf_ member with size out->len_ we now need to stream it to a std::ostream jas_stream_memobj_t* obj = (jas_stream_memobj_t*) out->obj_; fout.write((char*)obj->buf_, obj->len_); fout << std::flush; jas_stream_close(out); jas_image_destroy(jimage); return WriteResult::FILE_SAVED; }
virtual WriteResult writeImage(const osg::Image &img,const std::string& fileName, const osgDB::ReaderWriter::Options* options) const { std::string ext = osgDB::getFileExtension(fileName); if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED; if (!img.isDataContiguous()) { OSG_WARN<<"Warning: Writing of image data, that is non contiguous, is not supported by JPEG2000 plugin."<<std::endl; return WriteResult::ERROR_IN_WRITING_FILE; } jas_image_cmptparm_t cmptparms[4]; jas_image_cmptparm_t *cmptparm; int internalFormat = osg::Image::computeNumComponents(img.getPixelFormat()); jas_stream_t* mem = jas_stream_memopen((char*)img.data(), internalFormat*img.s()*img.t()); /* Create an image of the correct size. */ jas_image_t* jimage; int i; for (i = 0, cmptparm = cmptparms; i < internalFormat; ++i, ++cmptparm) { cmptparm->tlx = 0; cmptparm->tly = 0; cmptparm->hstep = 1; cmptparm->vstep = 1; cmptparm->width = img.s(); cmptparm->height = img.t(); cmptparm->prec = 8; cmptparm->sgnd = 0; } if (!(jimage = jas_image_create(internalFormat, cmptparms, JAS_CLRSPC_UNKNOWN))) { return WriteResult::ERROR_IN_WRITING_FILE; } if(internalFormat == 1) { jas_image_setclrspc(jimage, JAS_CLRSPC_GENGRAY); jas_image_setcmpttype(jimage, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y)); } else if(internalFormat == 2) { jas_image_setclrspc(jimage, JAS_CLRSPC_GENGRAY); jas_image_setcmpttype(jimage, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y)); jas_image_setcmpttype(jimage, 1, JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_OPACITY)); } else if(internalFormat == 3) { jas_image_setclrspc(jimage, JAS_CLRSPC_SRGB); jas_image_setcmpttype(jimage, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R)); jas_image_setcmpttype(jimage, 1, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G)); jas_image_setcmpttype(jimage, 2, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B)); } else if(internalFormat == 4) { jas_image_setclrspc(jimage, JAS_CLRSPC_SRGB); jas_image_setcmpttype(jimage, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R)); jas_image_setcmpttype(jimage, 1, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G)); jas_image_setcmpttype(jimage, 2, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B)); jas_image_setcmpttype(jimage, 3, JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_OPACITY)); } getdata(mem, jimage); FILE * fileHandle = osgDB::fopen(fileName.c_str(), "wb"); if (!fileHandle) { return WriteResult::ERROR_IN_WRITING_FILE; } jas_stream_t* out = jas_stream_freopen(fileName.c_str(), "wb", fileHandle); // Replacement for jas_stream_fopen() to be able to support UTF8 if (!out) { fclose(fileHandle); return WriteResult::ERROR_IN_WRITING_FILE; } char* opt = 0; if(options) { opt = new char[options->getOptionString().size() + 1]; strcpy(opt, options->getOptionString().c_str()); } jas_image_encode(jimage, out, _fmt_jp2, opt); if(opt) delete[] opt; jas_stream_flush(out); jas_stream_close(out); jas_image_destroy(jimage); fclose(fileHandle); return WriteResult::FILE_SAVED; }