void ImageWriter::plugSet( Gaffer::Plug *plug ) { if ( plug == fileNamePlug() ) { std::string fileName = fileNamePlug()->getValue(); fileName = Context::current()->substitute( fileName ); ImageOutput *out = ImageOutput::create( fileName.c_str() ); if ( !out ) { throw IECore::Exception( boost::str( boost::format( "Invalid filename: %s" ) % fileName ) ); return; } unsigned flags = writeModePlug()->getFlags(); if ( out->supports( "tiles" ) ) { writeModePlug()->setFlags( flags & ~Gaffer::Plug::ReadOnly ); } else { if ( !(flags & Gaffer::Plug::ReadOnly) ) { writeModePlug()->setValue( Scanline ); } writeModePlug()->setFlags( flags | Gaffer::Plug::ReadOnly ); } } }
/** * @brief Write imgage. * @details Write compostied image to the file system. */ void writeImage() { // Transfer to something OpenImageIO understands oiioPixels.resize(newWidth*newHeight*4*sizeof(float)); for (int row = 0; row < newHeight; row++) for (int col = 0; col < newWidth; col++){ oiioPixels[(row*newWidth+col)*4 + 0] = warppedPixels[row][col].r; oiioPixels[(row*newWidth+col)*4 + 1] = warppedPixels[row][col].g; oiioPixels[(row*newWidth+col)*4 + 2] = warppedPixels[row][col].b; oiioPixels[(row*newWidth+col)*4 + 3] = warppedPixels[row][col].a; } // Create output image ImageOutput *out = ImageOutput::create(outImage); // Error handeling if (!out) { printf("Error writing image: %s\n", geterror().c_str()); exit(EXIT_FAILURE); } // Create output image spec ImageSpec spec (newWidth, newHeight, 4, TypeDesc::FLOAT); // Open output image file out->open(outImage, spec); // Write output image to disk and close out->write_image(TypeDesc::FLOAT, &oiioPixels[0]); out->close(); delete out; }
void Ibl::Simulate(std::string const& filename) { auto width = 2000U; auto height = 1000U; std::vector<float> data(width * height); std::fill(data.begin(), data.end(), 0.f); for (int i = 0; i < 100000; ++i) { auto xy = SampleCoord(RadeonRays::float2(RadeonRays::rand_float(), RadeonRays::rand_float())); data[xy.y * width + xy.x] += 1.f; } using namespace OpenImageIO; ImageOutput* out = ImageOutput::create(filename); if (!out) { throw std::runtime_error("Can't create image file on disk"); } ImageSpec spec(width, height, 1, TypeDesc::UINT8); out->open(filename, spec); out->write_image(TypeDesc::FLOAT, &data[0]); out->close(); delete out; }
void lux::writeOIIOImage( const char* fname, Image& img, const map<string,string>& labels, float displayBrightness, float displayGamma ) { float* imagedata = new float[ img.Width()* img.Height() * 3 ]; // fill image with the contents of img long index = 0; for( int j=0;j<img.Height();j++ ) { for( int i=0;i<img.Width();i++ ) { vector<float> pix = img.pixel(i,img.Height() - j - 1); for( size_t c=0;c<3;c++ ) { pix[c] = imagePlaneValue( pix[c], displayGamma, displayBrightness ); imagedata[index++] = pix[c]; } } } ImageOutput *out = ImageOutput::create (fname); if( !out ) { cout << "Not able to write an image to file " << fname << endl; } else { ImageSpec spec (img.Width(), img.Height(), 3, TypeDesc::FLOAT); spec.attribute("user", "imageTools"); spec.attribute("writer", "OIIOFiles" ); if( labels.size() > 0 ) { map<string,string>::const_iterator lab = labels.begin(); while( lab != labels.end() ) { const string& name = lab->first; const string& value = lab->second; spec.attribute( name, value ); lab++; } } out->open (fname, spec); out->write_image (TypeDesc::FLOAT, imagedata); out->close (); cout <<endl<<endl<< "File " << fname << " written to file"<< endl; delete out; } delete[] imagedata; }
void SaveFrameBuffer(std::string const& name, float3 const* data) { OIIO_NAMESPACE_USING; std::vector<float3> tempbuf(g_window_width * g_window_height); tempbuf.assign(data, data + g_window_width*g_window_height); ImageOutput* out = ImageOutput::create(name); if (!out) { throw std::runtime_error("Can't create image file on disk"); } ImageSpec spec(g_window_width, g_window_height, 3, TypeDesc::FLOAT); out->open(name, spec); out->write_image(TypeDesc::FLOAT, &tempbuf[0], sizeof(float3)); out->close(); }
void Ibl::DumpPdf(std::string const& filename) { auto width = 2000U; auto height = 1000U; std::vector<float> data(width * height); for (auto x = 0U; x < width; ++x) for (auto y = 0U; y < height; ++y) { data[y * width + x] = GetPdf(RadeonRays::float2((float)x / m_width, (float)y / m_height)); } auto max = std::max_element(data.cbegin(), data.cend()); std::for_each(data.begin(), data.end(), [=](float& v) { v /= *max; }); using namespace OpenImageIO; ImageOutput* out = ImageOutput::create(filename); if (!out) { throw std::runtime_error("Can't create image file on disk"); } ImageSpec spec(width, height, 1, TypeDesc::UINT8); out->open(filename, spec); out->write_image(TypeDesc::FLOAT, &data[0]); out->close(); delete out; }
int main (int argc, const char *argv[]) { Timer timer; // Create a new shading system. We pass it the RendererServices // object that services callbacks from the shading system, NULL for // the TextureSystem (which will create a default OIIO one), and // an error handler. shadingsys = new ShadingSystem (&rend, NULL, &errhandler); // Register the layout of all closures known to this renderer // Any closure used by the shader which is not registered, or // registered with a different number of arguments will lead // to a runtime error. register_closures(shadingsys); // Remember that each shader parameter may optionally have a // metadata hint [[int lockgeom=...]], where 0 indicates that the // parameter may be overridden by the geometry itself, for example // with data interpolated from the mesh vertices, and a value of 1 // means that it is "locked" with respect to the geometry (i.e. it // will not be overridden with interpolated or // per-geometric-primitive data). // // In order to most fully optimize shader, we typically want any // shader parameter not explicitly specified to default to being // locked (i.e. no per-geometry override): shadingsys->attribute("lockgeom", 1); // Read command line arguments getargs (argc, argv); // Setup common attributes shadingsys->attribute ("debug", debug2 ? 2 : (debug ? 1 : 0)); shadingsys->attribute ("compile_report", debug|debug2); const char *opt_env = getenv ("TESTSHADE_OPT"); // overrides opt if (opt_env) shadingsys->attribute ("optimize", atoi(opt_env)); else if (O0 || O1 || O2) shadingsys->attribute ("optimize", O2 ? 2 : (O1 ? 1 : 0)); shadingsys->attribute ("debugnan", debugnan); // Loads a scene, creating camera, geometry and assigning shaders parse_scene(); // validate options if (aa < 1) aa = 1; if (num_threads < 1) num_threads = boost::thread::hardware_concurrency(); // prepare background importance table (if requested) if (backgroundResolution > 0 && backgroundShaderID >= 0) { // get a context so we can make several background shader calls OSL::PerThreadInfo *thread_info = shadingsys->create_thread_info(); ShadingContext *ctx = shadingsys->get_context (thread_info); // build importance table to optimize background sampling background.prepare(backgroundResolution, eval_background, ctx); // release context shadingsys->release_context (ctx); shadingsys->destroy_thread_info(thread_info); } else { // we aren't directly evaluating the background backgroundResolution = 0; } double setuptime = timer.lap (); std::vector<Color3> pixels(xres * yres, Color3(0,0,0)); // Create shared counter to iterate over one scanline at a time Counter scanline_counter(errhandler, yres, "Rendering"); // launch a scanline worker for each thread boost::thread_group workers; for (int i = 0; i < num_threads; i++) workers.add_thread(new boost::thread(scanline_worker, boost::ref(scanline_counter), boost::ref(pixels))); workers.join_all(); // Write image to disk ImageOutput* out = ImageOutput::create(imagefile); ImageSpec spec(xres, yres, 3, TypeDesc::HALF); if (out && out->open(imagefile, spec)) { out->write_image(TypeDesc::TypeFloat, &pixels[0]); } else { errhandler.error("Unable to write output image"); } delete out; // Print some debugging info if (debug || stats) { double runtime = timer.lap(); std::cout << "\n"; std::cout << "Setup: " << OIIO::Strutil::timeintervalformat (setuptime,2) << "\n"; std::cout << "Run : " << OIIO::Strutil::timeintervalformat (runtime,2) << "\n"; std::cout << "\n"; std::cout << shadingsys->getstats (5) << "\n"; OIIO::TextureSystem *texturesys = shadingsys->texturesys(); if (texturesys) std::cout << texturesys->getstats (5) << "\n"; std::cout << ustring::getstats() << "\n"; } // We're done with the shading system now, destroy it shaders.clear (); // Must release the group refs first delete shadingsys; return EXIT_SUCCESS; }
static int output_file (int argc, const char *argv[]) { ASSERT (argc == 2 && !strcmp(argv[0],"-o")); std::string filename = argv[1]; if (! ot.curimg.get()) { std::cerr << "oiiotool ERROR: -o " << filename << " did not have any current image to output.\n"; return 0; } if (ot.noclobber && Filesystem::exists(filename)) { std::cerr << "oiiotool ERROR: Output file \"" << filename << "\" already exists, not overwriting.\n"; return 0; } if (ot.verbose) std::cout << "Writing " << argv[1] << "\n"; ImageOutput *out = ImageOutput::create (filename.c_str()); if (! out) { std::cerr << "oiiotool ERROR: " << geterror() << "\n"; return 0; } bool supports_displaywindow = out->supports ("displaywindow"); ot.read (); ImageRecRef saveimg = ot.curimg; ImageRecRef ir (ot.curimg); if (! supports_displaywindow && ot.output_autocrop && (ir->spec()->x != ir->spec()->full_x || ir->spec()->y != ir->spec()->full_y || ir->spec()->width != ir->spec()->full_width || ir->spec()->height != ir->spec()->full_height)) { const char *argv[] = { "croptofull" }; int action_croptofull (int argc, const char *argv[]); // forward decl action_croptofull (1, argv); ir = ot.curimg; } ImageOutput::OpenMode mode = ImageOutput::Create; // initial open for (int s = 0, send = ir->subimages(); s < send; ++s) { for (int m = 0, mend = ir->miplevels(s); m < mend; ++m) { ImageSpec spec = *ir->spec(s,m); adjust_output_options (spec, ot); if (! out->open (filename, spec, mode)) { std::cerr << "oiiotool ERROR: " << out->geterror() << "\n"; return 0; } if (! (*ir)(s,m).write (out)) { std::cerr << "oiiotool ERROR: " << (*ir)(s,m).geterror() << "\n"; return 0; } if (mend > 1) { if (out->supports("mipmap")) { mode = ImageOutput::AppendMIPLevel; // for next level } else if (out->supports("multiimage")) { mode = ImageOutput::AppendSubimage; } else { std::cout << "oiiotool WARNING: " << out->format_name() << " does not support MIP-maps for " << filename << "\n"; break; } } } mode = ImageOutput::AppendSubimage; // for next subimage if (send > 1 && ! out->supports("multiimage")) { std::cout << "oiiotool WARNING: " << out->format_name() << " does not support multiple subimages for " << filename << "\n"; break; } } out->close (); delete out; if (ot.output_adjust_time) { std::string metadatatime = ir->spec(0,0)->get_string_attribute ("DateTime"); std::time_t in_time = ir->time(); if (! metadatatime.empty()) DateTime_to_time_t (metadatatime.c_str(), in_time); boost::filesystem::last_write_time (filename, in_time); } ot.curimg = saveimg; return 0; }
static void write_mipmap (ImageBuf &img, const ImageSpec &outspec_template, std::string outputfilename, std::string outformat, TypeDesc outputdatatype, bool mipmap) { ImageSpec outspec = outspec_template; outspec.set_format (outputdatatype); // Find an ImageIO plugin that can open the output file, and open it Timer writetimer; ImageOutput *out = ImageOutput::create (outformat.c_str()); if (! out) { std::cerr << "maketx ERROR: Could not find an ImageIO plugin to write " << outformat << " files:" << geterror() << "\n"; exit (EXIT_FAILURE); } if (! out->supports ("tiles")) { std::cerr << "maketx ERROR: \"" << outputfilename << "\" format does not support tiled images\n"; exit (EXIT_FAILURE); } if (mipmap && !out->supports ("multiimage") && !out->supports ("mipmap")) { std::cerr << "maketx ERROR: \"" << outputfilename << "\" format does not support multires images\n"; exit (EXIT_FAILURE); } if (! mipmap && ! strcmp (out->format_name(), "openexr")) { // Send hint to OpenEXR driver that we won't specify a MIPmap outspec.attribute ("openexr:levelmode", 0 /* ONE_LEVEL */); } if (mipmap && ! strcmp (out->format_name(), "openexr")) { outspec.attribute ("openexr:roundingmode", 0 /* ROUND_DOWN */); } // OpenEXR always uses border sampling for environment maps if ((envlatlmode || envcubemode) && !strcmp(out->format_name(), "openexr")) { src_samples_border = true; outspec.attribute ("oiio:updirection", "y"); outspec.attribute ("oiio:sampleborder", 1); } if (envlatlmode && src_samples_border) fix_latl_edges (img); if (! out->open (outputfilename.c_str(), outspec)) { std::cerr << "maketx ERROR: Could not open \"" << outputfilename << "\" : " << out->geterror() << "\n"; exit (EXIT_FAILURE); } // Write out the image if (verbose) { std::cout << " Writing file: " << outputfilename << std::endl; std::cout << " Filter \"" << filter->name() << "\" width = " << filter->width() << "\n"; } bool ok = true; ok &= img.write (out); stat_writetime += writetimer(); if (mipmap) { // Mipmap levels: if (verbose) std::cout << " Mipmapping...\n" << std::flush; ImageBuf tmp; ImageBuf *big = &img, *small = &tmp; while (ok && (outspec.width > 1 || outspec.height > 1)) { Timer miptimer; // Resize a factor of two smaller ImageSpec smallspec = outspec; smallspec.width = big->spec().width; smallspec.height = big->spec().height; smallspec.depth = big->spec().depth; if (smallspec.width > 1) smallspec.width /= 2; if (smallspec.height > 1) smallspec.height /= 2; smallspec.full_width = smallspec.width; smallspec.full_height = smallspec.height; smallspec.full_depth = smallspec.depth; smallspec.set_format (TypeDesc::FLOAT); small->alloc (smallspec); // Realocate with new size if (filtername == "box" && filter->width() == 1.0f) parallel_image (resize_block, small, big, smallspec.x, smallspec.x+smallspec.width, smallspec.y, smallspec.y+smallspec.height, nthreads); else parallel_image (resize_block_HQ, small, big, smallspec.x, smallspec.x+smallspec.width, smallspec.y, smallspec.y+smallspec.height, nthreads); stat_miptime += miptimer(); outspec = smallspec; outspec.set_format (outputdatatype); if (envlatlmode && src_samples_border) fix_latl_edges (*small); Timer writetimer; // If the format explicitly supports MIP-maps, use that, // otherwise try to simulate MIP-mapping with multi-image. bool ok = false; ImageOutput::OpenMode mode = out->supports ("mipmap") ? ImageOutput::AppendMIPLevel : ImageOutput::AppendSubimage; if (! out->open (outputfilename.c_str(), outspec, mode)) { std::cerr << "maketx ERROR: Could not append \"" << outputfilename << "\" : " << out->geterror() << "\n"; exit (EXIT_FAILURE); } ok &= small->write (out); stat_writetime += writetimer(); if (verbose) std::cout << " " << smallspec.width << 'x' << smallspec.height << "\n" << std::flush; std::swap (big, small); } } if (verbose) std::cout << " Wrote file: " << outputfilename << std::endl; writetimer.reset (); writetimer.start (); if (ok) ok &= out->close (); stat_writetime += writetimer (); delete out; if (! ok) { std::cerr << "maketx ERROR writing \"" << outputfilename << "\" : " << out->geterror() << "\n"; exit (EXIT_FAILURE); } }
bool SMT::save() { // Make sure we have some source images before continuing if( sourceFiles.size() == 0) { if( !quiet )cout << "ERROR: No source images to convert" << endl; return true; } // Build SMT Header // ////////////////////// char filename[256]; sprintf(filename, "%s.smt", outPrefix.c_str()); if( verbose ) printf("\nINFO: Creating %s\n", filename ); fstream smt( filename, ios::binary | ios::out ); if( !smt.good() ) { cout << "ERROR: fstream error." << endl; return true; } SMTHeader header; header.tileRes = tileRes; header.tileType = tileType; if( verbose ) { cout << " Version: " << header.version << endl; cout << " nTiles: n/a\n"; printf( " tileRes: (%i,%i)%i.\n", tileRes, tileRes, 4); cout << " tileType: "; if( tileType == DXT1 ) cout << "DXT1" << endl; cout << " tileSize: " << tileSize << " bytes" << endl; } smt.write( (char *)&header, sizeof(SMTHeader) ); smt.close(); // setup size for index dimensions int tcx = width * 16; // tile count x int tcz = length * 16; // tile count z unsigned int *indexPixels = new unsigned int[tcx * tcz]; // Load source image if( verbose )cout << "INFO: Loading Source Image(s)\n"; ImageBuf *bigBuf = buildBig(); ImageSpec bigSpec = bigBuf->spec(); // Process decals if( !decalFile.empty() ) { if( verbose )cout << "INFO: Processing decals\n"; pasteDecals( bigBuf ); } // Swizzle channels if( verbose )cout << "INFO: Swizzling channels\n"; ImageBuf fixBuf; int map[] = { 2, 1, 0, 3 }; ImageBufAlgo::channels( fixBuf, *bigBuf, 4, map ); bigBuf->copy( fixBuf ); fixBuf.clear(); // Process Tiles if( verbose )cout << "INFO: Processing tiles\n"; // Time reporting vars timeval t1, t2; double elapsedTime; deque<double> readings; double averageTime = 0; double intervalTime = 0; // Loop vars int totalTiles = tcx * tcz; int currentTile; // Tile Vars ROI roi; ImageSpec tileSpec(tileRes, tileRes, 4, TypeDesc::UINT8 ); // Comparison vars bool match; bool yee = false; unsigned int i; string hash; vector<string> hashTable; TileBufListEntry *listEntry; deque<TileBufListEntry *> tileList; // Open smt file for writing tiles smt.open(filename, ios::binary | ios::out | ios::app ); // loop through tile columns for ( int z = 0; z < tcz; z++) { // loop through tile rows for ( int x = 0; x < tcx; x++) { currentTile = z * tcx + x + 1; gettimeofday(&t1, NULL); // pull a region of the big image to use as a tile. roi.xbegin = x * tileRes; roi.xend = x * tileRes + tileRes; roi.ybegin = z * tileRes; roi.yend = z * tileRes + tileRes; roi.zbegin = 0; roi.zend = 1; roi.chbegin = 0; roi.chend = 4; ImageBuf tempBuf; ImageBufAlgo::crop( tempBuf, *bigBuf, roi ); ImageBuf *tileBuf = new ImageBuf( filename, tileSpec, tempBuf.localpixels() ); // reset match variables match = false; i = nTiles; if( cnum < 0) { // no attempt at reducing tile sizes i = nTiles; } else if( cnum == 0) { // only exact matches will be referenced. hash = ImageBufAlgo::computePixelHashSHA1( *tileBuf ); for( i = 0; i < hashTable.size(); ++i ) { if( !hashTable[i].compare( hash ) ) { match = true; break; } } if( !match ) hashTable.push_back( hash ); } else if( !yee ) { //Comparison based on numerical differences of pixels listEntry = new TileBufListEntry; listEntry->image.copy(*tileBuf); listEntry->tileNum = nTiles; ImageBufAlgo::CompareResults result; deque< TileBufListEntry * >::iterator it; for(it = tileList.begin(); it != tileList.end(); it++ ) { TileBufListEntry *listEntry2 = *it; ImageBufAlgo::compare( *tileBuf, listEntry2->image, cpet, 1.0f, result); //TODO give control on tweaking matching if((int)result.nfail < cnet) { match = true; i = listEntry2->tileNum; delete listEntry; break; } } if( !match ) { tileList.push_back(listEntry); if((int)tileList.size() > cnum) { delete tileList[0]; tileList.pop_front(); } } } else { //FIXME uncomment when OpenImageIO gets upgraded to v3 /* listEntry = new TileBufListEntry; listEntry->image.copy(*tileBuf); listEntry->tileNum = nTiles; ImageBufAlgo::CompareResults result; deque< TileBufListEntry * >::iterator it; for(it = tileList.begin(); it != tileList.end(); it++ ) { TileBufListEntry *listEntry2 = *it; ImageBufAlgo::compare_yee( *tileBuf, listEntry2->image, result, 1.0f, 1.0f ); if(result.nfail == 0) { match = true; i = listEntry2->tileNum; break; } } if( !match ) { tileList.push_back(listEntry); if((int)tileList.size() > 32) tileList.pop_front(); }*/ } // write tile to file. if( !match ) { unsigned char *std = (unsigned char *)tileBuf->localpixels(); // process into dds NVTTOutputHandler *nvttHandler = new NVTTOutputHandler(tileSize); nvtt::InputOptions inputOptions; inputOptions.setTextureLayout( nvtt::TextureType_2D, tileRes, tileRes ); inputOptions.setMipmapData( std, tileRes, tileRes ); nvtt::CompressionOptions compressionOptions; compressionOptions.setFormat(nvtt::Format_DXT1a); nvtt::OutputOptions outputOptions; outputOptions.setOutputHeader(false); outputOptions.setOutputHandler( nvttHandler ); nvtt::Compressor compressor; if( slow_dxt1 ) compressionOptions.setQuality(nvtt::Quality_Normal); else compressionOptions.setQuality(nvtt::Quality_Fastest); compressor.process(inputOptions, compressionOptions, outputOptions); smt.write( nvttHandler->buffer, tileSize ); delete nvttHandler; nTiles +=1; } delete tileBuf; // Write index to tilemap indexPixels[currentTile-1] = i; gettimeofday(&t2, NULL); // compute and print the elapsed time in millisec elapsedTime = (t2.tv_sec - t1.tv_sec) * 1000.0; // sec to ms elapsedTime += (t2.tv_usec - t1.tv_usec) / 1000.0; // us to ms readings.push_back(elapsedTime); if(readings.size() > 1000)readings.pop_front(); intervalTime += elapsedTime; if( verbose && intervalTime > 1 ) { for(unsigned int i = 0; i < readings.size(); ++i) averageTime+= readings[i]; averageTime /= readings.size(); intervalTime = 0; printf("\033[0G %i of %i %%%0.1f complete | %%%0.1f savings | %0.1fs remaining.", currentTile, totalTiles, (float)currentTile / totalTiles * 100, (float)(1 - (float)nTiles / (float)currentTile) * 100, averageTime * (totalTiles - currentTile) / 1000); } } } hashTable.clear(); if( verbose ) cout << endl; smt.close(); // retroactively fix up the tile count. smt.open(filename, ios::binary | ios::in | ios::out ); smt.seekp( 20); smt.write( (char *)&nTiles, 4); smt.close(); // Save tileindex ImageOutput *imageOutput; sprintf( filename, "%s_tilemap.exr", outPrefix.c_str() ); imageOutput = ImageOutput::create(filename); if( !imageOutput ) { delete [] indexPixels; return true; } ImageSpec tilemapSpec( tcx, tcz, 1, TypeDesc::UINT); imageOutput->open( filename, tilemapSpec ); imageOutput->write_image( TypeDesc::UINT, indexPixels ); imageOutput->close(); delete imageOutput; delete [] indexPixels; return false; }
// Function to write an image using OpenImageIO that reads and stores the pixel bein g displayed on screen using OpenGL void writeImage() { // Store the Output File Type in outfiletype, example .ppm or .jpg string outfiletype = outfilename.substr(outfilename.find(".")); // Create ImageOutput instance using the outfilename & exit if error in creating ImageOutput *out = ImageOutput::create(outfilename); if (!out) { cerr << "Could not create an ImageOutput for " << outfilename << "\nError: " << geterror()<<endl; exit(-1); } // Set outputchannels to 3 if outputfiletype is either ppm/pnm/pgm/pbm/hdr/rgbe else let it be equal to the number of channels of the input image (either 3 or 4) int outputchannels = (outfiletype==".ppm" || outfiletype==".pnm" || outfiletype==".pgm" || outfiletype==".pbm" || outfiletype==".hdr" || outfiletype==".rgbe" ? 3 : channels1 ); // Allocate memory based on the number of channels unsigned char *oiio_pixels = new unsigned char[xresWarped*yresWarped*outputchannels]; // Check if memory has been allocated successfully if (oiio_pixels==0) { // Memory not allocated successfully! Display message and Exit cout<<"Couldn't allocate memory. Exiting!"<<endl; exit(-1); delete out; } // If number of channels is 4 then read in RGBA format using GL_RGBA if(outputchannels==4) { for(int i=0, k=0; i<yresWarped && k<(xresWarped*yresWarped*outputchannels); i++) { for(int j=0; j<xresWarped; j++, k+=4) { oiio_pixels[k] = pixmapWarped[i][j].red; oiio_pixels[k+1] = pixmapWarped[i][j].green; oiio_pixels[k+2] = pixmapWarped[i][j].blue; oiio_pixels[k+3] = pixmapWarped[i][j].alpha; } } } // If number of channels is 3 then read in RGB format using GL_RGB else if(outputchannels==3) { for(int i=0, k=0; i<yresWarped && k<(xresWarped*yresWarped*outputchannels); i++) { for(int j=0; j<xresWarped; j++, k+=3) { oiio_pixels[k] = pixmapWarped[i][j].red; oiio_pixels[k+1] = pixmapWarped[i][j].green; oiio_pixels[k+2] = pixmapWarped[i][j].blue; } } } // Create ImageSpec for the output image with name outfile ImageSpec spec(xresWarped,yresWarped,outputchannels,TypeDesc::UINT8); if (! out->open (outfilename, spec)) { cerr << "Could not open " << outfilename << "\nError: " << out->geterror()<< endl; delete out; delete [] oiio_pixels; exit(-1); } // This particular call to write flips the image for us int scanlinesize = xresWarped * outputchannels * sizeof(oiio_pixels[0]); if(! out->write_image (TypeDesc::UINT8, (unsigned char*)oiio_pixels+(yresWarped-1)*scanlinesize, AutoStride, -scanlinesize, AutoStride)) { cerr << "Could not write pixels to " << outfilename << "\nError: " << out->geterror()<< endl; delete out; delete [] oiio_pixels; exit(-1); } // Close the output file if(! out->close ()) { std::cerr << "Error closing " << outfilename << "\nError: " << out->geterror() << endl; delete out; delete [] oiio_pixels; exit(-1); } delete out; delete [] oiio_pixels; }
static bool convert_file (const std::string &in_filename, const std::string &out_filename) { if (noclobber && Filesystem::exists(out_filename)) { std::cerr << "iconvert ERROR: Output file already exists \"" << out_filename << "\"\n"; return false; } if (verbose) std::cout << "Converting " << in_filename << " to " << out_filename << "\n"; std::string tempname = out_filename; if (tempname == in_filename) { tempname = out_filename + ".tmp" + Filesystem::extension (out_filename); } // Find an ImageIO plugin that can open the input file, and open it. ImageInput *in = ImageInput::open (in_filename.c_str()); if (! in) { std::string err = geterror(); std::cerr << "iconvert ERROR: " << (err.length() ? err : Strutil::format("Could not open \"%s\"", in_filename)) << "\n"; delete in; return false; } ImageSpec inspec = in->spec(); std::string metadatatime = inspec.get_string_attribute ("DateTime"); // Find an ImageIO plugin that can open the output file, and open it ImageOutput *out = ImageOutput::create (tempname.c_str()); if (! out) { std::cerr << "iconvert ERROR: Could not find an ImageIO plugin to write \"" << out_filename << "\" :" << geterror() << "\n"; delete in; return false; } // In order to deal with formats that support subimages, but not // subimage appending, we gather them all first. std::vector<ImageSpec> subimagespecs; if (out->supports("multiimage") && !out->supports("appendsubimage")) { ImageCache *imagecache = ImageCache::create (); int nsubimages = 0; ustring ufilename (in_filename); imagecache->get_image_info (ufilename, 0, 0, ustring("subimages"), TypeDesc::TypeInt, &nsubimages); if (nsubimages > 1) { subimagespecs.resize (nsubimages); for (int i = 0; i < nsubimages; ++i) { ImageSpec inspec = *imagecache->imagespec (ufilename, i, 0, true /*native*/); subimagespecs[i] = inspec; adjust_spec (in, out, inspec, subimagespecs[i]); } } ImageCache::destroy (imagecache); } bool ok = true; bool mip_to_subimage_warning = false; for (int subimage = 0; ok && in->seek_subimage(subimage,0,inspec); ++subimage) { if (subimage > 0 && !out->supports ("multiimage")) { std::cerr << "iconvert WARNING: " << out->format_name() << " does not support multiple subimages.\n"; std::cerr << "\tOnly the first subimage has been copied.\n"; break; // we're done } int miplevel = 0; do { // Copy the spec, with possible change in format ImageSpec outspec = inspec; bool nocopy = adjust_spec (in, out, inspec, outspec); if (miplevel > 0) { // Moving to next MIP level ImageOutput::OpenMode mode; if (out->supports ("mipmap")) mode = ImageOutput::AppendMIPLevel; else if (out->supports ("multiimage") && out->supports ("appendsubimage")) { mode = ImageOutput::AppendSubimage; // use if we must if (! mip_to_subimage_warning && strcmp(out->format_name(),"tiff")) { std::cerr << "iconvert WARNING: " << out->format_name() << " does not support MIPmaps.\n"; std::cerr << "\tStoring the MIPmap levels in subimages.\n"; } mip_to_subimage_warning = true; } else { std::cerr << "iconvert WARNING: " << out->format_name() << " does not support MIPmaps.\n"; std::cerr << "\tOnly the first level has been copied.\n"; break; // on to the next subimage } ok = out->open (tempname.c_str(), outspec, mode); } else if (subimage > 0) { // Moving to next subimage ok = out->open (tempname.c_str(), outspec, ImageOutput::AppendSubimage); } else { // First time opening if (subimagespecs.size()) ok = out->open (tempname.c_str(), int(subimagespecs.size()), &subimagespecs[0]); else ok = out->open (tempname.c_str(), outspec, ImageOutput::Create); } if (! ok) { std::string err = out->geterror(); std::cerr << "iconvert ERROR: " << (err.length() ? err : Strutil::format("Could not open \"%s\"", out_filename)) << "\n"; ok = false; break; } if (! nocopy) { ok = out->copy_image (in); if (! ok) std::cerr << "iconvert ERROR copying \"" << in_filename << "\" to \"" << out_filename << "\" :\n\t" << out->geterror() << "\n"; } else { // Need to do it by hand for some reason. Future expansion in which // only a subset of channels are copied, or some such. std::vector<char> pixels ((size_t)outspec.image_bytes(true)); ok = in->read_image (outspec.format, &pixels[0]); if (! ok) { std::cerr << "iconvert ERROR reading \"" << in_filename << "\" : " << in->geterror() << "\n"; } else { ok = out->write_image (outspec.format, &pixels[0]); if (! ok) std::cerr << "iconvert ERROR writing \"" << out_filename << "\" : " << out->geterror() << "\n"; } } ++miplevel; } while (ok && in->seek_subimage(subimage,miplevel,inspec)); } out->close (); delete out; in->close (); delete in; // Figure out a time for the input file -- either one supplied by // the metadata, or the actual time stamp of the input file. std::time_t in_time; if (metadatatime.empty() || ! DateTime_to_time_t (metadatatime.c_str(), in_time)) in_time = Filesystem::last_write_time (in_filename); if (out_filename != tempname) { if (ok) { Filesystem::remove (out_filename); Filesystem::rename (tempname, out_filename); } else Filesystem::remove (tempname); } // If user requested, try to adjust the file's modification time to // the creation time indicated by the file's DateTime metadata. if (ok && adjust_time) Filesystem::last_write_time (out_filename, in_time); return ok; }
bool ImageBufAlgo::make_texture (ImageBufAlgo::MakeTextureMode mode, const std::vector<std::string> &filenames, const std::string &_outputfilename, const ImageSpec &_configspec, std::ostream *outstream_ptr) { ASSERT (mode >= 0 && mode < ImageBufAlgo::_MakeTxLast); Timer alltime; ImageSpec configspec = _configspec; // const char *modenames[] = { "texture map", "shadow map", // "latlong environment map" }; std::stringstream localstream; // catch output when user doesn't want it std::ostream &outstream (outstream_ptr ? *outstream_ptr : localstream); double stat_readtime = 0; double stat_writetime = 0; double stat_resizetime = 0; double stat_miptime = 0; double stat_colorconverttime = 0; std::string filename = filenames[0]; if (! Filesystem::exists (filename)) { outstream << "maketx ERROR: \"" << filename << "\" does not exist\n"; return false; } std::string outputfilename = _outputfilename.length() ? _outputfilename : Filesystem::replace_extension (filename, ".tx"); // When was the input file last modified? std::time_t in_time = Filesystem::last_write_time (filename); // When in update mode, skip making the texture if the output already // exists and has the same file modification time as the input file. bool updatemode = configspec.get_int_attribute ("maketx:updatemode"); if (updatemode && Filesystem::exists (outputfilename) && (in_time == Filesystem::last_write_time (outputfilename))) { outstream << "maketx: no update required for \"" << outputfilename << "\"\n"; return true; } bool shadowmode = (mode == ImageBufAlgo::MakeTxShadow); bool envlatlmode = (mode == ImageBufAlgo::MakeTxEnvLatl); // Find an ImageIO plugin that can open the output file, and open it std::string outformat = configspec.get_string_attribute ("maketx:fileformatname", outputfilename); ImageOutput *out = ImageOutput::create (outformat.c_str()); if (! out) { outstream << "maketx ERROR: Could not find an ImageIO plugin to write " << outformat << " files:" << geterror() << "\n"; return false; } if (! out->supports ("tiles")) { outstream << "maketx ERROR: \"" << outputfilename << "\" format does not support tiled images\n"; return false; } ImageBuf src (filename); src.init_spec (filename, 0, 0); // force it to get the spec, not read // The cache might mess with the apparent data format. But for the // purposes of what we should output, figure it out now, before the // file has been read and cached. TypeDesc out_dataformat = src.spec().format; if (configspec.format != TypeDesc::UNKNOWN) out_dataformat = configspec.format; // We cannot compute the prman / oiio options until after out_dataformat // has been determined, as it's required (and can potentially change // out_dataformat too!) if (configspec.get_int_attribute("maketx:prman_options")) out_dataformat = set_prman_options (out_dataformat, configspec); else if (configspec.get_int_attribute("maketx:oiio_options")) out_dataformat = set_oiio_options (out_dataformat, configspec); // Read the full file locally if it's less than 1 GB, otherwise // allow the ImageBuf to use ImageCache to manage memory. bool read_local = (src.spec().image_bytes() < size_t(1024*1024*1024)); bool verbose = configspec.get_int_attribute ("maketx:verbose"); if (verbose) outstream << "Reading file: " << filename << std::endl; Timer readtimer; if (! src.read (0, 0, read_local)) { outstream << "maketx ERROR: Could not read \"" << filename << "\" : " << src.geterror() << "\n"; return false; } stat_readtime += readtimer(); // If requested - and we're a constant color - make a tiny texture instead // Only safe if the full/display window is the same as the data window. // Also note that this could affect the appearance when using "black" // wrap mode at runtime. std::vector<float> constantColor(src.nchannels()); bool isConstantColor = false; if (configspec.get_int_attribute("maketx:constant_color_detect") && src.spec().x == 0 && src.spec().y == 0 && src.spec().z == 0 && src.spec().full_x == 0 && src.spec().full_y == 0 && src.spec().full_z == 0 && src.spec().full_width == src.spec().width && src.spec().full_height == src.spec().height && src.spec().full_depth == src.spec().depth) { isConstantColor = ImageBufAlgo::isConstantColor (src, &constantColor[0]); if (isConstantColor) { // Reset the image, to a new image, at the tile size ImageSpec newspec = src.spec(); newspec.width = std::min (configspec.tile_width, src.spec().width); newspec.height = std::min (configspec.tile_height, src.spec().height); newspec.depth = std::min (configspec.tile_depth, src.spec().depth); newspec.full_width = newspec.width; newspec.full_height = newspec.height; newspec.full_depth = newspec.depth; std::string name = src.name() + ".constant_color"; src.reset(name, newspec); ImageBufAlgo::fill (src, &constantColor[0]); if (verbose) { outstream << " Constant color image detected. "; outstream << "Creating " << newspec.width << "x" << newspec.height << " texture instead.\n"; } } } int nchannels = configspec.get_int_attribute ("maketx:nchannels", -1); // If requested -- and alpha is 1.0 everywhere -- drop it. if (configspec.get_int_attribute("maketx:opaque_detect") && src.spec().alpha_channel == src.nchannels()-1 && nchannels <= 0 && ImageBufAlgo::isConstantChannel(src,src.spec().alpha_channel,1.0f)) { ImageBuf newsrc(src.name() + ".noalpha", src.spec()); ImageBufAlgo::setNumChannels (newsrc, src, src.nchannels()-1); src.copy (newsrc); if (verbose) { outstream << " Alpha==1 image detected. Dropping the alpha channel.\n"; } } // If requested - and we're a monochrome image - drop the extra channels if (configspec.get_int_attribute("maketx:monochrome_detect") && nchannels <= 0 && src.nchannels() == 3 && src.spec().alpha_channel < 0 && // RGB only ImageBufAlgo::isMonochrome(src)) { ImageBuf newsrc(src.name() + ".monochrome", src.spec()); ImageBufAlgo::setNumChannels (newsrc, src, 1); src.copy (newsrc); if (verbose) { outstream << " Monochrome image detected. Converting to single channel texture.\n"; } } // If we've otherwise explicitly requested to write out a // specific number of channels, do it. if ((nchannels > 0) && (nchannels != src.nchannels())) { ImageBuf newsrc(src.name() + ".channels", src.spec()); ImageBufAlgo::setNumChannels (newsrc, src, nchannels); src.copy (newsrc); if (verbose) { outstream << " Overriding number of channels to " << nchannels << "\n"; } } if (shadowmode) { // Some special checks for shadow maps if (src.spec().nchannels != 1) { outstream << "maketx ERROR: shadow maps require 1-channel images,\n" << "\t\"" << filename << "\" is " << src.spec().nchannels << " channels\n"; return false; } // Shadow maps only make sense for floating-point data. if (out_dataformat != TypeDesc::FLOAT && out_dataformat != TypeDesc::HALF && out_dataformat != TypeDesc::DOUBLE) out_dataformat = TypeDesc::FLOAT; } if (configspec.get_int_attribute("maketx:set_full_to_pixels")) { // User requested that we treat the image as uncropped or not // overscan ImageSpec &spec (src.specmod()); spec.full_x = spec.x = 0; spec.full_y = spec.y = 0; spec.full_z = spec.z = 0; spec.full_width = spec.width; spec.full_height = spec.height; spec.full_depth = spec.depth; } // Copy the input spec const ImageSpec &srcspec = src.spec(); ImageSpec dstspec = srcspec; bool orig_was_volume = srcspec.depth > 1 || srcspec.full_depth > 1; bool orig_was_crop = (srcspec.x > srcspec.full_x || srcspec.y > srcspec.full_y || srcspec.z > srcspec.full_z || srcspec.x+srcspec.width < srcspec.full_x+srcspec.full_width || srcspec.y+srcspec.height < srcspec.full_y+srcspec.full_height || srcspec.z+srcspec.depth < srcspec.full_z+srcspec.full_depth); bool orig_was_overscan = (srcspec.x < srcspec.full_x && srcspec.y < srcspec.full_y && srcspec.x+srcspec.width > srcspec.full_x+srcspec.full_width && srcspec.y+srcspec.height > srcspec.full_y+srcspec.full_height && (!orig_was_volume || (srcspec.z < srcspec.full_z && srcspec.z+srcspec.depth > srcspec.full_z+srcspec.full_depth))); // Make the output not a crop window if (orig_was_crop) { dstspec.x = 0; dstspec.y = 0; dstspec.z = 0; dstspec.width = srcspec.full_width; dstspec.height = srcspec.full_height; dstspec.depth = srcspec.full_depth; dstspec.full_x = 0; dstspec.full_y = 0; dstspec.full_z = 0; dstspec.full_width = dstspec.width; dstspec.full_height = dstspec.height; dstspec.full_depth = dstspec.depth; } if (orig_was_overscan) configspec.attribute ("wrapmodes", "black,black"); if ((dstspec.x < 0 || dstspec.y < 0 || dstspec.z < 0) && (out && !out->supports("negativeorigin"))) { // User passed negative origin but the output format doesn't // support it. Try to salvage the situation by shifting the // image into the positive range. if (dstspec.x < 0) { dstspec.full_x -= dstspec.x; dstspec.x = 0; } if (dstspec.y < 0) { dstspec.full_y -= dstspec.y; dstspec.y = 0; } if (dstspec.z < 0) { dstspec.full_z -= dstspec.z; dstspec.z = 0; } } // Make the output tiled, regardless of input dstspec.tile_width = configspec.tile_width ? configspec.tile_width : 64; dstspec.tile_height = configspec.tile_height ? configspec.tile_height : 64; dstspec.tile_depth = configspec.tile_depth ? configspec.tile_depth : 1; // Try to force zip (still can be overriden by configspec dstspec.attribute ("compression", "zip"); // Always prefer contiguous channels, unless overridden by configspec dstspec.attribute ("planarconfig", "contig"); // Default to black wrap mode, unless overridden by configspec dstspec.attribute ("wrapmodes", "black,black"); if (configspec.get_int_attribute ("maketx:ignore_unassoc")) dstspec.erase_attribute ("oiio:UnassociatedAlpha"); // Put a DateTime in the out file, either now, or matching the date // stamp of the input file (if update mode). time_t date; if (updatemode) date = in_time; // update mode: use the time stamp of the input else time (&date); // not update: get the time now dstspec.attribute ("DateTime", datestring(date)); std::string cmdline = configspec.get_string_attribute ("maketx:full_command_line"); if (! cmdline.empty()) { // Append command to image history std::string history = dstspec.get_string_attribute ("Exif:ImageHistory"); if (history.length() && ! Strutil::iends_with (history, "\n")) history += std::string("\n"); history += cmdline; dstspec.attribute ("Exif:ImageHistory", history); } bool prman_metadata = configspec.get_int_attribute ("maketx:prman_metadata"); if (shadowmode) { dstspec.attribute ("textureformat", "Shadow"); if (prman_metadata) dstspec.attribute ("PixarTextureFormat", "Shadow"); } else if (envlatlmode) { dstspec.attribute ("textureformat", "LatLong Environment"); configspec.attribute ("wrapmodes", "periodic,clamp"); if (prman_metadata) dstspec.attribute ("PixarTextureFormat", "Latlong Environment"); } else { dstspec.attribute ("textureformat", "Plain Texture"); if (prman_metadata) dstspec.attribute ("PixarTextureFormat", "Plain Texture"); } // FIXME -- should we allow tile sizes to reduce if the image is // smaller than the tile size? And when we do, should we also try // to make it bigger in the other direction to make the total tile // size more constant? // If --checknan was used and it's a floating point image, check for // nonfinite (NaN or Inf) values and abort if they are found. if (configspec.get_int_attribute("maketx:checknan") && (srcspec.format.basetype == TypeDesc::FLOAT || srcspec.format.basetype == TypeDesc::HALF || srcspec.format.basetype == TypeDesc::DOUBLE)) { int found_nonfinite = 0; ImageBufAlgo::parallel_image (boost::bind(check_nan_block, &src, _1, boost::ref(found_nonfinite)), OIIO::get_roi(dstspec)); if (found_nonfinite) { if (found_nonfinite > 3) outstream << "maketx ERROR: ...and Nan/Inf at " << (found_nonfinite-3) << " other pixels\n"; return false; } } // Fix nans/infs (if requested ImageBufAlgo::NonFiniteFixMode fixmode = ImageBufAlgo::NONFINITE_NONE; std::string fixnan = configspec.get_string_attribute("maketx:fixnan"); if (fixnan.empty() || fixnan == "none") { } else if (fixnan == "black") { fixmode = ImageBufAlgo::NONFINITE_BLACK; } else if (fixnan == "box3") { fixmode = ImageBufAlgo::NONFINITE_BOX3; } else { outstream << "maketx ERROR: Unknown --fixnan mode " << " fixnan\n"; return false; } int pixelsFixed = 0; if (!ImageBufAlgo::fixNonFinite (src, src, fixmode, &pixelsFixed)) { outstream << "maketx ERROR: Error fixing nans/infs.\n"; return false; } if (verbose && pixelsFixed>0) { outstream << " Warning: " << pixelsFixed << " nan/inf pixels fixed.\n"; } // Color convert the pixels, if needed, in place. If a color // conversion is required we will promote the src to floating point // (or there wont be enough precision potentially). Also, // independently color convert the constant color metadata ImageBuf * ccSrc = &src; // Ptr to cc'd src image ImageBuf colorBuffer; std::string incolorspace = configspec.get_string_attribute ("incolorspace"); std::string outcolorspace = configspec.get_string_attribute ("outcolorspace"); if (!incolorspace.empty() && !outcolorspace.empty() && incolorspace != outcolorspace) { if (src.spec().format != TypeDesc::FLOAT) { ImageSpec floatSpec = src.spec(); floatSpec.set_format(TypeDesc::FLOAT); colorBuffer.reset("bitdepth promoted", floatSpec); ccSrc = &colorBuffer; } Timer colorconverttimer; ColorConfig colorconfig; if (verbose) { outstream << " Converting from colorspace " << incolorspace << " to colorspace " << outcolorspace << std::endl; } if (colorconfig.error()) { outstream << "Error Creating ColorConfig\n"; outstream << colorconfig.geterror() << std::endl; return false; } ColorProcessor * processor = colorconfig.createColorProcessor ( incolorspace.c_str(), outcolorspace.c_str()); if (!processor || colorconfig.error()) { outstream << "Error Creating Color Processor." << std::endl; outstream << colorconfig.geterror() << std::endl; return false; } bool unpremult = configspec.get_int_attribute ("maketx:unpremult"); if (unpremult && verbose) outstream << " Unpremulting image..." << std::endl; if (!ImageBufAlgo::colorconvert (*ccSrc, src, processor, unpremult)) { outstream << "Error applying color conversion to image.\n"; return false; } if (isConstantColor) { if (!ImageBufAlgo::colorconvert (&constantColor[0], static_cast<int>(constantColor.size()), processor, unpremult)) { outstream << "Error applying color conversion to constant color.\n"; return false; } } ColorConfig::deleteColorProcessor(processor); processor = NULL; stat_colorconverttime += colorconverttimer(); } // Force float for the sake of the ImageBuf math dstspec.set_format (TypeDesc::FLOAT); // Handle resize to power of two, if called for if (configspec.get_int_attribute("maketx:resize") && ! shadowmode) { dstspec.width = pow2roundup (dstspec.width); dstspec.height = pow2roundup (dstspec.height); dstspec.full_width = dstspec.width; dstspec.full_height = dstspec.height; } bool do_resize = false; // Resize if we're up-resing for pow2 if (dstspec.width != srcspec.width || dstspec.height != srcspec.height || dstspec.full_depth != srcspec.full_depth) do_resize = true; // resize if the original was a crop if (orig_was_crop) do_resize = true; // resize if we're converting from non-border sampling to border sampling // (converting TO an OpenEXR environment map). if (envlatlmode && (Strutil::iequals(configspec.get_string_attribute("maketx:fileformatname"),"openexr") || Strutil::iends_with(outputfilename,".exr"))) do_resize = true; if (do_resize && orig_was_overscan && out && !out->supports("displaywindow")) { outstream << "maketx ERROR: format " << out->format_name() << " does not support separate display windows,\n" << " which is necessary when combining resizing" << " and an input image with overscan."; return false; } std::string filtername = configspec.get_string_attribute ("maketx:filtername", "box"); Filter2D *filter = setup_filter (filtername); if (! filter) { outstream << "maketx ERROR: could not make filter '" << filtername << "\n"; return false; } Timer resizetimer; ImageBuf dst ("temp", dstspec); ImageBuf *toplevel = &dst; // Ptr to top level of mipmap if (! do_resize) { // Don't need to resize if (dstspec.format == ccSrc->spec().format) { // Even more special case, no format change -- just use // the original copy. toplevel = ccSrc; } else { ImageBufAlgo::parallel_image (boost::bind(copy_block,&dst,ccSrc,_1), OIIO::get_roi(dstspec)); } } else { // Resize if (verbose) outstream << " Resizing image to " << dstspec.width << " x " << dstspec.height << std::endl; if (filtername == "box" && filter->width() == 1.0f) ImageBufAlgo::parallel_image (boost::bind(resize_block, &dst, ccSrc, _1, envlatlmode), OIIO::get_roi(dstspec)); else ImageBufAlgo::parallel_image (boost::bind(resize_block_HQ, &dst, ccSrc, _1, filter), OIIO::get_roi(dstspec)); } stat_resizetime += resizetimer(); // Update the toplevel ImageDescription with the sha1 pixel hash and constant color std::string desc = dstspec.get_string_attribute ("ImageDescription"); bool updatedDesc = false; // Eliminate any SHA-1 or ConstantColor hints in the ImageDescription. if (desc.size()) { desc = boost::regex_replace (desc, boost::regex("SHA-1=[[:xdigit:]]*[ ]*"), ""); static const char *fp_number_pattern = "([+-]?((?:(?:[[:digit:]]*\\.)?[[:digit:]]+(?:[eE][+-]?[[:digit:]]+)?)))"; const std::string color_pattern = std::string ("ConstantColor=(\\[?") + fp_number_pattern + ",?)+\\]?[ ]*"; desc = boost::regex_replace (desc, boost::regex(color_pattern), ""); updatedDesc = true; } // The hash is only computed for the top mipmap level of pixel data. // Thus, any additional information that will effect the lower levels // (such as filtering information) needs to be manually added into the // hash. std::ostringstream addlHashData; addlHashData << filter->name() << " "; addlHashData << filter->width() << " "; std::string hash_digest = ImageBufAlgo::computePixelHashSHA1 (*toplevel, addlHashData.str()); if (hash_digest.length()) { if (desc.length()) desc += " "; desc += "SHA-1="; desc += hash_digest; if (verbose) outstream << " SHA-1: " << hash_digest << std::endl; updatedDesc = true; dstspec.attribute ("oiio:SHA-1", hash_digest); } if (isConstantColor) { std::ostringstream os; // Emulate a JSON array os << "["; for (unsigned int i=0; i<constantColor.size(); ++i) { if (i!=0) os << ","; os << constantColor[i]; } os << "]"; if (desc.length()) desc += " "; desc += "ConstantColor="; desc += os.str(); if (verbose) outstream << " ConstantColor: " << os.str() << std::endl; updatedDesc = true; dstspec.attribute ("oiio:ConstantColor", os.str()); } if (updatedDesc) { dstspec.attribute ("ImageDescription", desc); } if (configspec.get_float_attribute("fovcot") == 0.0f) configspec.attribute("fovcot", float(srcspec.full_width) / float(srcspec.full_height)); maketx_merge_spec (dstspec, configspec); // Write out, and compute, the mipmap levels for the speicifed image bool nomipmap = configspec.get_int_attribute ("maketx:nomipmap"); bool ok = write_mipmap (mode, *toplevel, dstspec, outputfilename, out, out_dataformat, !shadowmode && !nomipmap, filter, configspec, outstream, stat_writetime, stat_miptime); delete out; // don't need it any more // If using update mode, stamp the output file with a modification time // matching that of the input file. if (ok && updatemode) Filesystem::last_write_time (outputfilename, in_time); Filter2D::destroy (filter); if (verbose || configspec.get_int_attribute("maketx:stats")) { double all = alltime(); outstream << Strutil::format ("maketx run time (seconds): %5.2f\n", all);; outstream << Strutil::format (" file read: %5.2f\n", stat_readtime); outstream << Strutil::format (" file write: %5.2f\n", stat_writetime); outstream << Strutil::format (" initial resize: %5.2f\n", stat_resizetime); outstream << Strutil::format (" mip computation: %5.2f\n", stat_miptime); outstream << Strutil::format (" color convert: %5.2f\n", stat_colorconverttime); outstream << Strutil::format (" unaccounted: %5.2f\n", all-stat_readtime-stat_writetime-stat_resizetime-stat_miptime); size_t kb = Sysutil::memory_used(true) / 1024; outstream << Strutil::format ("maketx memory used: %5.1f MB\n", (double)kb/1024.0); } return ok; }
OIIO_NAMESPACE_USING #include <algorithm> #include "Perlin.h" int main(int argc, char* argv[]) { try { options_description desc("Allowed options"); desc.add_options() ("help,h", "produce help message") ("xres,x", value<int>()->default_value(255), "x resolution") ("yres,y", value<int>()->default_value(255), "y resolution") ("sample-size,s", value<int>()->default_value(256), "sample size") ("seed,r", value<int>()->default_value(0), "psuedo-random seed") ("persistence,p", value<float>()->default_value(0.5f), "persistence value") ("octaves,o", value<int>()->default_value(2), "number of octaves") ; options_description hidden("Hidden options"); hidden.add_options() ("output-file", value<string>()->required(), "output file") ; options_description all("Allowed options"); all.add(desc).add(hidden); positional_options_description p; p.add("output-file", 1); variables_map vm; store(command_line_parser(argc, argv).options(all) .positional(p).run(), vm); if (vm.count("help")) { cout << "Usage: " << argv[0] << " [options] output-file" << endl; cout << desc << endl; return 0; } notify(vm); string outputfile = vm["output-file"].as<string>(); ImageOutput* out = ImageOutput::create(outputfile); if (!out) { cerr << "Could not create an ImageOutput for " << outputfile << ", error = " << OpenImageIO::geterror() << endl; return 0; } const int xres = vm["xres"].as<int>(); const int yres = vm["yres"].as<int>(); const int channels = 3; // RGB ImageSpec outspec(xres, yres, channels, TypeDesc::UINT8); if (!out->open(outputfile, outspec)) { cerr << "Could not open " << outputfile << ", error = " << out->geterror() << endl; ImageOutput::destroy(out); return 0; } const int sample_size = vm["sample-size"].as<int>(); const int seed = vm["seed"].as<int>(); Perlin perlin(sample_size, seed); float persistence = vm["persistence"].as<float>(); int octaves = vm["octaves"].as<int>(); unsigned char pixels[xres * yres * channels]; for (int y = 0; y < yres; y++) { for (int x = 0; x < xres; x++) { float frequency, amplitude; float total = 0.0f; for (int i = 1; i <= octaves; ++i) { frequency = pow(2.0f, i); amplitude = pow(persistence, i); total += (perlin.Noise2(frequency * x / sample_size, frequency * y / sample_size) + 1)/ 2.0f * amplitude; } total = min<float>(1.0f, max<float>(0.0f, total)); unsigned int noise = (unsigned int) (total * 255); pixels[y * xres * channels + x * channels] = noise; pixels[y * xres * channels + x * channels + 1] = noise; pixels[y * xres * channels + x * channels + 2] = noise; } } if (!out->write_image(TypeDesc::UINT8, pixels)) { cerr << "Could not write pixels to " << outputfile << ", error = " << out->geterror() << endl; ImageOutput::destroy(out); return 0; } ImageOutput::destroy(out); } catch (exception& e) { cerr << e.what() << endl; } }