Skip to content

Commit

Permalink
IOProxy support for SGI files and fix important bug (#3641)
Browse files Browse the repository at this point in the history
Add IOProxy support.
Fixes #3623

Along the way, noticed an important bug at line 209 of this change --
the header "imagename" field should be fully zeroed out even if there
is no ImageDescription metadata!
  • Loading branch information
lgritz authored Nov 2, 2022
1 parent 88152a6 commit 9c70640
Show file tree
Hide file tree
Showing 6 changed files with 189 additions and 165 deletions.
77 changes: 49 additions & 28 deletions src/doc/builtinplugins.rst
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ Z component of a normal map. This applies to images using DXT5 compression
and images using BC5/ATI2 compression (normal X & Y components are in
red & green channels).

**Attributes**

.. list-table::
:widths: 30 10 65
:header-rows: 1
Expand Down Expand Up @@ -204,27 +206,9 @@ When the attribute value is set to non-zero (default is zero), any input
image using BC5/ATI2 compression format is assumed to be a normal map,
even if pixel format "normal map" flag is not set.


**Configuration settings for DDS output**

When opening an DDS ImageOutput, the following special metadata tokens
control aspects of the writing itself:

.. list-table::
:widths: 30 10 65
:header-rows: 1

* - Output Configuration Attribute
- Type
- Meaning
* - ``oiio:ioproxy``
- ptr
- Pointer to a ``Filesystem::IOProxy`` that will handle the I/O, for
example by writing to a memory buffer.

**Custom I/O Overrides**

DDS supports the "custom I/O" feature via the
DDS input supports the "custom I/O" feature via the
special ``"oiio:ioproxy"`` attributes (see Sections
:ref:`sec-imageoutput-ioproxy` and :ref:`sec-imageinput-ioproxy`) as well as
the `set_ioproxy()` methods.
Expand Down Expand Up @@ -315,15 +299,15 @@ control aspects of the writing itself:
will keep unaltered pixel values (versus the default OIIO behavior
of automatically converting from RGB to the designated color space
as the pixels are written).
* - ``oiio:ioproxy``
- ptr
- Pointer to a ``Filesystem::IOProxy`` that will handle the I/O, for
example by writing to memory rather than the file system.
* - ``oiio:dither``
- int
- If nonzero and outputting UINT8 values in the file from a source of
higher bit depth, will add a small amount of random dither to combat
the appearance of banding.
* - ``oiio:ioproxy``
- ptr
- Pointer to a ``Filesystem::IOProxy`` that will handle the I/O, for
example by writing to memory rather than the file system.

**Custom I/O Overrides**

Expand Down Expand Up @@ -636,7 +620,7 @@ control aspects of the writing itself:

**Custom I/O Overrides**

GIF supports the "custom I/O" feature via the
GIF input and output support the "custom I/O" feature via the
special ``"oiio:ioproxy"`` attributes (see Sections
:ref:`sec-imageoutput-ioproxy` and :ref:`sec-imageinput-ioproxy`) as well as
the `set_ioproxy()` methods.
Expand Down Expand Up @@ -671,6 +655,7 @@ applications and to distribute HDR environment maps. But newer formats with
native HDR support, such as OpenEXR, are vastly superior and should be
preferred except when legacy file access is required.

**Attributes**

.. list-table::
:widths: 30 10 65
Expand Down Expand Up @@ -727,7 +712,7 @@ control aspects of the writing itself:

**Custom I/O Overrides**

HDR supports the "custom I/O" feature via the
HDR input and output support the "custom I/O" feature via the
special ``"oiio:ioproxy"`` attributes (see Sections
:ref:`sec-imageoutput-ioproxy` and :ref:`sec-imageinput-ioproxy`) as well as
the `set_ioproxy()` methods.
Expand Down Expand Up @@ -855,6 +840,8 @@ IFF

IFF files are used by Autodesk Maya and use the file extension :file:`.iff`.

**Attributes**

.. list-table::
:widths: 30 10 65
:header-rows: 1
Expand Down Expand Up @@ -1004,7 +991,7 @@ control aspects of the writing itself:

**Custom I/O Overrides**

JPEG supports the "custom I/O" feature
JPEG input and output support the "custom I/O" feature
via the `ImageInput::set_ioproxy()` method and the special
``"oiio:ioproxy"`` attributes (see Section :ref:`sec-imageinput-ioproxy`).

Expand Down Expand Up @@ -1420,6 +1407,8 @@ coordinate mapping. Layers may be scalar (1 channel) or vector (3 channel)
fields, and the voxel data are always `float`. OpenVDB files always
report as tiled, using the leaf dimension size.

**Attributes**

.. list-table::
:widths: 30 10 65
:header-rows: 1
Expand Down Expand Up @@ -1727,7 +1716,7 @@ Lab or duotone modes.

**Custom I/O Overrides**

PSD supports the "custom I/O" feature via the special ``"oiio:ioproxy"``
PSD output supports the "custom I/O" feature via the special ``"oiio:ioproxy"``
attributes (see Sections :ref:`sec-imageoutput-ioproxy` and
:ref:`sec-imageinput-ioproxy`) as well as the `set_ioproxy()` methods.

Expand All @@ -1748,6 +1737,7 @@ Ptex files, but the TextureSystem doesn't properly filter across face
boundaries when using it as a texture. OpenImageIO currently does not write
Ptex files at all.

**Attributes**

.. list-table::
:widths: 30 10 65
Expand Down Expand Up @@ -2023,6 +2013,24 @@ otherwise: no support for tiles, no MIPmaps, no multi-subimage, only 8- and
- string
- Image name.

**Configuration settings for SGI input**

When opening a SGI ImageInput with a *configuration* (see
Section :ref:`sec-input-with-config`), the following special configuration
options are supported:

.. list-table::
:widths: 30 10 65
:header-rows: 1

* - Input Configuration Attribute
- Type
- Meaning
* - ``oiio:ioproxy``
- ptr
- Pointer to a ``Filesystem::IOProxy`` that will handle the I/O, for
example by reading from memory rather than the file system.

**Configuration settings for SGI output**

When opening an SGI ImageOutput, the following special metadata tokens
Expand All @@ -2040,8 +2048,19 @@ control aspects of the writing itself:
- If nonzero and outputting UINT8 values in the file from a source of
higher bit depth, will add a small amount of random dither to combat
the appearance of banding.
* - ``oiio:ioproxy``
- ptr
- Pointer to a ``Filesystem::IOProxy`` that will handle the I/O, for
example by reading from memory rather than the file system.


**Custom I/O Overrides**

SGI input and output support the "custom I/O" feature via the
special ``"oiio:ioproxy"`` attributes (see Sections
:ref:`sec-imageoutput-ioproxy` and :ref:`sec-imageinput-ioproxy`) as well as
the `set_ioproxy()` methods.

|
.. _sec-bundledplugins-pic:
Expand All @@ -2057,6 +2076,8 @@ The Softimage PIC format is sometimes used for legacy apps, but has little
merit otherwise, so currently OpenImageIO only reads Softimage files and is
unable to write them.

**Attributes**

.. list-table::
:widths: 30 10 65
:header-rows: 1
Expand Down Expand Up @@ -2201,7 +2222,7 @@ control aspects of the writing itself:

**Custom I/O Overrides**

DDS supports the "custom I/O" feature via the
Targa input and output support the "custom I/O" feature via the
special ``"oiio:ioproxy"`` attributes (see Sections
:ref:`sec-imageoutput-ioproxy` and :ref:`sec-imageinput-ioproxy`) as well as
the `set_ioproxy()` methods.
Expand Down
5 changes: 0 additions & 5 deletions src/hdr.imageio/hdrinput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -498,11 +498,6 @@ HdrInput::read_native_scanline(int subimage, int miplevel, int y, int /*z*/,
bool
HdrInput::close()
{
// if (m_io_local) {
// // If we allocated our own ioproxy, close it.
// ioproxy_clear();
// }

init(); // Reset to initial state
return true;
}
Expand Down
12 changes: 12 additions & 0 deletions src/libOpenImageIO/imageinout_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,18 @@ test_write_proxy(string_view formatname, string_view extension,
Strutil::print("Write proxy via ImageBuf didn't match write file\n");
Strutil::print("Sizes outproxy {} vs readbuf {}\n",
outproxy.buffer().size(), readbuf.size());
#if 0
for (size_t i = 0, e = std::min(outproxy.buffer().size(), readbuf.size());
i < e; ++i) {
Strutil::print(" {0:2d}: {1:02x} '{1:c}' vs {2:02x} '{2:c}'\n",
i, outproxy.buffer()[i], readbuf[i]);
if (outproxy.buffer()[i] != readbuf[i]) {
Strutil::print(" Mismatch at byte {} outproxy {} vs readbuf {}\n",
i, outproxy.buffer()[i], readbuf[i]);
break;
}
}
#endif
}
OIIO_CHECK_ASSERT(outproxybuf.buffer() == readbuf
&& "Write proxy via ImageBuf didn't match write file");
Expand Down
93 changes: 0 additions & 93 deletions src/sgi.imageio/sgi_pvt.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,97 +61,4 @@ enum ColorMap {
} // namespace sgi_pvt



class SgiInput final : public ImageInput {
public:
SgiInput() { init(); }
~SgiInput() override { close(); }
const char* format_name(void) const override { return "sgi"; }
bool valid_file(const std::string& filename) const override;
bool open(const std::string& name, ImageSpec& spec) override;
bool close(void) override;
bool read_native_scanline(int subimage, int miplevel, int y, int z,
void* data) override;

private:
FILE* m_fd = nullptr;
std::string m_filename;
sgi_pvt::SgiHeader m_sgi_header;
std::vector<uint32_t> start_tab;
std::vector<uint32_t> length_tab;

void init()
{
m_fd = nullptr;
memset(&m_sgi_header, 0, sizeof(m_sgi_header));
}

// reads SGI file header (512 bytes) into m_sgi_header
// Return true if ok, false if there was a read error.
bool read_header();

// reads RLE scanline start offset and RLE scanline length tables
// RLE scanline start offset is stored in start_tab
// RLE scanline length is stored in length_tab
// Return true if ok, false if there was a read error.
bool read_offset_tables();

// read channel scanline data from file, uncompress it and save the data to
// 'out' buffer; 'out' should be allocate before call to this method.
// Return true if ok, false if there was a read error.
bool uncompress_rle_channel(int scanline_off, int scanline_len,
unsigned char* out);

/// Helper: read, with error detection
///
bool fread(void* buf, size_t itemsize, size_t nitems)
{
size_t n = ::fread(buf, itemsize, nitems, m_fd);
if (n != nitems)
errorfmt("Read error");
return n == nitems;
}
};



class SgiOutput final : public ImageOutput {
public:
SgiOutput() {}
~SgiOutput() override { close(); }
const char* format_name(void) const override { return "sgi"; }
int supports(string_view feature) const override;
bool open(const std::string& name, const ImageSpec& spec,
OpenMode mode = Create) override;
bool close(void) override;
bool write_scanline(int y, int z, TypeDesc format, const void* data,
stride_t xstride) override;
bool write_tile(int x, int y, int z, TypeDesc format, const void* data,
stride_t xstride, stride_t ystride,
stride_t zstride) override;

private:
FILE* m_fd = nullptr;
std::string m_filename;
std::vector<unsigned char> m_scratch;
unsigned int m_dither;
std::vector<unsigned char> m_tilebuffer;

void init() { m_fd = NULL; }

bool create_and_write_header();

/// Helper - write, with error detection
template<class T>
bool fwrite(const T* buf, size_t itemsize = sizeof(T), size_t nitems = 1)
{
size_t n = std::fwrite(buf, itemsize, nitems, m_fd);
if (n != nitems)
errorfmt("Error writing \"{}\" (wrote {}/{} records)", m_filename,
n, nitems);
return n == nitems;
}
};


OIIO_PLUGIN_NAMESPACE_END
Loading

0 comments on commit 9c70640

Please sign in to comment.