[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Openexr-devel] validity check on files
From: |
Paul Schneider |
Subject: |
Re: [Openexr-devel] validity check on files |
Date: |
Fri, 3 Oct 2003 13:29:46 -0700 |
Hi, James,
that's probably the most confusing part of the EXR interface. You're
basically relying on the fact that the EXR lib will never access pixels
outside of the data window. The first pixel the library accesses will
be at (dw.min.x, dw.min.y), and it will find that pixel in memory by
doing this:
pix = base + dw.min.x + dw.min.y * width;
Which of course gets you back to the first pixel you actually
allocated. rPixels doesn't have to know about the data window, because
everything that uses rPixels (the frameBuffer) does know about the data
window.
The concept you have to grasp is that the base address "points" to
pixel (0, 0), not to the first pixel in the data window of the image.
Here's some relevant text from the API documentation located at
http://www.openexr.com/api.html
1.2 Writing a Cropped Image
Now we are going to store a cropped image in a file. For this example,
we assume that we have a frame buffer that is large enough to hold an
image with width by height pixels, but only part of the frame buffer
contains valid data. In the file's header, the size of the whole image
is indicated by the display window, (0, 0) - (width-1, height-1), and
the data window specifies the region for which valid pixel data exist.
Only the pixels in the data window are stored in the file.
void
writeRgba2 (const char fileName[],
const Rgba *pixels,
int width,
int height,
const Box2i &dataWindow)
{
Box2i displayWindow (V2i (0, 0), V2i (width - 1, height - 1));
RgbaOutputFile file (fileName, displayWindow, dataWindow,
WRITE_RGBA);
file.setFrameBuffer (pixels, 1, width);
file.writePixels (dataWindow.max.y - dataWindow.min.y + 1);
}
The code above is similar to that in section 1.1, where the whole
image was stored in the file. Two things are different, however: When
the RgbaOutputFile object is created, the data window and the display
window are explicitly specified, rather than being derived from the
image's width and height. The number of scan lines stored in the file
by writePixels() is equal to the height of the data window, instead of
the height of the whole image. Since we are using the default
INCREASING_Y direction for storing the scan lines in the file,
writePixels() starts at the top of the data window, at y coordinate
dataWindow.min.y, and proceeds toward the bottom, at y coordinate
dataWindow.max.y.
Even though we are storing only part of the image in the file, the
frame buffer is still large enough to hold the whole image. In order
to save memory, a smaller frame buffer could have been allocated, just
big enough to hold the contents of the data window. Assuming that the
pixels were still stored in contiguous scan lines, with the pixels
pointer pointing to the pixel at the upper left corner of the data
window, at coordinates (dataWindow.min.x, dataWindow.min.y), the
arguments to the setFrameBuffer() call would have to be to be changed
as follows:
int dwWidth = dataWindow.max.x - dataWindow.min.x + 1;
file.setFrameBuffer
(pixels - dataWindow.min.x - dataWindow.min.y * dwWidth, 1,
dwWidth);
With these settings, evaluation of
base + x * xStride + y * yStride
for pixel (dataWindow.min.x, dataWindow.min.y) produces
pixels - dataWindow.min.x - dataWindow.min.y * dwWidth
+ dataWindow.min.x * 1
+ dataWindow.min.y * dwWidth
= pixels -
- dataWindow.min.x
- dataWindow.min.y * (dataWindow.max.x - dataWindow.min.x + 1)
+ dataWindow.min.x
+ dataWindow.min.y * (dataWindow.max.x - dataWindow.min.x + 1)
= pixels,
which is exactly what we want. Similarly, calculating the addresses
for pixels (dataWindow.min.x+1, dataWindow.min.y) and
(dataWindow.min.x, dataWindow.min.y+1) yields pixels+1 and
pixels+width, respectively.
On Friday, October 3, 2003, at 01:12 PM, James McPhail wrote:
Fabulous... thanks so much Paul!
I have one more quick question (feel free to post this to the board).
In the EXR examples, when reading from a file (say in function
readGZ1), a slice is inserted into a frameBuffer and a pixel array is
allocated:
rPixels.resizeErase (height, width);
frameBuffer.insert ("R", // name
Slice (HALF, // type
(char *) (&rPixels[0][0] - // base
dw.min.x -
dw.min.y * width),
sizeof (rPixels[0][0]) * 1, // xStride
sizeof (rPixels[0][0]) * width, // yStride
1, 1, // x/y sampling
0.0)); // fillValue
When specifying the base address to write to, the sample code goes
&rPixels[0][0] - // base
dw.min.x -
dw.min.y * width
I understand what this is attempting to do (allow for non-zero
dw.min's), but I don't understand how it is actually accomplishing it.
How does this not tell the toolkit to write to a memory location
before our actual buffer? rPixels has no knowledge of what dw.min.y or
dw.min.x are, it merely was passed the height and width of the image.
I am confused... please help! :)
James
Paul Schneider wrote:
The EXR library in general uses C++ exceptions as the preferred means
of letting you know that something went wrong, so you really should
be prepared to catch a exception from the library at any time.
In this case, the InputFile's constructor causes the file to be
opened and the header information to be read. If the header isn't
valid (not an EXR image, or an unsupported version), it will throw an
Iex::InputExc. Calling the what() method of this exception will let
you know what went wrong.
Since Iex::InputExc inherits from Iex::BaseExc, which inherits from
std::exception, you can catch any exeption that might be thrown like
this:
try
{
InputFile file(fileName);
}
catch (const std::exception& ex)
{
cerr << "couldn't open input file " << fileName << ": " <<
ex.what() << endl;
}
This will also let you handle exceptions such as std::bad_alloc (out
of memory), and Iex::ErrnoExc exceptions, which mean that the file
couldn't be opened for some reason (permissions, maybe).
Note that you can put the image reading code in the try block as
well, and you only have to worry about error handling in one place.
If you need more fine-grained error handling, you can catch specific
exceptions:
try
{
InputFile file(fileName);
}
catch (const EpermExc& ex)
{
cerr << "don't have permission to open that file" << endl;
}
catch (const Iex::InputExc& ex)
{
cerr << "file doesn't appear to really be an EXR file" << endl;
}
catch (const std::bad_alloc& ex)
{
cerr << "out of memory opening file" << endl;
}
catch (const std::exception& ex)
{
cerr << "unkown error" << endl;
}
This could let you silently ignore invalid EXR files, if you were
just filtering them in an open file dialog for example. In general,
you should probably pass the what() string along to the user in some
way, as they tend to be pretty descriptive.
Hope that helps,
Paul
On Friday, October 3, 2003, at 12:36 PM, James McPhail wrote:
I hope this hasn't been touched upon in a previous thread.
Is there functionality in the toolkit for determining if an
"InputFile" is bogus? Specifically, can the toolkit determine, when
passed a file name, that the given file is not of the EXR format?
I had initially wanted to try
InputFile file(fileName);
then had hoped there would be some flag or function call on this
'file' variable or its associated header which would indicate that
it was not a valid file, however this InputFile constructor throws
an exception (which I couldn't manage to catch) and then crashes.
Any help would be appreciated.
James
_______________________________________________
Openexr-devel mailing list
address@hidden
http://mail.nongnu.org/mailman/listinfo/openexr-devel