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 <cassert>
6 #include <cmath>
7 #include <cstdio>
8 #include <cstdlib>
9
10 #include <OpenImageIO/dassert.h>
11 #include <OpenImageIO/filesystem.h>
12 #include <OpenImageIO/imagebufalgo_util.h>
13 #include <OpenImageIO/imageio.h>
14
15 #include "rla_pvt.h"
16
17 OIIO_PLUGIN_NAMESPACE_BEGIN
18
19 using namespace RLA_pvt;
20
21
22 class RLAInput final : public ImageInput {
23 public:
RLAInput()24 RLAInput() { init(); }
~RLAInput()25 virtual ~RLAInput() { close(); }
format_name(void) const26 virtual const char* format_name(void) const override { return "rla"; }
27 virtual bool open(const std::string& name, ImageSpec& newspec) override;
current_subimage(void) const28 virtual int current_subimage(void) const override
29 {
30 lock_guard lock(m_mutex);
31 return m_subimage;
32 }
33 virtual bool seek_subimage(int subimage, int miplevel) override;
34 virtual bool close() override;
35 virtual bool read_native_scanline(int subimage, int miplevel, int y, int z,
36 void* data) override;
37
38 private:
39 std::string m_filename; ///< Stash the filename
40 FILE* m_file; ///< Open image handle
41 RLAHeader m_rla; ///< Wavefront RLA header
42 std::vector<unsigned char> m_buf; ///< Buffer the image pixels
43 int m_subimage; ///< Current subimage index
44 std::vector<uint32_t> m_sot; ///< Scanline offsets table
45 int m_stride; ///< Number of bytes a contig pixel takes
46
47 /// Reset everything to initial state
48 ///
init()49 void init()
50 {
51 m_file = NULL;
52 m_buf.clear();
53 }
54
55 /// Helper: raw read, with error detection
56 ///
fread(void * buf,size_t itemsize,size_t nitems)57 bool fread(void* buf, size_t itemsize, size_t nitems)
58 {
59 size_t n = ::fread(buf, itemsize, nitems, m_file);
60 if (n != nitems)
61 errorf("Read error: read %d records but %d expected %s", (int)n,
62 (int)nitems, feof(m_file) ? " (hit EOF)" : "");
63 return n == nitems;
64 }
65
66 /// Helper: read buf[0..nitems-1], swap endianness if necessary
read(T * buf,size_t nitems=1)67 template<typename T> bool read(T* buf, size_t nitems = 1)
68 {
69 if (!fread(buf, sizeof(T), nitems))
70 return false;
71 if (littleendian()
72 && (is_same<T, uint16_t>::value || is_same<T, int16_t>::value
73 || is_same<T, uint32_t>::value || is_same<T, int32_t>::value)) {
74 swap_endian(buf, nitems);
75 }
76 return true;
77 }
78
79 /// Helper function: translate 3-letter month abbreviation to number.
80 ///
81 inline int get_month_number(const char* s);
82
83 /// Helper: read the RLA header and scanline offset table.
84 ///
85 inline bool read_header();
86
87 /// Helper: read and decode a single channel group consisting of
88 /// channels [first_channel .. first_channel+num_channels-1], which
89 /// all share the same number of significant bits.
90 bool decode_channel_group(int first_channel, short num_channels,
91 short num_bits, int y);
92
93 /// Helper: decode a span of n RLE-encoded bytes from encoded[0..elen-1]
94 /// into buf[0],buf[stride],buf[2*stride]...buf[(n-1)*stride].
95 /// Return the number of encoded bytes we ate to fill buf.
96 size_t decode_rle_span(unsigned char* buf, int n, int stride,
97 const char* encoded, size_t elen);
98
99 /// Helper: determine channel TypeDesc
100 inline TypeDesc get_channel_typedesc(short chan_type, short chan_bits);
101
102 // debugging aid
preview(std::ostream & out)103 void preview(std::ostream& out)
104 {
105 OIIO_DASSERT(!feof(m_file));
106 long pos = ftell(m_file);
107 out << "@" << pos << ", next 4 bytes are ";
108 union { // trickery to avoid punned pointer warnings
109 unsigned char c[4];
110 uint16_t s[2];
111 uint32_t i;
112 } u;
113 read(&u.c, 4); // because it's char, it didn't swap endian
114 uint16_t s[2] = { u.s[0], u.s[1] };
115 uint32_t i = u.i;
116 if (littleendian()) {
117 swap_endian(s, 2);
118 swap_endian(&i);
119 }
120 out << Strutil::sprintf("%d/%u %d/%u %d/%u %d/%u (%d %d) (%u)\n",
121 u.c[0], ((char*)u.c)[0], u.c[1],
122 ((char*)u.c)[1], u.c[2], ((char*)u.c)[2],
123 u.c[3], ((char*)u.c)[3], s[0], s[1], i);
124 fseek(m_file, pos, SEEK_SET);
125 }
126 };
127
128
129
130 // Obligatory material to make this a recognizeable imageio plugin:
131 OIIO_PLUGIN_EXPORTS_BEGIN
132
133 OIIO_EXPORT ImageInput*
rla_input_imageio_create()134 rla_input_imageio_create()
135 {
136 return new RLAInput;
137 }
138
139 OIIO_EXPORT int rla_imageio_version = OIIO_PLUGIN_VERSION;
140
141 OIIO_EXPORT const char*
rla_imageio_library_version()142 rla_imageio_library_version()
143 {
144 return nullptr;
145 }
146
147 OIIO_EXPORT const char* rla_input_extensions[] = { "rla", nullptr };
148
149 OIIO_PLUGIN_EXPORTS_END
150
151
152
153 bool
open(const std::string & name,ImageSpec & newspec)154 RLAInput::open(const std::string& name, ImageSpec& newspec)
155 {
156 m_filename = name;
157
158 m_file = Filesystem::fopen(name, "rb");
159 if (!m_file) {
160 errorf("Could not open file \"%s\"", name);
161 return false;
162 }
163
164 // set a bogus subimage index so that seek_subimage actually seeks
165 m_subimage = 1;
166
167 bool ok = seek_subimage(0, 0);
168 newspec = spec();
169 return ok;
170 }
171
172
173
174 inline bool
read_header()175 RLAInput::read_header()
176 {
177 // Read the image header, which should have the same exact layout as
178 // the m_rla structure (except for endianness issues).
179 static_assert(sizeof(m_rla) == 740, "Bad RLA struct size");
180 if (!read(&m_rla)) {
181 errorf("RLA could not read the image header");
182 return false;
183 }
184 m_rla.rla_swap_endian(); // fix endianness
185
186 if (m_rla.Revision != (int16_t)0xFFFE
187 && m_rla.Revision != 0 /* for some reason, this can happen */) {
188 errorf("RLA header Revision number unrecognized: %d", m_rla.Revision);
189 return false; // unknown file revision
190 }
191 if (m_rla.NumOfChannelBits < 0 || m_rla.NumOfChannelBits > 32
192 || m_rla.NumOfMatteBits < 0 || m_rla.NumOfMatteBits > 32
193 || m_rla.NumOfAuxBits < 0 || m_rla.NumOfAuxBits > 32) {
194 errorf("Unsupported bit depth, or maybe corrupted file.");
195 return false;
196 }
197 if (m_rla.NumOfChannelBits == 0)
198 m_rla.NumOfChannelBits = 8; // apparently, this can happen
199
200 // Immediately following the header is the scanline offset table --
201 // one uint32_t for each scanline, giving absolute offsets (from the
202 // beginning of the file) where the RLE records start for each
203 // scanline of this subimage.
204 m_sot.resize(std::abs(m_rla.ActiveBottom - m_rla.ActiveTop) + 1, 0);
205 if (!read(&m_sot[0], m_sot.size())) {
206 errorf("RLA could not read the scanline offset table");
207 return false;
208 }
209 return true;
210 }
211
212
213
214 bool
seek_subimage(int subimage,int miplevel)215 RLAInput::seek_subimage(int subimage, int miplevel)
216 {
217 if (miplevel != 0 || subimage < 0)
218 return false;
219
220 if (subimage == current_subimage())
221 return true; // already on the right level
222
223 // RLA images allow multiple subimages; they are simply concatenated
224 // together, wth image N's header field NextOffset giving the
225 // absolute offset of the start of image N+1.
226 int diff = subimage - current_subimage();
227 if (subimage - current_subimage() < 0) {
228 // If we are requesting an image earlier than the current one,
229 // reset to the first subimage.
230 fseek(m_file, 0, SEEK_SET);
231 if (!read_header())
232 return false; // read_header always calls error()
233 diff = subimage;
234 }
235 // forward scrolling -- skip subimages until we're at the right place
236 while (diff > 0 && m_rla.NextOffset != 0) {
237 if (!fseek(m_file, m_rla.NextOffset, SEEK_SET)) {
238 errorf("Could not seek to header offset. Corrupted file?");
239 return false;
240 }
241 if (!read_header())
242 return false; // read_header always calls error()
243 --diff;
244 }
245 if (diff > 0 && m_rla.NextOffset == 0) { // no more subimages to read
246 errorf("Unknown subimage");
247 return false;
248 }
249
250 // Now m_rla holds the header of the requested subimage. Examine it
251 // to fill out our ImageSpec.
252
253 if (m_rla.ColorChannelType < 0 || m_rla.ColorChannelType > CT_FLOAT) {
254 errorf("Illegal color channel type: %d", m_rla.ColorChannelType);
255 return false;
256 }
257 if (m_rla.MatteChannelType < 0 || m_rla.MatteChannelType > CT_FLOAT) {
258 errorf("Illegal matte channel type: %d", m_rla.MatteChannelType);
259 return false;
260 }
261 if (m_rla.AuxChannelType < 0 || m_rla.AuxChannelType > CT_FLOAT) {
262 errorf("Illegal auxiliary channel type: %d", m_rla.AuxChannelType);
263 return false;
264 }
265
266 // pick maximum precision for the time being
267 TypeDesc col_type = get_channel_typedesc(m_rla.ColorChannelType,
268 m_rla.NumOfChannelBits);
269 TypeDesc mat_type = m_rla.NumOfMatteChannels
270 ? get_channel_typedesc(m_rla.MatteChannelType,
271 m_rla.NumOfMatteBits)
272 : TypeUnknown;
273 TypeDesc aux_type = m_rla.NumOfAuxChannels
274 ? get_channel_typedesc(m_rla.AuxChannelType,
275 m_rla.NumOfAuxBits)
276 : TypeUnknown;
277 TypeDesc maxtype = ImageBufAlgo::type_merge(col_type, mat_type, aux_type);
278 if (maxtype == TypeUnknown) {
279 errorf("Failed channel bytes sanity check");
280 return false; // failed sanity check
281 }
282
283 if (m_rla.NumOfColorChannels < 1 || m_rla.NumOfColorChannels > 3
284 || m_rla.NumOfMatteChannels < 0 || m_rla.NumOfMatteChannels > 3
285 || m_rla.NumOfAuxChannels < 0 || m_rla.NumOfAuxChannels > 256) {
286 errorf(
287 "Invalid number of channels (%d color, %d matte, %d aux), or corrupted header.",
288 m_rla.NumOfColorChannels, m_rla.NumOfMatteChannels,
289 m_rla.NumOfAuxChannels);
290 return false;
291 }
292 m_spec = ImageSpec(m_rla.ActiveRight - m_rla.ActiveLeft + 1,
293 (m_rla.ActiveTop - m_rla.ActiveBottom + 1)
294 / (m_rla.FieldRendered ? 2 : 1), // interlaced image?
295 m_rla.NumOfColorChannels + m_rla.NumOfMatteChannels
296 + m_rla.NumOfAuxChannels,
297 maxtype);
298
299 // set window dimensions etc.
300 m_spec.x = m_rla.ActiveLeft;
301 m_spec.y = m_spec.height - 1 - m_rla.ActiveTop;
302 m_spec.full_width = m_rla.WindowRight - m_rla.WindowLeft + 1;
303 m_spec.full_height = m_rla.WindowTop - m_rla.WindowBottom + 1;
304 m_spec.full_depth = 1;
305 m_spec.full_x = m_rla.WindowLeft;
306 m_spec.full_y = m_spec.full_height - 1 - m_rla.WindowTop;
307
308 // set channel formats and stride
309 int z_channel = -1;
310 m_stride = 0;
311 for (int i = 0; i < m_rla.NumOfColorChannels; ++i)
312 m_spec.channelformats.push_back(col_type);
313 m_stride += m_rla.NumOfColorChannels * col_type.size();
314 for (int i = 0; i < m_rla.NumOfMatteChannels; ++i)
315 m_spec.channelformats.push_back(mat_type);
316 if (m_rla.NumOfMatteChannels >= 1)
317 m_spec.alpha_channel = m_rla.NumOfColorChannels;
318 else
319 m_spec.alpha_channel = -1;
320 m_stride += m_rla.NumOfMatteChannels * mat_type.size();
321 for (int i = 0; i < m_rla.NumOfAuxChannels; ++i) {
322 m_spec.channelformats.push_back(aux_type);
323 // assume first float aux or 32 bit int channel is z
324 if (z_channel < 0
325 && (aux_type == TypeDesc::FLOAT || aux_type == TypeDesc::INT32
326 || aux_type == TypeDesc::UINT32)) {
327 z_channel = m_rla.NumOfColorChannels + m_rla.NumOfMatteChannels;
328 m_spec.z_channel = z_channel;
329 m_spec.channelnames[z_channel] = "Z";
330 }
331 }
332 m_stride += m_rla.NumOfAuxChannels * aux_type.size();
333
334 // But if all channels turned out the same, just use 'format' and don't
335 // bother sending back channelformats at all.
336 bool allsame = true;
337 for (int c = 1; c < m_spec.nchannels; ++c)
338 allsame &= (m_spec.channelformats[c] == m_spec.channelformats[0]);
339 if (allsame) {
340 m_spec.format = m_spec.channelformats[0];
341 m_spec.channelformats.clear();
342 m_spec.attribute("oiio:BitsPerSample", m_rla.NumOfChannelBits);
343 // N.B. don't set bps for mixed formats, it isn't well defined
344 }
345
346 // this is always true
347 m_spec.attribute("compression", "rle");
348
349 if (m_rla.DateCreated[0]) {
350 char month[4] = { 0, 0, 0, 0 };
351 int d, h, M, m, y;
352 if (sscanf(m_rla.DateCreated, "%c%c%c %d %d:%d %d", month + 0,
353 month + 1, month + 2, &d, &h, &m, &y)
354 == 7) {
355 M = get_month_number(month);
356 if (M > 0) {
357 // construct a date/time marker in OIIO convention
358 m_spec.attribute("DateTime",
359 Strutil::sprintf("%4d:%02d:%02d %02d:%02d:00",
360 y, M, d, h, m));
361 }
362 }
363 }
364
365 // save some typing by using macros
366 #define FIELD(x, name) \
367 if (m_rla.x > 0) \
368 m_spec.attribute(name, m_rla.x)
369 #define STRING_FIELD(x, name) \
370 if (m_rla.x[0]) \
371 m_spec.attribute(name, m_rla.x)
372
373 STRING_FIELD(Description, "ImageDescription");
374 FIELD(FrameNumber, "rla:FrameNumber");
375 FIELD(Revision, "rla:Revision");
376 FIELD(JobNumber, "rla:JobNumber");
377 FIELD(FieldRendered, "rla:FieldRendered");
378 STRING_FIELD(FileName, "rla:FileName");
379 STRING_FIELD(ProgramName, "Software");
380 STRING_FIELD(MachineName, "HostComputer");
381 STRING_FIELD(UserName, "Artist");
382 STRING_FIELD(Aspect, "rla:Aspect");
383 STRING_FIELD(ColorChannel, "rla:ColorChannel");
384 STRING_FIELD(Time, "rla:Time");
385 STRING_FIELD(Filter, "rla:Filter");
386 STRING_FIELD(AuxData, "rla:AuxData");
387 #undef STRING_FIELD
388 #undef FIELD
389
390 float gamma = Strutil::from_string<float>(m_rla.Gamma);
391 if (gamma > 0.f) {
392 // Round gamma to the nearest hundredth to prevent stupid
393 // precision choices and make it easier for apps to make
394 // decisions based on known gamma values. For example, you want
395 // 2.2, not 2.19998.
396 gamma = roundf(100.0 * gamma) / 100.0f;
397 if (gamma == 1.f)
398 m_spec.attribute("oiio:ColorSpace", "Linear");
399 else {
400 m_spec.attribute("oiio:ColorSpace",
401 Strutil::sprintf("GammaCorrected%.2g", gamma));
402 m_spec.attribute("oiio:Gamma", gamma);
403 }
404 }
405
406 float aspect = Strutil::stof(m_rla.AspectRatio);
407 if (aspect > 0.f)
408 m_spec.attribute("PixelAspectRatio", aspect);
409
410 float f[3]; // variable will be reused for chroma, thus the array
411 // read chromaticity points
412 if (m_rla.RedChroma[0]) {
413 int num = sscanf(m_rla.RedChroma, "%f %f %f", f + 0, f + 1, f + 2);
414 if (num >= 2)
415 m_spec.attribute("rla:RedChroma",
416 TypeDesc(TypeDesc::FLOAT,
417 num == 2 ? TypeDesc::VEC2 : TypeDesc::VEC3,
418 TypeDesc::POINT),
419 f);
420 }
421 if (m_rla.GreenChroma[0]) {
422 int num = sscanf(m_rla.GreenChroma, "%f %f %f", f + 0, f + 1, f + 2);
423 if (num >= 2)
424 m_spec.attribute("rla:GreenChroma",
425 TypeDesc(TypeDesc::FLOAT,
426 num == 2 ? TypeDesc::VEC2 : TypeDesc::VEC3,
427 TypeDesc::POINT),
428 f);
429 }
430 if (m_rla.BlueChroma[0]) {
431 int num = sscanf(m_rla.BlueChroma, "%f %f %f", f + 0, f + 1, f + 2);
432 if (num >= 2)
433 m_spec.attribute("rla:BlueChroma",
434 TypeDesc(TypeDesc::FLOAT,
435 num == 2 ? TypeDesc::VEC2 : TypeDesc::VEC3,
436 TypeDesc::POINT),
437 f);
438 }
439 if (m_rla.WhitePoint[0]) {
440 int num = sscanf(m_rla.WhitePoint, "%f %f %f", f + 0, f + 1, f + 2);
441 if (num >= 2)
442 m_spec.attribute("rla:WhitePoint",
443 TypeDesc(TypeDesc::FLOAT,
444 num == 2 ? TypeDesc::VEC2 : TypeDesc::VEC3,
445 TypeDesc::POINT),
446 f);
447 }
448
449 m_subimage = subimage;
450
451 // N.B. the file pointer is now immediately after the scanline
452 // offset table for this subimage.
453 return true;
454 }
455
456
457
458 bool
close()459 RLAInput::close()
460 {
461 if (m_file) {
462 fclose(m_file);
463 m_file = NULL;
464 }
465
466 init(); // Reset to initial state
467 return true;
468 }
469
470
471
472 size_t
decode_rle_span(unsigned char * buf,int n,int stride,const char * encoded,size_t elen)473 RLAInput::decode_rle_span(unsigned char* buf, int n, int stride,
474 const char* encoded, size_t elen)
475 {
476 size_t e = 0;
477 while (n > 0 && e < elen) {
478 signed char count = (signed char)encoded[e++];
479 if (count >= 0) {
480 // run count positive: value repeated count+1 times
481 for (int i = 0; i <= count && n; ++i, buf += stride, --n)
482 *buf = encoded[e];
483 ++e;
484 } else {
485 // run count negative: repeat bytes literally
486 count = -count; // make it positive
487 for (; count && n > 0 && e < elen; --count, buf += stride, --n)
488 *buf = encoded[e++];
489 }
490 }
491 if (n != 0) {
492 errorf("Read error: malformed RLE record");
493 return 0;
494 }
495 return e;
496 }
497
498
499
500 bool
decode_channel_group(int first_channel,short num_channels,short num_bits,int)501 RLAInput::decode_channel_group(int first_channel, short num_channels,
502 short num_bits, int /*y*/)
503 {
504 // Some preliminaries -- figure out various sizes and offsets
505 int chsize; // size of the channels in this group, in bytes
506 int offset; // buffer offset to first channel
507 int pixelsize; // spacing between pixels (in bytes) in the output
508 TypeDesc chantype; // data type for the channel
509 if (!m_spec.channelformats.size()) {
510 // No per-channel formats, they are all the same, so it's easy
511 chantype = m_spec.format;
512 chsize = chantype.size();
513 offset = first_channel * chsize;
514 pixelsize = chsize * m_spec.nchannels;
515 } else {
516 // Per-channel formats differ, need to sum them up
517 chantype = m_spec.channelformats[first_channel];
518 chsize = chantype.size();
519 offset = 0;
520 pixelsize = m_spec.pixel_bytes(true);
521 for (int i = 0; i < first_channel; ++i)
522 offset += m_spec.channelformats[i].size();
523 }
524
525 // Read the big-endian values into the buffer.
526 // The channels are simply concatenated together in order.
527 // Each channel starts with a length, from which we know how many
528 // bytes of encoded RLE data to read. Then there are RLE
529 // spans for each 8-bit slice of the channel.
530 std::vector<char> encoded;
531 for (int c = 0; c < num_channels; ++c) {
532 // Read the length
533 uint16_t length; // number of encoded bytes
534 if (!read(&length)) {
535 errorf("Read error: couldn't read RLE record length");
536 return false;
537 }
538 // Read the encoded RLE record
539 encoded.resize(length);
540 if (!read(&encoded[0], length)) {
541 errorf("Read error: couldn't read RLE data span");
542 return false;
543 }
544
545 if (chantype == TypeDesc::FLOAT) {
546 // Special case -- float data is just dumped raw, no RLE
547 for (int x = 0; x < m_spec.width; ++x)
548 *((float*)&m_buf[offset + c * chsize + x * pixelsize])
549 = ((float*)&encoded[0])[x];
550 continue;
551 }
552
553 // Decode RLE -- one pass for each significant byte of the file,
554 // which we re-interleave properly by passing the right offsets
555 // and strides to decode_rle_span.
556 size_t eoffset = 0;
557 for (int bytes = 0; bytes < chsize; ++bytes) {
558 size_t e = decode_rle_span(&m_buf[offset + c * chsize + bytes],
559 m_spec.width, pixelsize,
560 &encoded[eoffset], length);
561 if (!e)
562 return false;
563 eoffset += e;
564 }
565 }
566
567 // If we're little endian, swap endianness in place for 2- and
568 // 4-byte pixel data.
569 if (littleendian()) {
570 if (chsize == 2) {
571 if (num_channels == m_spec.nchannels)
572 swap_endian((uint16_t*)&m_buf[0], num_channels * m_spec.width);
573 else
574 for (int x = 0; x < m_spec.width; ++x)
575 swap_endian((uint16_t*)&m_buf[offset + x * pixelsize],
576 num_channels);
577 } else if (chsize == 4 && chantype != TypeDesc::FLOAT) {
578 if (num_channels == m_spec.nchannels)
579 swap_endian((uint32_t*)&m_buf[0], num_channels * m_spec.width);
580 else
581 for (int x = 0; x < m_spec.width; ++x)
582 swap_endian((uint32_t*)&m_buf[offset + x * pixelsize],
583 num_channels);
584 }
585 }
586
587 // If not 8*2^n bits, need to rescale. For example, if num_bits is
588 // 10, the data values run 0-1023, but are stored in uint16. So we
589 // now rescale to the full range of the output buffer range, per
590 // OIIO conventions.
591 if (num_bits == 8 || num_bits == 16 || num_bits == 32) {
592 // ok -- no rescaling needed
593 } else if (num_bits == 10) {
594 // fast, common case -- use templated hard-code
595 for (int x = 0; x < m_spec.width; ++x) {
596 uint16_t* b = (uint16_t*)(&m_buf[offset + x * pixelsize]);
597 for (int c = 0; c < num_channels; ++c)
598 b[c] = bit_range_convert<10, 16>(b[c]);
599 }
600 } else if (num_bits < 8) {
601 // rare case, use slow code to make this clause short and simple
602 for (int x = 0; x < m_spec.width; ++x) {
603 uint8_t* b = (uint8_t*)&m_buf[offset + x * pixelsize];
604 for (int c = 0; c < num_channels; ++c)
605 b[c] = bit_range_convert(b[c], num_bits, 8);
606 }
607 } else if (num_bits > 8 && num_bits < 16) {
608 // rare case, use slow code to make this clause short and simple
609 for (int x = 0; x < m_spec.width; ++x) {
610 uint16_t* b = (uint16_t*)&m_buf[offset + x * pixelsize];
611 for (int c = 0; c < num_channels; ++c)
612 b[c] = bit_range_convert(b[c], num_bits, 16);
613 }
614 } else if (num_bits > 16 && num_bits < 32) {
615 // rare case, use slow code to make this clause short and simple
616 for (int x = 0; x < m_spec.width; ++x) {
617 uint32_t* b = (uint32_t*)&m_buf[offset + x * pixelsize];
618 for (int c = 0; c < num_channels; ++c)
619 b[c] = bit_range_convert(b[c], num_bits, 32);
620 }
621 }
622 return true;
623 }
624
625
626
627 bool
read_native_scanline(int subimage,int miplevel,int y,int,void * data)628 RLAInput::read_native_scanline(int subimage, int miplevel, int y, int /*z*/,
629 void* data)
630 {
631 lock_guard lock(m_mutex);
632 if (!seek_subimage(subimage, miplevel))
633 return false;
634
635 // By convention, RLA images store their images bottom-to-top.
636 y = m_spec.height - (y - m_spec.y) - 1;
637
638 // Seek to scanline start, based on the scanline offset table
639 fseek(m_file, m_sot[y], SEEK_SET);
640
641 // Now decode and interleave the channels.
642 // The channels are non-interleaved (i.e. rrrrrgggggbbbbb...).
643 // Color first, then matte, then auxiliary channels. We can't
644 // decode all in one shot, though, because the data type and number
645 // of significant bits may be may be different for each class of
646 // channels, so we deal with them separately and interleave into
647 // our buffer as we go.
648 size_t size = m_spec.scanline_bytes(true);
649 m_buf.resize(size);
650 if (m_rla.NumOfColorChannels > 0)
651 if (!decode_channel_group(0, m_rla.NumOfColorChannels,
652 m_rla.NumOfChannelBits, y))
653 return false;
654 if (m_rla.NumOfMatteChannels > 0)
655 if (!decode_channel_group(m_rla.NumOfColorChannels,
656 m_rla.NumOfMatteChannels,
657 m_rla.NumOfMatteBits, y))
658 return false;
659 if (m_rla.NumOfAuxChannels > 0)
660 if (!decode_channel_group(m_rla.NumOfColorChannels
661 + m_rla.NumOfMatteChannels,
662 m_rla.NumOfAuxChannels, m_rla.NumOfAuxBits,
663 y))
664 return false;
665
666 memcpy(data, &m_buf[0], size);
667 return true;
668 }
669
670
671
672 inline int
get_month_number(const char * s)673 RLAInput::get_month_number(const char* s)
674 {
675 static const char* months[] = { "", "jan", "feb", "mar", "apr",
676 "may", "jun", "jul", "aug", "sep",
677 "oct", "nov", "dec" };
678 for (int i = 1; i <= 12; ++i)
679 if (Strutil::iequals(s, months[i]))
680 return i;
681 return -1;
682 }
683
684
685
686 inline TypeDesc
get_channel_typedesc(short chan_type,short chan_bits)687 RLAInput::get_channel_typedesc(short chan_type, short chan_bits)
688 {
689 switch (chan_type) {
690 case CT_BYTE:
691 // some non-spec-compliant images > 8bpc will have it set to
692 // byte anyway, so try guessing by bit depth instead
693 if (chan_bits > 8) {
694 switch ((chan_bits + 7) / 8) {
695 case 2: return TypeDesc::UINT16;
696 case 3:
697 case 4: return TypeDesc::UINT32;
698 default: OIIO_ASSERT(!"Invalid colour channel type");
699 }
700 } else
701 return TypeDesc::UINT8;
702 case CT_WORD: return TypeDesc::UINT16;
703 case CT_DWORD: return TypeDesc::UINT32;
704 case CT_FLOAT: return TypeDesc::FLOAT;
705 default: OIIO_ASSERT(!"Invalid colour channel type");
706 }
707 // shut up compiler
708 return TypeDesc::UINT8;
709 }
710
711 OIIO_PLUGIN_NAMESPACE_END
712