107
107
IffOutput::supports (string_view feature) const
108
108
{
109
109
return (feature == " tiles" || feature == " alpha" || feature == " nchannels"
110
- || feature == " ioproxy" );
110
+ || feature == " ioproxy" || feature == " origin " );
111
111
}
112
112
113
113
@@ -142,16 +142,37 @@ IffOutput::open(const std::string& name, const ImageSpec& spec, OpenMode mode)
142
142
return false ;
143
143
}
144
144
145
- // close(); // Close any already-opened file
146
145
// saving 'name' and 'spec' for later use
147
146
m_filename = name;
148
147
m_spec = spec;
149
148
149
+ // Maya docs say 8k is the limit
150
+ if (m_spec.width < 1 || m_spec.width > 8192 || m_spec.height < 1
151
+ || m_spec.height > 8192 ) {
152
+ errorfmt (" Image resolution {} x {} is not valid for an IFF file" ,
153
+ m_spec.width , m_spec.height );
154
+ return false ;
155
+ }
156
+ // This implementation only supports writing RGB and RGBA images as IFF
157
+ if (m_spec.nchannels < 3 || m_spec.nchannels > 4 ) {
158
+ errorfmt (" Cannot write IFF file with {} channels" , m_spec.nchannels );
159
+ return false ;
160
+ }
161
+
150
162
// tiles
151
163
m_spec.tile_width = tile_width ();
152
164
m_spec.tile_height = tile_height ();
153
165
m_spec.tile_depth = 1 ;
154
166
167
+ uint64_t xtiles = tile_width_size (m_spec.width );
168
+ uint64_t ytiles = tile_height_size (m_spec.height );
169
+ if (xtiles * ytiles >= (1 << 16 )) { // The format can't store it!
170
+ errorfmt (
171
+ " Too high a resolution ({}x{}), exceeds maximum of 64k tiles in the image\n " ,
172
+ m_spec.width , m_spec.height );
173
+ return false ;
174
+ }
175
+
155
176
ioproxy_retrieve_from_config (m_spec);
156
177
if (!ioproxy_use_or_open (name))
157
178
return false ;
@@ -172,16 +193,6 @@ IffOutput::open(const std::string& name, const ImageSpec& spec, OpenMode mode)
172
193
m_iff_header.compression
173
194
= (m_spec.get_string_attribute (" compression" ) == " none" ) ? NONE : RLE;
174
195
175
- uint64_t xtiles = tile_width_size (m_spec.width );
176
- uint64_t ytiles = tile_height_size (m_spec.height );
177
- if (xtiles * ytiles >= (1 << 16 )) { // The format can't store it!
178
- errorfmt (
179
- " Too high a resolution ({}x{}), exceeds maximum of 64k tiles in the image\n " ,
180
- m_spec.width , m_spec.height );
181
- close ();
182
- return false ;
183
- }
184
-
185
196
// we write the header of the file
186
197
m_iff_header.x = m_spec.x ;
187
198
m_iff_header.y = m_spec.y ;
@@ -274,6 +285,11 @@ bool
274
285
IffOutput::write_scanline (int y, int z, TypeDesc format, const void * data,
275
286
stride_t xstride)
276
287
{
288
+ if (!ioproxy_opened ()) {
289
+ errorfmt (" write_scanline called but file is not open." );
290
+ return false ;
291
+ }
292
+
277
293
// scanline not used for Maya IFF, uses tiles instead.
278
294
// Emulate by copying the scanline to the buffer we're accumulating.
279
295
std::vector<unsigned char > scratch;
@@ -291,6 +307,11 @@ bool
291
307
IffOutput::write_tile (int x, int y, int z, TypeDesc format, const void * data,
292
308
stride_t xstride, stride_t ystride, stride_t zstride)
293
309
{
310
+ if (!ioproxy_opened ()) {
311
+ errorfmt (" write_tile called but file is not open." );
312
+ return false ;
313
+ }
314
+
294
315
// auto stride
295
316
m_spec.auto_stride (xstride, ystride, zstride, format, spec ().nchannels ,
296
317
spec ().tile_width , spec ().tile_height );
@@ -353,15 +374,13 @@ IffOutput::close(void)
353
374
uint8_t channels = m_iff_header.pixel_channels ;
354
375
355
376
// set tile coordinates
356
- uint16_t xmin, xmax, ymin, ymax;
357
-
358
- // set xmin and xmax
359
- xmin = tx * tile_width ();
360
- xmax = std::min (xmin + tile_width (), m_spec.width ) - 1 ;
361
-
362
- // set ymin and ymax
363
- ymin = ty * tile_height ();
364
- ymax = std::min (ymin + tile_height (), m_spec.height ) - 1 ;
377
+ uint32_t xmin = tx * tile_width ();
378
+ uint32_t xmax
379
+ = std::min (xmin + tile_width (), uint32_t (m_spec.width )) - 1 ;
380
+ uint32_t ymin = ty * tile_height ();
381
+ uint32_t ymax = std::min (ymin + tile_height (),
382
+ uint32_t (m_spec.height ))
383
+ - 1 ;
365
384
366
385
// set width and height
367
386
uint32_t tw = xmax - xmin + 1 ;
@@ -408,13 +427,11 @@ IffOutput::close(void)
408
427
uint8_t * in_p = &in[0 ];
409
428
410
429
// set tile
411
- for (uint16_t py = ymin; py <= ymax; py++) {
430
+ for (uint32_t py = ymin; py <= ymax; py++) {
412
431
const uint8_t * in_dy
413
- = &m_buf[0 ]
414
- + (py * m_spec.width )
415
- * m_spec.pixel_bytes ();
432
+ = &m_buf[0 ] + py * m_spec.scanline_bytes ();
416
433
417
- for (uint16_t px = xmin; px <= xmax; px++) {
434
+ for (uint32_t px = xmin; px <= xmax; px++) {
418
435
// get pixel
419
436
uint8_t pixel;
420
437
const uint8_t * in_dx
@@ -445,6 +462,8 @@ IffOutput::close(void)
445
462
// set length
446
463
uint32_t align = align_size (length, 4 );
447
464
if (align > length) {
465
+ if (scratch.size () < index + align - length)
466
+ scratch.resize (index + align - length);
448
467
out_p = &scratch[0 ] + index;
449
468
// Pad.
450
469
for (uint32_t i = 0 ; i < align - length; i++) {
@@ -457,12 +476,12 @@ IffOutput::close(void)
457
476
}
458
477
}
459
478
if (!tile_compress) {
460
- for (uint16_t py = ymin; py <= ymax; py++) {
479
+ for (uint32_t py = ymin; py <= ymax; py++) {
461
480
const uint8_t * in_dy = &m_buf[0 ]
462
481
+ (py * m_spec.width )
463
482
* m_spec.pixel_bytes ();
464
483
465
- for (uint16_t px = xmin; px <= xmax; px++) {
484
+ for (uint32_t px = xmin; px <= xmax; px++) {
466
485
// Map: RGB(A)8 RGBA to BGRA
467
486
for (int c = channels - 1 ; c >= 0 ; --c) {
468
487
// get pixel
@@ -517,13 +536,11 @@ IffOutput::close(void)
517
536
uint8_t * in_p = &in[0 ];
518
537
519
538
// set tile
520
- for (uint16_t py = ymin; py <= ymax; py++) {
539
+ for (uint32_t py = ymin; py <= ymax; py++) {
521
540
const uint8_t * in_dy
522
- = &m_buf[0 ]
523
- + (py * m_spec.width )
524
- * m_spec.pixel_bytes ();
541
+ = &m_buf[0 ] + py * m_spec.scanline_bytes ();
525
542
526
- for (uint16_t px = xmin; px <= xmax; px++) {
543
+ for (uint32_t px = xmin; px <= xmax; px++) {
527
544
// get pixel
528
545
uint8_t pixel;
529
546
const uint8_t * in_dx
@@ -555,6 +572,8 @@ IffOutput::close(void)
555
572
// set length
556
573
uint32_t align = align_size (length, 4 );
557
574
if (align > length) {
575
+ if (scratch.size () < index + align - length)
576
+ scratch.resize (index + align - length);
558
577
out_p = &scratch[0 ] + index;
559
578
// Pad.
560
579
for (uint32_t i = 0 ; i < align - length; i++) {
@@ -568,12 +587,12 @@ IffOutput::close(void)
568
587
}
569
588
570
589
if (!tile_compress) {
571
- for (uint16_t py = ymin; py <= ymax; py++) {
590
+ for (uint32_t py = ymin; py <= ymax; py++) {
572
591
const uint8_t * in_dy = &m_buf[0 ]
573
592
+ (py * m_spec.width )
574
593
* m_spec.pixel_bytes ();
575
594
576
- for (uint16_t px = xmin; px <= xmax; px++) {
595
+ for (uint32_t px = xmin; px <= xmax; px++) {
577
596
// map: RGB(A) to BGRA
578
597
for (int c = channels - 1 ; c >= 0 ; --c) {
579
598
uint16_t pixel;
@@ -597,8 +616,8 @@ IffOutput::close(void)
597
616
return false ;
598
617
599
618
// write xmin, xmax, ymin and ymax
600
- if (!write (& xmin) || !write (& ymin) || ! write (&xmax )
601
- || !write (& ymax))
619
+ if (!write_short ( xmin) || !write_short ( ymin)
620
+ || !write_short (xmax) || ! write_short ( ymax))
602
621
return false ;
603
622
604
623
// write tile
0 commit comments