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