diff --git a/src/doc/builtinplugins.rst b/src/doc/builtinplugins.rst index af557bbbde..a2d2bb717b 100644 --- a/src/doc/builtinplugins.rst +++ b/src/doc/builtinplugins.rst @@ -816,6 +816,24 @@ Windows. ICO files use the file extension :file:`.ico`. - int - if nonzero, will cause the ICO to be written out using PNG format. +**Configuration settings for ICO input** + +When opening an ICO ImageInput with a *configuration* (see +Section :ref:`sec-input-with-config`), the following special configuration +attributes 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 ICO output** When opening an ICO ImageOutput, the following special metadata tokens diff --git a/src/ico.imageio/icoinput.cpp b/src/ico.imageio/icoinput.cpp index 2ea8f67933..114162fc2a 100644 --- a/src/ico.imageio/icoinput.cpp +++ b/src/ico.imageio/icoinput.cpp @@ -25,7 +25,13 @@ class ICOInput final : public ImageInput { ICOInput() { init(); } ~ICOInput() override { close(); } const char* format_name(void) const override { return "ico"; } + int supports(string_view feature) const override + { + return feature == "ioproxy"; + } bool open(const std::string& name, ImageSpec& newspec) override; + bool open(const std::string& name, ImageSpec& newspec, + const ImageSpec& config) override; bool close() override; int current_subimage(void) const override { @@ -38,7 +44,6 @@ class ICOInput final : public ImageInput { private: std::string m_filename; ///< Stash the filename - FILE* m_file; ///< Open image handle ico_header m_ico; ///< ICO header std::vector m_buf; ///< Buffer the image pixels int m_subimage; ///< What subimage are we looking at? @@ -58,25 +63,26 @@ class ICOInput final : public ImageInput { void init() { m_subimage = -1; - m_file = NULL; m_png = NULL; m_info = NULL; memset(&m_ico, 0, sizeof(m_ico)); m_buf.clear(); + ioproxy_clear(); } /// Helper function: read the image. /// bool readimg(); - /// Helper: read, with error detection - /// - bool fread(void* buf, size_t itemsize, size_t nitems) + // Callback for PNG that reads from an IOProxy. + static void PngReadCallback(png_structp png_ptr, png_bytep data, + png_size_t length) { - size_t n = ::fread(buf, itemsize, nitems, m_file); - if (n != nitems) - errorf("Read error"); - return n == nitems; + ICOInput* icoinput = (ICOInput*)png_get_io_ptr(png_ptr); + OIIO_DASSERT(icoinput); + if (!icoinput->ioread(data, length)) { + png_chunk_error(png_ptr, icoinput->geterror(false).c_str()); + } } }; @@ -103,20 +109,26 @@ OIIO_EXPORT const char* ico_input_extensions[] = { "ico", nullptr }; OIIO_PLUGIN_EXPORTS_END - - bool ICOInput::open(const std::string& name, ImageSpec& newspec) +{ + ImageSpec emptyconfig; + return open(name, newspec, emptyconfig); +} + +bool +ICOInput::open(const std::string& name, ImageSpec& newspec, + const ImageSpec& config) { m_filename = name; - m_file = Filesystem::fopen(name, "rb"); - if (!m_file) { - errorf("Could not open file \"%s\"", name); + ioproxy_retrieve_from_config(config); + if (!ioproxy_use_or_open(name)) return false; - } - if (!fread(&m_ico, 1, sizeof(m_ico))) + ioseek(0); + + if (!ioread(&m_ico, 1, sizeof(m_ico))) return false; if (bigendian()) { @@ -163,10 +175,9 @@ ICOInput::seek_subimage(int subimage, int miplevel) m_subimage = subimage; // read subimage header - fseek(m_file, sizeof(ico_header) + m_subimage * sizeof(ico_subimage), - SEEK_SET); + ioseek(sizeof(ico_header) + m_subimage * sizeof(ico_subimage), SEEK_SET); ico_subimage subimg; - if (!fread(&subimg, 1, sizeof(subimg))) + if (!ioread(&subimg, 1, sizeof(subimg))) return false; if (bigendian()) { @@ -179,11 +190,11 @@ ICOInput::seek_subimage(int subimage, int miplevel) swap_endian(&subimg.numColours); } - fseek(m_file, subimg.ofs, SEEK_SET); + ioseek(subimg.ofs, SEEK_SET); // test for a PNG icon char temp[8]; - if (!fread(temp, 1, sizeof(temp))) + if (!ioread(temp, 1, sizeof(temp))) return false; if (temp[1] == 'P' && temp[2] == 'N' && temp[3] == 'G') { // standard PNG initialization @@ -201,8 +212,9 @@ ICOInput::seek_subimage(int subimage, int miplevel) } //std::cerr << "[ico] reading PNG info\n"; + // Tell libpng to use our read callback to read from the IOProxy + png_set_read_fn(m_png, this, PngReadCallback); - png_init_io(m_png, m_file); png_set_sig_bytes(m_png, 8); // already read 8 bytes PNG_pvt::read_info(m_png, m_info, m_bpp, m_color_type, m_interlace_type, @@ -215,10 +227,10 @@ ICOInput::seek_subimage(int subimage, int miplevel) // otherwise it's a plain, ol' windoze DIB (device-independent bitmap) // roll back to where we began and read in the DIB header - fseek(m_file, subimg.ofs, SEEK_SET); + ioseek(subimg.ofs, SEEK_SET); ico_bitmapinfo bmi; - if (!fread(&bmi, 1, sizeof(bmi))) + if (!ioread(&bmi, 1, sizeof(bmi))) return false; if (bigendian()) { // ICOs are little endian @@ -297,7 +309,7 @@ ICOInput::readimg() std::vector palette(m_palette_size); if (m_bpp < 16) { // >= 16-bit icons are unpaletted for (int i = 0; i < m_palette_size; i++) - if (!fread(&palette[i], 1, sizeof(ico_palette_entry))) + if (!ioread(&palette[i], 1, sizeof(ico_palette_entry))) return false; } @@ -310,7 +322,7 @@ ICOInput::readimg() int k; int index; for (int y = m_spec.height - 1; y >= 0; y--) { - if (!fread(&scanline[0], 1, slb)) + if (!ioread(&scanline[0], 1, slb)) return false; for (int x = 0; x < m_spec.width; x++) { k = y * m_spec.width * 4 + x * 4; @@ -398,7 +410,7 @@ ICOInput::readimg() + (4 - ((m_spec.width + 7) / 8) % 4) % 4; // padding scanline.resize(slb); for (int y = m_spec.height - 1; y >= 0; y--) { - if (!fread(&scanline[0], 1, slb)) + if (!ioread(&scanline[0], 1, slb)) return false; for (int x = 0; x < m_spec.width; x += 8) { for (int b = 0; b < 8; b++) { // bit @@ -422,10 +434,6 @@ ICOInput::close() { if (m_png && m_info) PNG_pvt::destroy_read_struct(m_png, m_info); - if (m_file) { - fclose(m_file); - m_file = NULL; - } init(); // Reset to initial state return true;