Skip to content

Commit 9bcfd90

Browse files
brechtvlssh4net
authored andcommitted
feat(heif): Add IOProxy for input and output (AcademySoftwareFoundation#5017)
Add IOProxy support similar to other file formats. MyHeifWriter was renamed for consistency with other code. All input and output now goes through the proxy, so this is covered by existing tests. Signed-off-by: Brecht Van Lommel <brecht@blender.org> Signed-off-by: Vlad (Kuzmin) Erium <libalias@gmail.com>
1 parent 9da92aa commit 9bcfd90

3 files changed

Lines changed: 68 additions & 27 deletions

File tree

src/doc/builtinplugins.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -806,6 +806,10 @@ attributes are supported:
806806
having Orientation 1). If zero, then libheif will not reorient the
807807
image and the Orientation metadata will be set to reflect the camera
808808
orientation.
809+
* - ``oiio:ioproxy``
810+
- ptr
811+
- Pointer to a ``Filesystem::IOProxy`` that will handle the I/O, for
812+
example by reading from memory rather than the file system.
809813

810814
**Configuration settings for HEIF output**
811815

@@ -824,6 +828,10 @@ control aspects of the writing itself:
824828
- If supplied, can be ``"heic"`` or ``"avif"``, but may optionally have a
825829
quality value appended, like ``"heic:90"``. Quality can be 1-100, with
826830
100 meaning lossless. The default is 75.
831+
* - ``oiio:ioproxy``
832+
- ptr
833+
- Pointer to a ``Filesystem::IOProxy`` that will handle the I/O, for
834+
example by writing to memory rather than the file system.
827835

828836

829837

src/heif.imageio/heifinput.cpp

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,20 +32,49 @@
3232

3333
OIIO_PLUGIN_NAMESPACE_BEGIN
3434

