Beispiel #1
0
void write_half_exr( const boost::filesystem::path& p, Imf::Header& header,
			    const image::const_image_view_t& view, bool write_alpha)
{
    boost::gil::rgba16f_image_t img( view.width(), view.height());
    boost::gil::copy_and_convert_pixels( view, boost::gil::view( img));

    header.channels().insert( "R", Imf::HALF);
    header.channels().insert( "G", Imf::HALF);
    header.channels().insert( "B", Imf::HALF);

    if( write_alpha)
        header.channels().insert( "A", Imf::HALF);

    Imf::FrameBuffer frameBuffer;

    char *ptr = (char *) boost::gil::interleaved_view_get_raw_data( boost::gil::view( img));
    std::size_t xstride = 4 * sizeof(half);
    std::size_t ystride = xstride * img.width();

    frameBuffer.insert( "R", Imf::Slice( Imf::HALF, ptr, xstride, ystride)); ptr += sizeof(half);
    frameBuffer.insert( "G", Imf::Slice( Imf::HALF, ptr, xstride, ystride)); ptr += sizeof(half);
    frameBuffer.insert( "B", Imf::Slice( Imf::HALF, ptr, xstride, ystride)); ptr += sizeof(half);

    if( write_alpha)
        frameBuffer.insert( "A", Imf::Slice( Imf::HALF, ptr, xstride, ystride));

    Imf::OutputFile out_file( p.external_file_string().c_str(), header);
    out_file.setFrameBuffer( frameBuffer);
    out_file.writePixels( img.height());
}
Beispiel #2
0
void Bitmap::save(const std::string &filename) {
    cout << "Writing a " << cols() << "x" << rows() 
         << " OpenEXR file to \"" << filename << "\"" << endl;

    Imf::Header header((int) cols(), (int) rows());
    header.insert("comments", Imf::StringAttribute("Generated by Nori"));

    Imf::ChannelList &channels = header.channels();
    channels.insert("R", Imf::Channel(Imf::FLOAT));
    channels.insert("G", Imf::Channel(Imf::FLOAT));
    channels.insert("B", Imf::Channel(Imf::FLOAT));

    Imf::FrameBuffer frameBuffer;
    size_t compStride = sizeof(float),
           pixelStride = 3 * compStride,
           rowStride = pixelStride * cols();

    char *ptr = reinterpret_cast<char *>(data());
    frameBuffer.insert("R", Imf::Slice(Imf::FLOAT, ptr, pixelStride, rowStride)); ptr += compStride;
    frameBuffer.insert("G", Imf::Slice(Imf::FLOAT, ptr, pixelStride, rowStride)); ptr += compStride;
    frameBuffer.insert("B", Imf::Slice(Imf::FLOAT, ptr, pixelStride, rowStride)); 

    Imf::OutputFile file(filename.c_str(), header);
    file.setFrameBuffer(frameBuffer);
    file.writePixels((int) rows());
}
Beispiel #3
0
NORI_NAMESPACE_BEGIN

Bitmap::Bitmap(const std::string &filename) {
    Imf::InputFile file(filename.c_str());
    const Imf::Header &header = file.header();
    const Imf::ChannelList &channels = header.channels();

    Imath::Box2i dw = file.header().dataWindow();
    resize(dw.max.y - dw.min.y + 1, dw.max.x - dw.min.x + 1);

    cout << "Reading a " << cols() << "x" << rows() << " OpenEXR file from \""
         << filename << "\"" << endl;

    const char *ch_r = nullptr, *ch_g = nullptr, *ch_b = nullptr;
    for (Imf::ChannelList::ConstIterator it = channels.begin(); it != channels.end(); ++it) {
        std::string name = toLower(it.name());

        if (it.channel().xSampling != 1 || it.channel().ySampling != 1) {
            /* Sub-sampled layers are not supported */
            continue;
        }

        if (!ch_r && (name == "r" || name == "red" || 
                endsWith(name, ".r") || endsWith(name, ".red"))) {
            ch_r = it.name();
        } else if (!ch_g && (name == "g" || name == "green" || 
                endsWith(name, ".g") || endsWith(name, ".green"))) {
            ch_g = it.name();
        } else if (!ch_b && (name == "b" || name == "blue" || 
                endsWith(name, ".b") || endsWith(name, ".blue"))) {
            ch_b = it.name();
        }
    }

    if (!ch_r || !ch_g || !ch_b)
        throw NoriException("This is not a standard RGB OpenEXR file!");

    size_t compStride = sizeof(float),
           pixelStride = 3 * compStride,
           rowStride = pixelStride * cols();

    char *ptr = reinterpret_cast<char *>(data());

    Imf::FrameBuffer frameBuffer;
    frameBuffer.insert(ch_r, Imf::Slice(Imf::FLOAT, ptr, pixelStride, rowStride)); ptr += compStride;
    frameBuffer.insert(ch_g, Imf::Slice(Imf::FLOAT, ptr, pixelStride, rowStride)); ptr += compStride;
    frameBuffer.insert(ch_b, Imf::Slice(Imf::FLOAT, ptr, pixelStride, rowStride)); 
    file.setFrameBuffer(frameBuffer);
    file.readPixels(dw.min.y, dw.max.y);

    m_totalLuminance = getTotalLuminace();
}
		void SaveTexture(	const std::string& _filename,
							float* _data,
							int _w,
							int _h,
							bool _verbose)
		{
			int xRes 	  = _w;
			int yRes 	  = _h;
			int xOffset   = 0;
			int yOffset   = 0;
			int nChannels = 4;

			Imf::Header header(xRes, yRes);
			Imath::Box2i dataWindow(Imath::V2i(xOffset, yOffset), Imath::V2i(xOffset + xRes - 1, yOffset + yRes - 1));
			header.dataWindow() = dataWindow;

			header.channels().insert("R", Imf::Channel (Imf::HALF));
			header.channels().insert("G", Imf::Channel (Imf::HALF));
			header.channels().insert("B", Imf::Channel (Imf::HALF));
			header.channels().insert("A", Imf::Channel (Imf::HALF));

			::half *hchannels   = new ::half[nChannels * xRes * yRes];
			for (int y = 0; y < yRes; ++y)
			for (int x = 0; x < xRes; ++x)
			for (int c = 0; c < nChannels; ++c)
			{
				int iSrc = c + x*nChannels + (yRes-1-y)*xRes*nChannels; 
				int iDst = c + x*nChannels + y*xRes*nChannels;
				hchannels[iDst] = _data[iSrc];
			}

			Imf::FrameBuffer fb;
			fb.insert("R", Imf::Slice(Imf::HALF, (char *)hchannels,						nChannels*sizeof(::half), nChannels*xRes*sizeof(::half)));
			fb.insert("G", Imf::Slice(Imf::HALF, (char *)hchannels+1*sizeof(::half),	nChannels*sizeof(::half), nChannels*xRes*sizeof(::half)));
			fb.insert("B", Imf::Slice(Imf::HALF, (char *)hchannels+2*sizeof(::half),	nChannels*sizeof(::half), nChannels*xRes*sizeof(::half)));
			fb.insert("A", Imf::Slice(Imf::HALF, (char *)hchannels+3*sizeof(::half),	nChannels*sizeof(::half), nChannels*xRes*sizeof(::half)));

			Imf::OutputFile file(_filename.c_str(), header);
			file.setFrameBuffer(fb);
			try 
			{
				file.writePixels(yRes);
			}
			catch (const std::exception &e) 
			{
				Error("Unable to write image file \"%s\": %s", _filename.c_str(), e.what());
				assert(false);
			}

			delete[] hchannels;
		}
