openexr-devel
[Top][All Lists]
Advanced

[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










reply via email to

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