Ejemplo n.º 1
0
void EXRImageFileWriter::write(
    const char*             filename,
    const ICanvas&          image,
    const ImageAttributes&  image_attributes)
{
    initialize_openexr();

    try
    {
        // Retrieve canvas properties.
        const CanvasProperties& props = image.properties();

        // todo: lift this limitation.
        assert(props.m_channel_count <= 4);

        // Figure out the pixel type, based on the pixel format of the image.
        PixelType pixel_type = FLOAT;
        switch (props.m_pixel_format)
        {
          case PixelFormatUInt32: pixel_type = UINT; break;
          case PixelFormatHalf: pixel_type = HALF; break;
          case PixelFormatFloat: pixel_type = FLOAT; break;
          default: throw ExceptionUnsupportedImageFormat();
        }

        // Construct TileDescription object.
        const TileDescription tile_desc(
            static_cast<unsigned int>(props.m_tile_width),
            static_cast<unsigned int>(props.m_tile_height),
            ONE_LEVEL);

        // Construct ChannelList object.
        ChannelList channels;
        for (size_t c = 0; c < props.m_channel_count; ++c)
            channels.insert(ChannelName[c], Channel(pixel_type));

        // Construct Header object.
        Header header(
            static_cast<int>(props.m_canvas_width),
            static_cast<int>(props.m_canvas_height));
        header.setTileDescription(tile_desc);
        header.channels() = channels;

        // Add image attributes to the Header object.
        add_attributes(image_attributes, header);

        // Create the output file.
        TiledOutputFile file(filename, header);

        // Write tiles.
        for (size_t y = 0; y < props.m_tile_count_y; ++y)
        {
            for (size_t x = 0; x < props.m_tile_count_x; ++x)
            {
                const int ix              = static_cast<int>(x);
                const int iy              = static_cast<int>(y);
                const Box2i range         = file.dataWindowForTile(ix, iy);
                const Tile& tile          = image.tile(x, y);
                const size_t channel_size = Pixel::size(tile.get_pixel_format());
                const size_t stride_x     = channel_size * props.m_channel_count;
                const size_t stride_y     = stride_x * tile.get_width();
                const size_t tile_origin  = range.min.x * stride_x + range.min.y * stride_y;
                const char* tile_base     = reinterpret_cast<const char*>(tile.pixel(0, 0)) - tile_origin;

                // Construct FrameBuffer object.
                FrameBuffer framebuffer;
                for (size_t c = 0; c < props.m_channel_count; ++c)
                {
                    const char* base = tile_base + c * channel_size;
                    framebuffer.insert(
                        ChannelName[c],
                        Slice(
                            pixel_type,
                            const_cast<char*>(base),
                            stride_x,
                            stride_y));
                }

                // Write tile.
                file.setFrameBuffer(framebuffer);
                file.writeTile(ix, iy);
            }
        }
    }
    catch (const BaseExc& e)
    {
        // I/O error.
        throw ExceptionIOError(e.what());
    }
}
void ProgressiveEXRImageFileReader::open(const char* filename)
{
    assert(filename);
    assert(!is_open());

    initialize_openexr();

    try
    {
        try
        {
            // Open the file for reading, assuming the file is tiled.
            impl->m_tiled_file.reset(new TiledInputFile(filename));
            impl->m_is_tiled = true;
        }
        catch (const ArgExc&)
        {
            // The file is not tiled, open it as a scanline file.
            impl->m_scanline_file.reset(new InputFile(filename));
            impl->m_is_tiled = false;

            // Print a warning message if a logger was provided.
            if (impl->m_logger)
            {
                LOG_WARNING(
                    *impl->m_logger,
                    "the texture file %s is not tiled, performances might suffer.",
                    filename);
            }
        }

        // Retrieve the file header, and perform basic sanity checks on it.
        const Header& header = impl->m_is_tiled
            ? impl->m_tiled_file->header()
            : impl->m_scanline_file->header();
        header.sanityCheck(impl->m_is_tiled);

        // Retrieve the image channels.
        const ChannelList& channels = header.channels();
        impl->m_red = channels.findChannel("R");
        impl->m_green = channels.findChannel("G");
        impl->m_blue = channels.findChannel("B");
        impl->m_alpha = channels.findChannel("A");
        if (!(impl->m_red && impl->m_green && impl->m_blue))
            throw ExceptionUnsupportedImageFormat();

        // Make sure all channels use the same pixel format.
        if (!(impl->m_red->type == impl->m_green->type && impl->m_red->type == impl->m_blue->type))
            throw ExceptionUnsupportedImageFormat();
        if (impl->m_alpha)
        {
            if (impl->m_red->type != impl->m_alpha->type)
                throw ExceptionUnsupportedImageFormat();
        }

        // Figure out the pixel format, based on the pixel type of the file.
        PixelFormat pixel_format = PixelFormatFloat;
        switch (impl->m_red->type)
        {
          case UINT: pixel_format = PixelFormatUInt32; break;
          case HALF: pixel_format = PixelFormatHalf; break;
          case FLOAT: pixel_format = PixelFormatFloat; break;
          default: throw ExceptionUnsupportedImageFormat();
        }

        // Retrieve the dimensions of the image.
        impl->m_dw = header.dataWindow();

        // Compute the dimensions of the canvas.
        const size_t canvas_width = static_cast<size_t>(impl->m_dw.max.x - impl->m_dw.min.x + 1);
        const size_t canvas_height = static_cast<size_t>(impl->m_dw.max.y - impl->m_dw.min.y + 1);

        // Retrieve the dimensions of the tiles.
        size_t tile_width, tile_height;
        if (impl->m_is_tiled)
        {
            assert(header.hasTileDescription());
            const TileDescription& td = header.tileDescription();
            tile_width = static_cast<size_t>(td.xSize);
            tile_height = static_cast<size_t>(td.ySize);
        }
        else
        {
            tile_width = impl->m_default_tile_width;
            tile_height = impl->m_default_tile_height;
        }

        // Retrieve the number of tiles in each direction.
        size_t tile_count_x, tile_count_y;
        if (impl->m_is_tiled)
        {
            tile_count_x = static_cast<size_t>(impl->m_tiled_file->numXTiles());
            tile_count_y = static_cast<size_t>(impl->m_tiled_file->numYTiles());
        }
        else
        {
            const double nx = ceil(static_cast<double>(canvas_width) / tile_width);
            const double ny = ceil(static_cast<double>(canvas_height) / tile_height);
            tile_count_x = truncate<size_t>(nx);
            tile_count_y = truncate<size_t>(ny);
        }

        // Set canvas properties.
        impl->m_props.m_canvas_width = canvas_width;
        impl->m_props.m_canvas_height = canvas_height;
        impl->m_props.m_rcp_canvas_width = 1.0 / impl->m_props.m_canvas_width;
        impl->m_props.m_rcp_canvas_height = 1.0 / impl->m_props.m_canvas_height;
        impl->m_props.m_pixel_count = impl->m_props.m_canvas_width * impl->m_props.m_canvas_height;
        impl->m_props.m_tile_width = tile_width;
        impl->m_props.m_tile_height = tile_height;
        impl->m_props.m_rcp_tile_width = 1.0 / impl->m_props.m_tile_width;
        impl->m_props.m_rcp_tile_height = 1.0 / impl->m_props.m_tile_height;
        impl->m_props.m_tile_count_x = tile_count_x;
        impl->m_props.m_tile_count_y = tile_count_y;
        impl->m_props.m_tile_count = impl->m_props.m_tile_count_x * impl->m_props.m_tile_count_y;
        impl->m_props.m_pixel_format = pixel_format;
        impl->m_props.m_channel_count = impl->m_alpha ? 4 : 3;
        impl->m_props.m_pixel_size = impl->m_props.m_channel_count * Pixel::size(impl->m_props.m_pixel_format);

        // Allocate memory to store scanlines, if the file is not tiled.
        if (!impl->m_is_tiled)
        {
            const size_t size =
                  impl->m_props.m_canvas_width
                * impl->m_props.m_pixel_size
                * tile_height;
            impl->m_scanlines.resize(size);
        }

        // No tile previously accessed.
        impl->m_last_tile_y = ~0;
    }
    catch (const BaseExc& e)
    {
        // I/O error.
        throw ExceptionIOError(e.what());
    }
}