Beispiel #5
0
void ImgTools::write_rgba_layer(const char *filename, const Imf::Rgba* pixels, const Imath::Box2i &dispwin, const Imath::Box2i &datawin)
{
	using namespace Imf;

	const int DISP_WIDTH  = dispwin.max.x - dispwin.min.x + 1;
	const int DISP_HEIGHT = dispwin.max.y - dispwin.min.y + 1;

	const int DATA_WIDTH = datawin.max.x - datawin.min.x + 1;
	const int DATA_HEIGHT = datawin.max.y - datawin.min.y + 1;
	const Imf::Rgba* BASE = pixels - datawin.min.x - datawin.min.y * DATA_WIDTH;

	Imf::Header header(DISP_WIDTH, DISP_HEIGHT);
	header.dataWindow() = datawin;
	header.channels().insert("R", Imf::Channel(Imf::HALF));
	header.channels().insert("G", Imf::Channel(Imf::HALF));
	header.channels().insert("B", Imf::Channel(Imf::HALF));
	header.channels().insert("A", Imf::Channel(Imf::HALF));

	Imf::OutputFile exr(filename, header);
	Imf::FrameBuffer frameBuffer;

	frameBuffer.insert("R",                       // name
			Imf::Slice(Imf::HALF,                 // type
					(char *)(&BASE->r),           // base
					sizeof(*BASE),                // xStride
					sizeof(*BASE) * DATA_WIDTH)); // yStride

	frameBuffer.insert("G",                       // name
			Imf::Slice(Imf::HALF,                 // type
					(char *)(&BASE->g),           // base
					sizeof(*BASE),                // xStride
					sizeof(*BASE) * DATA_WIDTH)); // yStride

	frameBuffer.insert("B",                       // name
			Imf::Slice(Imf::HALF,                 // type
					(char *)(&BASE->b),           // base
					sizeof(*BASE),                // xStride
					sizeof(*BASE) * DATA_WIDTH)); // yStride

	frameBuffer.insert("A",                       // name
			Imf::Slice(Imf::HALF,                 // type
					(char *)(&BASE->a),           // base
					sizeof(*BASE),                // xStride
					sizeof(*BASE) * DATA_WIDTH)); // yStride

	exr.setFrameBuffer(frameBuffer);
	exr.writePixels(DATA_HEIGHT);
}
Beispiel #6
0
bool ImageIO::writeImage(QVector<float> &pixels, const QString &filePath, const LayerDesc &desc, int width, int height)
{
    try
    {
        Imf::Header header (width, height);
        Imf::FrameBuffer frameBuffer;

        for (int chan = 0; chan < desc.numChannels(); chan++) {
            QString chan_name = QString("%1.%2").arg(desc._layer_name).arg(desc._channels[chan]);
            header.channels().insert(qPrintable(chan_name), Imf::Channel(Imf::FLOAT));
            frameBuffer.insert(qPrintable(chan_name), Imf::Slice(Imf::FLOAT, (char *) pixels.data() + chan*sizeof(float), sizeof(float)*desc.numChannels(), sizeof(float)*width*desc.numChannels()));
        }

        Imf::OutputFile file(qPrintable(remapFilePath(filePath)), header);
        file.setFrameBuffer(frameBuffer);

        file.writePixels(height);
    }
    catch (const std::exception &e)
    {
        qWarning() << e.what();
        return false;
    }
    return true;
}
void CqExrInputFile::readPixelsImpl(TqUint8* buffer,
		TqInt startLine, TqInt numScanlines) const
{
	// correct the start line for OpenEXR conventions
	const Imath::Box2i& dataWindow = m_exrFile->header().dataWindow();
	startLine += dataWindow.min.y;
	// Set up an OpenEXR framebuffer
	Imf::FrameBuffer frameBuffer;
	const CqChannelList& channels = m_header.channelList();
	const TqChannelNameMap& nameMap = m_header.find<Attr::ExrChannelNameMap>();
	const TqInt xStride = channels.bytesPerPixel();
	const TqInt yStride = m_header.width()*xStride;
	// In OpenEXR, the buffer base pointer is assumed to point at the
	// coordinates of the (0,0) pixel.  We need to correct our buffer pointer
	// by subtracting the offset to (0,0) from the start of the data.
	buffer -= dataWindow.min.x*xStride + dataWindow.min.y*yStride;
	for(TqInt i = 0; i < channels.numChannels(); ++i)
	{
		frameBuffer.insert(nameMap.find(channels[i].name)->second.c_str(),
				Imf::Slice(
					exrChannelType(channels[i].type),
					reinterpret_cast<char*>(buffer + channels.channelByteOffset(i)),
					xStride,
					yStride
					)
				);
	}
	m_exrFile->setFrameBuffer(frameBuffer);
	// Read in the pixels
	m_exrFile->readPixels(startLine, startLine + numScanlines - 1);
}
void FExrImageWrapper::WriteFrameBufferChannel(Imf::FrameBuffer& ImfFrameBuffer, const char* ChannelName, const sourcetype* SrcData, TArray<uint8>& ChannelBuffer)
{
	const int32 OutputPixelSize = ((OutputFormat == Imf::HALF) ? 2 : 4);
	ChannelBuffer.AddUninitialized(Width*Height*OutputPixelSize);
	uint32 SrcChannels = GetNumChannelsFromFormat(RawFormat);
	ExtractAndConvertChannel(SrcData, SrcChannels, Width, Height, (typename TExrImageOutputChannelType<OutputFormat>::Type*)&ChannelBuffer[0]);
	Imf::Slice FrameChannel = Imf::Slice(OutputFormat, (char*)&ChannelBuffer[0], OutputPixelSize, Width*OutputPixelSize);
	ImfFrameBuffer.insert(ChannelName, FrameChannel);
}
Beispiel #9
0
bool
OpenEXRInput::read_native_scanlines (int ybegin, int yend, int z,
                                     int chbegin, int chend, void *data)
{
    chend = clamp (chend, chbegin+1, m_spec.nchannels);
//    std::cerr << "openexr rns " << ybegin << ' ' << yend << ", channels "
//              << chbegin << "-" << (chend-1) << "\n";
    if (m_input_scanline == NULL && m_scanline_input_part == NULL) {
        error ("called OpenEXRInput::read_native_scanlines without an open file");
        return false;
    }

    // Compute where OpenEXR needs to think the full buffers starts.
    // OpenImageIO requires that 'data' points to where the client wants
    // to put the pixels being read, but OpenEXR's frameBuffer.insert()
    // wants where the address of the "virtual framebuffer" for the
    // whole image.
    const PartInfo &part (m_parts[m_subimage]);
    size_t pixelbytes = m_spec.pixel_bytes (chbegin, chend, true);
    size_t scanlinebytes = (size_t)m_spec.width * pixelbytes;
    char *buf = (char *)data
              - m_spec.x * pixelbytes
              - ybegin * scanlinebytes;

    try {
        Imf::FrameBuffer frameBuffer;
        size_t chanoffset = 0;
        for (int c = chbegin;  c < chend;  ++c) {
            size_t chanbytes = m_spec.channelformat(c).size();
            frameBuffer.insert (m_spec.channelnames[c].c_str(),
                                Imf::Slice (part.pixeltype[c],
                                            buf + chanoffset,
                                            pixelbytes, scanlinebytes));
            chanoffset += chanbytes;
        }
        if (m_input_scanline) {
            m_input_scanline->setFrameBuffer (frameBuffer);
            m_input_scanline->readPixels (ybegin, yend-1);
#ifdef USE_OPENEXR_VERSION2
        } else if (m_scanline_input_part) {
            m_scanline_input_part->setFrameBuffer (frameBuffer);
            m_scanline_input_part->readPixels (ybegin, yend-1);
#endif
        } else {
            error ("Attempted to read scanline from a non-scanline file.");
            return false;
        }
    } catch (const std::exception &e) {
        error ("Failed OpenEXR read: %s", e.what());
        return false;
    } catch (...) {   // catch-all for edge cases or compiler bugs
        error ("Failed OpenEXR read: unknown exception");
        return false;
    }
    return true;
}
Beispiel #10
0
void SaveExr(const Image<unsigned char>& image_in, const pangolin::PixelFormat& fmt, const std::string& filename, bool top_line_first)
{
    PANGOLIN_UNUSED(image_in);
    PANGOLIN_UNUSED(fmt);
    PANGOLIN_UNUSED(filename);
    PANGOLIN_UNUSED(top_line_first);

#ifdef HAVE_OPENEXR
    ManagedImage<unsigned char> flip_image;
    Image<unsigned char> image;

    if(top_line_first) {
        image = image_in;
    }else{
        flip_image.Reinitialise(image_in.pitch,image_in.h);
        for(size_t y=0; y<image_in.h; ++y) {
            std::memcpy(flip_image.RowPtr(y), image_in.RowPtr(y), image_in.pitch);
        }
        image = flip_image;
    }


    Imf::Header header (image.w, image.h);
    SetOpenEXRChannels(header.channels(), fmt);

    Imf::OutputFile file (filename.c_str(), header);
    Imf::FrameBuffer frameBuffer;

    int ch=0;
    size_t ch_bits = 0;
    for(Imf::ChannelList::Iterator it = header.channels().begin(); it != header.channels().end(); ++it)
    {
        frameBuffer.insert(
            it.name(),
            Imf::Slice(
                it.channel().type,
                (char*)image.ptr + ch_bits/8,
                fmt.channel_bits[ch]/8,
                image.pitch
            )
        );

        ch_bits += fmt.channel_bits[ch++];
    }

    file.setFrameBuffer(frameBuffer);
    file.writePixels(image.h);

#else
    throw std::runtime_error("EXR Support not enabled. Please rebuild Pangolin.");
#endif // HAVE_OPENEXR
}
Beispiel #11
0
void write_half_rgb_exr( Imf::OStream& os, Imf::Header& header, const image::const_image_view_t& view)
{
    boost::gil::rgba16f_image_t img( view.width(), view.height());
    boost::gil::copy_and_convert_pixels( view, boost::gil::view( img));

    header.channels().insert( "R", Imf::HALF);
    header.channels().insert( "G", Imf::HALF);
    header.channels().insert( "B", Imf::HALF);

    Imf::FrameBuffer frameBuffer;

    char *ptr = (char *) boost::gil::interleaved_view_get_raw_data( boost::gil::view( img));
    std::size_t xstride = 4 * sizeof(half);
    std::size_t ystride = xstride * img.width();

    frameBuffer.insert( "R", Imf::Slice( Imf::HALF, ptr, xstride, ystride)); ptr += sizeof(half);
    frameBuffer.insert( "G", Imf::Slice( Imf::HALF, ptr, xstride, ystride)); ptr += sizeof(half);
    frameBuffer.insert( "B", Imf::Slice( Imf::HALF, ptr, xstride, ystride)); ptr += sizeof(half);

    Imf::OutputFile out_file( os, header);
    out_file.setFrameBuffer( frameBuffer);
    out_file.writePixels( img.height());
}
Beispiel #12
0
void SaveExr(const Image<unsigned char>& image_in, const pangolin::VideoPixelFormat& fmt, const std::string& filename, bool top_line_first)
{
#ifdef HAVE_OPENEXR
    Image<unsigned char> image;

    if(top_line_first) {
        image = image_in;
    }else{
        image.Alloc(image_in.w,image_in.h,image_in.pitch);
        for(size_t y=0; y<image_in.h; ++y) {
            std::memcpy(image.ptr + y*image.pitch, image_in.ptr + (image_in.h-y-1)*image_in.pitch, image.pitch);
        }
    }


    Imf::Header header (image.w, image.h);
    SetOpenEXRChannels(header.channels(), fmt);

    Imf::OutputFile file (filename.c_str(), header);
    Imf::FrameBuffer frameBuffer;

    int ch=0;
    size_t ch_bits = 0;
    for(Imf::ChannelList::Iterator it = header.channels().begin(); it != header.channels().end(); ++it)
    {
        frameBuffer.insert(
            it.name(),
            Imf::Slice(
                it.channel().type,
                (char*)image.ptr + ch_bits/8,
                fmt.channel_bits[ch]/8,
                image.pitch
            )
        );

        ch_bits += fmt.channel_bits[ch++];
    }

    file.setFrameBuffer(frameBuffer);
    file.writePixels(image.h);

    if(!top_line_first) {
        image.Dealloc();
    }

#else
    throw std::runtime_error("EXR Support not enabled. Please rebuild Pangolin.");
#endif // HAVE_OPENEXR
}
Beispiel #13
0
bool
OpenEXROutput::write_tile (int x, int y, int z,
                           TypeDesc format, const void *data,
                           stride_t xstride, stride_t ystride, stride_t zstride)
{
    bool native = (format == TypeDesc::UNKNOWN);
    size_t pixel_bytes = m_spec.pixel_bytes (native);
    if (native && xstride == AutoStride)
        xstride = (stride_t) pixel_bytes;
    m_spec.auto_stride (xstride, ystride, zstride, format, spec().nchannels,
                        spec().tile_width, spec().tile_height);
    data = to_native_tile (format, data, xstride, ystride, zstride, m_scratch);

    // Compute where OpenEXR needs to think the full buffers starts.
    // OpenImageIO requires that 'data' points to where the client wants
    // to put the pixels being read, but OpenEXR's frameBuffer.insert()
    // wants where the address of the "virtual framebuffer" for the
    // whole image.
    char *buf = (char *)data
              - x * pixel_bytes
              - y * pixel_bytes * m_spec.tile_width;

    try {
        Imf::FrameBuffer frameBuffer;
        size_t chanoffset = 0;
        for (int c = 0;  c < m_spec.nchannels;  ++c) {
            size_t chanbytes = m_spec.channelformats.size() 
                                  ? m_spec.channelformats[c].size() 
                                  : m_spec.format.size();
            frameBuffer.insert (m_spec.channelnames[c].c_str(),
                                Imf::Slice (m_pixeltype[c],
                                            buf + chanoffset, pixel_bytes,
                                            pixel_bytes*m_spec.tile_width));
            chanoffset += chanbytes;
        }
        m_output_tiled->setFrameBuffer (frameBuffer);
        m_output_tiled->writeTile ((x - m_spec.x) / m_spec.tile_width,
                                   (y - m_spec.y) / m_spec.tile_height,
                                   m_miplevel, m_miplevel);
    }
    catch (const std::exception &e) {
        error ("Failed OpenEXR write: %s", e.what());
        return false;
    }

    return true;
}
Beispiel #14
0
bool
OpenEXROutput::write_scanline (int y, int z, TypeDesc format,
                               const void *data, stride_t xstride)
{
    bool native = (format == TypeDesc::UNKNOWN);
    size_t pixel_bytes = m_spec.pixel_bytes (true);  // native
    if (native && xstride == AutoStride)
        xstride = (stride_t) pixel_bytes;
    m_spec.auto_stride (xstride, format, spec().nchannels);
    data = to_native_scanline (format, data, xstride, m_scratch);

    // Compute where OpenEXR needs to think the full buffers starts.
    // OpenImageIO requires that 'data' points to where the client wants
    // to put the pixels being read, but OpenEXR's frameBuffer.insert()
    // wants where the address of the "virtual framebuffer" for the
    // whole image.
    imagesize_t scanlinebytes = m_spec.scanline_bytes (native);
    char *buf = (char *)data
              - m_spec.x * pixel_bytes
              - y * scanlinebytes;

    try {
        Imf::FrameBuffer frameBuffer;
        size_t chanoffset = 0;
        for (int c = 0;  c < m_spec.nchannels;  ++c) {
            size_t chanbytes = m_spec.channelformats.size() 
                                  ? m_spec.channelformats[c].size() 
                                  : m_spec.format.size();
            frameBuffer.insert (m_spec.channelnames[c].c_str(),
                                Imf::Slice (m_pixeltype[c],
                                            buf + chanoffset,
                                            pixel_bytes, scanlinebytes));
            chanoffset += chanbytes;
        }
        m_output_scanline->setFrameBuffer (frameBuffer);
        m_output_scanline->writePixels (1);
    }
    catch (const std::exception &e) {
        error ("Failed OpenEXR write: %s", e.what());
        return false;
    }

    // FIXME -- can we checkpoint the file?

    return true;
}
Beispiel #15
0
bool
OpenEXRInput::read_native_scanlines (int ybegin, int yend, int z,
                                     int firstchan, int nchans, void *data)
{
//    std::cerr << "openexr rns " << ybegin << ' ' << yend << ", channels "
//              << firstchan << "-" << (firstchan+nchans-1) << "\n";
    if (m_input_scanline == NULL)
        return false;

    // Compute where OpenEXR needs to think the full buffers starts.
    // OpenImageIO requires that 'data' points to where the client wants
    // to put the pixels being read, but OpenEXR's frameBuffer.insert()
    // wants where the address of the "virtual framebuffer" for the
    // whole image.
    size_t pixelbytes = m_spec.pixel_bytes (firstchan, nchans, true);
    size_t scanlinebytes = (size_t)m_spec.width * pixelbytes;
    char *buf = (char *)data
              - m_spec.x * pixelbytes
              - ybegin * scanlinebytes;

    try {
        Imf::FrameBuffer frameBuffer;
        size_t chanoffset = 0;
        for (int c = 0;  c < nchans;  ++c) {
            size_t chanbytes = m_spec.channelformats.size() 
                                  ? m_spec.channelformats[c+firstchan].size() 
                                  : m_spec.format.size();
            frameBuffer.insert (m_spec.channelnames[c+firstchan].c_str(),
                                Imf::Slice (m_pixeltype[c+firstchan],
                                            buf + chanoffset,
                                            pixelbytes, scanlinebytes));
            chanoffset += chanbytes;
        }
        m_input_scanline->setFrameBuffer (frameBuffer);
        m_input_scanline->readPixels (ybegin, yend-1);
    }
    catch (const std::exception &e) {
        error ("Failed OpenEXR read: %s", e.what());
        return false;
    }
    return true;
}
Beispiel #16
0
bool
OpenEXRInput::read_native_tile (int x, int y, int z, void *data)
{
    ASSERT (m_input_tiled != NULL);

    // Compute where OpenEXR needs to think the full buffers starts.
    // OpenImageIO requires that 'data' points to where the client wants
    // to put the pixels being read, but OpenEXR's frameBuffer.insert()
    // wants where the address of the "virtual framebuffer" for the
    // whole image.
    size_t pixelbytes = m_spec.pixel_bytes (true);
    char *buf = (char *)data
              - x * pixelbytes
              - y * pixelbytes * m_spec.tile_width;

    try {
        Imf::FrameBuffer frameBuffer;
        size_t chanoffset = 0;
        for (int c = 0;  c < m_spec.nchannels;  ++c) {
            size_t chanbytes = m_spec.channelformats.size() 
                                  ? m_spec.channelformats[c].size() 
                                  : m_spec.format.size();
            frameBuffer.insert (m_spec.channelnames[c].c_str(),
                                Imf::Slice (m_pixeltype[c],
                                            buf + chanoffset, pixelbytes,
                                            pixelbytes*m_spec.tile_width));
            chanoffset += chanbytes;
        }
        m_input_tiled->setFrameBuffer (frameBuffer);
        m_input_tiled->readTile ((x - m_spec.x) / m_spec.tile_width,
                                 (y - m_spec.y) / m_spec.tile_height,
                                 m_miplevel, m_miplevel);
    }
    catch (const std::exception &e) {
        error ("Filed OpenEXR read: %s", e.what());
        return false;
    }

    return true;
}
Beispiel #17
0
void OpenEXRImpl :: load_channels(Imf::InputFile &file, Matrix& mat, int numChannels, const char *channelNames) {
	Imath::Box2i dw = file.header().dataWindow();
	int width = dw.max.x - dw.min.x + 1;
	int height = dw.max.y - dw.min.y + 1;

	mat.create(numChannels, Matrix::FLOAT32, width, height);

	Imf::FrameBuffer frameBuffer;
	for(int i=0; i < numChannels; i++) {
		char c[2];
		c[0] = channelNames[i];
		c[1] = '\0';
		frameBuffer.insert(c,
				Imf::Slice(Imf::FLOAT,
					(char *)(mat.data.fl + i),
					sizeof(float)*numChannels,
					sizeof(float)*numChannels*width));
	}

	file.setFrameBuffer(frameBuffer);
	file.readPixels(dw.min.y, dw.max.y);
}
Beispiel #18
0
bool saveExr(const Path &path, const float *img, int w, int h, int channels)
{
    if (channels <= 0 || channels > 4)
        return false;

    OutputStreamHandle outputStream = FileUtils::openOutputStream(path);
    if (!outputStream)
        return false;

    try {

    Imf::Header header(w, h, 1.0f, Imath::V2f(0, 0), 1.0f, Imf::INCREASING_Y, Imf::PIZ_COMPRESSION);
    Imf::FrameBuffer frameBuffer;

    std::unique_ptr<half[]> data(new half[w*h*channels]);
    for (int i = 0; i < w*h*channels; ++i)
        data[i] = half(img[i]);

    const char *channelNames[] = {"R", "G", "B", "A"};
    for (int i = 0; i < channels; ++i) {
        const char *channelName = (channels == 1) ? "Y" : channelNames[i];
        header.channels().insert(channelName, Imf::Channel(Imf::HALF));
        frameBuffer.insert(channelName, Imf::Slice(Imf::HALF, reinterpret_cast<char *>(data.get() + i),
                sizeof(half)*channels, sizeof(half)*channels*w));
    }

    ExrOStream out(std::move(outputStream));
    Imf::OutputFile file(out, header);
    file.setFrameBuffer(frameBuffer);
    file.writePixels(h);

    return true;

    } catch(const std::exception &e) {
        std::cout << "OpenEXR writer failed: " << e.what() << std::endl;
        return false;
    }
}
Beispiel #19
0
ImageError OpenEXRImpl :: save(const char *filename, AlloArray &mat) {
	ImageError err = IMAGE_ERROR_NONE;
	
	mImage.fromMatrix(&mat);

	Imf::Header header(mImage.header.dim[0], mImage.header.dim[1]);
	Imf::PixelType pt = pixelTypeForMatrixType(mImage.header.type);

	int planes = mImage.header.planes;
	int rowsize;
	mImage.getRowSize(rowsize);

	char channelNames[] = {0, 0, 0, 0};

	switch(planes) {
		case 1:
			channelNames[0] = 'Y';
			break;

		case 2:
			channelNames[0] = 'Y';
			channelNames[1] = 'A';
			break;

		case 3:
			channelNames[0] = 'R';
			channelNames[1] = 'G';
			channelNames[2] = 'B';
			break;

		case 4:
			channelNames[0] = 'R';
			channelNames[1] = 'G';
			channelNames[2] = 'B';
			channelNames[3] = 'A';
			break;
	}

	for(int i=0; i < planes; i++) {
		char c[] = {channelNames[i], '\0'};
		header.channels().insert(c, Imf::Channel(pt));
	}


	Imf::OutputFile file(filename, header);
	Imf::FrameBuffer frameBuffer;

	for(int i=0; i < planes; i++) {
		char c[] = {channelNames[i], '\0'};
		frameBuffer.insert (c,
						Imf::Slice(pt,
							   (char *)(mImage.data.fl + i),
							   sizeof(float)*planes,
							   rowsize));
	}

	file.setFrameBuffer(frameBuffer);
	file.writePixels(mImage.header.dim[1]);
	
	return err;
}
Beispiel #20
0
int FileEXR::write_frame(VFrame *frame, VFrame *data, FrameWriterUnit *unit)
{
	EXRUnit *exr_unit = (EXRUnit*)unit;
	int result = 0;

	VFrame *output_frame;
	data->set_compressed_size(0);


	int native_cmodel = asset->exr_use_alpha ? BC_RGBA_FLOAT : BC_RGB_FLOAT;
	int components = BC_CModels::components(native_cmodel);

	if(frame->get_color_model() != native_cmodel)
	{
		if(!exr_unit->temp_frame) exr_unit->temp_frame = new VFrame(0,
			asset->width,
			asset->height,
			native_cmodel);
		exr_unit->temp_frame->transfer_from(frame);
		output_frame = exr_unit->temp_frame;
	}
	else
		output_frame = frame;

	Imf::Header header(output_frame->get_w(), output_frame->get_h());
	header.compression() = (Imf::Compression)compression_to_exr(
		asset->exr_compression);
	header.channels().insert("R", Imf::Channel(Imf::FLOAT));
	header.channels().insert("G", Imf::Channel(Imf::FLOAT));
	header.channels().insert("B", Imf::Channel(Imf::FLOAT));
	if(asset->exr_use_alpha) header.channels().insert("A", Imf::Channel(Imf::FLOAT));

	EXROStream exr_stream(data);
	Imf::OutputFile file(exr_stream, header);
	Imf::FrameBuffer framebuffer;
	float **rows = (float**)output_frame->get_rows();
	framebuffer.insert("R",
		Imf::Slice(Imf::FLOAT,
			(char*)(rows[0]),
			sizeof(float) * components,
			sizeof(float) * components * output_frame->get_w()));
	framebuffer.insert("G",
		Imf::Slice(Imf::FLOAT,
			(char*)(rows[0] + 1),
			sizeof(float) * components,
			sizeof(float) * components * output_frame->get_w()));
	framebuffer.insert("B",
		Imf::Slice(Imf::FLOAT,
			(char*)(rows[0] + 2),
			sizeof(float) * components,
			sizeof(float) * components * output_frame->get_w()));
	if(asset->exr_use_alpha)
		framebuffer.insert("A",
			Imf::Slice(Imf::FLOAT,
				(char*)(rows[0] + 3),
				sizeof(float) * components,
				sizeof(float) * components * output_frame->get_w()));
	file.setFrameBuffer(framebuffer);
	file.writePixels(asset->height);
	return 0;
}
Beispiel #21
0
int FileEXR::read_frame(VFrame *frame, VFrame *data)
{
	EXRIStream exr_stream((char*)data->get_data(), data->get_compressed_size());
	Imf::InputFile file(exr_stream);
	Imath::Box2i dw = file.header().dataWindow();
    int dx = dw.min.x;
    int dy = dw.min.y;
	Imf::FrameBuffer framebuffer;
	float **rows = (float**)frame->get_rows();
	int components = BC_CModels::components(frame->get_color_model());

	if(is_yuv)
	{
		if(!temp_y) temp_y = new float[asset->width * asset->height];
		if(!temp_u) temp_u = new float[asset->width * asset->height / 4];
		if(!temp_v) temp_v = new float[asset->width * asset->height / 4];
		framebuffer.insert("Y", Imf::Slice(Imf::FLOAT, 
			(char*)(temp_y - dy * asset->width - dx),
			sizeof(float),
			sizeof(float) * frame->get_w()));
		framebuffer.insert("BY", Imf::Slice(Imf::FLOAT, 
			(char*)(temp_u - dy * asset->width / 4 - dx / 2),
			sizeof(float),
			sizeof(float) * frame->get_w() / 2,
			2, 
			2));
		framebuffer.insert("RY", Imf::Slice(Imf::FLOAT, 
			(char*)(temp_v - dy * asset->width / 4 - dx / 2),
			sizeof(float),
			sizeof(float) * frame->get_w() / 2,
			2, 
			2));
	}
	else
	{
		framebuffer.insert("R", Imf::Slice(Imf::FLOAT, 
			(char*)(&rows[-dy][-dx * components]),
			sizeof(float) * components,
			sizeof(float) * components * frame->get_w()));
		framebuffer.insert("G", Imf::Slice(Imf::FLOAT, 
			(char*)(&rows[-dy][-dx * components + 1]),
			sizeof(float) * components,
			sizeof(float) * components * frame->get_w()));
		framebuffer.insert("B", Imf::Slice(Imf::FLOAT, 
			(char*)(&rows[-dy][-dx * components + 2]),
			sizeof(float) * components,
			sizeof(float) * components * frame->get_w()));
	}

// Alpha always goes directly to the output frame
	if(components == 4)
	{
		framebuffer.insert("A", Imf::Slice(Imf::FLOAT, 
			(char*)(&rows[-dy][-dx * components + 3]),
			sizeof(float) * components,
			sizeof(float) * components * frame->get_w()));
	}

	file.setFrameBuffer(framebuffer);
	file.readPixels (dw.min.y, dw.max.y);



	if(is_yuv)
	{
// Convert to RGB using crazy ILM equations
		Imath::V3f yw;
		Imf::Chromaticities cr;
		yw = Imf::RgbaYca::computeYw(cr);

		for(int i = 0; i < asset->height - 1; i += 2)
		{
			float *y_row1 = temp_y + i * asset->width;
			float *y_row2 = temp_y + (i + 1) * asset->width;
			float *u_row = temp_u + (i * asset->width / 4);
			float *v_row = temp_v + (i * asset->width / 4);
			float *out_row1 = rows[i];
			float *out_row2 = rows[i + 1];
			for(int j = 0; j < asset->width - 1; j += 2)
			{
				float v = *u_row++;
				float u = *v_row++;
				float y;

				float r, g, b;
				y = *y_row1++;
				r = (u + 1) * y;
				b = (v + 1) * y;
				g = (y - r * yw.x - b * yw.z) / yw.y;
				*out_row1++ = r;
				*out_row1++ = g;
				*out_row1++ = b;
				if(components == 4) out_row1++;

				y = *y_row1++;
				r = (u + 1) * y;
				b = (v + 1) * y;
				g = (y - r * yw.x - b * yw.z) / yw.y;
				*out_row1++ = r;
				*out_row1++ = g;
				*out_row1++ = b;
				if(components == 4) out_row1++;

				y = *y_row2++;
				r = (u + 1) * y;
				b = (v + 1) * y;
				g = (y - r * yw.x - b * yw.z) / yw.y;
				*out_row2++ = r;
				*out_row2++ = g;
				*out_row2++ = b;
				if(components == 4) out_row1++;

				y = *y_row2++;
				r = (u + 1) * y;
				b = (v + 1) * y;
				g = (y - r * yw.x - b * yw.z) / yw.y;
				*out_row2++ = r;
				*out_row2++ = g;
				*out_row2++ = b;
				if(components == 4) out_row1++;
			}
		}
	}
	return 0;
}
Beispiel #22
0
bool
OpenEXROutput::write_tiles (int xbegin, int xend, int ybegin, int yend,
                            int zbegin, int zend, TypeDesc format,
                            const void *data, stride_t xstride,
                            stride_t ystride, stride_t zstride)
{
//    std::cerr << "exr::write_tiles " << xbegin << ' ' << xend 
//              << ' ' << ybegin << ' ' << yend << "\n";
    if (! m_output_tiled ||
        ! m_spec.valid_tile_range (xbegin, xend, ybegin, yend, zbegin, zend))
        return false;

    // Compute where OpenEXR needs to think the full buffers starts.
    // OpenImageIO requires that 'data' points to where the client wants
    // to put the pixels being read, but OpenEXR's frameBuffer.insert()
    // wants where the address of the "virtual framebuffer" for the
    // whole image.
    bool native = (format == TypeDesc::UNKNOWN);
    size_t user_pixelbytes = m_spec.pixel_bytes (native);
    size_t pixelbytes = m_spec.pixel_bytes (true);
    if (native && xstride == AutoStride)
        xstride = (stride_t) user_pixelbytes;
    m_spec.auto_stride (xstride, ystride, zstride, format, spec().nchannels,
                        (xend-xbegin), (yend-ybegin));
    data = to_native_rectangle (xbegin, xend, ybegin, yend, zbegin, zend,
                                format, data, xstride, ystride, zstride,
                                m_scratch);

    // clamp to the image edge
    xend = std::min (xend, m_spec.x+m_spec.width);
    yend = std::min (yend, m_spec.y+m_spec.height);
    zend = std::min (zend, m_spec.z+m_spec.depth);
    int firstxtile = (xbegin-m_spec.x) / m_spec.tile_width;
    int firstytile = (ybegin-m_spec.y) / m_spec.tile_height;
    int nxtiles = (xend - xbegin + m_spec.tile_width - 1) / m_spec.tile_width;
    int nytiles = (yend - ybegin + m_spec.tile_height - 1) / m_spec.tile_height;

    std::vector<char> padded;
    int width = nxtiles*m_spec.tile_width;
    int height = nytiles*m_spec.tile_height;
    stride_t widthbytes = width * pixelbytes;
    if (width != (xend-xbegin) || height != (yend-ybegin)) {
        // If the image region is not an even multiple of the tile size,
        // we need to copy and add padding.
        padded.resize (pixelbytes * width * height, 0);
        OIIO::copy_image (m_spec.nchannels, xend-xbegin,
                                    yend-ybegin, 1, data, pixelbytes,
                                    pixelbytes, (xend-xbegin)*pixelbytes,
                                    (xend-xbegin)*(yend-ybegin)*pixelbytes,
                                    &padded[0], pixelbytes, widthbytes,
                                    height*widthbytes);
        data = &padded[0];
    }

    char *buf = (char *)data
              - xbegin * pixelbytes
              - ybegin * widthbytes;

    try {
        Imf::FrameBuffer frameBuffer;
        size_t chanoffset = 0;
        for (int c = 0;  c < m_spec.nchannels;  ++c) {
            size_t chanbytes = m_spec.channelformats.size() 
                                  ? m_spec.channelformats[c].size() 
                                  : m_spec.format.size();
            frameBuffer.insert (m_spec.channelnames[c].c_str(),
                                Imf::Slice (m_pixeltype[c],
                                            buf + chanoffset, pixelbytes,
                                            widthbytes));
            chanoffset += chanbytes;
        }
        m_output_tiled->setFrameBuffer (frameBuffer);
        m_output_tiled->writeTiles (firstxtile, firstxtile+nxtiles-1,
                                    firstytile, firstytile+nytiles-1,
                                    m_miplevel, m_miplevel);
    }
    catch (const std::exception &e) {
        error ("Failed OpenEXR write: %s", e.what());
        return false;
    }

    return true;
}
Beispiel #23
0
static BOOL DLL_CALLCONV
Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
    const char *channel_name[4] = { "R", "G", "B", "A" };
    BOOL bIsFlipped = FALSE;
    half *halfData = NULL;

    if(!dib || !handle) return FALSE;

    try {
        // check for EXR_LC compression and verify that the format is RGB
        if((flags & EXR_LC) == EXR_LC) {
            FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
            if(((image_type != FIT_RGBF) && (image_type != FIT_RGBAF)) || ((flags & EXR_FLOAT) == EXR_FLOAT)) {
                THROW (Iex::IoExc, "EXR_LC compression is only available with RGB[A]F images");
            }
            if((FreeImage_GetWidth(dib) % 2) || (FreeImage_GetHeight(dib) % 2)) {
                THROW (Iex::IoExc, "EXR_LC compression only works when the width and height are a multiple of 2");
            }
        }

        // wrap the FreeImage IO stream
        C_OStream ostream(io, handle);

        // compression
        Imf::Compression compress;
        if((flags & EXR_NONE) == EXR_NONE) {
            // no compression
            compress = Imf::NO_COMPRESSION;
        } else if((flags & EXR_ZIP) == EXR_ZIP) {
            // zlib compression, in blocks of 16 scan lines
            compress = Imf::ZIP_COMPRESSION;
        } else if((flags & EXR_PIZ) == EXR_PIZ) {
            // piz-based wavelet compression
            compress = Imf::PIZ_COMPRESSION;
        } else if((flags & EXR_PXR24) == EXR_PXR24) {
            // lossy 24-bit float compression
            compress = Imf::PXR24_COMPRESSION;
        } else if((flags & EXR_B44) == EXR_B44) {
            // lossy 44% float compression
            compress = Imf::B44_COMPRESSION;
        } else {
            // default value
            compress = Imf::PIZ_COMPRESSION;
        }

        // create the header
        int width  = FreeImage_GetWidth(dib);
        int height = FreeImage_GetHeight(dib);
        int dx = 0, dy = 0;

        Imath::Box2i dataWindow (Imath::V2i (0, 0), Imath::V2i (width - 1, height - 1));
        Imath::Box2i displayWindow (Imath::V2i (-dx, -dy), Imath::V2i (width - dx - 1, height - dy - 1));

        Imf::Header header = Imf::Header(displayWindow, dataWindow, 1,
                                         Imath::V2f(0,0), 1,
                                         Imf::INCREASING_Y, compress);

        // handle thumbnail
        SetPreviewImage(dib, header);

        // check for EXR_LC compression
        if((flags & EXR_LC) == EXR_LC) {
            return SaveAsEXR_LC(ostream, dib, header, width, height);
        }

        // output pixel type
        Imf::PixelType pixelType;
        if((flags & EXR_FLOAT) == EXR_FLOAT) {
            pixelType = Imf::FLOAT;	// save as float data type
        } else {
            // default value
            pixelType = Imf::HALF;	// save as half data type
        }

        // check the data type and number of channels
        int components = 0;
        FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
        switch(image_type) {
        case FIT_FLOAT:
            components = 1;
            // insert luminance channel
            header.channels().insert ("Y", Imf::Channel(pixelType));
            break;
        case FIT_RGBF:
            components = 3;
            for(int c = 0; c < components; c++) {
                // insert R, G and B channels
                header.channels().insert (channel_name[c], Imf::Channel(pixelType));
            }
            break;
        case FIT_RGBAF:
            components = 4;
            for(int c = 0; c < components; c++) {
                // insert R, G, B and A channels
                header.channels().insert (channel_name[c], Imf::Channel(pixelType));
            }
            break;
        default:
            THROW (Iex::ArgExc, "Cannot save: invalid data type.\nConvert the image to float before saving as OpenEXR.");
        }

        // build a frame buffer (i.e. what we have on input)
        Imf::FrameBuffer frameBuffer;

        BYTE *bits = NULL;	// pointer to our pixel buffer
        size_t bytespp = 0;	// size of our pixel in bytes
        size_t bytespc = 0;	// size of our pixel component in bytes
        unsigned pitch = 0;	// size of our yStride in bytes


        if(pixelType == Imf::HALF) {
            // convert from float to half
            halfData = new(std::nothrow) half[width * height * components];
            if(!halfData) THROW (Iex::NullExc, FI_MSG_ERROR_MEMORY);

            for(int y = 0; y < height; y++) {
                float *src_bits = (float*)FreeImage_GetScanLine(dib, height - 1 - y);
                half *dst_bits = halfData + y * width * components;
                for(int x = 0; x < width; x++) {
                    for(int c = 0; c < components; c++) {
                        dst_bits[c] = src_bits[c];
                    }
                    src_bits += components;
                    dst_bits += components;
                }
            }
            bits = (BYTE*)halfData;
            bytespc = sizeof(half);
            bytespp = sizeof(half) * components;
            pitch = sizeof(half) * width * components;
        } else if(pixelType == Imf::FLOAT) {
            // invert dib scanlines
            bIsFlipped = FreeImage_FlipVertical(dib);

            bits = FreeImage_GetBits(dib);
            bytespc = sizeof(float);
            bytespp = sizeof(float) * components;
            pitch = FreeImage_GetPitch(dib);
        }

        if(image_type == FIT_FLOAT) {
            frameBuffer.insert ("Y",	// name
                                Imf::Slice (pixelType,	// type
                                            (char*)(bits),			// base
                                            bytespp,				// xStride
                                            pitch));				// yStride
        } else if((image_type == FIT_RGBF) || (image_type == FIT_RGBAF)) {
            for(int c = 0; c < components; c++) {
                char *channel_base = (char*)(bits) + c*bytespc;
                frameBuffer.insert (channel_name[c],// name
                                    Imf::Slice (pixelType,			// type
                                                channel_base,					// base
                                                bytespp,	// xStride
                                                pitch));	// yStride
            }
        }

        // write the data
        Imf::OutputFile file (ostream, header);
        file.setFrameBuffer (frameBuffer);
        file.writePixels (height);

        if(halfData != NULL) delete[] halfData;
        if(bIsFlipped) {
            // invert dib scanlines
            FreeImage_FlipVertical(dib);
        }

        return TRUE;

    } catch(Iex::BaseExc & e) {
        if(halfData != NULL) delete[] halfData;
        if(bIsFlipped) {
            // invert dib scanlines
            FreeImage_FlipVertical(dib);
        }

        FreeImage_OutputMessageProc(s_format_id, e.what());

        return FALSE;
    }
}
Beispiel #24
0
static FIBITMAP * DLL_CALLCONV
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
    bool bUseRgbaInterface = false;
    FIBITMAP *dib = NULL;

    if(!handle) {
        return NULL;
    }

    try {
        BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;

        // save the stream starting point
        const long stream_start = io->tell_proc(handle);

        // wrap the FreeImage IO stream
        C_IStream istream(io, handle);

        // open the file
        Imf::InputFile file(istream);

        // get file info
        const Imath::Box2i &dataWindow = file.header().dataWindow();
        int width  = dataWindow.max.x - dataWindow.min.x + 1;
        int height = dataWindow.max.y - dataWindow.min.y + 1;

        //const Imf::Compression &compression = file.header().compression();

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

        // check the number of components and check for a coherent format

        std::string exr_color_model;
        Imf::PixelType pixel_type = Imf::HALF;
        FREE_IMAGE_TYPE image_type = FIT_UNKNOWN;
        int components = 0;
        bool bMixedComponents = false;

        for (Imf::ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) {
            components++;
            if(components == 1) {
                exr_color_model += i.name();
                pixel_type = i.channel().type;
            } else {
                exr_color_model += "/";
                exr_color_model += i.name();
                if (i.channel().type != pixel_type) {
                    bMixedComponents = true;
                }
            }
        }

        if(bMixedComponents) {
            bool bHandled = false;
            // we may have a RGBZ or RGBAZ image ...
            if(components > 4) {
                if(channels.findChannel("R") && channels.findChannel("G") && channels.findChannel("B") && channels.findChannel("A")) {
                    std::string msg = "Warning: converting color model " + exr_color_model + " to RGBA color model";
                    FreeImage_OutputMessageProc(s_format_id, msg.c_str());
                    bHandled = true;
                }
            }
            else if(components > 3) {
                if(channels.findChannel("R") && channels.findChannel("G") && channels.findChannel("B")) {
                    std::string msg = "Warning: converting color model " + exr_color_model + " to RGB color model";
                    FreeImage_OutputMessageProc(s_format_id, msg.c_str());
                    bHandled = true;
                }
            }
            if(!bHandled) {
                THROW (Iex::InputExc, "Unable to handle mixed component types (color model = " << exr_color_model << ")");
            }
        }

        switch(pixel_type) {
        case Imf::UINT:
            THROW (Iex::InputExc, "Unsupported format: UINT");
            break;
        case Imf::HALF:
        case Imf::FLOAT:
        default:
            break;
        }

        // check for supported image color models
        // --------------------------------------------------------------

        if((components == 1) || (components == 2)) {
            // if the image is gray-alpha (YA), ignore the alpha channel
            if((components == 1) && channels.findChannel("Y")) {
                image_type = FIT_FLOAT;
                components = 1;
            } else {
                std::string msg = "Warning: loading color model " + exr_color_model + " as Y color model";
                FreeImage_OutputMessageProc(s_format_id, msg.c_str());
                image_type = FIT_FLOAT;
                // ignore the other channel
                components = 1;
            }
        } else if(components == 3) {
            if(channels.findChannel("R") && channels.findChannel("G") && channels.findChannel("B")) {
                image_type = FIT_RGBF;
            }
            else if(channels.findChannel("BY") && channels.findChannel("RY") && channels.findChannel("Y")) {
                image_type = FIT_RGBF;
                bUseRgbaInterface = true;
            }
        } else if(components >= 4) {
            if(channels.findChannel("R") && channels.findChannel("G") && channels.findChannel("B")) {
                if(channels.findChannel("A")) {
                    if(components > 4) {
                        std::string msg = "Warning: converting color model " + exr_color_model + " to RGBA color model";
                        FreeImage_OutputMessageProc(s_format_id, msg.c_str());
                    }
                    image_type = FIT_RGBAF;
                    // ignore other layers if there is more than one alpha layer
                    components = 4;
                } else {
                    std::string msg = "Warning: converting color model " + exr_color_model + " to RGB color model";
                    FreeImage_OutputMessageProc(s_format_id, msg.c_str());

                    image_type = FIT_RGBF;
                    // ignore other channels
                    components = 3;
                }
            }
        }

        if(image_type == FIT_UNKNOWN) {
            THROW (Iex::InputExc, "Unsupported color model: " << exr_color_model);
        }

        // allocate a new dib
        dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, 0);
        if(!dib) THROW (Iex::NullExc, FI_MSG_ERROR_MEMORY);

        // try to load the preview image
        // --------------------------------------------------------------

        if(file.header().hasPreviewImage()) {
            const Imf::PreviewImage& preview = file.header().previewImage();
            const unsigned thWidth = preview.width();
            const unsigned thHeight = preview.height();

            FIBITMAP* thumbnail = FreeImage_Allocate(thWidth, thHeight, 32);
            if(thumbnail) {
                const Imf::PreviewRgba *src_line = preview.pixels();
                BYTE *dst_line = FreeImage_GetScanLine(thumbnail, thHeight - 1);
                const unsigned dstPitch = FreeImage_GetPitch(thumbnail);

                for (unsigned y = 0; y < thHeight; ++y) {
                    const Imf::PreviewRgba *src_pixel = src_line;
                    RGBQUAD* dst_pixel = (RGBQUAD*)dst_line;

                    for(unsigned x = 0; x < thWidth; ++x) {
                        dst_pixel->rgbRed = src_pixel->r;
                        dst_pixel->rgbGreen = src_pixel->g;
                        dst_pixel->rgbBlue = src_pixel->b;
                        dst_pixel->rgbReserved = src_pixel->a;
                        src_pixel++;
                        dst_pixel++;
                    }
                    src_line += thWidth;
                    dst_line -= dstPitch;
                }
                FreeImage_SetThumbnail(dib, thumbnail);
                FreeImage_Unload(thumbnail);
            }
        }

        if(header_only) {
            // header only mode
            return dib;
        }

        // load pixels
        // --------------------------------------------------------------

        const BYTE *bits = FreeImage_GetBits(dib);			// pointer to our pixel buffer
        const size_t bytespp = sizeof(float) * components;	// size of our pixel in bytes
        const unsigned pitch = FreeImage_GetPitch(dib);		// size of our yStride in bytes

        Imf::PixelType pixelType = Imf::FLOAT;	// load as float data type;

        if(bUseRgbaInterface) {
            // use the RGBA interface (used when loading RY BY Y images )

            const int chunk_size = 16;

            BYTE *scanline = (BYTE*)bits;

            // re-open using the RGBA interface
            io->seek_proc(handle, stream_start, SEEK_SET);
            Imf::RgbaInputFile rgbaFile(istream);

            // read the file in chunks
            Imath::Box2i dw = dataWindow;
            Imf::Array2D<Imf::Rgba> chunk(chunk_size, width);
            while (dw.min.y <= dw.max.y) {
                // read a chunk
                rgbaFile.setFrameBuffer (&chunk[0][0] - dw.min.x - dw.min.y * width, 1, width);
                rgbaFile.readPixels (dw.min.y, MIN(dw.min.y + chunk_size - 1, dw.max.y));
                // fill the dib
                const int y_max = ((dw.max.y - dw.min.y) <= chunk_size) ? (dw.max.y - dw.min.y) : chunk_size;
                for(int y = 0; y < y_max; y++) {
                    FIRGBF *pixel = (FIRGBF*)scanline;
                    const Imf::Rgba *half_rgba = chunk[y];
                    for(int x = 0; x < width; x++) {
                        // convert from half to float
                        pixel[x].red = half_rgba[x].r;
                        pixel[x].green = half_rgba[x].g;
                        pixel[x].blue = half_rgba[x].b;
                    }
                    // next line
                    scanline += pitch;
                }
                // next chunk
                dw.min.y += chunk_size;
            }

        } else {
            // use the low level interface

            // build a frame buffer (i.e. what we want on output)
            Imf::FrameBuffer frameBuffer;

            // allow dataWindow with minimal bounds different form zero
            size_t offset = - dataWindow.min.x * bytespp - dataWindow.min.y * pitch;

            if(components == 1) {
                frameBuffer.insert ("Y",	// name
                                    Imf::Slice (pixelType,	// type
                                                (char*)(bits + offset), // base
                                                bytespp,				// xStride
                                                pitch,					// yStride
                                                1, 1,					// x/y sampling
                                                0.0));					// fillValue
            } else if((components == 3) || (components == 4)) {
                const char *channel_name[4] = { "R", "G", "B", "A" };

                for(int c = 0; c < components; c++) {
                    frameBuffer.insert (
                        channel_name[c],					// name
                        Imf::Slice (pixelType,				// type
                                    (char*)(bits + c * sizeof(float) + offset), // base
                                    bytespp,							// xStride
                                    pitch,								// yStride
                                    1, 1,								// x/y sampling
                                    0.0));								// fillValue
                }
            }

            // read the file
            file.setFrameBuffer(frameBuffer);
            file.readPixels(dataWindow.min.y, dataWindow.max.y);
        }

        // lastly, flip dib lines
        FreeImage_FlipVertical(dib);

    }
    catch(Iex::BaseExc & e) {
        if(dib != NULL) {
            FreeImage_Unload(dib);
        }
        FreeImage_OutputMessageProc(s_format_id, e.what());
        return NULL;
    }

    return dib;
}
Beispiel #25
0
bool
OpenEXRInput::read_native_tiles (int xbegin, int xend, int ybegin, int yend,
                                 int zbegin, int zend, 
                                 int chbegin, int chend, void *data)
{
    chend = clamp (chend, chbegin+1, m_spec.nchannels);
#if 0
    std::cerr << "openexr rnt " << xbegin << ' ' << xend << ' ' << ybegin 
              << ' ' << yend << ", chans " << chbegin
              << "-" << (chend-1) << "\n";
#endif
    if (! (m_input_tiled || m_tiled_input_part) ||
        ! m_spec.valid_tile_range (xbegin, xend, ybegin, yend, zbegin, zend)) {
        error ("called OpenEXRInput::read_native_tiles without an open file");
        return false;
    }

    // Compute where OpenEXR needs to think the full buffers starts.
    // OpenImageIO requires that 'data' points to where the client wants
    // to put the pixels being read, but OpenEXR's frameBuffer.insert()
    // wants where the address of the "virtual framebuffer" for the
    // whole image.
    const PartInfo &part (m_parts[m_subimage]);
    size_t pixelbytes = m_spec.pixel_bytes (chbegin, chend, true);
    int firstxtile = (xbegin-m_spec.x) / m_spec.tile_width;
    int firstytile = (ybegin-m_spec.y) / m_spec.tile_height;
    // clamp to the image edge
    xend = std::min (xend, m_spec.x+m_spec.width);
    yend = std::min (yend, m_spec.y+m_spec.height);
    zend = std::min (zend, m_spec.z+m_spec.depth);
    // figure out how many tiles we need
    int nxtiles = (xend - xbegin + m_spec.tile_width - 1) / m_spec.tile_width;
    int nytiles = (yend - ybegin + m_spec.tile_height - 1) / m_spec.tile_height;
    int whole_width = nxtiles * m_spec.tile_width;
    int whole_height = nytiles * m_spec.tile_height;
    
    boost::scoped_array<char> tmpbuf;
    void *origdata = data;
    if (whole_width != (xend-xbegin) || whole_height != (yend-ybegin)) {
        // Deal with the case of reading not a whole number of tiles --
        // OpenEXR will happily overwrite user memory in this case.
        tmpbuf.reset (new char [nxtiles * nytiles * m_spec.tile_bytes(true)]);
        data = &tmpbuf[0];
    }
    char *buf = (char *)data
              - xbegin * pixelbytes
              - ybegin * pixelbytes * m_spec.tile_width * nxtiles;

    try {
        Imf::FrameBuffer frameBuffer;
        size_t chanoffset = 0;
        for (int c = chbegin;  c < chend;  ++c) {
            size_t chanbytes = m_spec.channelformat(c).size();
            frameBuffer.insert (m_spec.channelnames[c].c_str(),
                                Imf::Slice (part.pixeltype[c],
                                            buf + chanoffset, pixelbytes,
                                            pixelbytes*m_spec.tile_width*nxtiles));
            chanoffset += chanbytes;
        }
        if (m_input_tiled) {
            m_input_tiled->setFrameBuffer (frameBuffer);
            m_input_tiled->readTiles (firstxtile, firstxtile+nxtiles-1,
                                      firstytile, firstytile+nytiles-1,
                                      m_miplevel, m_miplevel);
#ifdef USE_OPENEXR_VERSION2
        } else if (m_tiled_input_part) {
            m_tiled_input_part->setFrameBuffer (frameBuffer);
            m_tiled_input_part->readTiles (firstxtile, firstxtile+nxtiles-1,
                                           firstytile, firstytile+nytiles-1,
                                           m_miplevel, m_miplevel);
#endif
        } else {
            ASSERT (0);
        }
        if (data != origdata) {
            stride_t user_scanline_bytes = (xend-xbegin) * pixelbytes;
            stride_t scanline_stride = nxtiles*m_spec.tile_width*pixelbytes;
            for (int y = ybegin;  y < yend;  ++y)
                memcpy ((char *)origdata+(y-ybegin)*scanline_stride,
                        (char *)data+(y-ybegin)*scanline_stride,
                        user_scanline_bytes);
        }
    }
    catch (const std::exception &e) {
        error ("Failed OpenEXR read: %s", e.what());
        return false;
    }

    return true;
}
Beispiel #26
0
static std::unique_ptr<float[]> loadExr(const Path &path, TexelConversion request, int &w, int &h)
{
    InputStreamHandle inputStream = FileUtils::openInputStream(path);
    if (!inputStream)
        return nullptr;

    try {

    ExrIStream in(std::move(inputStream));
    Imf::InputFile file(in);
    Imath::Box2i dataWindow = file.header().dataWindow();
    w = dataWindow.max.x - dataWindow.min.x + 1;
    h = dataWindow.max.y - dataWindow.min.y + 1;
    int dx = dataWindow.min.x;
    int dy = dataWindow.min.y;

    const Imf::ChannelList &channels = file.header().channels();
    const Imf::Channel *rChannel = channels.findChannel("R");
    const Imf::Channel *gChannel = channels.findChannel("G");
    const Imf::Channel *bChannel = channels.findChannel("B");
    const Imf::Channel *aChannel = channels.findChannel("A");
    const Imf::Channel *yChannel = channels.findChannel("Y");

    Imf::FrameBuffer frameBuffer;

    bool isScalar = request != TexelConversion::REQUEST_RGB;
    bool acceptsAlpha =
            request == TexelConversion::REQUEST_ALPHA ||
            request == TexelConversion::REQUEST_AUTO;
    int targetChannels = isScalar ? 1 : 3;
    int sourceChannels = (rChannel ? 1 : 0) + (gChannel ? 1 : 0) + (bChannel ? 1 : 0);

    std::unique_ptr<float[]> texels(new float[w*h*targetChannels]);
    std::unique_ptr<float[]> img;
    size_t texelSize = sizeof(float)*targetChannels;
    char *base = reinterpret_cast<char *>(texels.get() - (dx + dy*w)*targetChannels);

    if (isScalar && (yChannel != nullptr || (acceptsAlpha && aChannel != nullptr))) {
        // The user requested a scalar texture and the file either contains an alpha channel or a luminance channel
        // The alpha channel is only allowed if it was explicitly requested or an auto conversion was requested
        // RGB -> Scalar falls through and is handled later
        const char *channelName = (acceptsAlpha && aChannel != nullptr) ? "A" : "Y";
        frameBuffer.insert(channelName, Imf::Slice(Imf::FLOAT, base, texelSize, texelSize*w));
    } else if (!isScalar && (rChannel || gChannel || bChannel)) {
        // The user wants RGB and we have (some) RGB channels
        if (rChannel) frameBuffer.insert("R", Imf::Slice(Imf::FLOAT, base + 0*sizeof(float), texelSize, texelSize*w));
        if (gChannel) frameBuffer.insert("G", Imf::Slice(Imf::FLOAT, base + 1*sizeof(float), texelSize, texelSize*w));
        if (bChannel) frameBuffer.insert("B", Imf::Slice(Imf::FLOAT, base + 2*sizeof(float), texelSize, texelSize*w));
        // If some channels are missing, replace them with black
        if (!rChannel || !gChannel || !bChannel)
            std::memset(texels.get(), 0, texelSize*w*h);
    } else if (!isScalar && yChannel) {
        // The user wants RGB and we have just luminance -> duplicate luminance across all three channels
        // This is not the best solution, but we don't want to deal with chroma subsampled images
        frameBuffer.insert("Y", Imf::Slice(Imf::FLOAT, base, texelSize, texelSize*w));
    } else if (isScalar) {
        // The user wants a scalar texture and we have (some) RGB channels
        // We can't read directly into the destination, but have to read to a temporary
        // and do a conversion to scalar later
        img.reset(new float[sourceChannels*w*h]);
        char *imgBase = reinterpret_cast<char *>(img.get() - (dx + dy*w)*sourceChannels);

        const Imf::Channel *channels[] = {rChannel, gChannel, bChannel};
        const char *channelNames[] = {"R", "G", "B"};
        int texel = 0;
        for (int i = 0; i < 3; ++i) {
            if (channels[i]) {
                frameBuffer.insert(channelNames[i], Imf::Slice(Imf::FLOAT, imgBase + texel*sizeof(float),
                        sourceChannels*sizeof(float), sourceChannels*sizeof(float)*w));
                texel++;
            }
        }
    } else {
        return false;
    }

    file.setFrameBuffer(frameBuffer);
    file.readPixels(dataWindow.min.y, dataWindow.max.y);

    if (img) {
        // We only get here if we need to make a scalar texture from an RGB input
        int texel = 0;
        int rLocation = -1, gLocation = -1, bLocation = -1;
        if (rChannel) rLocation = texel++;
        if (gChannel) gLocation = texel++;
        if (bChannel) bLocation = texel++;

        for (int i = 0; i < w*h; ++i) {
            float r = rChannel ? img[i*sourceChannels + rLocation] : 0.0f;
            float g = gChannel ? img[i*sourceChannels + gLocation] : 0.0f;
            float b = bChannel ? img[i*sourceChannels + bLocation] : 0.0f;
            texels[i] = convertToScalar(request, r, g, b, 0.0f, false);
        }
    } else if (!isScalar && yChannel) {
        // Here we need to duplicate the Y channel stored in R across G and B
        for (int i = 0; i < w*h; ++i)
            texels[i*3 + 1] = texels[i*3 + 2] = texels[i*3];
    }

    return std::move(texels);

    } catch(const std::exception &e) {
        std::cout << "OpenEXR loader failed: " << e.what() << std::endl;
        return nullptr;
    }
}
Beispiel #27
0
bool
OpenEXROutput::write_scanlines (int ybegin, int yend, int z,
                                TypeDesc format, const void *data,
                                stride_t xstride, stride_t ystride)
{
    yend = std::min (yend, spec().y+spec().height);
    bool native = (format == TypeDesc::UNKNOWN);
    imagesize_t scanlinebytes = spec().scanline_bytes(native);
    size_t pixel_bytes = m_spec.pixel_bytes (native);
    if (native && xstride == AutoStride)
        xstride = (stride_t) pixel_bytes;
    stride_t zstride = AutoStride;
    m_spec.auto_stride (xstride, ystride, zstride, format, m_spec.nchannels,
                        m_spec.width, m_spec.height);

    const imagesize_t limit = 16*1024*1024;   // Allocate 16 MB, or 1 scanline
    int chunk = std::max (1, int(limit / scanlinebytes));

    bool ok = true;
    for ( ;  ok && ybegin < yend;  ybegin += chunk) {
        int y1 = std::min (ybegin+chunk, yend);
        int nscanlines = y1 - ybegin;
        const void *d = to_native_rectangle (m_spec.x, m_spec.x+m_spec.width,
                                             ybegin, y1, z, z+1, format, data,
                                             xstride, ystride, zstride,
                                             m_scratch);

        // Compute where OpenEXR needs to think the full buffers starts.
        // OpenImageIO requires that 'data' points to where the client wants
        // to put the pixels being read, but OpenEXR's frameBuffer.insert()
        // wants where the address of the "virtual framebuffer" for the
        // whole image.
        char *buf = (char *)d
                  - m_spec.x * pixel_bytes
                  - ybegin * scanlinebytes;
        try {
            Imf::FrameBuffer frameBuffer;
            size_t chanoffset = 0;
            for (int c = 0;  c < m_spec.nchannels;  ++c) {
                size_t chanbytes = m_spec.channelformats.size() 
                                      ? m_spec.channelformats[c].size() 
                                      : m_spec.format.size();
                frameBuffer.insert (m_spec.channelnames[c].c_str(),
                                    Imf::Slice (m_pixeltype[c],
                                                buf + chanoffset,
                                                pixel_bytes, scanlinebytes));
                chanoffset += chanbytes;
            }
            m_output_scanline->setFrameBuffer (frameBuffer);
            m_output_scanline->writePixels (nscanlines);
        }
        catch (const std::exception &e) {
            error ("Failed OpenEXR write: %s", e.what());
            return false;
        }

        data = (const char *)data + ystride*nscanlines;
    }

    // If we allocated more than 1M, free the memory.  It's not wasteful,
    // because it means we're writing big chunks at a time, and therefore
    // there will be few allocations and deletions.
    if (m_scratch.size() > 1*1024*1024) {
        std::vector<unsigned char> dummy;
        std::swap (m_scratch, dummy);
    }
    return true;
}
Beispiel #28
0
// All the work is done here
int joinEXRs( int tilesX, int tilesY, const char* baseName, bool deleteTiles, bool Verbose )
{
   int exitCode = 0;

   // Expand names
   if( Verbose ) printf("Image file name = '%s', tilesX=%d, tilesY=%d\n", baseName, tilesX, tilesY);
   int numTiles = tilesX * tilesY;

   // Allocate memory:
   char ** tileNames = new char * [numTiles];
   Imf::InputFile ** iFiles = new Imf::InputFile * [numTiles];
   for( int i = 0; i < numTiles; i++)
   {
      tileNames[i] = new char[FILENAME_MAXLEN];
      iFiles[i] = 0;
   }

   // Insert tile info and check if files exist
   int nonEmptyTile = -1;
   struct stat stFileInfo;

   for( int i = 0; i < numTiles; i++)
   {
      sprintf( tileNames[i], "%s.tile_%d.exr", baseName, i);
      if( Verbose ) printf("Tile name  %d = '%s'\n", i, tileNames[i]);

      if( stat( tileNames[i], &stFileInfo ) == 0 )
      {
         // File exists - so open it and check for validness
         iFiles[i] = new Imf::InputFile( tileNames[i]);
         if( false == iFiles[i]->isComplete())
         {
            fprintf( stderr, "Error: File '%s' is incomplete or is not an OpenEXR file.\n", tileNames[i]); fflush( stderr);
            delete iFiles[i];
            iFiles[i] = 0;
            exitCode = 1;
         }
         else if( nonEmptyTile == -1 )
         {
            nonEmptyTile = i;
         }
      }
      else
      {
         fprintf( stderr, "Error: File '%s' not founded.\n", tileNames[i]); fflush( stderr);
         exitCode = 1;
      }
   }

   if( nonEmptyTile < 0) // All tiles were empty
   {
      fprintf( stderr, "Error: No tile files founded.\n"); fflush( stderr);
   }
   else
   {
   // Gather info from a non-empty tile file
   Imf::Header inHeader = iFiles[nonEmptyTile]->header();
   Imath::Box2i imageBox = inHeader.displayWindow(); // size of the resulting image
   int imageWidth = imageBox.max.x - imageBox.min.x + 1;
   int imageHeight = imageBox.max.y - imageBox.min.y + 1;

   // Iterate through all the channels and reserve mem for the whole display window
   // also add channels to the header of the output file
   Imf::Header outHeader( imageWidth, imageHeight);
   std::map< Imf::Name, ChannelInfo* > chInfos; // this will hold pixel data and stride for each channel in input files
   Imf::ChannelList channels = inHeader.channels();
   Imf::ChannelList::ConstIterator itCh;
   for( itCh = channels.begin(); itCh != channels.end(); itCh++ )
   {
      chInfos[itCh.name()] = new ChannelInfo( typeSize( itCh.channel().type), imageHeight, imageWidth );
      outHeader.channels().insert( itCh.name(), Imf::Channel( itCh.channel().type));
      if( Verbose) printf("Channel: '%s' | stride: %d\n", itCh.name(), typeSize( itCh.channel().type));
   }

   // Collect data from files
   Imath::Box2i tileBox;      // each tile's data window
   Imath::Box2i resultBox;    // resulting data window (should be sum of all tiles' data windows)
   Imf::FrameBuffer fb;
   for( int i = 0; i < numTiles; i++)
   {
      if( iFiles[i] == 0) // no file for this tile
         continue;

      tileBox = iFiles[i]->header().dataWindow();
      resultBox.extendBy( tileBox );

      if( Verbose) printf("Data win: xmin=%d xmax=%d ymin=%d ymax=%d\n", tileBox.min.x, tileBox.max.x, tileBox.min.y, tileBox.max.y);

      channels = iFiles[i]->header().channels();
      for( itCh = channels.begin(); itCh != channels.end(); itCh++ )
         fb.insert( itCh.name(),
                    Imf::Slice( itCh.channel().type,                // pixel type
                    (char*)&chInfos[itCh.name()]->array2d[0][0],    // base
                    chInfos[itCh.name()]->stride,                   // x stride
                    chInfos[itCh.name()]->stride * imageWidth,      // y stride
                    1, 1, 0.0 ) );                                  // x,y sampling, fill value

      iFiles[i]->setFrameBuffer(fb);
      iFiles[i]->readPixels( tileBox.min.y, tileBox.max.y);
   }

   // Write out everything:
   outHeader.dataWindow() = resultBox;
   Imf::OutputFile imageFile( baseName, outHeader );
   imageFile.setFrameBuffer(fb);
   imageFile.writePixels( resultBox.max.y-resultBox.min.y+1 );

   printf("Joined EXR image successfully written.\n");

   // Free files:
   for( int i = 0; i < numTiles; i++)
      if( iFiles[i] != 0 ) delete iFiles[i];
   delete [] iFiles;

   if( deleteTiles )
   {
      for( int i = 0; i < numTiles; i++)
         if( unlink( tileNames[i]) != 0)
         {
            perror("Remove");
            printf("Can't remove file '%s'\n", tileNames[i]);
         }
   }
   }

   // Free names:
   for( int i = 0; i < numTiles; i++)
      delete [] tileNames[i];
   delete [] tileNames;

   return exitCode;
}
Beispiel #29
0
int FileEXR::write_frame(VFrame *frame, VFrame *data, FrameWriterUnit *unit)
{
	EXRUnit *exr_unit = (EXRUnit*)unit;

	VFrame *output_frame;
	data->set_compressed_size(0);


	int native_cmodel = asset->exr_use_alpha ? BC_RGBA_FLOAT : BC_RGB_FLOAT;
	int components = cmodel_components(native_cmodel);

	if(frame->get_color_model() != native_cmodel)
	{
		if(!exr_unit->temp_frame) exr_unit->temp_frame = new VFrame(0,
			-1,
			asset->width,
			asset->height,
			native_cmodel,
			-1);
		BC_CModels::transfer(exr_unit->temp_frame->get_rows(), /* Leave NULL if non existent */
			frame->get_rows(),
			exr_unit->temp_frame->get_y(), /* Leave NULL if non existent */
			exr_unit->temp_frame->get_u(),
			exr_unit->temp_frame->get_v(),
			frame->get_y(), /* Leave NULL if non existent */
			frame->get_u(),
			frame->get_v(),
			0,        /* Dimensions to capture from input frame */
			0,
			asset->width,
			asset->height,
			0,       /* Dimensions to project on output frame */
			0,
			asset->width,
			asset->height,
			frame->get_color_model(),
			native_cmodel,
			0,         /* When transfering BC_RGBA8888 to non-alpha this is the background color in 0xRRGGBB hex */
			asset->width,       /* For planar use the luma rowspan */
			asset->height);
		output_frame = exr_unit->temp_frame;
	}
	else
		output_frame = frame;

	Imf::Header header(output_frame->get_w(), output_frame->get_h());
	header.compression() = (Imf::Compression)compression_to_exr(
		asset->exr_compression);
	header.channels().insert("R", Imf::Channel(Imf::FLOAT));
	header.channels().insert("G", Imf::Channel(Imf::FLOAT));
	header.channels().insert("B", Imf::Channel(Imf::FLOAT));
	if(asset->exr_use_alpha) header.channels().insert("A", Imf::Channel(Imf::FLOAT));

	EXROStream exr_stream(data);
	Imf::OutputFile file(exr_stream, header);
	Imf::FrameBuffer framebuffer;
	float **rows = (float**)output_frame->get_rows();
	framebuffer.insert("R",
		Imf::Slice(Imf::FLOAT,
			(char*)(rows[0]),
			sizeof(float) * components,
			sizeof(float) * components * output_frame->get_w()));
	framebuffer.insert("G",
		Imf::Slice(Imf::FLOAT,
			(char*)(rows[0] + 1),
			sizeof(float) * components,
			sizeof(float) * components * output_frame->get_w()));
	framebuffer.insert("B",
		Imf::Slice(Imf::FLOAT,
			(char*)(rows[0] + 2),
			sizeof(float) * components,
			sizeof(float) * components * output_frame->get_w()));
	if(asset->exr_use_alpha)
		framebuffer.insert("A",
			Imf::Slice(Imf::FLOAT,
				(char*)(rows[0] + 3),
				sizeof(float) * components,
				sizeof(float) * components * output_frame->get_w()));
	file.setFrameBuffer(framebuffer);
	file.writePixels(asset->height);
	return 0;
}
bool ImageWriterEXR::writeStandardImage(const std::string& filePath, const OutputImage& image, unsigned int channels, bool fullFloat)
{
	unsigned int width = image.getWidth();
	unsigned int height = image.getHeight();

	Imf::Header header(width, height);

	Imf::StringAttribute sourceAttribute;
	sourceAttribute.value() = "Created with Imagine 0.98";
	header.insert("comments", sourceAttribute);

	Imf::PixelType pixelType = (fullFloat) ? Imf::FLOAT : Imf::HALF;

	if (channels & ImageWriter::RGB)
	{
		header.channels().insert("R", Imf::Channel(pixelType));
		header.channels().insert("G", Imf::Channel(pixelType));
		header.channels().insert("B", Imf::Channel(pixelType));
	}

	if (channels & ImageWriter::ALPHA)
		header.channels().insert("A", Imf::Channel(pixelType));

	// if we haven't got any depth data, don't bother
	if (!(image.components() & COMPONENT_DEPTH))
		channels = channels & ~ImageWriter::DEPTH;

	if (channels & ImageWriter::DEPTH)
		header.channels().insert("Z", Imf::Channel(pixelType));

	// if we haven't got any normal data, don't bother
	if (!(image.components() & COMPONENT_NORMAL))
		channels = channels & ~ImageWriter::NORMALS;

	if (channels & ImageWriter::NORMALS)
	{
		header.channels().insert("normal.X", Imf::Channel(pixelType));
		header.channels().insert("normal.Y", Imf::Channel(pixelType));
		header.channels().insert("normal.Z", Imf::Channel(pixelType));
	}

	// if we haven't got any wpp data, don't bother
	if (!(image.components() & COMPONENT_WPP))
		channels = channels & ~ImageWriter::WPP;

	if (channels & ImageWriter::WPP)
	{
		header.channels().insert("wpp.X", Imf::Channel(pixelType));
		header.channels().insert("wpp.Y", Imf::Channel(pixelType));
		header.channels().insert("wpp.Z", Imf::Channel(pixelType));
	}

	// if we haven't got shadows, don't write them
	if (!(image.components() & COMPONENT_SHADOWS))
		channels = channels & ~ImageWriter::SHADOWS;

	if (channels & ImageWriter::SHADOWS)
	{
		// cope with Nuke's limitations by putting ".r" on the end so it shows up in channel list...
		header.channels().insert("shadows.r", Imf::Channel(pixelType));
	}

	unsigned int rgbStride = (channels & ImageWriter::ALPHA) ? 4 : 3;

	T* rgba = NULL;
	if (channels & ImageWriter::RGB)
		rgba = new T[width * height * rgbStride];
	T* pDepth = NULL;
	if (channels & ImageWriter::DEPTH)
		pDepth = new T[width * height];
	T* pNormal = NULL;
	if (channels & ImageWriter::NORMALS)
		pNormal = new T[width * height * 3];
	T* pWPP = NULL;
	if (channels & ImageWriter::WPP)
		pWPP = new T[width * height * 3];
	T* pShadows = NULL;
	if (channels & ImageWriter::SHADOWS)
		pShadows = new T[width * height];

	const Colour4f* pRow = NULL;
	const float* pDepthRow = NULL;
	const Colour3f* pNormalRow = NULL;
	const Colour3f* pWPPRow = NULL;
	const float* pShadowsRow = NULL;

	for (unsigned int y = 0; y < height; y++)
	{
		pRow = image.colourRowPtr(y);

		if (channels & ImageWriter::DEPTH)
			pDepthRow = image.depthRowPtr(y);

		if (channels & ImageWriter::NORMALS)
			pNormalRow = image.normalRowPtr(y);

		if (channels & ImageWriter::WPP)
			pWPPRow = image.wppRowPtr(y);

		if (channels & ImageWriter::SHADOWS)
			pShadowsRow = image.shadowsRowPtr(y);

		unsigned int rgbStartPos = width * y * rgbStride;
		unsigned int normalStartPos = width * y * 3;
		unsigned int wppStartPos = width * y * 3;

		for (unsigned int x = 0; x < width; x++)
		{
			unsigned int pixelPos = rgbStartPos + (x * rgbStride);

			if (channels & ImageWriter::RGB)
			{
				float red = ColourSpace::convertSRGBToLinearAccurate(pRow->r);
				float green = ColourSpace::convertSRGBToLinearAccurate(pRow->g);
				float blue = ColourSpace::convertSRGBToLinearAccurate(pRow->b);

				rgba[pixelPos++] = red;
				rgba[pixelPos++] = green;
				rgba[pixelPos++] = blue;
			}
			else
			{
				pixelPos += 3;
			}

			if (channels & ImageWriter::ALPHA)
				rgba[pixelPos++] = pRow->a;

			if (channels & ImageWriter::DEPTH)
			{
				pDepth[(width * y) + x] = *pDepthRow++;
			}

			if (channels & ImageWriter::NORMALS && pNormalRow)
			{
				const Colour3f& normal = *pNormalRow;

				unsigned int normalPixelPos = normalStartPos + (x * 3);

				pNormal[normalPixelPos++] = normal.r;
				pNormal[normalPixelPos++] = normal.g;
				pNormal[normalPixelPos++] = normal.b;

				pNormalRow++;
			}

			if (channels & ImageWriter::WPP && pWPPRow)
			{
				const Colour3f& wpp = *pWPPRow;

				unsigned int wppPixelPos = wppStartPos + (x * 3);

				pWPP[wppPixelPos++] = wpp.r;
				pWPP[wppPixelPos++] = wpp.g;
				pWPP[wppPixelPos++] = wpp.b;

				pWPPRow++;
			}

			if (channels & ImageWriter::SHADOWS)
			{
				pShadows[(width * y) + x] = *pShadowsRow++;
			}

			pRow++;
		}
	}

	Imf::FrameBuffer fb;
	if (channels & ImageWriter::RGB)
	{
		fb.insert("R", Imf::Slice(pixelType, (char *)rgba, rgbStride*sizeof(T), rgbStride*width*sizeof(T)));
		fb.insert("G", Imf::Slice(pixelType, (char *)rgba + sizeof(T), rgbStride*sizeof(T), rgbStride*width*sizeof(T)));
		fb.insert("B", Imf::Slice(pixelType, (char *)rgba + 2 * sizeof(T), rgbStride*sizeof(T), rgbStride*width*sizeof(T)));
	}

	if (channels & ImageWriter::ALPHA)
		fb.insert("A", Imf::Slice(pixelType, (char *)rgba+3*sizeof(T), rgbStride*sizeof(T), rgbStride*width*sizeof(T)));

	if (channels & ImageWriter::DEPTH)
	{
		fb.insert("Z", Imf::Slice(pixelType, (char *)&(*pDepth), sizeof(T), width * sizeof(T)));
	}

	if (channels & ImageWriter::NORMALS)
	{
		fb.insert("normal.X", Imf::Slice(pixelType, (char *)pNormal, 3 * sizeof(T), 3 * width * sizeof(T)));
		fb.insert("normal.Y", Imf::Slice(pixelType, (char *)pNormal + sizeof(T), 3*sizeof(T), 3*width*sizeof(T)));
		fb.insert("normal.Z", Imf::Slice(pixelType, (char *)pNormal + 2 * sizeof(T), 3*sizeof(T), 3*width*sizeof(T)));
	}

	if (channels & ImageWriter::WPP)
	{
		fb.insert("wpp.X", Imf::Slice(pixelType, (char *)pWPP, 3 * sizeof(T), 3 * width * sizeof(T)));
		fb.insert("wpp.Y", Imf::Slice(pixelType, (char *)pWPP + sizeof(T), 3*sizeof(T), 3*width*sizeof(T)));
		fb.insert("wpp.Z", Imf::Slice(pixelType, (char *)pWPP + 2 * sizeof(T), 3*sizeof(T), 3*width*sizeof(T)));
	}

	if (channels & ImageWriter::SHADOWS)
	{
		fb.insert("shadows.r", Imf::Slice(pixelType, (char *)&(*pShadows), sizeof(T), width * sizeof(T)));
	}

	Imf::OutputFile file(filePath.c_str(), header);
	file.setFrameBuffer(fb);
	file.writePixels(height);

	if (rgba)
		delete [] rgba;
	if (pDepth)
		delete [] pDepth;
	if (pNormal)
		delete [] pNormal;
	if (pWPP)
		delete [] pWPP;
	if (pShadows)
		delete [] pShadows;

	return true;
}