ChannelList
channelsInView (const string & viewName,
	        const ChannelList & channelList,
		const StringVector & multiView)
{
    //
    // Return a list of all channels belonging to view viewName.
    //

    ChannelList q;

    for (ChannelList::ConstIterator i = channelList.begin();
	 i != channelList.end();
	 ++i)
    {
	//
	// Get view name for this channel
	//

	string view = viewFromChannelName (i.name(), multiView);


	//
	// Insert channel into q if it's a member of view viewName
	//

	if (view == viewName)
	   q.insert (i.name(), i.channel());
    }

    return q;
}
Example #2
0
void EXRReaderPlugin::updateCombos()
{
	const std::string filename( getAbsoluteFirstFilename() );
	//TUTTLE_COUT("update Combo");
	if( bfs::exists( filename ) )
	{
		// read dims
		InputFile in( filename.c_str() );
		const Header& h  = in.header();
		const ChannelList& cl = h.channels();
		
		// Hide output channel selection till we don't select a channel.
		for( std::size_t i = 0; i < _vChannelChoice.size(); ++i )
		{
			//_vChannelChoice[i]->setIsSecret( true );
			_vChannelChoice[i]->resetOptions();
		}
		_vChannelNames.clear();
		for( ChannelList::ConstIterator it = cl.begin(); it != cl.end(); ++it )
		{
			_vChannelNames.push_back( it.name() );
			//TUTTLE_COUT_VAR( it.name() );
			for( std::size_t j = 0; j < _vChannelChoice.size(); ++j )
			{
				_vChannelChoice[j]->appendOption( it.name() );
			}
			++_channels;
			switch( _channels )
			{
				case 1:
				{
					for( std::size_t j = 0; j < _vChannelChoice.size(); j++ )
						_vChannelChoice.at(j)->setValue( 0 );
					break;
				}
				case 3:
				{
					for( std::size_t j = 0; j < _vChannelChoice.size() - 1; j++ )
						_vChannelChoice.at(j)->setValue( 2 - j );
					_vChannelChoice.at(3)->setValue( 0 );
					break;
				}
				case 4:
				{
					for( std::size_t j = 0; j < _vChannelChoice.size(); j++ )
						_vChannelChoice.at(j)->setValue( 3 - j );
					break;
				}
			}
		}
	}
}
Example #3
0
static int exr_is_multilayer(InputFile *file)
{
	const StringAttribute *comments = file->header().findTypedAttribute<StringAttribute>("BlenderMultiChannel");
	const ChannelList &channels = file->header().channels();
	std::set <std::string> layerNames;

	/* will not include empty layer names */
	channels.layers(layerNames);

	if (comments || layerNames.size() > 1)
		return 1;

	if (layerNames.size()) {
		/* if layerNames is not empty, it means at least one layer is non-empty,
		 * but it also could be layers without names in the file and such case
		 * shall be considered a multilayer exr
		 *
		 * that's what we do here: test whether there're empty layer names together
		 * with non-empty ones in the file
		 */
		for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); i++) {
			std::string layerName = i.name();
			size_t pos = layerName.rfind ('.');

			if (pos == std::string::npos)
				return 1;
		}
	}

	return 0;
}
void
ChannelListAttribute::writeValueTo (OStream &os, int version) const
{
    for (ChannelList::ConstIterator i = _value.begin();
	 i != _value.end();
	 ++i)
    {
	//
	// Write name
	//

	Xdr::write <StreamIO> (os, i.name());

	//
	// Write Channel struct
	//

	Xdr::write <StreamIO> (os, int (i.channel().type));
	Xdr::pad   <StreamIO> (os, 4);
	Xdr::write <StreamIO> (os, i.channel().xSampling);
	Xdr::write <StreamIO> (os, i.channel().ySampling);
    }

    //
    // Write end of list marker
    //

    Xdr::write <StreamIO> (os, "");
}
Example #5
0
/* read from file */
int IMB_exr_begin_read(void *handle, const char *filename, int *width, int *height)
{
	ExrHandle *data = (ExrHandle *)handle;

	if (BLI_exists(filename) && BLI_file_size(filename) > 32) {   /* 32 is arbitrary, but zero length files crashes exr */
		/* avoid crash/abort when we don't have permission to write here */
		try {
			data->ifile_stream = new IFileStream(filename);
			data->ifile = new InputFile(*(data->ifile_stream));
		}
		catch (const std::exception &) {
			delete data->ifile;
			delete data->ifile_stream;

			data->ifile = NULL;
			data->ifile_stream = NULL;
		}

		if (data->ifile) {
			Box2i dw = data->ifile->header().dataWindow();
			data->width = *width  = dw.max.x - dw.min.x + 1;
			data->height = *height = dw.max.y - dw.min.y + 1;

			const ChannelList &channels = data->ifile->header().channels();

			for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
				IMB_exr_add_channel(data, NULL, i.name(), 0, 0, NULL);

			return 1;
		}
	}
	return 0;
}
Example #6
0
/* debug only */
static void exr_print_filecontents(InputFile *file)
{
	const ChannelList &channels = file->header().channels();

	for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) {
		const Channel &channel = i.channel();
		printf("OpenEXR-load: Found channel %s of type %d\n", i.name(), channel.type);
	}
}
Example #7
0
void EXRReader::open()
{
    // open file and read dimensions
    m_data.reset( new EXRReaderData(filename().c_str()) );

    int width  = m_data->dtw_.max.x - m_data->dtw_.min.x + 1;
    int height = m_data->dtw_.max.y - m_data->dtw_.min.y + 1;

    assert(width > 0);
    assert(height > 0);

    // check that file contains RGB data
    bool red = false;
    bool green = false;
    bool blue = false;
    const ChannelList &channels = m_data->file_.header().channels();
    for ( ChannelList::ConstIterator i = channels.begin(), iEnd = channels.end();
            i != iEnd; ++i )
    {
        if ( !strcmp(i.name(), "R") ) red = true;
        else if ( !strcmp(i.name(), "G") ) green = true;
        else if ( !strcmp(i.name(), "B") ) blue = true;
    }

    if ( !(red && green && blue) ) {
        throw pfs::io::InvalidHeader("OpenEXR file " + filename() + " does " \
                                     " not contain RGB data");
    }

    // check boundaries
    /*
    if ( (m_data->dtw_.min.x < m_data->dw_.min.x &&
          m_data->dtw_.max.x > m_data->dw_.max.x) ||
         (m_data->dtw_.min.y < m_data->dw_.min.y &&
          m_data->dtw_.max.y > m_data->dw_.max.y) )
    {
        throw pfs::io::InvalidHeader("No support for OpenEXR files DataWindow" \
                                     " greater than DisplayWindow" );
    }
    */

    setWidth(width);
    setHeight(height);
}
Example #8
0
// Read the header of an EXR file.
// (ref) http://www.openexr.com/ReadingAndWritingImageFiles.pdf
int vtkOpenEXR::exrInfo(const char *fileName, std::vector<std::string> &channelNames)
{
  // parse filename
  QFileInfo fi(fileName);

  QString extension = fi.suffix().toLower();
  if ( extension.compare("exr") != 0 ) {
//    qDebug() << "the exr file was not found";
    return false;
  }

  if (!fi.exists())
  {
//    qDebug() << "the exr file was not found";
    return false;
  }

  int numChannels = 0;

  try {
    RgbaInputFile file(fileName);

    const ChannelList &ch = file.header().channels();

    int ic = 0;
    for (ChannelList::ConstIterator i = ch.begin(); i != ch.end(); ++i) {
      const Channel &channel = i.channel();
      const char* channelName = i.name(); // by Min
      PixelType type = channel.type;
      const char* t = (type == UINT) ? "uint" :
          ((type == HALF) ? "half" : "float");

      channelNames.push_back(channelName);
      ++ic;
//      qDebug() << "channel " << ic << ": " << t << ": " << channelName ;
    }
    numChannels = ic;
    const StringAttribute *comments =
    file.header().findTypedAttribute <StringAttribute> ("comments");

    const M44fAttribute *cameraTransform =
    file.header().findTypedAttribute <M44fAttribute> ("cameraTransform");

//    if (comments)
//       qDebug() << "comments\n   " << comments->value() ;

//    if (cameraTransform)
//       qDebug() << "cameraTransform\n" << cameraTransform->value() << flush;

  } catch (const std::exception &exc) {
//    qDebug() << exc.what();
    return false;
  }

  return numChannels; // number of channels
}
Example #9
0
void EXRImageReader::channelNames( vector<string> &names )
{
	open( true );

	const ChannelList &channels = m_inputFile->header().channels();
	names.clear();
	for( ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i )
	{
		names.push_back( i.name() );
	}
}
Example #10
0
/* for non-multilayer, map  R G B A channel names to something that's in this file */
static const char *exr_rgba_channelname(InputFile *file, const char *chan)
{
	const ChannelList &channels = file->header().channels();

	for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) {
		/* const Channel &channel = i.channel(); */ /* Not used yet */
		const char *str = i.name();
		int len = strlen(str);
		if (len) {
			if (BLI_strcasecmp(chan, str + len - 1) == 0) {
				return str;
			}
		}
	}
	return chan;
}
Example #11
0
void
printChannelList (const ChannelList &cl)
{
    for (ChannelList::ConstIterator i = cl.begin(); i != cl.end(); ++i)
    {
        cout << "\n    " << i.name() << ", ";

        printPixelType (i.channel().type);

        cout << ", sampling " <<
        i.channel().xSampling << " " <<
        i.channel().ySampling;

        if (i.channel().pLinear)
            cout << ", plinear";
    }
}
Example #12
0
/* read from file */
int IMB_exr_begin_read(void *handle, const char *filename, int *width, int *height)
{
	ExrHandle *data= (ExrHandle *)handle;
	
	if(BLI_exists(filename) && BLI_filepathsize(filename)>32) {	/* 32 is arbitrary, but zero length files crashes exr */
		data->ifile = new InputFile(filename);
		if(data->ifile) {
			Box2i dw = data->ifile->header().dataWindow();
			data->width= *width  = dw.max.x - dw.min.x + 1;
			data->height= *height = dw.max.y - dw.min.y + 1;
			
			const ChannelList &channels = data->ifile->header().channels();
			
			for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
				IMB_exr_add_channel(data, NULL, i.name(), 0, 0, NULL);
			
			return 1;
		}
	}
	return 0;
}
Example #13
0
void EXRReaderPlugin::updateCombos()
{
	const std::string filepath( getAbsoluteFirstFilename() );
	if( ! bfs::exists( filepath ) )
		return;
	
	// read dims
	InputFile in( filepath.c_str() );
	const Header& h  = in.header();
	const ChannelList& cl = h.channels();

	_par = h.pixelAspectRatio();

	Imf::Compression compression = h.compression();
	
	switch( compression )
	{
		case RLE_COMPRESSION:
			_paramFileCompression->setValue( eParamCompression_RLE );
			break;
		case ZIPS_COMPRESSION:
			_paramFileCompression->setValue( eParamCompression_ZIPS );
			break;
		case ZIP_COMPRESSION:
			_paramFileCompression->setValue( eParamCompression_ZIP );
			break;
		case PIZ_COMPRESSION:
			_paramFileCompression->setValue( eParamCompression_PIZ );
			break;
		case PXR24_COMPRESSION:
			_paramFileCompression->setValue( eParamCompression_PXR24 );
			break;
		case B44_COMPRESSION:
			_paramFileCompression->setValue( eParamCompression_B44 );
			break;
		case B44A_COMPRESSION:
			_paramFileCompression->setValue( eParamCompression_B44A );
			break;
		case NO_COMPRESSION:
			_paramFileCompression->setValue( eParamCompression_None );
			break;
		default:
			_paramFileCompression->setValue( eParamCompression_None );
			TUTTLE_LOG_WARNING( "EXRReader: Unknown compression " << compression );
			break;
	}
	
	// Hide output channel selection till we don't select a channel.
	for( std::size_t i = 0; i < _paramsChannelChoice.size(); ++i )
	{
		//_vChannelChoice[i]->setIsSecret( true );
		_paramsChannelChoice[i]->resetOptions();
	}
	_channelNames.clear();
	for( ChannelList::ConstIterator it = cl.begin(); it != cl.end(); ++it )
	{
		_channelNames.push_back( it.name() );
		//TUTTLE_LOG_VAR( it.name() );
		for( std::size_t j = 0; j < _paramsChannelChoice.size(); ++j )
		{
			_paramsChannelChoice[j]->appendOption( it.name() );
		}
	}
	switch( _channelNames.size() )
	{
		case 1:
		{
			for( std::size_t j = 0; j < _paramsChannelChoice.size(); j++ )
				_paramsChannelChoice.at(j)->setValue( 0 );
			break;
		}
		case 3:
		{
			for( std::size_t j = 0; j < _paramsChannelChoice.size() - 1; j++ )
				_paramsChannelChoice.at(j)->setValue( 2 - j );
			_paramsChannelChoice.at(3)->setValue( 0 );
			break;
		}
		case 4:
		{
			for( std::size_t j = 0; j < _paramsChannelChoice.size(); j++ )
				_paramsChannelChoice.at(j)->setValue( 3 - j );
			break;
		}
	}
	
	const std::string& firstChannelName = _channelNames[ _paramsChannelChoice[0]->getValue() ];
	Imf::PixelType firstChannelType = cl.find(firstChannelName.c_str()).channel().type;
	switch( firstChannelType )
	{
		case Imf::UINT:
			_paramFileBitDepth->setValue( eTuttlePluginFileBitDepth32 );
			break;
		case Imf::HALF:
			_paramFileBitDepth->setValue( eTuttlePluginFileBitDepth16f );
			break;
		case Imf::FLOAT:
			_paramFileBitDepth->setValue( eTuttlePluginFileBitDepth32f );
			break;
		default:
			_paramFileBitDepth->setValue( eTuttlePluginFileBitDepthNone );
			TUTTLE_LOG_WARNING( "EXRReader: Unknown bit depth " << firstChannelType );
			break;
	}
}
void	
ScanLineInputFile::setFrameBuffer (const FrameBuffer &frameBuffer)
{
    Lock lock (*_streamData);

    
    
    const ChannelList &channels = _data->header.channels();
    for (FrameBuffer::ConstIterator j = frameBuffer.begin();
	 j != frameBuffer.end();
	 ++j)
    {
	ChannelList::ConstIterator i = channels.find (j.name());

	if (i == channels.end())
	    continue;

	if (i.channel().xSampling != j.slice().xSampling ||
	    i.channel().ySampling != j.slice().ySampling)
	    THROW (IEX_NAMESPACE::ArgExc, "X and/or y subsampling factors "
				"of \"" << i.name() << "\" channel "
				"of input file \"" << fileName() << "\" are "
				"not compatible with the frame buffer's "
				"subsampling factors.");
    }

    //
    // Check if the new frame buffer descriptor is
    // compatible with the image file header.
    //
    
    
    if (!GLOBAL_SYSTEM_LITTLE_ENDIAN)
    {
        _data->optimizationMode._destination._format = OptimizationMode::PIXELFORMAT_OTHER;
        _data->optimizationMode._source._format      = OptimizationMode::PIXELFORMAT_OTHER;
    }
    else
    {
        StringVector * v=NULL;
        if(hasMultiView(_data->header))
        {
            v = &multiView(_data->header);
        }
        _data->optimizationMode = detectOptimizationMode(frameBuffer, channels,v);
    }
    
    // TODO-pk this disables optimization
    // _data->optimizationMode._destination._format = Imf::OptimizationMode::PIXELFORMAT_OTHER;
    

    //
    // Initialize the slice table for readPixels().
    //

    vector<InSliceInfo> slices;
    ChannelList::ConstIterator i = channels.begin();

    for (FrameBuffer::ConstIterator j = frameBuffer.begin();
	 j != frameBuffer.end();
	 ++j)
    {
	while (i != channels.end() && strcmp (i.name(), j.name()) < 0)
	{
	    //
	    // Channel i is present in the file but not
	    // in the frame buffer; data for channel i
	    // will be skipped during readPixels().
	    //

	    slices.push_back (InSliceInfo (i.channel().type,
					   i.channel().type,
					   0, // base
					   0, // xStride
					   0, // yStride
					   i.channel().xSampling,
					   i.channel().ySampling,
					   false,  // fill
					   true, // skip
					   0.0)); // fillValue
	    ++i;
	}

	bool fill = false;

	if (i == channels.end() || strcmp (i.name(), j.name()) > 0)
	{
	    //
	    // Channel i is present in the frame buffer, but not in the file.
	    // In the frame buffer, slice j will be filled with a default value.
	    //

	    fill = true;
	}

	slices.push_back (InSliceInfo (j.slice().type,
				       fill? j.slice().type:
				             i.channel().type,
				       j.slice().base,
				       j.slice().xStride,
				       j.slice().yStride,
				       j.slice().xSampling,
				       j.slice().ySampling,
				       fill,
				       false, // skip
				       j.slice().fillValue));

	if (i != channels.end() && !fill)
	    ++i;
    }

    //
    // Store the new frame buffer.
    //

    _data->frameBuffer = frameBuffer;
    _data->slices = slices;
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    char *exrFileName;
    double *mxData;
    int width = 0;
    int height = 0;
    int nSlices = 0;
    
    if (nrhs != 1 || !mxIsChar(prhs[0])) {
        mexErrMsgTxt("Usage: ReadMultichannelEXR('exrFile')\n");
    }
    
    // read the exr file with OpenEXR general interface
    exrFileName = mxArrayToString(prhs[0]);
    InputFile file (exrFileName);
    
    // query general file properties
    Box2i dw = file.header().dataWindow();
    width = dw.max.x - dw.min.x + 1;
    height = dw.max.y - dw.min.y + 1;
    
    const ChannelList &channels = file.header().channels();
    for (ChannelList::ConstIterator iter = channels.begin();
    iter != channels.end();
    ++iter) {
        nSlices++;
    }
    
    mexPrintf("Read \"%s\": width=%d height=%d nSlices=%d\n",
            exrFileName, width, height, nSlices);
    mxFree(exrFileName);
    
    // return a struct with info about image slices
    mwSize nDims = 2;
    mwSize infoDims[] = {1, 0};
    infoDims[1] = nSlices;
    const char* fieldNames[] = {"name", "pixelType",
    "xSampling", "ySampling", "isLinear"};
    int nFields = sizeof(fieldNames)/sizeof(fieldNames[0]);
    plhs[0] = mxCreateStructArray(nDims, infoDims, nFields, fieldNames);
    
    // return a double array with size [height width nSlices]
    nDims = 3;
    mwSize dataDims[] = {0, 0, 0};
    dataDims[0] = height;
    dataDims[1] = width;
    dataDims[2] = nSlices;
    plhs[1] = mxCreateNumericArray(nDims, dataDims, mxDOUBLE_CLASS, mxREAL);
    if (NULL == plhs[1]) {
        mexPrintf("Could not allocate image array of size [%d %d %d]\n",
                dataDims[0], dataDims[1], dataDims[2]);
        return;
    }
    double* data = mxGetPr(plhs[1]);
    
    // fill in info struct and data array
    int channelIndex = 0;
    for (ChannelList::ConstIterator iter = channels.begin(); iter != channels.end(); ++iter) {
        const Channel &channel = iter.channel();
        
        // fill in info struct for this channel
        mxSetField(plhs[0], channelIndex, "name", mxCreateString(iter.name()));
        mxSetField(plhs[0], channelIndex, "xSampling", mxCreateDoubleScalar((double)channel.xSampling));
        mxSetField(plhs[0], channelIndex, "ySampling", mxCreateDoubleScalar((double)channel.ySampling));
        mxSetField(plhs[0], channelIndex, "isLinear", mxCreateLogicalScalar((mxLogical)channel.pLinear));
        
        // fill in a slice of the data matrix for this channel
        //  memory allocation depends on slice pixel type
        mxArray* typeName = NULL;
        FrameBuffer frameBuffer;
        switch (channel.type) {
            case UINT:{
                typeName = mxCreateString("UINT");
                
                // copy slice data from file to a frame buffer
                Array2D<MATLAB_UINT32> slicePixels;
                slicePixels.resizeErase(height, width);
                frameBuffer.insert(iter.name(),
                        Slice(HALF,
                        (char *)(&slicePixels[0][0] - dw.min.x - dw.min.y * width),
                        sizeof(slicePixels[0][0]) * 1,
                        sizeof(slicePixels[0][0]) * width,
                        channel.xSampling,
                        channel.ySampling,
                        0.0));
                file.setFrameBuffer (frameBuffer);
                file.readPixels (dw.min.y, dw.max.y);
                
                // copy slice data from frame buffer to data array
                for (int i = 0; i < height; i++) {
                    for (int j = 0; j < width; j++) {
                        data[M3I(height, width, i, j, channelIndex)] = slicePixels[i][j];
                    }
                }
                
                break;
            }
            
            case HALF:{
                typeName = mxCreateString("HALF");
                
                // copy slice data from file to a frame buffer
                Array2D<half> slicePixels;
                slicePixels.resizeErase(height, width);
                frameBuffer.insert(iter.name(),
                        Slice(HALF,
                        (char *)(&slicePixels[0][0] - dw.min.x - dw.min.y * width),
                        sizeof(slicePixels[0][0]) * 1,
                        sizeof(slicePixels[0][0]) * width,
                        channel.xSampling,
                        channel.ySampling,
                        0.0));
                file.setFrameBuffer (frameBuffer);
                file.readPixels (dw.min.y, dw.max.y);
                
                // copy slice data from frame buffer to data array
                for (int i = 0; i < height; i++) {
                    for (int j = 0; j < width; j++) {
                        data[M3I(height, width, i, j, channelIndex)] = slicePixels[i][j];
                    }
                }
                
                break;
            }
            
            case FLOAT:{
                typeName = mxCreateString("FLOAT");
                
                // copy slice data from file to a frame buffer
                Array2D<half> slicePixels;
                slicePixels.resizeErase(height, width);
                frameBuffer.insert(iter.name(),
                        Slice(HALF,
                        (char *)(&slicePixels[0][0] - dw.min.x - dw.min.y * width),
                        sizeof(slicePixels[0][0]) * 1,
                        sizeof(slicePixels[0][0]) * width,
                        channel.xSampling,
                        channel.ySampling,
                        0.0));
                file.setFrameBuffer (frameBuffer);
                file.readPixels (dw.min.y, dw.max.y);
                
                // copy slice data from frame buffer to data array
                for (int i = 0; i < height; i++) {
                    for (int j = 0; j < width; j++) {
                        data[M3I(height, width, i, j, channelIndex)] = slicePixels[i][j];
                    }
                }
                
                break;
            }
            
            default:{
                typeName = mxCreateString("UNKNOWN");
                break;
            }
        }
        mxSetField(plhs[0], channelIndex, "pixelType",  typeName);
        
        channelIndex++;
        
        //mexPrintf("  channel \"%s\": type=%d xSampling=%d ySampling=%d, isLinear=%d\n",
        //        iter.name(), channel.type,
        //        channel.xSampling, channel.ySampling, channel.pLinear);
    }
}
Example #16
0
void	
OutputFile::setFrameBuffer (const FrameBuffer &frameBuffer)
{
    Lock lock (*_data);
    
    //
    // Check if the new frame buffer descriptor
    // is compatible with the image file header.
    //

    const ChannelList &channels = _data->header.channels();

    for (ChannelList::ConstIterator i = channels.begin();
	 i != channels.end();
	 ++i)
    {
	FrameBuffer::ConstIterator j = frameBuffer.find (i.name());

	if (j == frameBuffer.end())
	    continue;

	if (i.channel().type != j.slice().type)
	{
	    THROW (Iex::ArgExc, "Pixel type of \"" << i.name() << "\" channel "
			        "of output file \"" << fileName() << "\" is "
			        "not compatible with the frame buffer's "
			        "pixel type.");
	}

	if (i.channel().xSampling != j.slice().xSampling ||
	    i.channel().ySampling != j.slice().ySampling)
	{
	    THROW (Iex::ArgExc, "X and/or y subsampling factors "
				"of \"" << i.name() << "\" channel "
				"of output file \"" << fileName() << "\" are "
				"not compatible with the frame buffer's "
				"subsampling factors.");
	}
    }
    
    //
    // Initialize slice table for writePixels().
    //

    vector<OutSliceInfo> slices;

    for (ChannelList::ConstIterator i = channels.begin();
	 i != channels.end();
	 ++i)
    {
	FrameBuffer::ConstIterator j = frameBuffer.find (i.name());

	if (j == frameBuffer.end())
	{
	    //
	    // Channel i is not present in the frame buffer.
	    // In the file, channel i will contain only zeroes.
	    //

	    slices.push_back (OutSliceInfo (i.channel().type,
					    0, // base
					    0, // xStride,
					    0, // yStride,
					    i.channel().xSampling,
					    i.channel().ySampling,
					    true)); // zero
	}
	else
	{
	    //
	    // Channel i is present in the frame buffer.
	    //

	    slices.push_back (OutSliceInfo (j.slice().type,
					    j.slice().base,
					    j.slice().xStride,
					    j.slice().yStride,
					    j.slice().xSampling,
					    j.slice().ySampling,
					    false)); // zero
	}
    }

    //
    // Store the new frame buffer.
    //

    _data->frameBuffer = frameBuffer;
    _data->slices = slices;
}
Example #17
0
void		
Header::sanityCheck (bool isTiled, bool isMultipartFile) const
{
    //
    // The display window and the data window must each
    // contain at least one pixel.  In addition, the
    // coordinates of the window corners must be small
    // enough to keep expressions like max-min+1 or
    // max+min from overflowing.
    //

    const Box2i &displayWindow = this->displayWindow();

    if (displayWindow.min.x > displayWindow.max.x ||
	displayWindow.min.y > displayWindow.max.y ||
	displayWindow.min.x <= -(INT_MAX / 2) ||
	displayWindow.min.y <= -(INT_MAX / 2) ||
	displayWindow.max.x >=  (INT_MAX / 2) ||
	displayWindow.max.y >=  (INT_MAX / 2))
    {
	throw IEX_NAMESPACE::ArgExc ("Invalid display window in image header.");
    }

    const Box2i &dataWindow = this->dataWindow();

    if (dataWindow.min.x > dataWindow.max.x ||
	dataWindow.min.y > dataWindow.max.y ||
	dataWindow.min.x <= -(INT_MAX / 2) ||
	dataWindow.min.y <= -(INT_MAX / 2) ||
	dataWindow.max.x >=  (INT_MAX / 2) ||
	dataWindow.max.y >=  (INT_MAX / 2))
    {
	throw IEX_NAMESPACE::ArgExc ("Invalid data window in image header.");
    }

    if (maxImageWidth > 0 &&
        maxImageWidth < (dataWindow.max.x - dataWindow.min.x + 1))
    {
	THROW (IEX_NAMESPACE::ArgExc, "The width of the data window exceeds the "
			    "maximum width of " << maxImageWidth << "pixels.");
    }

    if (maxImageHeight > 0 &&
	maxImageHeight < dataWindow.max.y - dataWindow.min.y + 1)
    {
	THROW (IEX_NAMESPACE::ArgExc, "The width of the data window exceeds the "
			    "maximum width of " << maxImageHeight << "pixels.");
    }

   // chunk table must be smaller than the maximum image area
   // (only reachable for unknown types or damaged files: will have thrown earlier
   //  for regular image types)
   if( maxImageHeight>0 && maxImageWidth>0 && 
       hasChunkCount() && chunkCount()>Int64(maxImageWidth)*Int64(maxImageHeight))
   {
       THROW (IEX_NAMESPACE::ArgExc, "chunkCount exceeds maximum area of "
       << Int64(maxImageWidth)*Int64(maxImageHeight) << " pixels." );
       
   }


    //
    // The pixel aspect ratio must be greater than 0.
    // In applications, numbers like the the display or
    // data window dimensions are likely to be multiplied
    // or divided by the pixel aspect ratio; to avoid
    // arithmetic exceptions, we limit the pixel aspect
    // ratio to a range that is smaller than theoretically
    // possible (real aspect ratios are likely to be close
    // to 1.0 anyway).
    //

    float pixelAspectRatio = this->pixelAspectRatio();

    const float MIN_PIXEL_ASPECT_RATIO = 1e-6f;
    const float MAX_PIXEL_ASPECT_RATIO = 1e+6f;

    if (pixelAspectRatio < MIN_PIXEL_ASPECT_RATIO ||
	pixelAspectRatio > MAX_PIXEL_ASPECT_RATIO)
    {
	throw IEX_NAMESPACE::ArgExc ("Invalid pixel aspect ratio in image header.");
    }

    //
    // The screen window width must not be less than 0.
    // The size of the screen window can vary over a wide
    // range (fish-eye lens to astronomical telescope),
    // so we can't limit the screen window width to a
    // small range.
    //

    float screenWindowWidth = this->screenWindowWidth();

    if (screenWindowWidth < 0)
	throw IEX_NAMESPACE::ArgExc ("Invalid screen window width in image header.");

    //
    // If the file has multiple parts, verify that each header has attribute
    // name and type.
    // (TODO) We may want to check more stuff here.
    //

    if (isMultipartFile)
    {
        if (!hasName())
        {
            throw IEX_NAMESPACE::ArgExc ("Headers in a multipart file should"
                               " have name attribute.");
        }

        if (!hasType())
        {
            throw IEX_NAMESPACE::ArgExc ("Headers in a multipart file should"
                               " have type attribute.");
        }

    }
    
    const std::string & part_type=hasType() ? type() : "";
    
    if(part_type!="" && !isSupportedType(part_type))
    {
        //
        // skip remaining sanity checks with unsupported types - they may not hold
        //
        return;
    }
    
   
    //
    // If the file is tiled, verify that the tile description has reasonable
    // values and check to see if the lineOrder is one of the predefined 3.
    // If the file is not tiled, then the lineOrder can only be INCREASING_Y
    // or DECREASING_Y.
    //

    LineOrder lineOrder = this->lineOrder();

    if (isTiled)
    {
	if (!hasTileDescription())
	{
	    throw IEX_NAMESPACE::ArgExc ("Tiled image has no tile "
			       "description attribute.");
	}

	const TileDescription &tileDesc = tileDescription();

	if (tileDesc.xSize <= 0 || tileDesc.ySize <= 0)
	    throw IEX_NAMESPACE::ArgExc ("Invalid tile size in image header.");

	if (maxTileWidth > 0 &&
	    maxTileWidth < int(tileDesc.xSize))
	{
	    THROW (IEX_NAMESPACE::ArgExc, "The width of the tiles exceeds the maximum "
				"width of " << maxTileWidth << "pixels.");
	}

	if (maxTileHeight > 0 &&
	    maxTileHeight < int(tileDesc.ySize))
	{
	    THROW (IEX_NAMESPACE::ArgExc, "The width of the tiles exceeds the maximum "
				"width of " << maxTileHeight << "pixels.");
	}

	if (tileDesc.mode != ONE_LEVEL &&
	    tileDesc.mode != MIPMAP_LEVELS &&
	    tileDesc.mode != RIPMAP_LEVELS)
	    throw IEX_NAMESPACE::ArgExc ("Invalid level mode in image header.");

	if (tileDesc.roundingMode != ROUND_UP &&
	    tileDesc.roundingMode != ROUND_DOWN)
	    throw IEX_NAMESPACE::ArgExc ("Invalid level rounding mode in image header.");

	if (lineOrder != INCREASING_Y &&
	    lineOrder != DECREASING_Y &&
	    lineOrder != RANDOM_Y)
	    throw IEX_NAMESPACE::ArgExc ("Invalid line order in image header.");
    }
    else
    {
        if (lineOrder != INCREASING_Y &&
            lineOrder != DECREASING_Y)
            throw IEX_NAMESPACE::ArgExc ("Invalid line order in image header.");
        
        
    }

    //
    // The compression method must be one of the predefined values.
    //

    if (!isValidCompression (this->compression()))
  	throw IEX_NAMESPACE::ArgExc ("Unknown compression type in image header.");
    
    if(isDeepData(part_type))
    {
        if (!isValidDeepCompression (this->compression()))
            throw IEX_NAMESPACE::ArgExc ("Compression type in header not valid for deep data");
    }

    //
    // Check the channel list:
    //
    // If the file is tiled then for each channel, the type must be one of the
    // predefined values, and the x and y sampling must both be 1.
    //
    // If the file is not tiled then for each channel, the type must be one
    // of the predefined values, the x and y coordinates of the data window's
    // upper left corner must be divisible by the x and y subsampling factors,
    // and the width and height of the data window must be divisible by the
    // x and y subsampling factors.
    //

    const ChannelList &channels = this->channels();
    
    if (isTiled)
    {
	for (ChannelList::ConstIterator i = channels.begin();
	     i != channels.end();
	     ++i)
	{
	    if (i.channel().type != UINT &&
		i.channel().type != HALF &&
		i.channel().type != FLOAT)
	    {
		THROW (IEX_NAMESPACE::ArgExc, "Pixel type of \"" << i.name() << "\" "
			            "image channel is invalid.");
	    }

	    if (i.channel().xSampling != 1)
	    {
		THROW (IEX_NAMESPACE::ArgExc, "The x subsampling factor for the "
				    "\"" << i.name() << "\" channel "
				    "is not 1.");
	    }	

	    if (i.channel().ySampling != 1)
	    {
		THROW (IEX_NAMESPACE::ArgExc, "The y subsampling factor for the "
				    "\"" << i.name() << "\" channel "
				    "is not 1.");
	    }	
	}
    }
    else
    {
	for (ChannelList::ConstIterator i = channels.begin();
	     i != channels.end();
	     ++i)
	{
	    if (i.channel().type != UINT &&
		i.channel().type != HALF &&
		i.channel().type != FLOAT)
	    {
		THROW (IEX_NAMESPACE::ArgExc, "Pixel type of \"" << i.name() << "\" "
			            "image channel is invalid.");
	    }

	    if (i.channel().xSampling < 1)
	    {
		THROW (IEX_NAMESPACE::ArgExc, "The x subsampling factor for the "
				    "\"" << i.name() << "\" channel "
				    "is invalid.");
	    }

	    if (i.channel().ySampling < 1)
	    {
		THROW (IEX_NAMESPACE::ArgExc, "The y subsampling factor for the "
				    "\"" << i.name() << "\" channel "
				    "is invalid.");
	    }

	    if (dataWindow.min.x % i.channel().xSampling)
	    {
		THROW (IEX_NAMESPACE::ArgExc, "The minimum x coordinate of the "
				    "image's data window is not a multiple "
				    "of the x subsampling factor of "
				    "the \"" << i.name() << "\" channel.");
	    }

	    if (dataWindow.min.y % i.channel().ySampling)
	    {
		THROW (IEX_NAMESPACE::ArgExc, "The minimum y coordinate of the "
				    "image's data window is not a multiple "
				    "of the y subsampling factor of "
				    "the \"" << i.name() << "\" channel.");
	    }

	    if ((dataWindow.max.x - dataWindow.min.x + 1) %
		    i.channel().xSampling)
	    {
		THROW (IEX_NAMESPACE::ArgExc, "Number of pixels per row in the "
				    "image's data window is not a multiple "
				    "of the x subsampling factor of "
				    "the \"" << i.name() << "\" channel.");
	    }

	    if ((dataWindow.max.y - dataWindow.min.y + 1) %
		    i.channel().ySampling)
	    {
		THROW (IEX_NAMESPACE::ArgExc, "Number of pixels per column in the "
				    "image's data window is not a multiple "
				    "of the y subsampling factor of "
				    "the \"" << i.name() << "\" channel.");
	    }
	}
    }
}
Example #18
0
void
DeepScanLineOutputFile::setFrameBuffer (const DeepFrameBuffer &frameBuffer)
{
    Lock lock (*_data->_streamData);

    //
    // Check if the new frame buffer descriptor
    // is compatible with the image file header.
    //

    const ChannelList &channels = _data->header.channels();

    for (ChannelList::ConstIterator i = channels.begin();
            i != channels.end();
            ++i)
    {
        DeepFrameBuffer::ConstIterator j = frameBuffer.find (i.name());

        if (j == frameBuffer.end())
            continue;

        if (i.channel().type != j.slice().type)
        {
            THROW (IEX_NAMESPACE::ArgExc, "Pixel type of \"" << i.name() << "\" channel "
                   "of output file \"" << fileName() << "\" is "
                   "not compatible with the frame buffer's "
                   "pixel type.");
        }

        if (i.channel().xSampling != j.slice().xSampling ||
                i.channel().ySampling != j.slice().ySampling)
        {
            THROW (IEX_NAMESPACE::ArgExc, "X and/or y subsampling factors "
                   "of \"" << i.name() << "\" channel "
                   "of output file \"" << fileName() << "\" are "
                   "not compatible with the frame buffer's "
                   "subsampling factors.");
        }
    }

    //
    // Store the pixel sample count table.
    // (TODO) Support for different sampling rates?
    //

    const Slice& sampleCountSlice = frameBuffer.getSampleCountSlice();
    if (sampleCountSlice.base == 0)
    {
        throw IEX_NAMESPACE::ArgExc ("Invalid base pointer, please set a proper sample count slice.");
    }
    else
    {
        _data->sampleCountSliceBase = sampleCountSlice.base;
        _data->sampleCountXStride = sampleCountSlice.xStride;
        _data->sampleCountYStride = sampleCountSlice.yStride;
    }

    //
    // Initialize slice table for writePixels().
    // Pixel sample count slice is not presented in the header,
    // so it wouldn't be added here.
    // Store the pixel base pointer table.
    // (TODO) Support for different sampling rates?
    //

    vector<OutSliceInfo*> slices;

    for (ChannelList::ConstIterator i = channels.begin();
            i != channels.end();
            ++i)
    {
        DeepFrameBuffer::ConstIterator j = frameBuffer.find (i.name());

        if (j == frameBuffer.end())
        {
            //
            // Channel i is not present in the frame buffer.
            // In the file, channel i will contain only zeroes.
            //

            slices.push_back (new OutSliceInfo (i.channel().type,
                                                NULL,// base
                                                0,// sampleStride,
                                                0,// xStride
                                                0,// yStride
                                                i.channel().xSampling,
                                                i.channel().ySampling,
                                                true)); // zero
        }
        else
        {
            //
            // Channel i is present in the frame buffer.
            //

            slices.push_back (new OutSliceInfo (j.slice().type,
                                                j.slice().base,
                                                j.slice().sampleStride,
                                                j.slice().xStride,
                                                j.slice().yStride,
                                                j.slice().xSampling,
                                                j.slice().ySampling,
                                                false)); // zero

        }
    }

    //
    // Store the new frame buffer.
    //

    _data->frameBuffer = frameBuffer;

    for (size_t i = 0; i < _data->slices.size(); i++)
        delete _data->slices[i];
    _data->slices = slices;
}
void	
ScanLineInputFile::setFrameBuffer (const FrameBuffer &frameBuffer)
{
    Lock lock (*_streamData);

    
    
    const ChannelList &channels = _data->header.channels();
    for (FrameBuffer::ConstIterator j = frameBuffer.begin();
	 j != frameBuffer.end();
	 ++j)
    {
	ChannelList::ConstIterator i = channels.find (j.name());

	if (i == channels.end())
	    continue;

	if (i.channel().xSampling != j.slice().xSampling ||
	    i.channel().ySampling != j.slice().ySampling)
	    THROW (IEX_NAMESPACE::ArgExc, "X and/or y subsampling factors "
				"of \"" << i.name() << "\" channel "
				"of input file \"" << fileName() << "\" are "
				"not compatible with the frame buffer's "
				"subsampling factors.");
    }

    // optimization is possible if this is a little endian system
    // and both inputs and outputs are half floats
    // 
    bool optimizationPossible = true;
    
    if (!GLOBAL_SYSTEM_LITTLE_ENDIAN)
    {
        optimizationPossible =false;
    }
    
    vector<sliceOptimizationData> optData;
    

    //
    // Initialize the slice table for readPixels().
    //

    vector<InSliceInfo> slices;
    ChannelList::ConstIterator i = channels.begin();
    
    // current offset of channel: pixel data starts at offset*width into the
    // decompressed scanline buffer
    size_t offset = 0;
    
    for (FrameBuffer::ConstIterator j = frameBuffer.begin();
	 j != frameBuffer.end();
	 ++j)
    {
	while (i != channels.end() && strcmp (i.name(), j.name()) < 0)
	{
	    //
	    // Channel i is present in the file but not
	    // in the frame buffer; data for channel i
	    // will be skipped during readPixels().
	    //

	    slices.push_back (InSliceInfo (i.channel().type,
					   i.channel().type,
					   0, // base
					   0, // xStride
					   0, // yStride
					   i.channel().xSampling,
					   i.channel().ySampling,
					   false,  // fill
					   true, // skip
					   0.0)); // fillValue
	    
              switch(i.channel().type)
              {
                  case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF :
                      offset++;
                      break;
                  case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT :
                      offset+=2;
                      break;
                  case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT :
                      offset+=2;
                      break;
              }
              ++i;
	}

	bool fill = false;

	if (i == channels.end() || strcmp (i.name(), j.name()) > 0)
	{
	    //
	    // Channel i is present in the frame buffer, but not in the file.
	    // In the frame buffer, slice j will be filled with a default value.
	    //

	    fill = true;
	}

	slices.push_back (InSliceInfo (j.slice().type,
				       fill? j.slice().type:
				             i.channel().type,
				       j.slice().base,
				       j.slice().xStride,
				       j.slice().yStride,
				       j.slice().xSampling,
				       j.slice().ySampling,
				       fill,
				       false, // skip
				       j.slice().fillValue));

          if(!fill && i.channel().type!=OPENEXR_IMF_INTERNAL_NAMESPACE::HALF)
          {
              optimizationPossible = false;
          }
          
          if(j.slice().type != OPENEXR_IMF_INTERNAL_NAMESPACE::HALF)
          {
              optimizationPossible = false;
          }
          if(j.slice().xSampling!=1 || j.slice().ySampling!=1)
          {
              optimizationPossible = false;
          }

          
          if(optimizationPossible)
          {
              sliceOptimizationData dat;
              dat.base = j.slice().base;
              dat.fill = fill;
              dat.fillValue = j.slice().fillValue;
              dat.offset = offset;
              dat.xStride = j.slice().xStride;
              dat.yStride = j.slice().yStride;
              dat.xSampling = j.slice().xSampling;
              dat.ySampling = j.slice().ySampling;
              optData.push_back(dat);
          }
          
          if(!fill)
          {
              switch(i.channel().type)
              {
                  case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF :
                      offset++;
                      break;
                  case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT :
                      offset+=2;
                      break;
                  case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT :
                      offset+=2;
                      break;
              }
          }
          

          
	if (i != channels.end() && !fill)
	    ++i;
    }

   
   if(optimizationPossible)
   {
       //
       // check optimisibility
       // based on channel ordering and fill channel positions
       //
       sort(optData.begin(),optData.end());
       _data->optimizationMode = detectOptimizationMode(optData);
   }
   
   if(!optimizationPossible || _data->optimizationMode._optimizable==false)
   {   
       optData = vector<sliceOptimizationData>();
       _data->optimizationMode._optimizable=false;
   }
    
    //
    // Store the new frame buffer.
    //

    _data->frameBuffer = frameBuffer;
    _data->slices = slices;
    _data->optimizationData = optData;
}
void	
TiledOutputFile::setFrameBuffer (const FrameBuffer &frameBuffer)
{
    Lock lock (*_streamData);

    //
    // Check if the new frame buffer descriptor
    // is compatible with the image file header.
    //

    const ChannelList &channels = _data->header.channels();

    for (ChannelList::ConstIterator i = channels.begin();
	 i != channels.end();
	 ++i)
    {
	FrameBuffer::ConstIterator j = frameBuffer.find (i.name());

	if (j == frameBuffer.end())
	    continue;

	if (i.channel().type != j.slice().type)
	    THROW (IEX_NAMESPACE::ArgExc, "Pixel type of \"" << i.name() << "\" channel "
				"of output file \"" << fileName() << "\" is "
				"not compatible with the frame buffer's "
				"pixel type.");

	if (j.slice().xSampling != 1 || j.slice().ySampling != 1)
	    THROW (IEX_NAMESPACE::ArgExc, "All channels in a tiled file must have"
				"sampling (1,1).");
    }
    
    //
    // Initialize slice table for writePixels().
    //

    vector<TOutSliceInfo> slices;

    for (ChannelList::ConstIterator i = channels.begin();
	 i != channels.end();
	 ++i)
    {
	FrameBuffer::ConstIterator j = frameBuffer.find (i.name());

	if (j == frameBuffer.end())
	{
	    //
	    // Channel i is not present in the frame buffer.
	    // In the file, channel i will contain only zeroes.
	    //

	    slices.push_back (TOutSliceInfo (i.channel().type,
					     0, // base
					     0, // xStride,
					     0, // yStride,
					     true)); // zero
	}
	else
	{
	    //
	    // Channel i is present in the frame buffer.
	    //

	    slices.push_back (TOutSliceInfo (j.slice().type,
					     j.slice().base,
					     j.slice().xStride,
					     j.slice().yStride,
					     false, // zero
                                             (j.slice().xTileCoords)? 1: 0,
                                             (j.slice().yTileCoords)? 1: 0));
	}
    }

    //
    // Store the new frame buffer.
    //

    _data->frameBuffer = frameBuffer;
    _data->slices = slices;
}
Example #21
0
void
makeMultiView (const vector <string> &viewNames,
	       const vector <const char *> &inFileNames,
	       const char *outFileName,
	       Compression compression,
	       bool verbose)
{
    Header header;
    Image image;
    FrameBuffer outFb;

    //
    // Find the size of the dataWindow, check files
    //
    
    Box2i d;
    
    
    for (int i = 0; i < viewNames.size(); ++i)
    {
	InputFile in (inFileNames[i]);

	if (verbose)
	{
	    cout << "reading file " << inFileNames[i] << " "
		    "for " << viewNames[i] << " view" << endl;
	}

	if (hasMultiView (in.header()))
	{
	    THROW (IEX_NAMESPACE::NoImplExc,
		   "The image in file " << inFileNames[i] << " is already a "
		   "multi-view image.  Cannot combine multiple multi-view "
		   "images.");
	}

        header = in.header();
	if (i == 0)
        {
             d=header.dataWindow();
	}else{
             d.extendBy(header.dataWindow());
        }
    }
    
    
    image.resize (d);
    
    header.dataWindow()=d;
    
    // blow away channels; we'll rebuild them
    header.channels()=ChannelList();
    
    
    //
    // Read the input image files
    //

    for (int i = 0; i < viewNames.size(); ++i)
    {
	InputFile in (inFileNames[i]);

	if (verbose)
	{
	    cout << "reading file " << inFileNames[i] << " "
		    "for " << viewNames[i] << " view" << endl;
	}

	FrameBuffer inFb;

	for (ChannelList::ConstIterator j = in.header().channels().begin();
	     j != in.header().channels().end();
	     ++j)
	{
	    const Channel &inChannel = j.channel();
	    string inChanName = j.name();
	    string outChanName = insertViewName (inChanName, viewNames, i);

	    image.addChannel (outChanName, inChannel);
            image.channel(outChanName).black();
            
	    header.channels().insert (outChanName, inChannel);

	    inFb.insert  (inChanName,  image.channel(outChanName).slice());
	    outFb.insert (outChanName, image.channel(outChanName).slice());
	}

	in.setFrameBuffer (inFb);
	in.readPixels (in.header().dataWindow().min.y, in.header().dataWindow().max.y);
    }

    //
    // Write the output image file
    //

    {
	header.compression() = compression;
	addMultiView (header, viewNames);

	OutputFile out (outFileName, header);

	if (verbose)
	    cout << "writing file " << outFileName << endl;

	out.setFrameBuffer (outFb);

	out.writePixels
	    (header.dataWindow().max.y - header.dataWindow().min.y + 1);
    }
}
Example #22
0
void	
ScanLineInputFile::setFrameBuffer (const FrameBuffer &frameBuffer)
{
    Lock lock (*_data);

    //
    // Check if the new frame buffer descriptor is
    // compatible with the image file header.
    //

    const ChannelList &channels = _data->header.channels();

    for (FrameBuffer::ConstIterator j = frameBuffer.begin();
	 j != frameBuffer.end();
	 ++j)
    {
	ChannelList::ConstIterator i = channels.find (j.name());

	if (i == channels.end())
	    continue;

	if (i.channel().xSampling != j.slice().xSampling ||
	    i.channel().ySampling != j.slice().ySampling)
	    THROW (Iex::ArgExc, "X and/or y subsampling factors "
				"of \"" << i.name() << "\" channel "
				"of input file \"" << fileName() << "\" are "
				"not compatible with the frame buffer's "
				"subsampling factors.");
    }

    //
    // Initialize the slice table for readPixels().
    //

    vector<InSliceInfo> slices;
    ChannelList::ConstIterator i = channels.begin();

    for (FrameBuffer::ConstIterator j = frameBuffer.begin();
	 j != frameBuffer.end();
	 ++j)
    {
	while (i != channels.end() && strcmp (i.name(), j.name()) < 0)
	{
	    //
	    // Channel i is present in the file but not
	    // in the frame buffer; data for channel i
	    // will be skipped during readPixels().
	    //

	    slices.push_back (InSliceInfo (i.channel().type,
					   i.channel().type,
					   0, // base
					   0, // xStride
					   0, // yStride
					   i.channel().xSampling,
					   i.channel().ySampling,
					   false,  // fill
					   true, // skip
					   0.0)); // fillValue
	    ++i;
	}

	bool fill = false;

	if (i == channels.end() || strcmp (i.name(), j.name()) > 0)
	{
	    //
	    // Channel i is present in the frame buffer, but not in the file.
	    // In the frame buffer, slice j will be filled with a default value.
	    //

	    fill = true;
	}

	slices.push_back (InSliceInfo (j.slice().type,
				       fill? j.slice().type:
				             i.channel().type,
				       j.slice().base,
				       j.slice().xStride,
				       j.slice().yStride,
				       j.slice().xSampling,
				       j.slice().ySampling,
				       fill,
				       false, // skip
				       j.slice().fillValue));

	if (i != channels.end() && !fill)
	    ++i;
    }

    //
    // Store the new frame buffer.
    //

    _data->frameBuffer = frameBuffer;
    _data->slices = slices;
}
Example #23
0
/* creates channels, makes a hierarchy and assigns memory to channels */
static ExrHandle *imb_exr_begin_read_mem(InputFile *file, int width, int height)
{
	ExrLayer *lay;
	ExrPass *pass;
	ExrChannel *echan;
	ExrHandle *data= (ExrHandle *)IMB_exr_get_handle();
	int a;
	char layname[EXR_TOT_MAXNAME], passname[EXR_TOT_MAXNAME];
	
	data->ifile= file;
	data->width= width;
	data->height= height;
	
	const ChannelList &channels = data->ifile->header().channels();

	for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
		IMB_exr_add_channel(data, NULL, i.name(), 0, 0, NULL);
	
	/* now try to sort out how to assign memory to the channels */
	/* first build hierarchical layer list */
	for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next) {
		if( imb_exr_split_channel_name(echan, layname, passname) ) {
			ExrLayer *lay= imb_exr_get_layer(&data->layers, layname);
			ExrPass *pass= imb_exr_get_pass(&lay->passes, passname);
			
			pass->chan[pass->totchan]= echan;
			pass->totchan++;
			if(pass->totchan>=EXR_PASS_MAXCHAN)
				break;
		}
	}
	if(echan) {
		printf("error, too many channels in one pass: %s\n", echan->name);
		IMB_exr_close(data);
		return NULL;
	}
	
	/* with some heuristics, try to merge the channels in buffers */
	for(lay= (ExrLayer *)data->layers.first; lay; lay= lay->next) {
		for(pass= (ExrPass *)lay->passes.first; pass; pass= pass->next) {
			if(pass->totchan) {
				pass->rect= (float *)MEM_mapallocN(width*height*pass->totchan*sizeof(float), "pass rect");
				if(pass->totchan==1) {
					echan= pass->chan[0];
					echan->rect= pass->rect;
					echan->xstride= 1;
					echan->ystride= width;
					pass->chan_id[0]= echan->chan_id;
				}
				else {
					char lookup[256];
					
					memset(lookup, 0, sizeof(lookup));
						   
					/* we can have RGB(A), XYZ(W), UVA */
					if(pass->totchan==3 || pass->totchan==4) {
						if(pass->chan[0]->chan_id=='B' || pass->chan[1]->chan_id=='B' ||  pass->chan[2]->chan_id=='B') {
							lookup[(unsigned int)'R']= 0;
							lookup[(unsigned int)'G']= 1;
							lookup[(unsigned int)'B']= 2;
							lookup[(unsigned int)'A']= 3;
						}
						else if(pass->chan[0]->chan_id=='Y' || pass->chan[1]->chan_id=='Y' ||  pass->chan[2]->chan_id=='Y') {
							lookup[(unsigned int)'X']= 0;
							lookup[(unsigned int)'Y']= 1;
							lookup[(unsigned int)'Z']= 2;
							lookup[(unsigned int)'W']= 3;
						}
						else {
							lookup[(unsigned int)'U']= 0;
							lookup[(unsigned int)'V']= 1;
							lookup[(unsigned int)'A']= 2;
						}
						for(a=0; a<pass->totchan; a++) {
							echan= pass->chan[a];
							echan->rect= pass->rect + lookup[(unsigned int)echan->chan_id];
							echan->xstride= pass->totchan;
							echan->ystride= width*pass->totchan;
							pass->chan_id[ (unsigned int)lookup[(unsigned int)echan->chan_id] ]= echan->chan_id;
						}
					}
					else { /* unknown */
						for(a=0; a<pass->totchan; a++) {
							echan= pass->chan[a];
							echan->rect= pass->rect + a;
							echan->xstride= pass->totchan;
							echan->ystride= width*pass->totchan;
							pass->chan_id[a]= echan->chan_id;
						}
					}
				}
			}
		}
	}
	
	return data;
}
void readFrames( int argc, char* argv[] )
{
  pfs::DOMIO pfsio;

  bool verbose = false;
  bool keepRGB = false;

  // Parse command line parameters
  static struct option cmdLineOptions[] = {
    { "help", no_argument, NULL, 'h' },
    { "verbose", no_argument, NULL, 'v' },
    { "keep-rgb", no_argument, NULL, 'k' },
    { "linear", no_argument, NULL, 'l' },
    { NULL, 0, NULL, 0 }
  };
  static const char optstring[] = "lkhv";
    
  pfs::FrameFileIterator it( argc, argv, "rb", NULL, NULL,
    optstring, cmdLineOptions );
    
  int optionIndex = 0;
  while( 1 ) {
    int c = getopt_long (argc, argv, optstring, cmdLineOptions, &optionIndex);
    if( c == -1 ) break;
    switch( c ) {
    case 'h':
      printHelp();
      throw QuietException();
    case 'v':
      verbose = true;
      break;
    case 'k':
      keepRGB = true;
      break;
    case 'l':
      std::cerr << PROG_NAME << " warning: linearize option ignored for an HDR input!"
                << std::endl;
      break;
    case '?':
      throw QuietException();
    case ':':
      throw QuietException();
    }
  }

  VERBOSE_STR << "keep RGB channels untouch: " << (keepRGB ? "yes" : "no") << std::endl;
  
  while( true )
  {
    pfs::FrameFile ff = it.getNextFrameFile();
    if( ff.fh == NULL ) break; // No more frames
    it.closeFrameFile( ff );

    InputFile file( ff.fileName );

    FrameBuffer frameBuffer;
    
    Box2i dw = file.header().displayWindow();
    Box2i dtw = file.header().dataWindow();
    int width  = dw.max.x - dw.min.x + 1;
    int height = dw.max.y - dw.min.y + 1;

    if( dtw.min.x < dw.min.x && dtw.max.x > dw.max.x ||
      dtw.min.y < dw.min.y && dtw.max.y > dw.max.y )
      throw pfs::Exception( "No support for OpenEXR files DataWidnow greater than DisplayWindow" );
    

    pfs::Frame *frame = pfsio.createFrame( width, height );

    const ChannelList &channels = file.header().channels();

    bool processColorChannels = false;
    pfs::Channel *X, *Y, *Z;
    if( !keepRGB ) {            // Keep RGB channels as they are
      const Channel *rChannel = channels.findChannel( "R" );
      const Channel *gChannel = channels.findChannel( "G" );
      const Channel *bChannel = channels.findChannel( "B" );
      if( rChannel!=NULL && gChannel!=NULL && bChannel!=NULL ) {
        frame->createXYZChannels( X, Y, Z );

        frameBuffer.insert( "R",				  // name
          Slice( FLOAT,			  // type
//            (char*)(X->getRawData()),
            (char*)(X->getRawData()),
            sizeof(float),	  // xStride
            sizeof(float) * width,// yStride
            1, 1,			  // x/y sampling
            0.0));			  // fillValue

        frameBuffer.insert( "G",				  // name
          Slice( FLOAT,			  // type
            (char*)(Y->getRawData()),
            sizeof(float),	  // xStride
            sizeof(float) * width,// yStride
            1, 1,			  // x/y sampling
            0.0));			  // fillValue

        frameBuffer.insert( "B",				  // name
          Slice( FLOAT,			  // type
            (char*)(Z->getRawData()),
            sizeof(float),	  // xStride
            sizeof(float) * width,// yStride
            1, 1,			  // x/y sampling
            0.0)); // fillValue

        processColorChannels = true;
      }
    }
    
    for( ChannelList::ConstIterator i = channels.begin();
         i != channels.end(); ++i )
    {
      const Channel &channel = i.channel();
        
      if( processColorChannels ) { // Skip color channels
        if( !strcmp( i.name(), "R" ) || !strcmp( i.name(), "G" ) ||
          !strcmp( i.name(), "B" ) ) continue;
      }

      const char *channelName = i.name();
      if( !strcmp( channelName, "Z" ) ) {
        channelName = "DEPTH";
      }
        
      pfs::Channel *pfsCh = frame->createChannel( channelName );
      frameBuffer.insert( i.name(),				  // name
        Slice( FLOAT,			  // type
          (char *)pfsCh->getRawData(),
          sizeof(float),	  // xStride
          sizeof(float) * width,// yStride
          1, 1,			  // x/y sampling
          0.0));			  // fillValue
    }     

    // Copy attributes to tags
    {
      for( Header::ConstIterator it = file.header().begin();
           it != file.header().end(); it++ ) {
        const char *attribName = it.name();
        const char *colon = strstr( attribName, ":" );
        const StringAttribute *attrib =
          file.header().findTypedAttribute<StringAttribute>(attribName);

        if( attrib == NULL ) continue; // Skip if type is not String
        
//         fprintf( stderr, "Tag: %s = %s\n", attribName, attrib->value().c_str() );
        
        if( colon == NULL ) {   // frame tag
          frame->getTags()->setString( attribName, escapeString(attrib->value()).c_str() );
        } else {                // channel tag
          string channelName = string( attribName, colon-attribName );
          pfs::Channel *ch = frame->getChannel( channelName.c_str() );
          if( ch == NULL ) {
            fprintf( stderr, PROG_NAME ": Warning! Can not set tag for '%s' channel because it does not exist\n", channelName.c_str() );
            continue;
          }
          ch->getTags()->setString(  colon+1, escapeString( attrib->value() ).c_str() );
        }
        
      }
    }
    
    file.setFrameBuffer( frameBuffer );
    file.readPixels( dw.min.y, dw.max.y );

    VERBOSE_STR << "reading file (linear) '" << ff.fileName << "'" << std::endl;
    
    if( processColorChannels ) {      
      // Rescale values if WhiteLuminance is present
      if( hasWhiteLuminance( file.header() ) ) {
        float scaleFactor = whiteLuminance( file.header() );
        int pixelCount = frame->getHeight()*frame->getWidth();
        for( int i = 0; i < pixelCount; i++ ) {
          (*X)(i) *= scaleFactor;
          (*Y)(i) *= scaleFactor;
          (*Z)(i) *= scaleFactor;
        }
        const StringAttribute *relativeLum =
          file.header().findTypedAttribute<StringAttribute>("RELATIVE_LUMINANCE");

        const char *luminanceTag = frame->getTags()->getString( "LUMINANCE" );
        if( luminanceTag == NULL )
          frame->getTags()->setString( "LUMINANCE", "ABSOLUTE" );
      }  
      pfs::transformColorSpace( pfs::CS_RGB, X, Y, Z, pfs::CS_XYZ, X, Y, Z );
    }    
    frame->getTags()->setString( "FILE_NAME", ff.fileName );
    
    pfsio.writeFrame( frame, stdout );
    pfsio.freeFrame( frame );
  }
}