bool encode_load_input_images(int argc, char **argv, Images &images) { int nb_input_images = argc-1; while(argc>1) { Image image; v_printf(2,"\r"); if (!image.load(argv[0])) { e_printf("Could not read input file: %s\n", argv[0]); return false; }; images.push_back(std::move(image)); Image& last_image = images.back(); if (last_image.rows() != images[0].rows() || last_image.cols() != images[0].cols()) { e_printf("Dimensions of all input images should be the same!\n"); e_printf(" First image is %ux%u\n",images[0].cols(),images[0].rows()); e_printf(" This image is %ux%u: %s\n",last_image.cols(),last_image.rows(),argv[0]); return false; } if (last_image.numPlanes() < images[0].numPlanes()) { if (images[0].numPlanes() == 3) last_image.ensure_chroma(); else if (images[0].numPlanes() == 4) last_image.ensure_alpha(); else { e_printf("Problem while loading input images, please report this.\n"); return false; } } else if (last_image.numPlanes() > images[0].numPlanes()) { if (last_image.numPlanes() == 3) { for (Image& i : images) i.ensure_chroma(); } else if (last_image.numPlanes() == 4) { for (Image& i : images) i.ensure_alpha(); } else { e_printf("Problem while loading input images, please report this.\n"); return false; } } argc--; argv++; if (nb_input_images>1) {v_printf(2," (%i/%i) ",(int)images.size(),nb_input_images); v_printf(4,"\n");} } v_printf(2,"\n"); return true; }
Images LoadImagesFromDisk(const std::string & path) { Images result; int exceptionCounter = 0; for (int i = 0; i != 100; ++i) { try { result.push_back(Image::fromFile(path + std::to_string(i))); } catch (boost::exception & exc) { exc << ProgressTag(i); if (const std::string * fileName = boost::get_error_info<FileNameTag>(exc)) { std::cerr << "Failed to load image " << i << "/100: " << *fileName << ". Origin: "; const char * file = *boost::get_error_info<boost::throw_file>(exc); int line = *boost::get_error_info<boost::throw_line>(exc); const char * func = *boost::get_error_info<boost::throw_function>(exc); std::cerr << file << ":" << line << ": " << func << std::endl; if (++exceptionCounter >= 10) { BOOST_THROW_EXCEPTION(TooManyErrors() << InformationTag("Too many exceptions. Bailing out.")); } } } } return result; }
bool encode_load_input_images(int argc, char **argv, Images &images) { int nb_input_images = argc-1; while(argc>1) { Image image; v_printf(2,"\r"); if (!image.load(argv[0])) { e_printf("Could not read input file: %s\n", argv[0]); return false; }; images.push_back(std::move(image)); const Image& last_image = images.back(); if (last_image.rows() != images[0].rows() || last_image.cols() != images[0].cols() || last_image.numPlanes() != images[0].numPlanes()) { e_printf("Dimensions of all input images should be the same!\n"); e_printf(" First image is %ux%u, %i channels.\n",images[0].cols(),images[0].rows(),images[0].numPlanes()); e_printf(" This image is %ux%u, %i channels: %s\n",last_image.cols(),last_image.rows(),last_image.numPlanes(),argv[0]); return false; } argc--; argv++; if (nb_input_images>1) {v_printf(2," (%i/%i) ",(int)images.size(),nb_input_images); v_printf(4,"\n");} } v_printf(2,"\n"); return true; }
Images FrameData::startReadback( const Frame& frame, util::ObjectManager& glObjects, const DrawableConfig& config, const PixelViewports& regions ) { if( _impl->data.buffers == Frame::BUFFER_NONE ) return Images(); const Zoom& zoom = frame.getZoom(); if( !zoom.isValid( )) { LBWARN << "Invalid zoom factor, skipping frame" << std::endl; return Images(); } const eq::PixelViewport& framePVP = getPixelViewport(); const PixelViewport absPVP = framePVP + frame.getOffset(); if( !absPVP.isValid( )) return Images(); Images images; // readback the whole screen when using textures if( getType() == eq::Frame::TYPE_TEXTURE ) { Image* image = newImage( getType(), config ); if( image->startReadback( getBuffers(), absPVP, zoom, glObjects )) images.push_back( image ); image->setOffset( 0, 0 ); return images; } //else read only required regions #if 0 // TODO: issue #85: move automatic ROI detection to eq::Channel PixelViewports regions; if( _impl->data.buffers & Frame::BUFFER_DEPTH && zoom == Zoom::NONE ) regions = _impl->roiFinder->findRegions( _impl->data.buffers, absPVP, zoom, frame.getAssemblyStage(), frame.getFrameID(), glObjects); else regions.push_back( absPVP ); #endif LBASSERT( getType() == eq::Frame::TYPE_MEMORY ); const eq::Pixel& pixel = getPixel(); for( uint32_t i = 0; i < regions.size(); ++i ) { PixelViewport pvp = regions[ i ] + frame.getOffset(); pvp.intersect( absPVP ); if( !pvp.hasArea( )) continue; Image* image = newImage( getType(), config ); if( image->startReadback( getBuffers(), pvp, zoom, glObjects )) images.push_back( image ); pvp -= frame.getOffset(); pvp.apply( zoom ); image->setOffset( (pvp.x - framePVP.x) * pixel.w, (pvp.y - framePVP.y) * pixel.h ); } return images; }
int main(int argc, char **argv) { Images images; int mode = 0; // 0 = encode, 1 = decode int method = 0; // 1=non-interlacing, 2=interlacing int quality = 100; // 100 = everything, positive value: partial decode, negative value: only rough data int learn_repeats = -1; int acb = -1; // try auto color buckets int scale = 1; int frame_delay = 100; int palette_size = 512; int lookback = 1; if (strcmp(argv[0],"flif") == 0) mode = 0; if (strcmp(argv[0],"dflif") == 0) mode = 1; if (strcmp(argv[0],"deflif") == 0) mode = 1; if (strcmp(argv[0],"decflif") == 0) mode = 1; static struct option optlist[] = { {"help", 0, NULL, 'h'}, {"encode", 0, NULL, 'e'}, {"decode", 0, NULL, 'd'}, {"first", 1, NULL, 'f'}, {"verbose", 0, NULL, 'v'}, {"interlace", 0, NULL, 'i'}, {"no-interlace", 0, NULL, 'n'}, {"acb", 0, NULL, 'a'}, {"no-acb", 0, NULL, 'b'}, {"quality", 1, NULL, 'q'}, {"scale", 1, NULL, 's'}, {"palette", 1, NULL, 'p'}, {"repeats", 1, NULL, 'r'}, {"frame-delay", 1, NULL, 'f'}, {"lookback", 1, NULL, 'l'}, {0, 0, 0, 0} }; int i,c; while ((c = getopt_long (argc, argv, "hedvinabq:s:p:r:f:l:", optlist, &i)) != -1) { switch (c) { case 'e': mode=0; break; case 'd': mode=1; break; case 'v': verbosity++; break; case 'i': if (method==0) method=2; break; case 'n': method=1; break; case 'a': acb=1; break; case 'b': acb=0; break; case 'p': palette_size=atoi(optarg); if (palette_size < -1 || palette_size > 30000) {fprintf(stderr,"Not a sensible number for option -p\n"); return 1; } if (palette_size == 0) {v_printf(2,"Palette disabled\n"); } break; case 'q': quality=atoi(optarg); if (quality < -1 || quality > 100) {fprintf(stderr,"Not a sensible number for option -q\n"); return 1; } break; case 's': scale=atoi(optarg); if (scale < 1 || scale > 128) {fprintf(stderr,"Not a sensible number for option -s\n"); return 1; } break; case 'r': learn_repeats=atoi(optarg); if (learn_repeats < 0 || learn_repeats > 1000) {fprintf(stderr,"Not a sensible number for option -r\n"); return 1; } break; case 'f': frame_delay=atoi(optarg); if (frame_delay < 0 || frame_delay > 60000) {fprintf(stderr,"Not a sensible number for option -f\n"); return 1; } break; case 'l': lookback=atoi(optarg); if (lookback < -1 || lookback > 256) {fprintf(stderr,"Not a sensible number for option -l\n"); return 1; } break; case 'h': default: show_help(); return 0; } } argc -= optind; argv += optind; v_printf(3," _____ __ (__) _____"); v_printf(3,"\n (___ || | | || ___) ");v_printf(2,"FLIF 0.1 [2 October 2015]"); v_printf(3,"\n (__ || |_|__|| __) Free Lossless Image Format"); v_printf(3,"\n (__||______) |__) (c) 2010-2015 J.Sneyers & P.Wuille, GNU GPL v3+\n"); v_printf(3,"\n"); if (argc == 0) { //fprintf(stderr,"Input file missing.\n"); if (verbosity == 1) show_help(); return 1; } if (argc == 1) { fprintf(stderr,"Output file missing.\n"); show_help(); return 1; } if (file_exists(argv[0])) { if (mode == 0 && file_is_flif(argv[0])) { v_printf(2,"Input file is a FLIF file, adding implicit -d\n"); mode = 1; } char *f = strrchr(argv[0],'/'); char *ext = f ? strrchr(f,'.') : strrchr(argv[0],'.'); if (mode == 0) { if (ext && ( !strcasecmp(ext,".png") || !strcasecmp(ext,".pnm") || !strcasecmp(ext,".ppm") || !strcasecmp(ext,".pgm") || !strcasecmp(ext,".pbm") || !strcasecmp(ext,".pam"))) { // ok } else { fprintf(stderr,"Warning: expected \".png\" or \".pnm\" file name extension for input file, trying anyway...\n"); } } else { if (ext && ( !strcasecmp(ext,".flif") || ( !strcasecmp(ext,".flf") ))) { // ok } else { fprintf(stderr,"Warning: expected file name extension \".flif\" for input file, trying anyway...\n"); } } } else if (argc>0) { fprintf(stderr,"Input file does not exist: %s\n",argv[0]); return 1; } if (mode == 0) { int nb_input_images = argc-1; while(argc>1) { Image image; v_printf(2,"\r"); if (!image.load(argv[0])) { fprintf(stderr,"Could not read input file: %s\n", argv[0]); return 2; }; images.push_back(image); if (image.rows() != images[0].rows() || image.cols() != images[0].cols() || image.numPlanes() != images[0].numPlanes()) { fprintf(stderr,"Dimensions of all input images should be the same!\n"); fprintf(stderr," First image is %ux%u, %i channels.\n",images[0].cols(),images[0].rows(),images[0].numPlanes()); fprintf(stderr," This image is %ux%u, %i channels: %s\n",image.cols(),image.rows(),image.numPlanes(),argv[0]); return 2; } argc--; argv++; if (nb_input_images>1) {v_printf(2," (%i/%i) ",(int)images.size(),nb_input_images); v_printf(4,"\n");} } v_printf(2,"\n"); bool flat=true; for (Image &image : images) if (image.uses_alpha()) flat=false; if (flat && images[0].numPlanes() == 4) { v_printf(2,"Alpha channel not actually used, dropping it.\n"); for (Image &image : images) image.drop_alpha(); } uint64_t nb_pixels = (uint64_t)images[0].rows() * images[0].cols(); std::vector<std::string> desc; desc.push_back("YIQ"); // convert RGB(A) to YIQ(A) desc.push_back("BND"); // get the bounds of the color spaces if (palette_size > 0) desc.push_back("PLA"); // try palette (including alpha) if (palette_size > 0) desc.push_back("PLT"); // try palette (without alpha) if (acb == -1) { // not specified if ACB should be used if (nb_pixels > 10000) desc.push_back("ACB"); // try auto color buckets on large images } else if (acb) desc.push_back("ACB"); // try auto color buckets if forced if (method == 0) { // no method specified, pick one heuristically if (nb_pixels < 10000) method=1; // if the image is small, not much point in doing interlacing else method=2; // default method: interlacing } if (images.size() > 1) { desc.push_back("DUP"); // find duplicate frames desc.push_back("FRS"); // get the shapes of the frames if (lookback != 0) desc.push_back("FRA"); // make a "deep" alpha channel (negative values are transparent to some previous frame) } if (learn_repeats < 0) { // no number of repeats specified, pick a number heuristically learn_repeats = TREE_LEARN_REPEATS; if (nb_pixels < 5000) learn_repeats--; // avoid large trees for small images if (learn_repeats < 0) learn_repeats=0; } encode(argv[0], images, desc, method, learn_repeats, acb, frame_delay, palette_size, lookback); } else { char *ext = strrchr(argv[1],'.'); if (ext && ( !strcasecmp(ext,".png") || !strcasecmp(ext,".pnm") || !strcasecmp(ext,".ppm") || !strcasecmp(ext,".pgm") || !strcasecmp(ext,".pbm") || !strcasecmp(ext,".pam"))) { // ok } else { fprintf(stderr,"Error: expected \".png\", \".pnm\" or \".pam\" file name extension for output file\n"); return 1; } if (!decode(argv[0], images, quality, scale)) return 3; if (scale>1) v_printf(3,"Downscaling output: %ux%u -> %ux%u\n",images[0].cols(),images[0].rows(),images[0].cols()/scale,images[0].rows()/scale); if (images.size() == 1) { if (!images[0].save(argv[1],scale)) return 2; } else { int counter=0; std::vector<char> vfilename(strlen(argv[1])+6); char *filename = &vfilename[0]; strcpy(filename,argv[1]); char *a_ext = strrchr(filename,'.'); for (Image& image : images) { sprintf(a_ext,"-%03d%s",counter++,ext); if (!image.save(filename,scale)) return 2; v_printf(2," (%i/%i) \r",counter,(int)images.size()); v_printf(4,"\n"); } } v_printf(2,"\n"); } for (Image &image : images) image.clear(); return 0; }
int main( int argc, char **argv ) { // use an ArgumentParser object to manage the program arguments. osg::ArgumentParser arguments(&argc,argv); // set up the usage document, in case we need to print out how to use this program. arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the example which demonstrates use of 3D textures."); arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ..."); arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information"); arguments.getApplicationUsage()->addCommandLineOption("--images [filenames]","Specify a stack of 2d images to build the 3d volume from."); arguments.getApplicationUsage()->addCommandLineOption("--shader","Use OpenGL Shading Language. (default)"); arguments.getApplicationUsage()->addCommandLineOption("--no-shader","Disable use of OpenGL Shading Language."); arguments.getApplicationUsage()->addCommandLineOption("--gpu-tf","Aply the transfer function on the GPU. (default)"); arguments.getApplicationUsage()->addCommandLineOption("--cpu-tf","Apply the transfer function on the CPU."); arguments.getApplicationUsage()->addCommandLineOption("--mip","Use Maximum Intensity Projection (MIP) filtering."); arguments.getApplicationUsage()->addCommandLineOption("--isosurface","Use Iso surface render."); arguments.getApplicationUsage()->addCommandLineOption("--light","Use normals computed on the GPU to render a lit volume."); arguments.getApplicationUsage()->addCommandLineOption("-n","Use normals computed on the GPU to render a lit volume."); arguments.getApplicationUsage()->addCommandLineOption("--xSize <size>","Relative width of rendered brick."); arguments.getApplicationUsage()->addCommandLineOption("--ySize <size>","Relative length of rendered brick."); arguments.getApplicationUsage()->addCommandLineOption("--zSize <size>","Relative height of rendered brick."); arguments.getApplicationUsage()->addCommandLineOption("--maxTextureSize <size>","Set the texture maximum resolution in the s,t,r (x,y,z) dimensions."); arguments.getApplicationUsage()->addCommandLineOption("--s_maxTextureSize <size>","Set the texture maximum resolution in the s (x) dimension."); arguments.getApplicationUsage()->addCommandLineOption("--t_maxTextureSize <size>","Set the texture maximum resolution in the t (y) dimension."); arguments.getApplicationUsage()->addCommandLineOption("--r_maxTextureSize <size>","Set the texture maximum resolution in the r (z) dimension."); arguments.getApplicationUsage()->addCommandLineOption("--modulate-alpha-by-luminance","For each pixel multiply the alpha value by the luminance."); arguments.getApplicationUsage()->addCommandLineOption("--replace-alpha-with-luminance","For each pixel set the alpha value to the luminance."); arguments.getApplicationUsage()->addCommandLineOption("--replace-rgb-with-luminance","For each rgb pixel convert to the luminance."); arguments.getApplicationUsage()->addCommandLineOption("--num-components <num>","Set the number of components to in he target image."); arguments.getApplicationUsage()->addCommandLineOption("--no-rescale","Disable the rescaling of the pixel data to 0.0 to 1.0 range"); arguments.getApplicationUsage()->addCommandLineOption("--rescale","Enable the rescale of the pixel data to 0.0 to 1.0 range (default)."); arguments.getApplicationUsage()->addCommandLineOption("--shift-min-to-zero","Shift the pixel data so min value is 0.0."); arguments.getApplicationUsage()->addCommandLineOption("--sequence-length <num>","Set the length of time that a sequence of images with run for."); arguments.getApplicationUsage()->addCommandLineOption("--sd <num>","Short hand for --sequence-length"); arguments.getApplicationUsage()->addCommandLineOption("--sdwm <num>","Set the SampleDensityWhenMovingProperty to specified value"); arguments.getApplicationUsage()->addCommandLineOption("--lod","Enable techniques to reduce the level of detail when moving."); // arguments.getApplicationUsage()->addCommandLineOption("--raw <sizeX> <sizeY> <sizeZ> <numberBytesPerComponent> <numberOfComponents> <endian> <filename>","read a raw image data"); // construct the viewer. osgViewer::Viewer viewer(arguments); // add the window size toggle handler viewer.addEventHandler(new osgViewer::WindowSizeHandler); { osg::ref_ptr<osgGA::KeySwitchMatrixManipulator> keyswitchManipulator = new osgGA::KeySwitchMatrixManipulator; keyswitchManipulator->addMatrixManipulator( '1', "Trackball", new osgGA::TrackballManipulator() ); osgGA::FlightManipulator* flightManipulator = new osgGA::FlightManipulator(); flightManipulator->setYawControlMode(osgGA::FlightManipulator::NO_AUTOMATIC_YAW); keyswitchManipulator->addMatrixManipulator( '2', "Flight", flightManipulator ); viewer.setCameraManipulator( keyswitchManipulator.get() ); } // add the stats handler viewer.addEventHandler(new osgViewer::StatsHandler); viewer.getCamera()->setClearColor(osg::Vec4(0.0f,0.0f,0.0f,0.0f)); // if user request help write it out to cout. if (arguments.read("-h") || arguments.read("--help")) { arguments.getApplicationUsage()->write(std::cout); return 1; } std::string outputFile; while (arguments.read("-o",outputFile)) {} osg::ref_ptr<osg::TransferFunction1D> transferFunction; std::string tranferFunctionFile; while (arguments.read("--tf",tranferFunctionFile)) { transferFunction = readTransferFunctionFile(tranferFunctionFile); } while (arguments.read("--tf-255",tranferFunctionFile)) { transferFunction = readTransferFunctionFile(tranferFunctionFile,1.0f/255.0f); } while(arguments.read("--test")) { transferFunction = new osg::TransferFunction1D; transferFunction->setColor(0.0, osg::Vec4(1.0,0.0,0.0,0.0)); transferFunction->setColor(0.5, osg::Vec4(1.0,1.0,0.0,0.5)); transferFunction->setColor(1.0, osg::Vec4(0.0,0.0,1.0,1.0)); } while(arguments.read("--test2")) { transferFunction = new osg::TransferFunction1D; transferFunction->setColor(0.0, osg::Vec4(1.0,0.0,0.0,0.0)); transferFunction->setColor(0.5, osg::Vec4(1.0,1.0,0.0,0.5)); transferFunction->setColor(1.0, osg::Vec4(0.0,0.0,1.0,1.0)); transferFunction->assign(transferFunction->getColorMap()); } { // deprecated options bool invalidOption = false; unsigned int numSlices=500; while (arguments.read("-s",numSlices)) { OSG_NOTICE<<"Warning: -s option no longer supported."<<std::endl; invalidOption = true; } float sliceEnd=1.0f; while (arguments.read("--clip",sliceEnd)) { OSG_NOTICE<<"Warning: --clip option no longer supported."<<std::endl; invalidOption = true; } if (invalidOption) return 1; } float xMultiplier=1.0f; while (arguments.read("--xMultiplier",xMultiplier)) {} float yMultiplier=1.0f; while (arguments.read("--yMultiplier",yMultiplier)) {} float zMultiplier=1.0f; while (arguments.read("--zMultiplier",zMultiplier)) {} float alphaFunc=0.02f; while (arguments.read("--alphaFunc",alphaFunc)) {} ShadingModel shadingModel = Standard; while(arguments.read("--mip")) shadingModel = MaximumIntensityProjection; while (arguments.read("--isosurface") || arguments.read("--iso-surface")) shadingModel = Isosurface; while (arguments.read("--light") || arguments.read("-n")) shadingModel = Light; float xSize=0.0f, ySize=0.0f, zSize=0.0f; while (arguments.read("--xSize",xSize)) {} while (arguments.read("--ySize",ySize)) {} while (arguments.read("--zSize",zSize)) {} osg::ref_ptr<TestSupportOperation> testSupportOperation = new TestSupportOperation; viewer.setRealizeOperation(testSupportOperation.get()); viewer.realize(); int maximumTextureSize = testSupportOperation->maximumTextureSize; int s_maximumTextureSize = maximumTextureSize; int t_maximumTextureSize = maximumTextureSize; int r_maximumTextureSize = maximumTextureSize; while(arguments.read("--maxTextureSize",maximumTextureSize)) { s_maximumTextureSize = maximumTextureSize; t_maximumTextureSize = maximumTextureSize; r_maximumTextureSize = maximumTextureSize; } while(arguments.read("--s_maxTextureSize",s_maximumTextureSize)) {} while(arguments.read("--t_maxTextureSize",t_maximumTextureSize)) {} while(arguments.read("--r_maxTextureSize",r_maximumTextureSize)) {} // set up colour space operation. osg::ColorSpaceOperation colourSpaceOperation = osg::NO_COLOR_SPACE_OPERATION; osg::Vec4 colourModulate(0.25f,0.25f,0.25f,0.25f); while(arguments.read("--modulate-alpha-by-luminance")) { colourSpaceOperation = osg::MODULATE_ALPHA_BY_LUMINANCE; } while(arguments.read("--modulate-alpha-by-colour", colourModulate.x(),colourModulate.y(),colourModulate.z(),colourModulate.w() )) { colourSpaceOperation = osg::MODULATE_ALPHA_BY_COLOR; } while(arguments.read("--replace-alpha-with-luminance")) { colourSpaceOperation = osg::REPLACE_ALPHA_WITH_LUMINANCE; } while(arguments.read("--replace-rgb-with-luminance")) { colourSpaceOperation = osg::REPLACE_RGB_WITH_LUMINANCE; } enum RescaleOperation { NO_RESCALE, RESCALE_TO_ZERO_TO_ONE_RANGE, SHIFT_MIN_TO_ZERO }; RescaleOperation rescaleOperation = RESCALE_TO_ZERO_TO_ONE_RANGE; while(arguments.read("--no-rescale")) rescaleOperation = NO_RESCALE; while(arguments.read("--rescale")) rescaleOperation = RESCALE_TO_ZERO_TO_ONE_RANGE; while(arguments.read("--shift-min-to-zero")) rescaleOperation = SHIFT_MIN_TO_ZERO; bool resizeToPowerOfTwo = false; unsigned int numComponentsDesired = 0; while(arguments.read("--num-components", numComponentsDesired)) {} bool useManipulator = false; while(arguments.read("--manipulator") || arguments.read("-m")) { useManipulator = true; } bool useShader = true; while(arguments.read("--shader")) { useShader = true; } while(arguments.read("--no-shader")) { useShader = false; } bool gpuTransferFunction = true; while(arguments.read("--gpu-tf")) { gpuTransferFunction = true; } while(arguments.read("--cpu-tf")) { gpuTransferFunction = false; } double sampleDensityWhenMoving = 0.0; while(arguments.read("--sdwm", sampleDensityWhenMoving)) {} while(arguments.read("--lod")) { sampleDensityWhenMoving = 0.02; } double sequenceLength = 10.0; while(arguments.read("--sequence-duration", sequenceLength) || arguments.read("--sd", sequenceLength)) {} typedef std::list< osg::ref_ptr<osg::Image> > Images; Images images; std::string vh_filename; while (arguments.read("--vh", vh_filename)) { std::string raw_filename, transfer_filename; int xdim(0), ydim(0), zdim(0); osgDB::ifstream header(vh_filename.c_str()); if (header) { header >> raw_filename >> transfer_filename >> xdim >> ydim >> zdim >> xSize >> ySize >> zSize; } if (xdim*ydim*zdim==0) { std::cout<<"Error in reading volume header "<<vh_filename<<std::endl; return 1; } if (!raw_filename.empty()) { images.push_back(readRaw(xdim, ydim, zdim, 1, 1, "little", raw_filename)); } if (!transfer_filename.empty()) { osgDB::ifstream fin(transfer_filename.c_str()); if (fin) { osg::TransferFunction1D::ColorMap colorMap; float value = 0.0; while(fin && value<=1.0) { float red, green, blue, alpha; fin >> red >> green >> blue >> alpha; if (fin) { colorMap[value] = osg::Vec4(red/255.0f,green/255.0f,blue/255.0f,alpha/255.0f); std::cout<<"value = "<<value<<" ("<<red<<", "<<green<<", "<<blue<<", "<<alpha<<")"; std::cout<<" ("<<colorMap[value]<<")"<<std::endl; } value += 1/255.0; } if (colorMap.empty()) { std::cout<<"Error: No values read from transfer function file: "<<transfer_filename<<std::endl; return 0; } transferFunction = new osg::TransferFunction1D; transferFunction->assign(colorMap); } } }
bool flif_decode(IO& io, Images &images, int quality, int scale, uint32_t (*callback)(int,int), Images &partial_images) { if (scale != 1 && scale != 2 && scale != 4 && scale != 8 && scale != 16 && scale != 32 && scale != 64 && scale != 128) { e_printf("Invalid scale down factor: %i\n", scale); return false; } char buff[5]; if (!io.gets(buff,5)) { e_printf("Could not read header from file: %s\n",io.getName()); return false; } if (!strcmp(buff,"!<ar")) { // FLIF file in an archive, try to find find the main image if (!io.gets(buff,5)) return false; if (strcmp(buff,"ch>\n")) return false; char ar_header[61]; while (true) { if (!io.gets(ar_header,61)) { e_printf("Archive does not contain a FLIF image\n"); return false; } if (!strncmp(ar_header,"__image.flif/",13)) { if (!io.gets(buff,5)) { e_printf("Corrupt archive?\n"); return false; } break; } else { long skip = strtol(&ar_header[48],NULL,10); if (skip < 0) return false; if (skip & 1) skip++; io.fseek(skip,SEEK_CUR); } } } if (strcmp(buff,"FLIF")) { e_printf("Not a FLIF file: %s (header: \"%s\")\n",io.getName(),buff); return false; } int c = io.getc(); if (c < ' ' || c > ' '+32+15+32) { e_printf("Invalid or unknown FLIF format byte\n"); return false;} c -= ' '; int numFrames=1; if (c > 47) { c -= 32; numFrames = io.getc(); if (numFrames < 2 || numFrames >= 255) return false; } const int encoding=c/16; if (encoding < 1 || encoding > 2) { e_printf("Invalid or unknown FLIF encoding method\n"); return false;} if (scale != 1 && encoding==1) { v_printf(1,"Cannot decode non-interlaced FLIF file at lower scale! Ignoring scale...\n");} if (quality < 100 && encoding==1) { v_printf(1,"Cannot decode non-interlaced FLIF file at lower quality! Ignoring quality...\n");} int numPlanes=c%16; if (numPlanes < 1 || numPlanes > 4) {e_printf("Invalid FLIF header (unsupported color channels)\n"); return false;} c = io.getc(); if (c < '0' || c > '2') {e_printf("Invalid FLIF header (unsupported color depth)\n"); return false;} int width=io.getc() << 8; width += io.getc(); int height=io.getc() << 8; height += io.getc(); if (width < 1 || height < 1) {e_printf("Invalid FLIF header\n"); return false;} // TODO: implement downscaled decoding without allocating a fullscale image buffer! RacIn<IO> rac(io); SimpleSymbolCoder<FLIFBitChanceMeta, RacIn<IO>, 24> metaCoder(rac); // image.init(width, height, 0, 0, 0); v_printf(3,"Decoding %ux%u image, channels:",width,height); int maxmax=0; for (int p = 0; p < numPlanes; p++) { // int min = 0; int max = 255; if (c=='2') max=65535; else if (c=='0') max=(1 << metaCoder.read_int(1, 16)) - 1; if (max>maxmax) maxmax=max; // image.add_plane(min, max); // v_printf(2," [%i] %i bpp (%i..%i)",p,ilog2(image.max(p)+1),image.min(p), image.max(p)); if (c=='0') v_printf(3," [%i] %i bpp",p,ilog2(max+1)); } if (c=='1') v_printf(3," %i, depth: 8 bit",numPlanes); if (c=='2') v_printf(3," %i, depth: 16 bit",numPlanes); if (numFrames>1) v_printf(3,", frames: %i",numFrames); v_printf(3,"\n"); if (numFrames>1) { // ignored for now (assuming loop forever) metaCoder.read_int(0, 100); // repeats (0=infinite) } for (int i=0; i<numFrames; i++) { images.push_back(Image()); if (!images[i].init(width,height,0,maxmax,numPlanes)) return false; if (numFrames>1) images[i].frame_delay = metaCoder.read_int(0, 60000); // time in ms between frames if (callback) partial_images.push_back(Image()); //if (numFrames>1) partial_images[i].frame_delay = images[i].frame_delay; } std::vector<const ColorRanges*> rangesList; std::vector<Transform<IO>*> transforms; rangesList.push_back(getRanges(images[0])); v_printf(4,"Transforms: "); int tcount=0; transform_l=0; while (rac.read()) { if (transform_l > MAX_TRANSFORM) return false; std::string desc = read_name(rac); Transform<IO> *trans = create_transform<IO>(desc); if (!trans) { e_printf("Unknown transformation '%s'\n", desc.c_str()); return false; } if (!trans->init(rangesList.back())) { e_printf("Transformation '%s' failed\n", desc.c_str()); return false; } if (tcount++ > 0) v_printf(4,", "); v_printf(4,"%s", desc.c_str()); if (desc == "FRA" && images.size()<2) return false; if (desc == "FRS") { if (images.size()<2) return false; int unique_frames=images.size()-1; // not considering first frame for (Image& i : images) if (i.seen_before >= 0) unique_frames--; if (unique_frames < 1) {return false;} trans->configure(unique_frames*images[0].rows()); trans->configure(images[0].cols()); } if (desc == "DUP") { if (images.size()<2) return false; else trans->configure(images.size()); } if (!trans->load(rangesList.back(), rac)) return false; rangesList.push_back(trans->meta(images, rangesList.back())); transforms.push_back(trans); } if (tcount==0) v_printf(4,"none\n"); else v_printf(4,"\n"); const ColorRanges* ranges = rangesList.back(); grey.clear(); for (int p = 0; p < ranges->numPlanes(); p++) grey.push_back((ranges->min(p)+ranges->max(p))/2); pixels_todo = (int64_t)width*height*ranges->numPlanes()/scale/scale; pixels_done = 0; for (int p = 0; p < ranges->numPlanes(); p++) { v_printf(7,"Plane %i: %i..%i\n",p,ranges->min(p),ranges->max(p)); } for (int p = 0; p < ranges->numPlanes(); p++) { if (ranges->min(p) >= ranges->max(p)) { v_printf(4,"Constant plane %i at color value %i\n",p,ranges->min(p)); //for (ColorVal_intern& x : image(p).data) x=ranges->min(p); for (int fr = 0; fr < numFrames; fr++) for (uint32_t r=0; r<images[fr].rows(); r++) { for (uint32_t c=0; c<images[fr].cols(); c++) { images[fr].set(p,r,c,ranges->min(p)); } } } } int mbits = 0; for (int p = 0; p < ranges->numPlanes(); p++) { if (ranges->max(p) > ranges->min(p)) { int nBits = ilog2((ranges->max(p) - ranges->min(p))*2-1)+1; if (nBits > mbits) mbits = nBits; } } int bits = 10; #ifdef SUPPORT_HDR if (mbits >10) bits=18; #endif if (mbits > bits) { e_printf("This FLIF cannot decode >8 bit per channel files. Please compile with SUPPORT_HDR.\n"); return false;} std::vector<Tree> forest(ranges->numPlanes(), Tree()); int roughZL = 0; if (encoding == 2) { roughZL = images[0].zooms() - NB_NOLEARN_ZOOMS-1; if (roughZL < 0) roughZL = 0; // v_printf(2,"Decoding rough data\n"); if (bits==10) flif_decode_FLIF2_pass<IO, RacIn<IO>, FinalPropertySymbolCoder<FLIFBitChancePass2, RacIn<IO>, 10> >(rac, images, ranges, forest, images[0].zooms(), roughZL+1, 100, scale, transforms, callback, partial_images); #ifdef SUPPORT_HDR else flif_decode_FLIF2_pass<IO, RacIn<IO>, FinalPropertySymbolCoder<FLIFBitChancePass2, RacIn<IO>, 18> >(rac, images, ranges, forest, images[0].zooms(), roughZL+1, 100, scale, transforms, callback, partial_images); #endif } if (encoding == 2 && quality <= 0) { v_printf(3,"Not decoding MANIAC tree\n"); } else { v_printf(3,"Decoded header + rough data. Decoding MANIAC tree.\n"); if (!flif_decode_tree<FLIFBitChanceTree, RacIn<IO>>(rac, ranges, forest, encoding)) return false; } switch(encoding) { case 1: v_printf(3,"Decoding data (scanlines)\n"); if (bits==10) flif_decode_scanlines_pass<IO, RacIn<IO>, FinalPropertySymbolCoder<FLIFBitChancePass2, RacIn<IO>, 10> >(rac, images, ranges, forest, transforms, callback, partial_images); #ifdef SUPPORT_HDR else flif_decode_scanlines_pass<IO, RacIn<IO>, FinalPropertySymbolCoder<FLIFBitChancePass2, RacIn<IO>, 18> >(rac, images, ranges, forest, transforms, callback, partial_images); #endif break; case 2: v_printf(3,"Decoding data (interlaced)\n"); if (bits==10) flif_decode_FLIF2_pass<IO, RacIn<IO>, FinalPropertySymbolCoder<FLIFBitChancePass2, RacIn<IO>, 10> >(rac, images, ranges, forest, roughZL, 0, quality, scale, transforms, callback, partial_images); #ifdef SUPPORT_HDR else flif_decode_FLIF2_pass<IO, RacIn<IO>, FinalPropertySymbolCoder<FLIFBitChancePass2, RacIn<IO>, 18> >(rac, images, ranges, forest, roughZL, 0, quality, scale, transforms, callback, partial_images); #endif break; } if (quality==100 && scale==1) { uint32_t checksum = images[0].checksum(); v_printf(8,"Computed checksum: %X\n", checksum); uint32_t checksum2 = metaCoder.read_int(0, 0xFFFF); checksum2 *= 0x10000; checksum2 += metaCoder.read_int(0, 0xFFFF); v_printf(8,"Read checksum: %X\n", checksum2); if (checksum != checksum2) v_printf(1,"\nCORRUPTION DETECTED! (partial file?)\n\n"); else v_printf(2,"Image decoded, checksum verified.\n"); } else { v_printf(2,"Not checking checksum, lossy partial decoding was chosen.\n"); } if (numFrames==1) v_printf(2,"\rDecoding done, %li bytes for %ux%u pixels (%.4fbpp) \n",rac.ftell(), images[0].cols()/scale, images[0].rows()/scale, 8.0*rac.ftell()/images[0].rows()/images[0].cols()/scale/scale); else v_printf(2,"\rDecoding done, %li bytes for %i frames of %ux%u pixels (%.4fbpp) \n",rac.ftell(), numFrames, images[0].cols()/scale, images[0].rows()/scale, 8.0*rac.ftell()/numFrames/images[0].rows()/images[0].cols()/scale/scale); for (int i=(int)transforms.size()-1; i>=0; i--) { transforms[i]->invData(images); delete transforms[i]; } transforms.clear(); for (unsigned int i=0; i<rangesList.size(); i++) { delete rangesList[i]; } rangesList.clear(); return true; }
bool encode_load_input_images(int argc, char **argv, Images &images, flif_options &options) { int nb_input_images = argc-1; int nb_actual_images = 0; metadata_options md; md.icc = options.color_profile; md.xmp = options.metadata; md.exif = options.metadata; while(argc>1) { int maxlength = strlen(argv[0])+100; std::vector<char> vfilename(maxlength); char *filename = argv[0]; int framecounter = 0; int stop_searching = 0; bool multiple=false; if (!file_exists(argv[0]) && strchr(argv[0],'%')) { multiple=true; filename = &vfilename[0]; } for ( ; framecounter < 0xFFFFFFF && stop_searching < 1000; framecounter++ ) { if (multiple) { snprintf(filename,maxlength,argv[0],framecounter); if (!file_exists(filename)) { stop_searching++; continue; } stop_searching = 0; } Image image; if (options.keep_palette) image.palette = true; // tells the PNG loader to keep palette intact v_printf_tty(2,"\r"); if (!image.load(filename,md)) { e_printf("Could not read input file: %s\n", argv[0]); return false; }; if (image.numPlanes() > 0) { nb_actual_images++; images.push_back(std::move(image)); Image& last_image = images.back(); if (last_image.rows() != images[0].rows() || last_image.cols() != images[0].cols()) { e_printf("Dimensions of all input images should be the same!\n"); e_printf(" First image is %ux%u\n",images[0].cols(),images[0].rows()); e_printf(" This image is %ux%u: %s\n",last_image.cols(),last_image.rows(),filename); return false; } if (last_image.numPlanes() < images[0].numPlanes()) { if (images[0].numPlanes() == 3) last_image.ensure_chroma(); else if (images[0].numPlanes() == 4) last_image.ensure_alpha(); else { e_printf("Problem while loading input images, please report this.\n"); return false; } } else if (last_image.numPlanes() > images[0].numPlanes()) { if (last_image.numPlanes() == 3) { for (Image& i : images) i.ensure_chroma(); } else if (last_image.numPlanes() == 4) { for (Image& i : images) i.ensure_alpha(); } else { e_printf("Problem while loading input images, please report this.\n"); return false; } } } else { if (images.size() == 0) { e_printf("First specify the actual image(s), then the metadata.\n"); return false; } for (size_t i=0; i<image.metadata.size(); i++) images[0].metadata.push_back(image.metadata[i]); } if (nb_input_images>1) {v_printf(2," (%i/%i) ",(int)images.size(),nb_input_images); v_printf(4,"\n");} if (!multiple) break; } argc--; argv++; } if (nb_actual_images > 0) return true; e_printf("Error: no actual input images to be encoded!\n"); return false; }
bool handle_encode_arguments(int argc, char **argv, Images &images, int palette_size, int acb, flifEncodingOptional method, int lookback, int learn_repeats, int frame_delay) { int nb_input_images = argc-1; while(argc>1) { Image image; v_printf(2,"\r"); if (!image.load(argv[0])) { e_printf("Could not read input file: %s\n", argv[0]); return 2; }; images.push_back(std::move(image)); const Image& last_image = images.back(); if (last_image.rows() != images[0].rows() || last_image.cols() != images[0].cols() || last_image.numPlanes() != images[0].numPlanes()) { e_printf("Dimensions of all input images should be the same!\n"); e_printf(" First image is %ux%u, %i channels.\n",images[0].cols(),images[0].rows(),images[0].numPlanes()); e_printf(" This image is %ux%u, %i channels: %s\n",last_image.cols(),last_image.rows(),last_image.numPlanes(),argv[0]); return 2; } argc--; argv++; if (nb_input_images>1) {v_printf(2," (%i/%i) ",(int)images.size(),nb_input_images); v_printf(4,"\n");} } v_printf(2,"\n"); bool flat=true; for (Image &image : images) if (image.uses_alpha()) flat=false; if (flat && images[0].numPlanes() == 4) { v_printf(2,"Alpha channel not actually used, dropping it.\n"); for (Image &image : images) image.drop_alpha(); } uint64_t nb_pixels = (uint64_t)images[0].rows() * images[0].cols(); std::vector<std::string> desc; desc.push_back("YIQ"); // convert RGB(A) to YIQ(A) desc.push_back("BND"); // get the bounds of the color spaces if (palette_size > 0) desc.push_back("PLA"); // try palette (including alpha) if (palette_size > 0) desc.push_back("PLT"); // try palette (without alpha) if (acb == -1) { // not specified if ACB should be used if (nb_pixels > 10000) desc.push_back("ACB"); // try auto color buckets on large images } else if (acb) desc.push_back("ACB"); // try auto color buckets if forced if (method.o == Optional::undefined) { // no method specified, pick one heuristically if (nb_pixels < 10000) method.encoding=flifEncoding::nonInterlaced; // if the image is small, not much point in doing interlacing else method.encoding=flifEncoding::interlaced; // default method: interlacing } if (images.size() > 1) { desc.push_back("DUP"); // find duplicate frames desc.push_back("FRS"); // get the shapes of the frames if (lookback != 0) desc.push_back("FRA"); // make a "deep" alpha channel (negative values are transparent to some previous frame) } if (learn_repeats < 0) { // no number of repeats specified, pick a number heuristically learn_repeats = TREE_LEARN_REPEATS; if (nb_pixels < 5000) learn_repeats--; // avoid large trees for small images if (learn_repeats < 0) learn_repeats=0; } FILE *file = fopen(argv[0],"wb"); if (!file) return false; FileIO fio(file, argv[0]); return flif_encode(fio, images, desc, method.encoding, learn_repeats, acb, frame_delay, palette_size, lookback); }