1 // Copyright 2008-present Contributors to the OpenImageIO project.
2 // SPDX-License-Identifier: BSD-3-Clause
3 // https://github.com/OpenImageIO/oiio/blob/master/LICENSE.md
4 
5 #include <cmath>
6 #include <cstdio>
7 #include <cstdlib>
8 #include <memory>
9 #include <vector>
10 
11 #include <OpenImageIO/dassert.h>
12 #include <OpenImageIO/deepdata.h>
13 #include <OpenImageIO/filesystem.h>
14 #include <OpenImageIO/fmath.h>
15 #include <OpenImageIO/imageio.h>
16 #include <OpenImageIO/parallel.h>
17 #include <OpenImageIO/strutil.h>
18 #include <OpenImageIO/typedesc.h>
19 
20 #include "imageio_pvt.h"
21 
22 OIIO_NAMESPACE_BEGIN
23 using namespace pvt;
24 
25 
26 
27 void*
operator new(size_t size)28 ImageInput::operator new(size_t size)
29 {
30     return ::operator new(size);
31     // Note: if we ever need to guarantee alignment, we can change to:
32     // return aligned_malloc (size, alignment);
33 }
34 
35 
36 
37 void
operator delete(void * ptr)38 ImageInput::operator delete(void* ptr)
39 {
40     ImageInput* in = (ImageInput*)ptr;
41     ::operator delete(in);
42     // Note: if we ever need to guarantee alignment, we can change to:
43     // aligned_free (ptr);
44 }
45 
46 
47 
ImageInput()48 ImageInput::ImageInput()
49     : m_threads(0)
50 {
51 }
52 
53 
54 
~ImageInput()55 ImageInput::~ImageInput() {}
56 
57 
58 
59 // Default implementation of valid_file: try to do a full open.  If it
60 // succeeds, it's the right kind of file.  We assume that most plugins
61 // will override this with something smarter and much less expensive,
62 // like reading just the first few bytes of the file to check for magic
63 // numbers.
64 bool
valid_file(const std::string & filename) const65 ImageInput::valid_file(const std::string& filename) const
66 {
67     ImageSpec tmpspec;
68     bool ok = const_cast<ImageInput*>(this)->open(filename, tmpspec);
69     if (ok)
70         const_cast<ImageInput*>(this)->close();
71     return ok;
72 }
73 
74 
75 
76 std::unique_ptr<ImageInput>
open(const std::string & filename,const ImageSpec * config,Filesystem::IOProxy * ioproxy)77 ImageInput::open(const std::string& filename, const ImageSpec* config,
78                  Filesystem::IOProxy* ioproxy)
79 {
80     if (!config) {
81         // Without config, this is really just a call to create-with-open.
82         return ImageInput::create(filename, true, nullptr, ioproxy);
83     }
84 
85     // With config, create without open, then try to open with config.
86     auto in = ImageInput::create(filename, false, config, ioproxy);
87     if (!in)
88         return in;  // create() failed, return the empty ptr
89     ImageSpec newspec;
90     if (!in->open(filename, newspec, *config)) {
91         // The open failed.  Transfer the error from 'in' to the global OIIO
92         // error, delete the ImageInput we allocated, and return NULL.
93         std::string err = in->geterror();
94         if (err.size())
95             OIIO::pvt::errorf("%s", err);
96         in.reset();
97     }
98 
99     return in;
100 }
101 
102 
103 
104 ImageSpec
spec(int subimage,int miplevel)105 ImageInput::spec(int subimage, int miplevel)
106 {
107     // This default base class implementation just locks, calls
108     // seek_subimage, then copies the spec. But ImageInput subclass
109     // implementations are free to do something more efficient, e.g. if they
110     // already internally cache all of the subimage specs and thus don't
111     // need a seek.
112     ImageSpec ret;
113     lock_guard lock(m_mutex);
114     if (seek_subimage(subimage, miplevel))
115         ret = m_spec;
116     return ret;
117     // N.B. single return of named value should guaranteed copy elision.
118 }
119 
120 
121 
122 ImageSpec
spec_dimensions(int subimage,int miplevel)123 ImageInput::spec_dimensions(int subimage, int miplevel)
124 {
125     // This default base class implementation just locks, calls
126     // seek_subimage, then copies the spec. But ImageInput subclass
127     // implementations are free to do something more efficient, e.g. if they
128     // already internally cache all of the subimage specs and thus don't
129     // need a seek.
130     ImageSpec ret;
131     lock_guard lock(m_mutex);
132     if (seek_subimage(subimage, miplevel))
133         ret.copy_dimensions(m_spec);
134     return ret;
135     // N.B. single return of named value should guaranteed copy elision.
136 }
137 
138 
139 
140 bool
read_scanline(int y,int z,TypeDesc format,void * data,stride_t xstride)141 ImageInput::read_scanline(int y, int z, TypeDesc format, void* data,
142                           stride_t xstride)
143 {
144     lock_guard lock(m_mutex);
145 
146     // native_pixel_bytes is the size of a pixel in the FILE, including
147     // the per-channel format.
148     stride_t native_pixel_bytes = (stride_t)m_spec.pixel_bytes(true);
149     // perchanfile is true if the file has different per-channel formats
150     bool perchanfile = m_spec.channelformats.size();
151     // native_data is true if the user asking for data in the native format
152     bool native_data = (format == TypeDesc::UNKNOWN
153                         || (format == m_spec.format && !perchanfile));
154     // buffer_pixel_bytes is the size in the buffer
155     stride_t buffer_pixel_bytes = native_data
156                                       ? native_pixel_bytes
157                                       : format.size() * m_spec.nchannels;
158     if (native_data && xstride == AutoStride)
159         xstride = native_pixel_bytes;
160     else
161         m_spec.auto_stride(xstride, format, m_spec.nchannels);
162     // Do the strides indicate that the data area is contiguous?
163     bool contiguous = (xstride == buffer_pixel_bytes);
164 
165     // If user's format and strides are set up to accept the native data
166     // layout, read the scanline directly into the user's buffer.
167     if (native_data && contiguous)
168         return read_native_scanline(current_subimage(), current_miplevel(), y,
169                                     z, data);
170 
171     // Complex case -- either changing data type or stride
172     int scanline_values = m_spec.width * m_spec.nchannels;
173 
174     unsigned char* buf;
175     OIIO_ALLOCATE_STACK_OR_HEAP(buf, unsigned char,
176                                 m_spec.scanline_bytes(true));
177 
178     bool ok = read_native_scanline(current_subimage(), current_miplevel(), y, z,
179                                    buf);
180     if (!ok)
181         return false;
182     if (m_spec.channelformats.empty()) {
183         // No per-channel formats -- do the conversion in one shot
184         ok = contiguous ? convert_types(m_spec.format, buf, format, data,
185                                         scanline_values)
186                         : convert_image(m_spec.nchannels, m_spec.width, 1, 1,
187                                         buf, m_spec.format, AutoStride,
188                                         AutoStride, AutoStride, data, format,
189                                         xstride, AutoStride, AutoStride);
190     } else {
191         // Per-channel formats -- have to convert/copy channels individually
192         OIIO_DASSERT(m_spec.channelformats.size() == (size_t)m_spec.nchannels);
193         size_t offset = 0;
194         for (int c = 0; ok && c < m_spec.nchannels; ++c) {
195             TypeDesc chanformat = m_spec.channelformats[c];
196             ok = convert_image(1 /* channels */, m_spec.width, 1, 1,
197                                buf + offset, chanformat, native_pixel_bytes,
198                                AutoStride, AutoStride,
199                                (char*)data + c * format.size(), format, xstride,
200                                AutoStride, AutoStride);
201             offset += chanformat.size();
202         }
203     }
204 
205     if (!ok)
206         errorf("ImageInput::read_scanline : no support for format %s",
207                m_spec.format);
208     return ok;
209 }
210 
211 
212 
213 bool
read_scanlines(int ybegin,int yend,int z,TypeDesc format,void * data,stride_t xstride,stride_t ystride)214 ImageInput::read_scanlines(int ybegin, int yend, int z, TypeDesc format,
215                            void* data, stride_t xstride, stride_t ystride)
216 {
217     lock_guard lock(m_mutex);
218     return read_scanlines(current_subimage(), current_miplevel(), ybegin, yend,
219                           z, 0, m_spec.nchannels, format, data, xstride,
220                           ystride);
221 }
222 
223 
224 
225 bool
read_scanlines(int ybegin,int yend,int z,int chbegin,int chend,TypeDesc format,void * data,stride_t xstride,stride_t ystride)226 ImageInput::read_scanlines(int ybegin, int yend, int z, int chbegin, int chend,
227                            TypeDesc format, void* data, stride_t xstride,
228                            stride_t ystride)
229 {
230     lock_guard lock(m_mutex);
231     return read_scanlines(current_subimage(), current_miplevel(), ybegin, yend,
232                           z, chbegin, chend, format, data, xstride, ystride);
233 }
234 
235 
236 
237 bool
read_scanlines(int subimage,int miplevel,int ybegin,int yend,int z,int chbegin,int chend,TypeDesc format,void * data,stride_t xstride,stride_t ystride)238 ImageInput::read_scanlines(int subimage, int miplevel, int ybegin, int yend,
239                            int z, int chbegin, int chend, TypeDesc format,
240                            void* data, stride_t xstride, stride_t ystride)
241 {
242     ImageSpec spec;
243     int rps = 0;
244     {
245         // We need to lock briefly to retrieve rps from the spec
246         lock_guard lock(m_mutex);
247         if (!seek_subimage(subimage, miplevel))
248             return false;
249         // Copying the dimensions of the designated subimage/miplevel to a
250         // local `spec` means that we can release the lock!  (Calls to
251         // read_native_* will internally lock again if necessary.)
252         spec.copy_dimensions(m_spec);
253         // For scanline files, we also need one piece of metadata
254         if (!spec.tile_width)
255             rps = m_spec.get_int_attribute("tiff:RowsPerStrip", 64);
256     }
257     if (spec.image_bytes() < 1) {
258         errorfmt("Invalid image size {} x {} ({} chans)", m_spec.width,
259                  m_spec.height, m_spec.nchannels);
260         return false;
261     }
262 
263     chend                     = clamp(chend, chbegin + 1, spec.nchannels);
264     int nchans                = chend - chbegin;
265     yend                      = std::min(yend, spec.y + spec.height);
266     size_t native_pixel_bytes = spec.pixel_bytes(chbegin, chend, true);
267     imagesize_t native_scanline_bytes
268         = clamped_mult64((imagesize_t)spec.width,
269                          (imagesize_t)native_pixel_bytes);
270     bool native        = (format == TypeDesc::UNKNOWN);
271     size_t pixel_bytes = native ? native_pixel_bytes : format.size() * nchans;
272     if (native && xstride == AutoStride)
273         xstride = pixel_bytes;
274     stride_t zstride = AutoStride;
275     spec.auto_stride(xstride, ystride, zstride, format, nchans, spec.width,
276                      spec.height);
277     stride_t buffer_pixel_bytes    = native ? native_pixel_bytes
278                                             : format.size() * nchans;
279     stride_t buffer_scanline_bytes = native ? native_scanline_bytes
280                                             : buffer_pixel_bytes * spec.width;
281     bool contiguous                = (xstride == (stride_t)buffer_pixel_bytes
282                        && ystride == (stride_t)buffer_scanline_bytes);
283 
284     if (native && contiguous) {
285         if (chbegin == 0 && chend == spec.nchannels)
286             return read_native_scanlines(subimage, miplevel, ybegin, yend, z,
287                                          data);
288         else
289             return read_native_scanlines(subimage, miplevel, ybegin, yend, z,
290                                          chbegin, chend, data);
291     }
292 
293     // No such luck.  Read scanlines in chunks.
294 
295     // Split into reasonable chunks -- try to use around 64 MB, but
296     // round up to a multiple of the TIFF rows per strip (or 64).
297     int chunk = std::max(1, (1 << 26) / int(spec.scanline_bytes(true)));
298     chunk     = std::max(chunk, int(oiio_read_chunk));
299     chunk     = round_to_multiple(chunk, rps);
300     std::unique_ptr<char[]> buf(new char[chunk * native_scanline_bytes]);
301 
302     bool ok             = true;
303     int scanline_values = spec.width * nchans;
304     for (; ok && ybegin < yend; ybegin += chunk) {
305         int y1 = std::min(ybegin + chunk, yend);
306         ok &= read_native_scanlines(subimage, miplevel, ybegin, y1, z, chbegin,
307                                     chend, &buf[0]);
308         if (!ok)
309             break;
310 
311         int nscanlines  = y1 - ybegin;
312         int chunkvalues = scanline_values * nscanlines;
313         if (spec.channelformats.empty()) {
314             // No per-channel formats -- do the conversion in one shot
315             if (contiguous) {
316                 ok = convert_types(spec.format, &buf[0], format, data,
317                                    chunkvalues);
318             } else {
319                 ok = parallel_convert_image(nchans, spec.width, nscanlines, 1,
320                                             &buf[0], spec.format, AutoStride,
321                                             AutoStride, AutoStride, data,
322                                             format, xstride, ystride, zstride,
323                                             threads());
324             }
325         } else {
326             // Per-channel formats -- have to convert/copy channels individually
327             size_t offset = 0;
328             int n         = 1;
329             for (int c = 0; ok && c < nchans; c += n) {
330                 TypeDesc chanformat = spec.channelformats[c + chbegin];
331                 // Try to do more than one channel at a time to improve
332                 // memory coherence, if there are groups of adjacent
333                 // channels needing the same data conversion.
334                 for (n = 1; c + n < nchans; ++n)
335                     if (spec.channelformats[c + chbegin + n] != chanformat)
336                         break;
337                 ok = parallel_convert_image(n /* channels */, spec.width,
338                                             nscanlines, 1, &buf[offset],
339                                             chanformat, native_pixel_bytes,
340                                             AutoStride, AutoStride,
341                                             (char*)data + c * format.size(),
342                                             format, xstride, ystride, zstride,
343                                             threads());
344                 offset += n * chanformat.size();
345             }
346         }
347         if (!ok)
348             errorf("ImageInput::read_scanlines : no support for format %s",
349                    spec.format);
350         data = (char*)data + ystride * nscanlines;
351     }
352     return ok;
353 }
354 
355 
356 
357 bool
read_native_scanlines(int subimage,int miplevel,int ybegin,int yend,int z,void * data)358 ImageInput::read_native_scanlines(int subimage, int miplevel, int ybegin,
359                                   int yend, int z, void* data)
360 {
361     // Base class implementation of read_native_scanlines just repeatedly
362     // calls read_native_scanline, which is supplied by every plugin.
363     // Only the hardcore ones will overload read_native_scanlines with
364     // their own implementation.
365     lock_guard lock(m_mutex);
366     size_t ystride = m_spec.scanline_bytes(true);
367     yend           = std::min(yend, spec().y + spec().height);
368     for (int y = ybegin; y < yend; ++y) {
369         bool ok = read_native_scanline(subimage, miplevel, y, z, data);
370         if (!ok)
371             return false;
372         data = (char*)data + ystride;
373     }
374     return true;
375 }
376 
377 
378 
379 bool
read_native_scanlines(int subimage,int miplevel,int ybegin,int yend,int z,int chbegin,int chend,void * data)380 ImageInput::read_native_scanlines(int subimage, int miplevel, int ybegin,
381                                   int yend, int z, int chbegin, int chend,
382                                   void* data)
383 {
384     ImageSpec spec = spec_dimensions(subimage, miplevel);  // thread-safe
385     if (spec.undefined())
386         return false;
387 
388     // All-channel case just reduces to the simpler read_native_scanlines.
389     if (chbegin == 0 && chend >= spec.nchannels)
390         return read_native_scanlines(subimage, miplevel, ybegin, yend, z, data);
391 
392     // Base class implementation of read_native_scanlines (with channel
393     // subset) just calls read_native_scanlines (all channels), and
394     // copies the appropriate subset.
395     size_t prefix_bytes   = spec.pixel_bytes(0, chbegin, true);
396     size_t subset_bytes   = spec.pixel_bytes(chbegin, chend, true);
397     size_t subset_ystride = size_t(spec.width) * subset_bytes;
398 
399     // Read all channels of the scanlines into a temp buffer.
400     size_t native_pixel_bytes = spec.pixel_bytes(true);
401     size_t native_ystride     = size_t(spec.width) * native_pixel_bytes;
402     std::unique_ptr<char[]> buf(new char[native_ystride * (yend - ybegin)]);
403     yend    = std::min(yend, spec.y + spec.height);
404     bool ok = read_native_scanlines(subimage, miplevel, ybegin, yend, z,
405                                     buf.get());
406     if (!ok)
407         return false;
408 
409     // Now copy out the subset of channels we want. We can do this in
410     // parallel.
411     // clang-format off
412     parallel_for (0, yend-ybegin,
413                   [&,subset_bytes,prefix_bytes,native_pixel_bytes](int64_t y){
414         char *b = buf.get() + native_ystride * y;
415         char *d = (char *)data + subset_ystride * y;
416         for (int x = 0;  x < spec.width;  ++x)
417             memcpy (d + subset_bytes*x,
418                     &b[prefix_bytes+native_pixel_bytes*x], subset_bytes);
419     });
420     // clang-format on
421     return true;
422 }
423 
424 
425 
426 bool
read_tile(int x,int y,int z,TypeDesc format,void * data,stride_t xstride,stride_t ystride,stride_t zstride)427 ImageInput::read_tile(int x, int y, int z, TypeDesc format, void* data,
428                       stride_t xstride, stride_t ystride, stride_t zstride)
429 {
430     lock_guard lock(m_mutex);
431     if (!m_spec.tile_width || ((x - m_spec.x) % m_spec.tile_width) != 0
432         || ((y - m_spec.y) % m_spec.tile_height) != 0
433         || ((z - m_spec.z) % m_spec.tile_depth) != 0)
434         return false;  // coordinates are not a tile corner
435 
436     // native_pixel_bytes is the size of a pixel in the FILE, including
437     // the per-channel format.
438     stride_t native_pixel_bytes = (stride_t)m_spec.pixel_bytes(true);
439     // perchanfile is true if the file has different per-channel formats
440     bool perchanfile = m_spec.channelformats.size();
441     // native_data is true if the user asking for data in the native format
442     bool native_data = (format == TypeDesc::UNKNOWN
443                         || (format == m_spec.format && !perchanfile));
444     if (format == TypeDesc::UNKNOWN && xstride == AutoStride)
445         xstride = native_pixel_bytes;
446     m_spec.auto_stride(xstride, ystride, zstride, format, m_spec.nchannels,
447                        m_spec.tile_width, m_spec.tile_height);
448     stride_t buffer_pixel_bytes = native_data
449                                       ? native_pixel_bytes
450                                       : format.size() * m_spec.nchannels;
451     // Do the strides indicate that the data area is contiguous?
452     bool contiguous
453         = xstride == buffer_pixel_bytes
454           && (ystride == xstride * m_spec.tile_width
455               && (zstride == ystride * m_spec.tile_height || zstride == 0));
456 
457     // If user's format and strides are set up to accept the native data
458     // layout, read the tile directly into the user's buffer.
459     if (native_data && contiguous)
460         return read_native_tile(current_subimage(), current_miplevel(), x, y, z,
461                                 data);  // Simple case
462 
463     // Complex case -- either changing data type or stride
464     size_t tile_values = (size_t)m_spec.tile_pixels() * m_spec.nchannels;
465 
466     std::unique_ptr<char[]> buf(new char[m_spec.tile_bytes(true)]);
467     bool ok = read_native_tile(current_subimage(), current_miplevel(), x, y, z,
468                                &buf[0]);
469     if (!ok)
470         return false;
471     if (m_spec.channelformats.empty()) {
472         // No per-channel formats -- do the conversion in one shot
473         ok = contiguous ? convert_types(m_spec.format, &buf[0], format, data,
474                                         tile_values)
475                         : convert_image(m_spec.nchannels, m_spec.tile_width,
476                                         m_spec.tile_height, m_spec.tile_depth,
477                                         &buf[0], m_spec.format, AutoStride,
478                                         AutoStride, AutoStride, data, format,
479                                         xstride, ystride, zstride);
480     } else {
481         // Per-channel formats -- have to convert/copy channels individually
482         OIIO_DASSERT(m_spec.channelformats.size() == (size_t)m_spec.nchannels);
483         size_t offset = 0;
484         for (int c = 0; c < m_spec.nchannels; ++c) {
485             TypeDesc chanformat = m_spec.channelformats[c];
486             ok = convert_image(1 /* channels */, m_spec.tile_width,
487                                m_spec.tile_height, m_spec.tile_depth,
488                                &buf[offset], chanformat, native_pixel_bytes,
489                                AutoStride, AutoStride,
490                                (char*)data + c * format.size(), format, xstride,
491                                AutoStride, AutoStride);
492             offset += chanformat.size();
493         }
494     }
495 
496     if (!ok)
497         errorf("ImageInput::read_tile : no support for format %s",
498                m_spec.format);
499     return ok;
500 }
501 
502 
503 
504 bool
read_tiles(int xbegin,int xend,int ybegin,int yend,int zbegin,int zend,TypeDesc format,void * data,stride_t xstride,stride_t ystride,stride_t zstride)505 ImageInput::read_tiles(int xbegin, int xend, int ybegin, int yend, int zbegin,
506                        int zend, TypeDesc format, void* data, stride_t xstride,
507                        stride_t ystride, stride_t zstride)
508 {
509     int subimage, miplevel, chend;
510     {
511         lock_guard lock(m_mutex);
512         subimage = current_subimage();
513         miplevel = current_miplevel();
514         chend    = spec().nchannels;
515     }
516     return read_tiles(subimage, miplevel, xbegin, xend, ybegin, yend, zbegin,
517                       zend, 0, chend, format, data, xstride, ystride, zstride);
518 }
519 
520 
521 
522 bool
read_tiles(int xbegin,int xend,int ybegin,int yend,int zbegin,int zend,int chbegin,int chend,TypeDesc format,void * data,stride_t xstride,stride_t ystride,stride_t zstride)523 ImageInput::read_tiles(int xbegin, int xend, int ybegin, int yend, int zbegin,
524                        int zend, int chbegin, int chend, TypeDesc format,
525                        void* data, stride_t xstride, stride_t ystride,
526                        stride_t zstride)
527 {
528     int subimage, miplevel;
529     {
530         lock_guard lock(m_mutex);
531         subimage = current_subimage();
532         miplevel = current_miplevel();
533     }
534     return read_tiles(subimage, miplevel, xbegin, xend, ybegin, yend, zbegin,
535                       zend, chbegin, chend, format, data, xstride, ystride,
536                       zstride);
537 }
538 
539 
540 
541 bool
read_tiles(int subimage,int miplevel,int xbegin,int xend,int ybegin,int yend,int zbegin,int zend,int chbegin,int chend,TypeDesc format,void * data,stride_t xstride,stride_t ystride,stride_t zstride)542 ImageInput::read_tiles(int subimage, int miplevel, int xbegin, int xend,
543                        int ybegin, int yend, int zbegin, int zend, int chbegin,
544                        int chend, TypeDesc format, void* data, stride_t xstride,
545                        stride_t ystride, stride_t zstride)
546 {
547     ImageSpec spec = spec_dimensions(subimage, miplevel);  // thread-safe
548     if (spec.undefined())
549         return false;
550 
551     chend = clamp(chend, chbegin + 1, spec.nchannels);
552     if (!spec.valid_tile_range(xbegin, xend, ybegin, yend, zbegin, zend))
553         return false;
554 
555     int nchans = chend - chbegin;
556     // native_pixel_bytes is the size of a pixel in the FILE, including
557     // the per-channel format.
558     stride_t native_pixel_bytes = (stride_t)spec.pixel_bytes(chbegin, chend,
559                                                              true);
560     // perchanfile is true if the file has different per-channel formats
561     bool perchanfile = spec.channelformats.size();
562     // native_data is true if the user asking for data in the native format
563     bool native_data = (format == TypeDesc::UNKNOWN
564                         || (format == spec.format && !perchanfile));
565     if (format == TypeDesc::UNKNOWN && xstride == AutoStride)
566         xstride = native_pixel_bytes;
567     spec.auto_stride(xstride, ystride, zstride, format, nchans, xend - xbegin,
568                      yend - ybegin);
569     // Do the strides indicate that the data area is contiguous?
570     bool contiguous = (native_data && xstride == native_pixel_bytes)
571                       || (!native_data
572                           && xstride == (stride_t)spec.pixel_bytes(false));
573     contiguous
574         &= (ystride == xstride * (xend - xbegin)
575             && (zstride == ystride * (yend - ybegin) || (zend - zbegin) <= 1));
576 
577     int nxtiles = (xend - xbegin + spec.tile_width - 1) / spec.tile_width;
578     int nytiles = (yend - ybegin + spec.tile_height - 1) / spec.tile_height;
579     int nztiles = (zend - zbegin + spec.tile_depth - 1) / spec.tile_depth;
580 
581     // If user's format and strides are set up to accept the native data
582     // layout, and we're asking for a whole number of tiles (no partial
583     // tiles at the edges), then read the tile directly into the user's
584     // buffer.
585     if (native_data && contiguous
586         && (xend - xbegin) == nxtiles * spec.tile_width
587         && (yend - ybegin) == nytiles * spec.tile_height
588         && (zend - zbegin) == nztiles * spec.tile_depth) {
589         if (chbegin == 0 && chend == spec.nchannels)
590             return read_native_tiles(subimage, miplevel, xbegin, xend, ybegin,
591                                      yend, zbegin, zend,
592                                      data);  // Simple case
593         else
594             return read_native_tiles(subimage, miplevel, xbegin, xend, ybegin,
595                                      yend, zbegin, zend, chbegin, chend, data);
596     }
597 
598     // No such luck.  Just punt and read tiles individually.
599     bool ok                        = true;
600     stride_t pixelsize             = native_data ? native_pixel_bytes
601                                                  : (format.size() * nchans);
602     stride_t native_pixelsize      = spec.pixel_bytes(true);
603     stride_t full_pixelsize        = native_data ? native_pixelsize
604                                                  : (format.size() * spec.nchannels);
605     stride_t full_tilewidthbytes   = full_pixelsize * spec.tile_width;
606     stride_t full_tilewhbytes      = full_tilewidthbytes * spec.tile_height;
607     stride_t full_tilebytes        = full_tilewhbytes * spec.tile_depth;
608     stride_t full_native_tilebytes = spec.tile_bytes(true);
609     size_t prefix_bytes = native_data ? spec.pixel_bytes(0, chbegin, true)
610                                       : format.size() * chbegin;
611     bool allchans       = (chbegin == 0 && chend == spec.nchannels);
612     std::vector<char> buf;
613     for (int z = zbegin; z < zend; z += std::max(1, spec.tile_depth)) {
614         int zd      = std::min(zend - z, spec.tile_depth);
615         bool full_z = (zd == spec.tile_depth);
616         for (int y = ybegin; ok && y < yend; y += spec.tile_height) {
617             char* tilestart = ((char*)data + (z - zbegin) * zstride
618                                + (y - ybegin) * ystride);
619             int yh          = std::min(yend - y, spec.tile_height);
620             bool full_y     = (yh == spec.tile_height);
621             int x           = xbegin;
622             // If we're reading full y and z tiles and not doing any funny
623             // business with channels, try to read as many complete x tiles
624             // as we can in this row.
625             int x_full_tiles = (xend - xbegin) / spec.tile_width;
626             if (full_z && full_y && allchans && !perchanfile
627                 && x_full_tiles >= 1) {
628                 int x_full_tile_end = xbegin + x_full_tiles * spec.tile_width;
629                 if (buf.size() < size_t(full_native_tilebytes * x_full_tiles))
630                     buf.resize(full_native_tilebytes * x_full_tiles);
631                 ok &= read_native_tiles(subimage, miplevel, xbegin,
632                                         x_full_tile_end, y, y + yh, z, z + zd,
633                                         chbegin, chend, &buf[0]);
634                 if (ok)
635                     convert_image(nchans, x_full_tiles * spec.tile_width, yh,
636                                   zd, &buf[0], spec.format, native_pixelsize,
637                                   native_pixelsize * x_full_tiles
638                                       * spec.tile_width,
639                                   native_pixelsize * x_full_tiles
640                                       * spec.tile_width * spec.tile_height,
641                                   tilestart, format, xstride, ystride, zstride);
642                 tilestart += x_full_tiles * spec.tile_width * xstride;
643                 x += x_full_tiles * spec.tile_width;
644             }
645 
646             // Now get the rest in the row, anything that is only a
647             // partial tile, which needs extra care.
648             // Since we are here relying on the non-thread-safe read_tile()
649             // call, we re-establish the lock and make sure we're on the
650             // right subimage/miplevel.
651             for (; ok && x < xend; x += spec.tile_width) {
652                 int xw      = std::min(xend - x, spec.tile_width);
653                 bool full_x = (xw == spec.tile_width);
654                 // Full tiles are read directly into the user buffer,
655                 // but partial tiles (such as at the image edge) or
656                 // partial channel subsets are read into a buffer and
657                 // then copied.
658                 if (full_x && full_y && full_z && allchans && !perchanfile) {
659                     // Full tile, either native data or not needing
660                     // per-tile data format conversion.
661                     lock_guard lock(m_mutex);
662                     if (!seek_subimage(subimage, miplevel))
663                         return false;
664                     ok &= read_tile(x, y, z, format, tilestart, xstride,
665                                     ystride, zstride);
666                     if (!ok)
667                         return false;
668                 } else {
669                     if (buf.size() < size_t(full_tilebytes))
670                         buf.resize(full_tilebytes);
671                     {
672                         lock_guard lock(m_mutex);
673                         if (!seek_subimage(subimage, miplevel))
674                             return false;
675                         ok &= read_tile(x, y, z, format, &buf[0],
676                                         full_pixelsize, full_tilewidthbytes,
677                                         full_tilewhbytes);
678                     }
679                     if (ok)
680                         copy_image(nchans, xw, yh, zd, &buf[prefix_bytes],
681                                    pixelsize, full_pixelsize,
682                                    full_tilewidthbytes, full_tilewhbytes,
683                                    tilestart, xstride, ystride, zstride);
684                     // N.B. It looks like read_tiles doesn't handle the
685                     // per-channel data types case fully, but it does!
686                     // The call to read_tile() above handles the case of
687                     // per-channel data types, converting to to desired
688                     // format, so all we have to do on our own is the
689                     // copy_image.
690                 }
691                 tilestart += spec.tile_width * xstride;
692             }
693             if (!ok)
694                 break;
695         }
696     }
697 
698     return ok;
699 }
700 
701 
702 
703 bool
read_native_tile(int,int,int,int,int,void *)704 ImageInput::read_native_tile(int /*subimage*/, int /*miplevel*/, int /*x*/,
705                              int /*y*/, int /*z*/, void* /*data*/)
706 {
707     // The base class read_native_tile fails. A format reader that supports
708     // tiles MUST overload this virtual method that reads a single tile
709     // (all channels).
710     return false;
711 }
712 
713 
714 bool
read_native_tiles(int subimage,int miplevel,int xbegin,int xend,int ybegin,int yend,int zbegin,int zend,void * data)715 ImageInput::read_native_tiles(int subimage, int miplevel, int xbegin, int xend,
716                               int ybegin, int yend, int zbegin, int zend,
717                               void* data)
718 {
719     // A format reader that supports reading multiple tiles at once (in
720     // a way that's more efficient than reading the tiles one at a time)
721     // is advised (but not required) to overload this virtual method.
722     // If an ImageInput subclass does not overload this, the default
723     // implementation here is simply to loop over the tiles, calling the
724     // single-tile read_native_tile() for each one.
725     ImageSpec spec = spec_dimensions(subimage, miplevel);  // thread-safe
726     if (spec.undefined())
727         return false;
728     if (!spec.valid_tile_range(xbegin, xend, ybegin, yend, zbegin, zend))
729         return false;
730 
731     // Base class implementation of read_native_tiles just repeatedly
732     // calls read_native_tile, which is supplied by every plugin that
733     // supports tiles.  Only the hardcore ones will overload
734     // read_native_tiles with their own implementation.
735     stride_t pixel_bytes = (stride_t)spec.pixel_bytes(true);
736     stride_t tileystride = pixel_bytes * spec.tile_width;
737     stride_t tilezstride = tileystride * spec.tile_height;
738     stride_t ystride     = (xend - xbegin) * pixel_bytes;
739     stride_t zstride     = (yend - ybegin) * ystride;
740     std::unique_ptr<char[]> pels(new char[spec.tile_bytes(true)]);
741     for (int z = zbegin; z < zend; z += spec.tile_depth) {
742         for (int y = ybegin; y < yend; y += spec.tile_height) {
743             for (int x = xbegin; x < xend; x += spec.tile_width) {
744                 bool ok = read_native_tile(subimage, miplevel, x, y, z,
745                                            &pels[0]);
746                 if (!ok)
747                     return false;
748                 copy_image(spec.nchannels, spec.tile_width, spec.tile_height,
749                            spec.tile_depth, &pels[0], size_t(pixel_bytes),
750                            pixel_bytes, tileystride, tilezstride,
751                            (char*)data + (z - zbegin) * zstride
752                                + (y - ybegin) * ystride
753                                + (x - xbegin) * pixel_bytes,
754                            pixel_bytes, ystride, zstride);
755             }
756         }
757     }
758     return true;
759 }
760 
761 
762 
763 bool
read_native_tiles(int subimage,int miplevel,int xbegin,int xend,int ybegin,int yend,int zbegin,int zend,int chbegin,int chend,void * data)764 ImageInput::read_native_tiles(int subimage, int miplevel, int xbegin, int xend,
765                               int ybegin, int yend, int zbegin, int zend,
766                               int chbegin, int chend, void* data)
767 {
768     // A format reader that supports reading multiple tiles at once, and can
769     // handle a channel subset while doing so, is advised (but not required)
770     // to overload this virtual method. If an ImageInput subclass does not
771     // overload this, the default implementation here is simply to loop over
772     // the tiles, calling the single-tile read_native_tile() for each one
773     // (and copying carefully to handle the channel subset issues).
774     ImageSpec spec = spec_dimensions(subimage, miplevel);  // thread-safe
775     if (spec.undefined())
776         return false;
777 
778     chend = clamp(chend, chbegin + 1, spec.nchannels);
779     // All-channel case just reduces to the simpler version of
780     // read_native_tiles.
781     if (chbegin == 0 && chend >= spec.nchannels)
782         return read_native_tiles(subimage, miplevel, xbegin, xend, ybegin, yend,
783                                  zbegin, zend, data);
784     // More complicated cases follow.
785 
786     if (!spec.valid_tile_range(xbegin, xend, ybegin, yend, zbegin, zend))
787         return false;
788 
789     // Base class implementation of read_native_tiles just repeatedly
790     // calls read_native_tile, which is supplied by every plugin that
791     // supports tiles.  Only the hardcore ones will overload
792     // read_native_tiles with their own implementation.
793 
794     int nchans                  = chend - chbegin;
795     stride_t native_pixel_bytes = (stride_t)spec.pixel_bytes(true);
796     stride_t native_tileystride = native_pixel_bytes * spec.tile_width;
797     stride_t native_tilezstride = native_tileystride * spec.tile_height;
798 
799     size_t prefix_bytes     = spec.pixel_bytes(0, chbegin, true);
800     size_t subset_bytes     = spec.pixel_bytes(chbegin, chend, true);
801     stride_t subset_ystride = (xend - xbegin) * subset_bytes;
802     stride_t subset_zstride = (yend - ybegin) * subset_ystride;
803 
804     std::unique_ptr<char[]> pels(new char[spec.tile_bytes(true)]);
805     for (int z = zbegin; z < zend; z += spec.tile_depth) {
806         for (int y = ybegin; y < yend; y += spec.tile_height) {
807             for (int x = xbegin; x < xend; x += spec.tile_width) {
808                 bool ok = read_native_tile(subimage, miplevel, x, y, z,
809                                            &pels[0]);
810                 if (!ok)
811                     return false;
812                 copy_image(nchans, spec.tile_width, spec.tile_height,
813                            spec.tile_depth, &pels[prefix_bytes], subset_bytes,
814                            native_pixel_bytes, native_tileystride,
815                            native_tilezstride,
816                            (char*)data + (z - zbegin) * subset_zstride
817                                + (y - ybegin) * subset_ystride
818                                + (x - xbegin) * subset_bytes,
819                            subset_bytes, subset_ystride, subset_zstride);
820             }
821         }
822     }
823     return true;
824 }
825 
826 
827 
828 bool
read_image(TypeDesc format,void * data,stride_t xstride,stride_t ystride,stride_t zstride,ProgressCallback progress_callback,void * progress_callback_data)829 ImageInput::read_image(TypeDesc format, void* data, stride_t xstride,
830                        stride_t ystride, stride_t zstride,
831                        ProgressCallback progress_callback,
832                        void* progress_callback_data)
833 {
834     return read_image(0, -1, format, data, xstride, ystride, zstride,
835                       progress_callback, progress_callback_data);
836 }
837 
838 
839 
840 bool
read_image(int chbegin,int chend,TypeDesc format,void * data,stride_t xstride,stride_t ystride,stride_t zstride,ProgressCallback progress_callback,void * progress_callback_data)841 ImageInput::read_image(int chbegin, int chend, TypeDesc format, void* data,
842                        stride_t xstride, stride_t ystride, stride_t zstride,
843                        ProgressCallback progress_callback,
844                        void* progress_callback_data)
845 {
846     int subimage, miplevel;
847     {
848         lock_guard lock(m_mutex);
849         subimage = current_subimage();
850         miplevel = current_miplevel();
851     }
852     return read_image(subimage, miplevel, chbegin, chend, format, data, xstride,
853                       ystride, zstride, progress_callback,
854                       progress_callback_data);
855 }
856 
857 
858 
859 bool
read_image(int subimage,int miplevel,int chbegin,int chend,TypeDesc format,void * data,stride_t xstride,stride_t ystride,stride_t zstride,ProgressCallback progress_callback,void * progress_callback_data)860 ImageInput::read_image(int subimage, int miplevel, int chbegin, int chend,
861                        TypeDesc format, void* data, stride_t xstride,
862                        stride_t ystride, stride_t zstride,
863                        ProgressCallback progress_callback,
864                        void* progress_callback_data)
865 {
866     ImageSpec spec;
867     int rps = 0;
868     {
869         // We need to lock briefly to retrieve rps from the spec
870         lock_guard lock(m_mutex);
871         if (!seek_subimage(subimage, miplevel))
872             return false;
873         // Copying the dimensions of the designated subimage/miplevel to a
874         // local `spec` means that we can release the lock!  (Calls to
875         // read_native_* will internally lock again if necessary.)
876         spec.copy_dimensions(m_spec);
877         // For scanline files, we also need one piece of metadata
878         if (!spec.tile_width)
879             rps = m_spec.get_int_attribute("tiff:RowsPerStrip", 64);
880     }
881     if (spec.image_bytes() < 1) {
882         errorfmt("Invalid image size {} x {} ({} chans)", m_spec.width,
883                  m_spec.height, m_spec.nchannels);
884         return false;
885     }
886 
887     if (chend < 0)
888         chend = spec.nchannels;
889     chend                = clamp(chend, chbegin + 1, spec.nchannels);
890     int nchans           = chend - chbegin;
891     bool native          = (format == TypeDesc::UNKNOWN);
892     stride_t pixel_bytes = native ? (stride_t)spec.pixel_bytes(chbegin, chend,
893                                                                native)
894                                   : (stride_t)(format.size() * nchans);
895     if (native && xstride == AutoStride)
896         xstride = pixel_bytes;
897     spec.auto_stride(xstride, ystride, zstride, format, nchans, spec.width,
898                      spec.height);
899     bool ok = true;
900     if (progress_callback)
901         if (progress_callback(progress_callback_data, 0.0f))
902             return ok;
903     if (spec.tile_width) {  // Tiled image -- rely on read_tiles
904         // Read in chunks of a whole row of tiles at once. If tiles are
905         // 64x64, a 2k image has 32 tiles across. That's fine for now (for
906         // parallelization purposes), but as typical core counts increase,
907         // we may someday want to revisit this to batch multiple rows.
908         for (int z = 0; z < spec.depth; z += spec.tile_depth) {
909             for (int y = 0; y < spec.height && ok; y += spec.tile_height) {
910                 ok &= read_tiles(subimage, miplevel, spec.x,
911                                  spec.x + spec.width, y + spec.y,
912                                  std::min(y + spec.y + spec.tile_height,
913                                           spec.y + spec.height),
914                                  z + spec.z,
915                                  std::min(z + spec.z + spec.tile_depth,
916                                           spec.z + spec.depth),
917                                  chbegin, chend, format,
918                                  (char*)data + z * zstride + y * ystride,
919                                  xstride, ystride, zstride);
920                 if (progress_callback
921                     && progress_callback(progress_callback_data,
922                                          (float)y / spec.height))
923                     return ok;
924             }
925         }
926     } else {  // Scanline image -- rely on read_scanlines.
927         // Split into reasonable chunks -- try to use around 64 MB or the
928         // oiio_read_chunk value, which ever is bigger, but also round up to
929         // a multiple of the TIFF rows per strip (or 64).
930         int chunk = std::max(1, (1 << 26) / int(spec.scanline_bytes(true)));
931         chunk     = std::max(chunk, int(oiio_read_chunk));
932         chunk     = round_to_multiple(chunk, rps);
933         for (int z = 0; z < spec.depth; ++z) {
934             for (int y = 0; y < spec.height && ok; y += chunk) {
935                 int yend = std::min(y + spec.y + chunk, spec.y + spec.height);
936                 ok &= read_scanlines(subimage, miplevel, y + spec.y, yend,
937                                      z + spec.z, chbegin, chend, format,
938                                      (char*)data + z * zstride + y * ystride,
939                                      xstride, ystride);
940                 if (progress_callback)
941                     if (progress_callback(progress_callback_data,
942                                           (float)y / spec.height))
943                         return ok;
944             }
945         }
946     }
947     if (progress_callback)
948         progress_callback(progress_callback_data, 1.0f);
949     return ok;
950 }
951 
952 
953 
954 bool
read_native_deep_scanlines(int,int,int,int,int,int,int,DeepData &)955 ImageInput::read_native_deep_scanlines(int /*subimage*/, int /*miplevel*/,
956                                        int /*ybegin*/, int /*yend*/, int /*z*/,
957                                        int /*chbegin*/, int /*chend*/,
958                                        DeepData& /*deepdata*/)
959 {
960     return false;  // default: doesn't support deep images
961 }
962 
963 
964 
965 bool
read_native_deep_tiles(int,int,int,int,int,int,int,int,int,int,DeepData &)966 ImageInput::read_native_deep_tiles(int /*subimage*/, int /*miplevel*/,
967                                    int /*xbegin*/, int /*xend*/, int /*ybegin*/,
968                                    int /*yend*/, int /*zbegin*/, int /*zend*/,
969                                    int /*chbegin*/, int /*chend*/,
970                                    DeepData& /*deepdata*/)
971 {
972     return false;  // default: doesn't support deep images
973 }
974 
975 
976 
977 bool
read_native_deep_image(int subimage,int miplevel,DeepData & deepdata)978 ImageInput::read_native_deep_image(int subimage, int miplevel,
979                                    DeepData& deepdata)
980 {
981     ImageSpec spec = spec_dimensions(subimage, miplevel);  // thread-safe
982     if (spec.undefined())
983         return false;
984 
985     if (spec.depth > 1) {
986         errorf(
987             "read_native_deep_image is not supported for volume (3D) images.");
988         return false;
989         // FIXME? - not implementing 3D deep images for now.  The only
990         // format that supports deep images at this time is OpenEXR, and
991         // it doesn't support volumes.
992     }
993     if (spec.tile_width) {
994         // Tiled image
995         return read_native_deep_tiles(subimage, miplevel, spec.x,
996                                       spec.x + spec.width, spec.y,
997                                       spec.y + spec.height, spec.z,
998                                       spec.z + spec.depth, 0, spec.nchannels,
999                                       deepdata);
1000     } else {
1001         // Scanline image
1002         return read_native_deep_scanlines(subimage, miplevel, spec.y,
1003                                           spec.y + spec.height, 0, 0,
1004                                           spec.nchannels, deepdata);
1005     }
1006 }
1007 
1008 
1009 
1010 int
send_to_input(const char *,...)1011 ImageInput::send_to_input(const char* /*format*/, ...)
1012 {
1013     // FIXME -- I can't remember how this is supposed to work
1014     return 0;
1015 }
1016 
1017 
1018 
1019 int
send_to_client(const char *,...)1020 ImageInput::send_to_client(const char* /*format*/, ...)
1021 {
1022     // FIXME -- I can't remember how this is supposed to work
1023     return 0;
1024 }
1025 
1026 
1027 
1028 void
append_error(const std::string & message) const1029 ImageInput::append_error(const std::string& message) const
1030 {
1031     lock_guard lock(m_mutex);
1032     OIIO_DASSERT(
1033         m_errmessage.size() < 1024 * 1024 * 16
1034         && "Accumulated error messages > 16MB. Try checking return codes!");
1035     if (m_errmessage.size())
1036         m_errmessage += '\n';
1037     m_errmessage += message;
1038 }
1039 
1040 OIIO_NAMESPACE_END
1041