openexr-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Openexr-devel] OpenEXR Data Channel Configurations


From: Paul Schneider
Subject: Re: [Openexr-devel] OpenEXR Data Channel Configurations
Date: Fri, 19 Nov 2004 16:22:50 -0800


In case people are still interested, here's a very simple program that reads in all of the channels of an OpenEXR file. Once the channels are in memory, you could do just about anything with them; this program just writes them out to a new file. You can use "diff" or similar to verify that the new file is identical to the old one, and therefore all of the file's contents must have been read (I reuse the header from the input file to preserve attributes and compression type).

Note that the "SliceAndStorage" class is just a very simple class for managing pixel storage, that reuses much of the OpenEXR code. In a real application, you would almost certainly manage your pixel storage in a more sophisticated way.

- Paul


//-----------------------------------------------------------------------------
// deepexample.cpp
//
// A simple example program that demonstrates how to read OpenEXR files
// with arbitrary channels and channel types. This example does not
// demonstrate use of the tiled API.
//
// Written by Paul Schneider - 11/15/2004
//-----------------------------------------------------------------------------
// To build on a unix-like system:
// CC deepexample.cpp -o deepexample -I/usr/local/include/OpenEXR -L/usr/local/lib -lHalf -lIex -lImath -lIlmImf -lz

#include <ImfInputFile.h>
#include <ImfOutputFile.h>
#include <ImfChannelList.h>
#include <iostream>
#include <string>
#include <vector>

using namespace Imf;
using namespace Imath;

using std::cout;
using std::cerr;
using std::endl;


//-----------------------------------------------------------------------------
// SliceAndStorage
//-----------------------------------------------------------------------------
// The simplest example of an image "slice". This class manages storage
// for the pixels in the slice; pixels are stored tightly packed.

class SliceAndStorage
{
public:

SliceAndStorage (PixelType type, int w, int h, int size,

int xSampling, int ySampling);
~SliceAndStorage ();


const Slice& slice () const;


private:


// unimplemented
SliceAndStorage ();
SliceAndStorage (const SliceAndStorage&);
SliceAndStorage& operator= (const SliceAndStorage&);


char* _storage;
Slice _slice;
};


//-----------------------------------------------------------------------------
// SliceAndStorage
//-----------------------------------------------------------------------------
// allocate enough storage for the pixels in this slice, and construct
// an Imf::Slice that points to the storage.

SliceAndStorage::SliceAndStorage (PixelType type, int w, int h, int size,

int xSampling, int ySampling)
:
_storage (new char [w * h * size]), // pixel storage
_slice (type, // type
_storage, // base
size, // x stride
w * size, // y stride
xSampling, // x sampling
ySampling) // y sampling
{
// nothing
}


//-----------------------------------------------------------------------------
// ~SliceAndStorage
//-----------------------------------------------------------------------------
// delete the pixel storage

SliceAndStorage::~SliceAndStorage ()
{
delete[] _storage;
}


//-----------------------------------------------------------------------------
// SliceAndStorage::slice
//-----------------------------------------------------------------------------
// access to the Imf::slice

inline const Slice&
SliceAndStorage::slice () const
{
return _slice;
}


//-----------------------------------------------------------------------------
// pixelTypeSize
//-----------------------------------------------------------------------------
// return the size, in bytes, of a pixel of type pixelType

static int
pixelTypeSize (PixelType pixelType)
{
switch (pixelType)
{
case HALF: return 2; break;
case FLOAT: return 4; break;
case UINT: return 4; break;
}

cerr << "WARNING: unknown pixel type " << pixelType << "; assuming 4 bytes per pixel" << endl;
return 4;
}


//-----------------------------------------------------------------------------
// processFile
//-----------------------------------------------------------------------------
// Basic strategy:
//
// - examine the given OpenEXR file
// - construct slices for each channel
// - read all of the channels into the storage
// - write the pixels back out to a new file
//
// the original file and the new file can be compared using "diff"
// or a similar utility to ensure that the pixels were read
// and written correctly.

static void
processFile (const char* filename)
{
InputFile inputFile (filename);
const ChannelList& channelList (inputFile.header().channels());
const Box2i& dw (inputFile.header().dataWindow());
FrameBuffer fb;
std::vector< SliceAndStorage* > slices;


// for each channel in the input file, insert a "slice" into the
// framebuffer to store that channel's pixels.

for (ChannelList::ConstIterator i = channelList.begin();
i != channelList.end(); ++i)
{
const Channel& c = i.channel(); // channel
int s = pixelTypeSize (c.type); // size of a pixel in bytes
int w = (dw.max.x - dw.min.x + 1); // width of the slice
int h = (dw.max.y - dw.min.y + 1); // height of the slice



// take subsampling into account - we only need storage for
// the pixels for which we have samples


w /= c.xSampling;
h /= c.ySampling;




// store this slice so we can properly dispose of it when we're done


slices.push_back (new SliceAndStorage (c.type, w, h, s, c.xSampling, c.ySampling));


// add the slice to our framebuffer

fb.insert (i.name(), slices.back()->slice());
}


// tell the input file to read pixels into our framebuffer

inputFile.setFrameBuffer (fb);


// read pixels

cout << "reading " << inputFile.fileName() << "..." << endl;
inputFile.readPixels (dw.min.y, dw.max.y);


// create an output file to save the pixels to
// reuse the header from the InputFile, so that all
// of the attributes will be preserved

std::string copyFile (filename);
copyFile += ".copy.exr";

OutputFile outputFile (copyFile.c_str(), inputFile.header());


// tell the output file to get pixels from our framebuffer

outputFile.setFrameBuffer (fb);


// save the file

cout << "writing " << outputFile.fileName() << "..." << endl;
outputFile.writePixels (dw.max.y - dw.min.y + 1);


// delete pixel storage

for (int i = 0; i < slices.size(); ++i)
{
delete slices[i];
}
}


//-----------------------------------------------------------------------------
// main
//-----------------------------------------------------------------------------
// process specified OpenEXR files

int
main (int argc, char * const argv[])
{
const char* programName = (argc > 0 && argv[0] != NULL) ?

argv[0] : "deepexample";

if (argc < 2)
{
cerr << "usage: " << programName << " exrfile1 [exrfile2 exrfile3 ..]" << endl;
return 1;
}

for (int i = 1; i < argc; ++i)
{
try
{
processFile (argv[i]);
}
catch (std::exception& e)
{
cerr << "Exception processing \"" << argv[i] << "\": " << e.what() << endl;
}
}


cout << "done." << endl;

return 0;
}




reply via email to

[Prev in Thread] Current Thread [Next in Thread]