35+
36+
class HeifReader final : public heif::Context::Reader {
37+
public:
38+
HeifReader(Filesystem::IOProxy* ioproxy)
39+
: m_ioproxy(ioproxy)
40+
{
41+
m_ioproxy->seek(0);
42+
}
43+
int64_t get_position() const override { return m_ioproxy->tell(); }
44+
int read(void* data, size_t size) override
45+
{
46+
return m_ioproxy->read(data, size) == size ? 0 : -1;
47+
}
48+
int seek(int64_t position) override
49+
{
50+
return m_ioproxy->seek(position) ? 0 : -1;
51+
}
52+
heif_reader_grow_status wait_for_file_size(int64_t target_size) override
53+
{
54+
return target_size <= int64_t(m_ioproxy->size())
55+
? heif_reader_grow_status_size_reached
56+
: heif_reader_grow_status_size_beyond_eof;
57+
}
58+
59+
private:
60+
Filesystem::IOProxy* m_ioproxy;
61+
};
62+
63+
3564
class HeifInput final : public ImageInput {
3665
public:
3766
HeifInput() {}
3867
~HeifInput() override { close(); }
3968
const char* format_name(void) const override { return "heif"; }
4069
int supports(string_view feature) const override
4170
{
42-
return feature == "exif"
71+
return feature == "exif" || feature == "ioproxy"
4372
#if LIBHEIF_HAVE_VERSION(1, 9, 0)
4473
|| feature == "cicp"
4574
#endif
4675
;
4776
}
48-
bool valid_file(const std::string& filename) const override;
77+
bool valid_file(Filesystem::IOProxy* ioproxy) const override;
4978
bool open(const std::string& name, ImageSpec& newspec) override;
5079
bool open(const std::string& name, ImageSpec& newspec,
5180
const ImageSpec& config) override;
@@ -67,14 +96,14 @@ class HeifInput final : public ImageInput {
6796
bool m_do_associate = false;
6897
bool m_reorient = true;
6998
std::unique_ptr<heif::Context> m_ctx;
99+
std::unique_ptr<HeifReader> m_reader;
70100
heif_item_id m_primary_id; // id of primary image
71101
std::vector<heif_item_id> m_item_ids; // ids of all other images
72102
heif::ImageHandle m_ihandle;
73103
heif::Image m_himage;
74104
};
75105

76106

77-
78107
void
79108
oiio_heif_init()
80109
{
@@ -111,10 +140,12 @@ OIIO_PLUGIN_EXPORTS_END
111140

112141

113142
bool
114-
HeifInput::valid_file(const std::string& filename) const
143+
HeifInput::valid_file(Filesystem::IOProxy* ioproxy) const
115144
{
145+
if (!ioproxy || ioproxy->mode() != Filesystem::IOProxy::Mode::Read)
146+
return false;
116147
uint8_t magic[12];
117-
if (Filesystem::read_bytes(filename, magic, sizeof(magic)) != sizeof(magic))
148+
if (ioproxy->pread(magic, sizeof(magic), 0) != sizeof(magic))
118149
return false;
119150
heif_filetype_result filetype_check = heif_check_filetype(magic,
120151
sizeof(magic));
@@ -141,7 +172,12 @@ HeifInput::open(const std::string& name, ImageSpec& newspec,
141172
m_filename = name;
142173
m_subimage = -1;
143174

175+
ioproxy_retrieve_from_config(config);
176+
if (!ioproxy_use_or_open(name))
177+
return false;
178+
144179
m_ctx.reset(new heif::Context);
180+
m_reader.reset(new HeifReader(ioproxy()));
145181
m_himage = heif::Image();
146182
m_ihandle = heif::ImageHandle();
147183

@@ -150,8 +186,7 @@ HeifInput::open(const std::string& name, ImageSpec& newspec,
150186
m_reorient = config.get_int_attribute("oiio:reorient", 1);
151187

152188
try {
153-
m_ctx->read_from_file(name);
154-
// FIXME: should someday be read_from_reader to give full flexibility
189+
m_ctx->read_from_reader(*m_reader);
155190

156191
m_item_ids = m_ctx->get_list_of_top_level_image_IDs();
157192
m_primary_id = m_ctx->get_primary_image_ID();
@@ -187,6 +222,7 @@ HeifInput::close()
187222
m_himage = heif::Image();
188223
m_ihandle = heif::ImageHandle();
189224
m_ctx.reset();
225+
m_reader.reset();
190226
m_subimage = -1;
191227
m_num_subimages = 0;
192228
m_associated_alpha = true;

src/heif.imageio/heifoutput.cpp

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ class HeifOutput final : public ImageOutput {
2929
const char* format_name(void) const override { return "heif"; }
3030
int supports(string_view feature) const override
3131
{
32-
return feature == "alpha" || feature == "exif" || feature == "tiles"
32+
return feature == "alpha" || feature == "exif" || feature == "ioproxy"
33+
|| feature == "tiles"
3334
#if LIBHEIF_HAVE_VERSION(1, 9, 0)
3435
|| feature == "cicp"
3536
#endif
@@ -58,12 +59,9 @@ class HeifOutput final : public ImageOutput {
5859
};
5960

6061

61-
62-
namespace {
63-
64-
class MyHeifWriter final : public heif::Context::Writer {
62+
class HeifWriter final : public heif::Context::Writer {
6563
public:
66-
MyHeifWriter(Filesystem::IOProxy* ioproxy)
64+
HeifWriter(Filesystem::IOProxy* ioproxy)
6765
: m_ioproxy(ioproxy)
6866
{
6967
}
@@ -84,9 +82,6 @@ class MyHeifWriter final : public heif::Context::Writer {
8482
Filesystem::IOProxy* m_ioproxy = nullptr;
8583
};
8684

87-
} // namespace
88-
89-
9085

9186
OIIO_PLUGIN_EXPORTS_BEGIN
9287

@@ -114,6 +109,11 @@ HeifOutput::open(const std::string& name, const ImageSpec& newspec,
114109

115110
m_filename = name;
116111

112+
ioproxy_retrieve_from_config(m_spec);
113+
if (!ioproxy_use_or_open(name)) {
114+
return false;
115+
}
116+
117117
m_bitdepth = m_spec.format.size() > TypeUInt8.size() ? 10 : 8;
118118
m_bitdepth = m_spec.get_int_attribute("oiio:BitsPerSample", m_bitdepth);
119119
if (m_bitdepth == 10 || m_bitdepth == 12) {
@@ -221,7 +221,9 @@ HeifOutput::write_tile(int x, int y, int z, TypeDesc format, const void* data,
221221
bool
222222
HeifOutput::close()
223223
{
224-
if (!m_ctx) { // already closed
224+
if (!m_ctx || !ioproxy_opened()) { // already closed
225+
m_ctx.reset();
226+
ioproxy_clear();
225227
return true;
226228
}
227229

@@ -286,25 +288,20 @@ HeifOutput::close()
286288
#endif
287289
}
288290
m_ctx->set_primary_image(m_ihandle);
289-
Filesystem::IOFile ioproxy(m_filename, Filesystem::IOProxy::Write);
290-
if (ioproxy.mode() != Filesystem::IOProxy::Write) {
291-
errorfmt("Could not open \"{}\"", m_filename);
292-
ok = false;
293-
} else {
294-
MyHeifWriter writer(&ioproxy);
295-
m_ctx->write(writer);
296-
}
291+
HeifWriter writer(ioproxy());
292+
m_ctx->write(writer);
297293
} catch (const heif::Error& err) {
298294
std::string e = err.get_message();
299295
errorfmt("{}", e.empty() ? "unknown exception" : e.c_str());
300-
return false;
296+
ok = false;
301297
} catch (const std::exception& err) {
302298
std::string e = err.what();
303299
errorfmt("{}", e.empty() ? "unknown exception" : e.c_str());
304-
return false;
300+
ok = false;
305301
}
306302

307303
m_ctx.reset();
304+
ioproxy_clear();
308305
return ok;
309306
}
310307

0 commit comments

Comments
 (0)