~ubuntu-branches/ubuntu/saucy/openexr/saucy

« back to all changes in this revision

Viewing changes to IlmImf/ImfOutputFile.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Adeodato Simó
  • Date: 2008-03-24 23:00:21 UTC
  • mfrom: (3.1.2 lenny)
  • Revision ID: james.westby@ubuntu.com-20080324230021-gnofz9mnvcj1xlv3
Tags: 1.6.1-3
Disable (hopefully temporarily) the test suite on arm and ia64.

Show diffs side-by-side

added added

removed removed

Lines of Context:
45
45
#include <ImfMisc.h>
46
46
#include <ImfStdIO.h>
47
47
#include <ImfCompressor.h>
48
 
#include <ImathBox.h>
49
 
#include <ImathFun.h>
 
48
#include "ImathBox.h"
 
49
#include "ImathFun.h"
50
50
#include <ImfArray.h>
51
51
#include <ImfXdr.h>
52
52
#include <ImfPreviewImageAttribute.h>
53
 
#include <Iex.h>
 
53
#include "IlmThreadPool.h"
 
54
#include "IlmThreadSemaphore.h"
 
55
#include "IlmThreadMutex.h"
 
56
#include "Iex.h"
54
57
#include <string>
55
58
#include <vector>
56
59
#include <fstream>
65
68
using std::string;
66
69
using std::vector;
67
70
using std::ofstream;
68
 
 
 
71
using std::min;
 
72
using std::max;
 
73
using IlmThread::Mutex;
 
74
using IlmThread::Lock;
 
75
using IlmThread::Semaphore;
 
76
using IlmThread::Task;
 
77
using IlmThread::TaskGroup;
 
78
using IlmThread::ThreadPool;
69
79
 
70
80
namespace {
71
81
 
108
118
}
109
119
 
110
120
 
 
121
struct LineBuffer
 
122
{
 
123
    Array<char>         buffer;
 
124
    const char *        dataPtr;
 
125
    int                 dataSize;
 
126
    char *              endOfLineBufferData;
 
127
    int                 minY;
 
128
    int                 maxY;
 
129
    int                 scanLineMin;
 
130
    int                 scanLineMax;
 
131
    Compressor *        compressor;
 
132
    bool                partiallyFull;        // has incomplete data
 
133
    bool                hasException;
 
134
    string              exception;
 
135
 
 
136
    LineBuffer (Compressor *comp);
 
137
    ~LineBuffer ();
 
138
 
 
139
    void                wait () {_sem.wait();}
 
140
    void                post () {_sem.post();}
 
141
 
 
142
  private:
 
143
 
 
144
    Semaphore           _sem;
 
145
};
 
146
 
 
147
 
 
148
LineBuffer::LineBuffer (Compressor *comp) :
 
149
    dataPtr (0),
 
150
    dataSize (0),
 
151
    compressor (comp),
 
152
    partiallyFull (false),
 
153
    hasException (false),
 
154
    exception (),
 
155
    _sem (1)
 
156
{
 
157
    // empty
 
158
}
 
159
 
 
160
 
 
161
LineBuffer::~LineBuffer ()
 
162
{
 
163
    delete compressor;
 
164
}
 
165
 
111
166
} // namespace
112
167
 
113
168
 
114
 
struct OutputFile::Data
 
169
struct OutputFile::Data: public Mutex
115
170
{
116
 
    Header               header;
117
 
    int                  version;
118
 
    Int64                previewPosition;
119
 
    FrameBuffer          frameBuffer;
120
 
    int                  currentScanLine;
121
 
    int                  missingScanLines;
122
 
    LineOrder            lineOrder;
123
 
    int                  minX;
124
 
    int                  maxX;
125
 
    int                  minY;
126
 
    int                  maxY;
127
 
    vector<Int64>        lineOffsets;
128
 
    int                  linesInBuffer;
129
 
    size_t               lineBufferSize;
130
 
    int                  lineBufferMinY;
131
 
    int                  lineBufferMaxY;
132
 
    Array<char>          lineBuffer;
133
 
    char *               endOfLineBufferData;
134
 
    vector<size_t>       bytesPerLine;
135
 
    vector<size_t>       offsetInLineBuffer;
136
 
    Compressor *         compressor;
137
 
    Compressor::Format   format;
138
 
    vector<OutSliceInfo> slices;
139
 
    OStream *            os;
 
171
    Header               header;                // the image header
 
172
    int                  version;               // file format version
 
173
    Int64                previewPosition;       // file position for preview
 
174
    FrameBuffer          frameBuffer;           // framebuffer to write into
 
175
    int                  currentScanLine;       // next scanline to be written
 
176
    int                  missingScanLines;      // number of lines to write
 
177
    LineOrder            lineOrder;             // the file's lineorder
 
178
    int                  minX;                  // data window's min x coord
 
179
    int                  maxX;                  // data window's max x coord
 
180
    int                  minY;                  // data window's min y coord
 
181
    int                  maxY;                  // data window's max x coord
 
182
    vector<Int64>        lineOffsets;           // stores offsets in file for
 
183
                                                // each scanline
 
184
    vector<size_t>       bytesPerLine;          // combined size of a line over
 
185
                                                // all channels
 
186
    vector<size_t>       offsetInLineBuffer;    // offset for each scanline in
 
187
                                                // its linebuffer
 
188
    Compressor::Format   format;                // compressor's data format
 
189
    vector<OutSliceInfo> slices;                // info about channels in file
 
190
    OStream *            os;                    // file stream to write to
140
191
    bool                 deleteStream;
141
 
    Int64                lineOffsetsPosition;
142
 
    Int64                currentPosition;
143
 
 
144
 
     Data (bool del);
 
192
    Int64                lineOffsetsPosition;   // file position for line
 
193
                                                // offset table
 
194
    Int64                currentPosition;       // current file position
 
195
 
 
196
    vector<LineBuffer*>  lineBuffers;           // each holds one line buffer
 
197
    int                  linesInBuffer;         // number of scanlines each
 
198
                                                // buffer holds
 
199
    size_t               lineBufferSize;        // size of the line buffer
 
200
 
 
201
     Data (bool deleteStream, int numThreads);
145
202
    ~Data ();
 
203
 
 
204
 
 
205
    inline LineBuffer * getLineBuffer (int number); // hash function from line
 
206
                                                    // buffer indices into our
 
207
                                                    // vector of line buffers
146
208
};
147
209
 
148
210
 
149
 
OutputFile::Data::Data (bool del):
 
211
OutputFile::Data::Data (bool deleteStream, int numThreads):
150
212
    os (0),
151
 
    compressor (0),
152
 
    deleteStream (del),
 
213
    deleteStream (deleteStream),
153
214
    lineOffsetsPosition (0)
154
215
{
155
 
    // empty
 
216
    //
 
217
    // We need at least one lineBuffer, but if threading is used,
 
218
    // to keep n threads busy we need 2*n lineBuffers.
 
219
    //
 
220
 
 
221
    lineBuffers.resize (max (1, 2 * numThreads));
156
222
}
157
223
 
158
224
 
161
227
    if (deleteStream)
162
228
        delete os;
163
229
 
164
 
    delete compressor;
 
230
    for (size_t i = 0; i < lineBuffers.size(); i++)
 
231
        delete lineBuffers[i];
 
232
}
 
233
 
 
234
 
 
235
LineBuffer*
 
236
OutputFile::Data::getLineBuffer (int number)
 
237
{
 
238
    return lineBuffers[number % lineBuffers.size()];
165
239
}
166
240
 
167
241
 
185
259
 
186
260
void
187
261
writePixelData (OutputFile::Data *ofd,
 
262
                int lineBufferMinY,
188
263
                const char pixelData[],
189
264
                int pixelDataSize)
190
265
{
191
266
    //
192
267
    // Store a block of pixel data in the output file, and try
193
 
    // to keep track of the current writing position the file,
 
268
    // to keep track of the current writing position the file
194
269
    // without calling tellp() (tellp() can be fairly expensive).
195
270
    //
196
271
 
209
284
 
210
285
    #endif
211
286
 
212
 
    Xdr::write <StreamIO> (*ofd->os, ofd->lineBufferMinY);
 
287
    Xdr::write <StreamIO> (*ofd->os, lineBufferMinY);
213
288
    Xdr::write <StreamIO> (*ofd->os, pixelDataSize);
214
289
    ofd->os->write (pixelData, pixelDataSize);
215
290
 
220
295
}
221
296
 
222
297
 
 
298
inline void
 
299
writePixelData (OutputFile::Data *ofd, const LineBuffer *lineBuffer)
 
300
{
 
301
    writePixelData (ofd,
 
302
                    lineBuffer->minY,
 
303
                    lineBuffer->dataPtr,
 
304
                    lineBuffer->dataSize);
 
305
}
 
306
 
 
307
 
223
308
void
224
 
convertToXdr (OutputFile::Data *ofd, int inSize)
 
309
convertToXdr (OutputFile::Data *ofd,
 
310
              Array<char> &lineBuffer,
 
311
              int lineBufferMinY,
 
312
              int lineBufferMaxY,
 
313
              int inSize)
225
314
{
226
315
    //
227
 
    // Convert the contents of an OutputFile's lineBuffer from the machine's
228
 
    // native representation to Xdr format.  This function is called by
229
 
    // writePixels(), below, if the compressor wanted its input pixel data
230
 
    // in the machine's native format, but then failed to compress the data
231
 
    // (most compressors will expand rather than compress random input data).
 
316
    // Convert the contents of a lineBuffer from the machine's native
 
317
    // representation to Xdr format.  This function is called by
 
318
    // CompressLineBuffer::execute(), below, if the compressor wanted
 
319
    // its input pixel data in the machine's native format, but then
 
320
    // failed to compress the data (most compressors will expand rather
 
321
    // than compress random input data).
232
322
    //
233
 
    // Note that this routine assumes that the machine's native representation
234
 
    // of the pixel data has the same size as the Xdr representation.  This
235
 
    // makes it possible to convert the pixel data in place, without an
236
 
    // intermediate temporary buffer.
 
323
    // Note that this routine assumes that the machine's native
 
324
    // representation of the pixel data has the same size as the
 
325
    // Xdr representation.  This makes it possible to convert the
 
326
    // pixel data in place, without an intermediate temporary buffer.
237
327
    //
238
328
   
239
329
    int startY, endY;           // The first and last scanlines in
240
330
                                // the file that are in the lineBuffer.
241
 
    int dy;
 
331
    int step;
242
332
    
243
333
    if (ofd->lineOrder == INCREASING_Y)
244
334
    {
245
 
        startY = std::max (ofd->lineBufferMinY, ofd->minY);
246
 
        endY = std::min (ofd->lineBufferMaxY, ofd->maxY) + 1;
247
 
        dy = 1;
 
335
        startY = max (lineBufferMinY, ofd->minY);
 
336
        endY = min (lineBufferMaxY, ofd->maxY) + 1;
 
337
        step = 1;
248
338
    }
249
339
    else
250
340
    {
251
 
        startY = std::min (ofd->lineBufferMaxY, ofd->maxY);
252
 
        endY = std::max (ofd->lineBufferMinY, ofd->minY) - 1;
253
 
        dy = -1;
 
341
        startY = min (lineBufferMaxY, ofd->maxY);
 
342
        endY = max (lineBufferMinY, ofd->minY) - 1;
 
343
        step = -1;
254
344
    }
255
345
 
256
346
    //
257
347
    // Iterate over all scanlines in the lineBuffer to convert.
258
348
    //
259
349
 
260
 
    for (int y = startY; y != endY; y += dy)
 
350
    for (int y = startY; y != endY; y += step)
261
351
    {
262
352
        //
263
353
        // Set these to point to the start of line y.
264
 
        // We will write to writePtr from pixelPtr.
 
354
        // We will write to writePtr from readPtr.
265
355
        //
266
356
        
267
 
        char *writePtr = ofd->lineBuffer +
268
 
                         ofd->offsetInLineBuffer[y - ofd->minY];
269
 
 
270
 
        char *pixelPtr = writePtr;
 
357
        char *writePtr = lineBuffer + ofd->offsetInLineBuffer[y - ofd->minY];
 
358
        const char *readPtr = writePtr;
271
359
        
272
360
        //
273
361
        // Iterate over all slices in the file.
298
386
            //
299
387
            // Convert the samples in place.
300
388
            //
301
 
 
302
 
            switch (slice.type)
303
 
            {
304
 
              case UINT:
305
 
 
306
 
                while (dMinX <= dMaxX)
307
 
                {
308
 
                    Xdr::write <CharPtrIO>
309
 
                        (writePtr, *(const unsigned int *) pixelPtr);
310
 
                    pixelPtr += sizeof(unsigned int);
311
 
 
312
 
                    dMinX += 1;
313
 
                }
314
 
                break;
315
 
 
316
 
              case HALF:
317
 
 
318
 
                while (dMinX <= dMaxX)
319
 
                {                
320
 
                    Xdr::write <CharPtrIO>
321
 
                        (writePtr, *(const half *) pixelPtr);
322
 
                    pixelPtr += sizeof(half);
323
 
 
324
 
                    dMinX += 1;
325
 
                }
326
 
                break;
327
 
 
328
 
              case FLOAT:
329
 
 
330
 
                while (dMinX <= dMaxX)
331
 
                {
332
 
                    Xdr::write <CharPtrIO>
333
 
                        (writePtr, *(const float *) pixelPtr);
334
 
                    pixelPtr += sizeof(float);
335
 
 
336
 
                    dMinX += 1;
337
 
                }
338
 
                break;
339
 
 
340
 
              default:
341
 
 
342
 
                throw Iex::ArgExc ("Unknown pixel data type.");
343
 
            }           
344
 
        }
345
 
 
346
 
        #ifdef DEBUG
347
 
 
348
 
            assert (writePtr == pixelPtr);
349
 
 
350
 
        #endif
 
389
            
 
390
            convertInPlace (writePtr, readPtr, slice.type, dMaxX - dMinX + 1);
 
391
        }
 
392
    }
 
393
}
 
394
 
 
395
 
 
396
//
 
397
// A LineBufferTask encapsulates the task of copying a set of scanlines
 
398
// from the user's frame buffer into a LineBuffer object, compressing
 
399
// the data if necessary.
 
400
//
 
401
 
 
402
class LineBufferTask: public Task
 
403
{
 
404
  public:
 
405
 
 
406
    LineBufferTask (TaskGroup *group,
 
407
                    OutputFile::Data *ofd,
 
408
                    int number,
 
409
                    int scanLineMin,
 
410
                    int scanLineMax);
 
411
 
 
412
    virtual ~LineBufferTask (); 
 
413
 
 
414
    virtual void        execute ();
 
415
 
 
416
  private:
 
417
 
 
418
    OutputFile::Data *  _ofd;
 
419
    LineBuffer *        _lineBuffer;
 
420
};
 
421
 
 
422
 
 
423
LineBufferTask::LineBufferTask
 
424
    (TaskGroup *group,
 
425
     OutputFile::Data *ofd,
 
426
     int number,
 
427
     int scanLineMin,
 
428
     int scanLineMax)
 
429
:
 
430
    Task (group),
 
431
    _ofd (ofd),
 
432
    _lineBuffer (_ofd->getLineBuffer(number))
 
433
{
 
434
    //
 
435
    // Wait for the lineBuffer to become available
 
436
    //
 
437
 
 
438
    _lineBuffer->wait ();
 
439
    
 
440
    //
 
441
    // Initialize the lineBuffer data if necessary
 
442
    //
 
443
 
 
444
    if (!_lineBuffer->partiallyFull)
 
445
    {
 
446
        _lineBuffer->endOfLineBufferData = _lineBuffer->buffer;
 
447
 
 
448
        _lineBuffer->minY = _ofd->minY + number * _ofd->linesInBuffer;
 
449
 
 
450
        _lineBuffer->maxY = min (_lineBuffer->minY + _ofd->linesInBuffer - 1,
 
451
                                 _ofd->maxY);
 
452
 
 
453
        _lineBuffer->partiallyFull = true;
 
454
    }
 
455
    
 
456
    _lineBuffer->scanLineMin = max (_lineBuffer->minY, scanLineMin);
 
457
    _lineBuffer->scanLineMax = min (_lineBuffer->maxY, scanLineMax);
 
458
}
 
459
 
 
460
 
 
461
LineBufferTask::~LineBufferTask ()
 
462
{
 
463
    //
 
464
    // Signal that the line buffer is now free
 
465
    //
 
466
 
 
467
    _lineBuffer->post ();
 
468
}
 
469
 
 
470
 
 
471
void
 
472
LineBufferTask::execute ()
 
473
{
 
474
    try
 
475
    {
 
476
        //
 
477
        // First copy the pixel data from the
 
478
        // frame buffer into the line buffer
 
479
        //
 
480
        
 
481
        int yStart, yStop, dy;
 
482
 
 
483
        if (_ofd->lineOrder == INCREASING_Y)
 
484
        {
 
485
            yStart = _lineBuffer->scanLineMin;
 
486
            yStop = _lineBuffer->scanLineMax + 1;
 
487
            dy = 1;
 
488
        }
 
489
        else
 
490
        {
 
491
            yStart = _lineBuffer->scanLineMax;
 
492
            yStop = _lineBuffer->scanLineMin - 1;
 
493
            dy = -1;
 
494
        }
 
495
    
 
496
        int y;
 
497
 
 
498
        for (y = yStart; y != yStop; y += dy)
 
499
        {
 
500
            //
 
501
            // Gather one scan line's worth of pixel data and store
 
502
            // them in _ofd->lineBuffer.
 
503
            //
 
504
        
 
505
            char *writePtr = _lineBuffer->buffer +
 
506
                             _ofd->offsetInLineBuffer[y - _ofd->minY];
 
507
            //
 
508
            // Iterate over all image channels.
 
509
            //
 
510
        
 
511
            for (unsigned int i = 0; i < _ofd->slices.size(); ++i)
 
512
            {
 
513
                //
 
514
                // Test if scan line y of this channel contains any data
 
515
                // (the scan line contains data only if y % ySampling == 0).
 
516
                //
 
517
        
 
518
                const OutSliceInfo &slice = _ofd->slices[i];
 
519
        
 
520
                if (modp (y, slice.ySampling) != 0)
 
521
                    continue;
 
522
        
 
523
                //
 
524
                // Find the x coordinates of the leftmost and rightmost
 
525
                // sampled pixels (i.e. pixels within the data window
 
526
                // for which x % xSampling == 0).
 
527
                //
 
528
        
 
529
                int dMinX = divp (_ofd->minX, slice.xSampling);
 
530
                int dMaxX = divp (_ofd->maxX, slice.xSampling);
 
531
        
 
532
                //
 
533
                // Fill the line buffer with with pixel data.
 
534
                //
 
535
        
 
536
                if (slice.zero)
 
537
                {
 
538
                    //
 
539
                    // The frame buffer contains no data for this channel.
 
540
                    // Store zeroes in _lineBuffer->buffer.
 
541
                    //
 
542
                    
 
543
                    fillChannelWithZeroes (writePtr, _ofd->format, slice.type,
 
544
                                           dMaxX - dMinX + 1);
 
545
                }
 
546
                else
 
547
                {
 
548
                    //
 
549
                    // If necessary, convert the pixel data to Xdr format.
 
550
                    // Then store the pixel data in _ofd->lineBuffer.
 
551
                    //
 
552
        
 
553
                    const char *linePtr = slice.base +
 
554
                                          divp (y, slice.ySampling) *
 
555
                                          slice.yStride;
 
556
        
 
557
                    const char *readPtr = linePtr + dMinX * slice.xStride;
 
558
                    const char *endPtr  = linePtr + dMaxX * slice.xStride;
 
559
    
 
560
                    copyFromFrameBuffer (writePtr, readPtr, endPtr,
 
561
                                         slice.xStride, _ofd->format,
 
562
                                         slice.type);
 
563
                }
 
564
            }
 
565
        
 
566
            if (_lineBuffer->endOfLineBufferData < writePtr)
 
567
                _lineBuffer->endOfLineBufferData = writePtr;
 
568
        
 
569
            #ifdef DEBUG
 
570
        
 
571
                assert (writePtr - (_lineBuffer->buffer +
 
572
                        _ofd->offsetInLineBuffer[y - _ofd->minY]) ==
 
573
                        (int) _ofd->bytesPerLine[y - _ofd->minY]);
 
574
        
 
575
            #endif
 
576
        
 
577
        }
 
578
    
 
579
        //
 
580
        // If the next scanline isn't past the bounds of the lineBuffer
 
581
        // then we are done, otherwise compress the linebuffer
 
582
        //
 
583
    
 
584
        if (y >= _lineBuffer->minY && y <= _lineBuffer->maxY)
 
585
            return;
 
586
    
 
587
        _lineBuffer->dataPtr = _lineBuffer->buffer;
 
588
 
 
589
        _lineBuffer->dataSize = _lineBuffer->endOfLineBufferData -
 
590
                                _lineBuffer->buffer;
 
591
    
 
592
        //
 
593
        // Compress the data
 
594
        //
 
595
 
 
596
        Compressor *compressor = _lineBuffer->compressor;
 
597
 
 
598
        if (compressor)
 
599
        {
 
600
            const char *compPtr;
 
601
 
 
602
            int compSize = compressor->compress (_lineBuffer->dataPtr,
 
603
                                                 _lineBuffer->dataSize,
 
604
                                                 _lineBuffer->minY, compPtr);
 
605
    
 
606
            if (compSize < _lineBuffer->dataSize)
 
607
            {
 
608
                _lineBuffer->dataSize = compSize;
 
609
                _lineBuffer->dataPtr = compPtr;
 
610
            }
 
611
            else if (_ofd->format == Compressor::NATIVE)
 
612
            {
 
613
                //
 
614
                // The data did not shrink during compression, but
 
615
                // we cannot write to the file using the machine's
 
616
                // native format, so we need to convert the lineBuffer
 
617
                // to Xdr.
 
618
                //
 
619
    
 
620
                convertToXdr (_ofd, _lineBuffer->buffer, _lineBuffer->minY,
 
621
                              _lineBuffer->maxY, _lineBuffer->dataSize);
 
622
            }
 
623
        }
 
624
 
 
625
        _lineBuffer->partiallyFull = false;
 
626
    }
 
627
    catch (std::exception &e)
 
628
    {
 
629
        if (!_lineBuffer->hasException)
 
630
        {
 
631
            _lineBuffer->exception = e.what ();
 
632
            _lineBuffer->hasException = true;
 
633
        }
 
634
    }
 
635
    catch (...)
 
636
    {
 
637
        if (!_lineBuffer->hasException)
 
638
        {
 
639
            _lineBuffer->exception = "unrecognized exception";
 
640
            _lineBuffer->hasException = true;
 
641
        }
351
642
    }
352
643
}
353
644
 
354
645
} // namespace
355
646
 
356
647
 
357
 
OutputFile::OutputFile (const char fileName[], const Header &header):
358
 
    _data (new Data (true))
 
648
OutputFile::OutputFile
 
649
    (const char fileName[],
 
650
     const Header &header,
 
651
     int numThreads)
 
652
:
 
653
    _data (new Data (true, numThreads))
359
654
{
360
655
    try
361
656
    {
371
666
                        "\"" << fileName << "\". " << e);
372
667
        throw;
373
668
    }
 
669
    catch (...)
 
670
    {
 
671
        delete _data;
 
672
        throw;
 
673
    }
374
674
}
375
675
 
376
676
 
377
 
OutputFile::OutputFile (OStream &os, const Header &header):
378
 
    _data (new Data (false))
 
677
OutputFile::OutputFile
 
678
    (OStream &os,
 
679
     const Header &header,
 
680
     int numThreads)
 
681
:
 
682
    _data (new Data (false, numThreads))
379
683
{
380
684
    try
381
685
    {
391
695
                        "\"" << os.fileName() << "\". " << e);
392
696
        throw;
393
697
    }
 
698
    catch (...)
 
699
    {
 
700
        delete _data;
 
701
        throw;
 
702
    }
394
703
}
395
704
 
396
705
 
414
723
    size_t maxBytesPerLine = bytesPerLineTable (_data->header,
415
724
                                                _data->bytesPerLine);
416
725
 
417
 
    _data->compressor = newCompressor (_data->header.compression(),
418
 
                                       maxBytesPerLine,
419
 
                                       _data->header);
420
 
 
421
 
    _data->linesInBuffer = _data->compressor?
422
 
                               _data->compressor->numScanLines(): 1;
423
 
 
424
 
    _data->format = _data->compressor?
425
 
                        _data->compressor->format(): Compressor::XDR;
426
 
 
 
726
    for (size_t i = 0; i < _data->lineBuffers.size(); ++i)
 
727
    {
 
728
        _data->lineBuffers[i] =
 
729
            new LineBuffer (newCompressor (_data->header.compression(),
 
730
                                           maxBytesPerLine,
 
731
                                           _data->header));
 
732
    }
 
733
 
 
734
    LineBuffer *lineBuffer = _data->lineBuffers[0];
 
735
    _data->format = defaultFormat (lineBuffer->compressor);
 
736
    _data->linesInBuffer = numLinesInBuffer (lineBuffer->compressor);
427
737
    _data->lineBufferSize = maxBytesPerLine * _data->linesInBuffer;
428
 
    _data->lineBuffer.resizeErase (_data->lineBufferSize);
429
 
    _data->endOfLineBufferData = _data->lineBuffer;
430
 
 
431
 
    _data->lineBufferMinY = lineBufferMinY (_data->currentScanLine,
432
 
                                            _data->minY,
433
 
                                            _data->linesInBuffer);
434
 
 
435
 
    _data->lineBufferMaxY = lineBufferMaxY (_data->currentScanLine,
436
 
                                            _data->minY,
437
 
                                            _data->linesInBuffer);
 
738
 
 
739
    for (size_t i = 0; i < _data->lineBuffers.size(); i++)
 
740
        _data->lineBuffers[i]->buffer.resizeErase(_data->lineBufferSize);
438
741
 
439
742
    int lineOffsetSize = (dataWindow.max.y - dataWindow.min.y +
440
743
                          _data->linesInBuffer) / _data->linesInBuffer;
459
762
{
460
763
    if (_data)
461
764
    {
462
 
        if (_data->lineOffsetsPosition > 0)
463
 
        {
464
 
            try
465
 
            {
466
 
                _data->os->seekp (_data->lineOffsetsPosition);
467
 
                writeLineOffsets (*_data->os, _data->lineOffsets);
468
 
            }
469
 
            catch (...)
470
 
            {
471
 
                //
472
 
                // We cannot safely throw any exceptions from here.
473
 
                // This destructor may have been called because the
474
 
                // stack is currently being unwound for another
475
 
                // exception.
476
 
                //
477
 
            }
478
 
        }
 
765
        {
 
766
            if (_data->lineOffsetsPosition > 0)
 
767
            {
 
768
                try
 
769
                {
 
770
                    _data->os->seekp (_data->lineOffsetsPosition);
 
771
                    writeLineOffsets (*_data->os, _data->lineOffsets);
 
772
                }
 
773
                catch (...)
 
774
                {
 
775
                    //
 
776
                    // We cannot safely throw any exceptions from here.
 
777
                    // This destructor may have been called because the
 
778
                    // stack is currently being unwound for another
 
779
                    // exception.
 
780
                    //
 
781
                }
 
782
            }
 
783
        }
479
784
 
480
785
        delete _data;
481
786
    }
499
804
void    
500
805
OutputFile::setFrameBuffer (const FrameBuffer &frameBuffer)
501
806
{
 
807
    Lock lock (*_data);
 
808
    
502
809
    //
503
810
    // Check if the new frame buffer descriptor
504
811
    // is compatible with the image file header.
589
896
const FrameBuffer &
590
897
OutputFile::frameBuffer () const
591
898
{
 
899
    Lock lock (*_data);
592
900
    return _data->frameBuffer;
593
901
}
594
902
 
598
906
{
599
907
    try
600
908
    {
 
909
        Lock lock (*_data);
 
910
 
601
911
        if (_data->slices.size() == 0)
602
912
            throw Iex::ArgExc ("No frame buffer specified "
603
913
                               "as pixel data source.");
604
914
 
605
 
        while (numScanLines)
 
915
        //
 
916
        // Maintain two iterators:
 
917
        //     nextWriteBuffer: next linebuffer to be written to the file
 
918
        //     nextCompressBuffer: next linebuffer to compress
 
919
        //
 
920
 
 
921
        int first = (_data->currentScanLine - _data->minY) /
 
922
                         _data->linesInBuffer;
 
923
 
 
924
        int nextWriteBuffer = first;
 
925
        int nextCompressBuffer;
 
926
        int stop;
 
927
        int step;
 
928
        int scanLineMin;
 
929
        int scanLineMax;
 
930
 
 
931
        {
 
932
            //
 
933
            // Create a task group for all line buffer tasks. When the
 
934
            // taskgroup goes out of scope, the destructor waits until
 
935
            // all tasks are complete.
 
936
            //
 
937
            
 
938
            TaskGroup taskGroup;
 
939
            
 
940
            //
 
941
            // Determine the range of lineBuffers that intersect the scan
 
942
            // line range.  Then add the initial compression tasks to the
 
943
            // thread pool.  We always add in at least one task but the
 
944
            // individual task might not do anything if numScanLines == 0.
 
945
            //
 
946
    
 
947
            if (_data->lineOrder == INCREASING_Y)
 
948
            {
 
949
                int last = (_data->currentScanLine + (numScanLines - 1) -
 
950
                            _data->minY) / _data->linesInBuffer;
 
951
    
 
952
                scanLineMin = _data->currentScanLine;
 
953
                scanLineMax = _data->currentScanLine + numScanLines - 1;
 
954
    
 
955
                int numTasks = max (min ((int)_data->lineBuffers.size(),
 
956
                                         last - first + 1),
 
957
                                    1);
 
958
 
 
959
                for (int i = 0; i < numTasks; i++)
 
960
                {
 
961
                    ThreadPool::addGlobalTask
 
962
                        (new LineBufferTask (&taskGroup, _data, first + i,
 
963
                                             scanLineMin, scanLineMax));
 
964
                }
 
965
    
 
966
                nextCompressBuffer = first + numTasks;
 
967
                stop = last + 1;
 
968
                step = 1;
 
969
            }
 
970
            else
 
971
            {
 
972
                int last = (_data->currentScanLine - (numScanLines - 1) -
 
973
                            _data->minY) / _data->linesInBuffer;
 
974
    
 
975
                scanLineMax = _data->currentScanLine;
 
976
                scanLineMin = _data->currentScanLine - numScanLines + 1;
 
977
    
 
978
                int numTasks = max (min ((int)_data->lineBuffers.size(),
 
979
                                         first - last + 1),
 
980
                                    1);
 
981
 
 
982
                for (int i = 0; i < numTasks; i++)
 
983
                {
 
984
                    ThreadPool::addGlobalTask
 
985
                        (new LineBufferTask (&taskGroup, _data, first - i,
 
986
                                             scanLineMin, scanLineMax));
 
987
                }
 
988
    
 
989
                nextCompressBuffer = first - numTasks;
 
990
                stop = last - 1;
 
991
                step = -1;
 
992
            }
 
993
            
 
994
            while (true)
 
995
            {
 
996
                if (_data->missingScanLines <= 0)
 
997
                {
 
998
                    throw Iex::ArgExc ("Tried to write more scan lines "
 
999
                                       "than specified by the data window.");
 
1000
                }
 
1001
    
 
1002
                //
 
1003
                // Wait until the next line buffer is ready to be written
 
1004
                //
 
1005
 
 
1006
                LineBuffer *writeBuffer =
 
1007
                    _data->getLineBuffer (nextWriteBuffer);
 
1008
 
 
1009
                writeBuffer->wait();
 
1010
                
 
1011
                int numLines = writeBuffer->scanLineMax - 
 
1012
                               writeBuffer->scanLineMin + 1;
 
1013
 
 
1014
                _data->missingScanLines -= numLines;
 
1015
    
 
1016
                //
 
1017
                // If the line buffer is only partially full, then it is
 
1018
                // not complete and we cannot write it to disk yet.
 
1019
                //
 
1020
 
 
1021
                if (writeBuffer->partiallyFull)
 
1022
                {
 
1023
                    _data->currentScanLine = _data->currentScanLine +
 
1024
                                             step * numLines;
 
1025
                    writeBuffer->post();
 
1026
    
 
1027
                    return;
 
1028
                }
 
1029
    
 
1030
                //
 
1031
                // Write the line buffer
 
1032
                //
 
1033
 
 
1034
                writePixelData (_data, writeBuffer);
 
1035
                nextWriteBuffer += step;
 
1036
 
 
1037
                _data->currentScanLine = _data->currentScanLine +
 
1038
                                         step * numLines;
 
1039
    
 
1040
                #ifdef DEBUG
 
1041
    
 
1042
                    assert (_data->currentScanLine ==
 
1043
                            ((_data->lineOrder == INCREASING_Y) ?
 
1044
                             writeBuffer->scanLineMax + 1:
 
1045
                             writeBuffer->scanLineMin - 1));
 
1046
    
 
1047
                #endif
 
1048
                
 
1049
                //
 
1050
                // Release the lock on the line buffer
 
1051
                //
 
1052
 
 
1053
                writeBuffer->post();
 
1054
                
 
1055
                //
 
1056
                // If this was the last line buffer in the scanline range
 
1057
                //
 
1058
 
 
1059
                if (nextWriteBuffer == stop)
 
1060
                    break;
 
1061
    
 
1062
                //
 
1063
                // If there are no more line buffers to compress,
 
1064
                // then only continue to write out remaining lineBuffers
 
1065
                //
 
1066
 
 
1067
                if (nextCompressBuffer == stop)
 
1068
                    continue;
 
1069
    
 
1070
                //
 
1071
                // Add nextCompressBuffer as a compression task
 
1072
                //
 
1073
 
 
1074
                ThreadPool::addGlobalTask
 
1075
                    (new LineBufferTask (&taskGroup, _data, nextCompressBuffer,
 
1076
                                         scanLineMin, scanLineMax));
 
1077
                
 
1078
                //
 
1079
                // Update the next line buffer we need to compress
 
1080
                //
 
1081
 
 
1082
                nextCompressBuffer += step;
 
1083
            }
 
1084
        
 
1085
            //
 
1086
            // Finish all tasks
 
1087
            //
 
1088
        }
 
1089
        
 
1090
        //
 
1091
        // Exeption handling:
 
1092
        //
 
1093
        // LineBufferTask::execute() may have encountered exceptions, but
 
1094
        // those exceptions occurred in another thread, not in the thread
 
1095
        // that is executing this call to OutputFile::writePixels().
 
1096
        // LineBufferTask::execute() has caught all exceptions and stored
 
1097
        // the exceptions' what() strings in the line buffers.
 
1098
        // Now we check if any line buffer contains a stored exception; if
 
1099
        // this is the case then we re-throw the exception in this thread.
 
1100
        // (It is possible that multiple line buffers contain stored
 
1101
        // exceptions.  We re-throw the first exception we find and
 
1102
        // ignore all others.)
 
1103
        //
 
1104
 
 
1105
        const string *exception = 0;
 
1106
 
 
1107
        for (int i = 0; i < _data->lineBuffers.size(); ++i)
606
1108
        {
607
 
            if (_data->missingScanLines <= 0)
608
 
            {
609
 
                throw Iex::ArgExc ("Tried to write more scan lines "
610
 
                                   "than specified by the data window.");
611
 
            }
612
 
 
613
 
            #ifdef DEBUG
614
 
 
615
 
                assert (_data->currentScanLine >= _data->lineBufferMinY &&
616
 
                        _data->currentScanLine <= _data->lineBufferMaxY);
617
 
 
618
 
            #endif
619
 
 
620
 
            //
621
 
            // Convert one scan line's worth of pixel data to
622
 
            // a machine-independent representation, and store
623
 
            // the result in _data->lineBuffer.
624
 
            //
625
 
 
626
 
            int y = _data->currentScanLine;
627
 
 
628
 
            char *writePtr = _data->lineBuffer +
629
 
                             _data->offsetInLineBuffer[y - _data->minY];
630
 
 
631
 
            //
632
 
            // Iterate over all image channels.
633
 
            //
634
 
 
635
 
            for (unsigned int i = 0; i < _data->slices.size(); ++i)
636
 
            {
637
 
                //
638
 
                // Test if scan line y of this channel is
639
 
                // contains any data (the scan line contains
640
 
                // data only if y % ySampling == 0).
641
 
                //
642
 
 
643
 
                const OutSliceInfo &slice = _data->slices[i];
644
 
 
645
 
                if (modp (y, slice.ySampling) != 0)
646
 
                    continue;
647
 
 
648
 
                //
649
 
                // Find the x coordinates of the leftmost and rightmost
650
 
                // sampled pixels (i.e. pixels within the data window
651
 
                // for which x % xSampling == 0).
652
 
                //
653
 
 
654
 
                int dMinX = divp (_data->minX, slice.xSampling);
655
 
                int dMaxX = divp (_data->maxX, slice.xSampling);
656
 
 
657
 
                //
658
 
                // Iterate over the sampled pixels.
659
 
                //
660
 
 
661
 
                if (slice.zero)
662
 
                {
663
 
                    //
664
 
                    // The frame buffer contains no data for this channel.
665
 
                    // Store zeroes in _data->lineBuffer.
666
 
                    //
667
 
 
668
 
                    if (_data->format == Compressor::XDR)
669
 
                    {
670
 
                        //
671
 
                        // The compressor expects data in Xdr format.
672
 
                        //
673
 
 
674
 
                        switch (slice.type)
675
 
                        {
676
 
                          case UINT:
677
 
 
678
 
                            while (dMinX <= dMaxX)
679
 
                            {
680
 
                                Xdr::write <CharPtrIO>
681
 
                                    (writePtr, (unsigned int) 0);
682
 
                                dMinX += 1;
683
 
                            }
684
 
                            break;
685
 
 
686
 
                          case HALF:
687
 
 
688
 
                            while (dMinX <= dMaxX)
689
 
                            {
690
 
                                Xdr::write <CharPtrIO>
691
 
                                    (writePtr, (half) 0);
692
 
                                dMinX += 1;
693
 
                            }
694
 
                            break;
695
 
 
696
 
                          case FLOAT:
697
 
 
698
 
                            while (dMinX <= dMaxX)
699
 
                            {
700
 
                                Xdr::write <CharPtrIO>
701
 
                                    (writePtr, (float) 0);
702
 
                                dMinX += 1;
703
 
                            }
704
 
                            break;
705
 
                            
706
 
                          default:
707
 
 
708
 
                            throw Iex::ArgExc ("Unknown pixel data type.");
709
 
                        }
710
 
                    }
711
 
                    else
712
 
                    {
713
 
                        //
714
 
                        // The compressor expects data in
715
 
                        // the machines native format.
716
 
                        //
717
 
 
718
 
                        switch (slice.type)
719
 
                        {
720
 
                          case UINT:
721
 
 
722
 
                            while (dMinX <= dMaxX)
723
 
                            {
724
 
                                static unsigned int ui = 0;
725
 
 
726
 
                                for (size_t i = 0; i < sizeof (ui); ++i)
727
 
                                    *writePtr++ = ((char *) &ui)[i];
728
 
 
729
 
                                dMinX += 1;
730
 
                            }
731
 
                            break;
732
 
 
733
 
                          case HALF:
734
 
 
735
 
                            while (dMinX <= dMaxX)
736
 
                            {
737
 
                                *(half *) writePtr = half (0);
738
 
                                writePtr += sizeof (half);
739
 
                                dMinX += 1;
740
 
                            }
741
 
                            break;
742
 
 
743
 
                          case FLOAT:
744
 
 
745
 
                            while (dMinX <= dMaxX)
746
 
                            {
747
 
                                static float f = 0;
748
 
 
749
 
                                for (size_t i = 0; i < sizeof (f); ++i)
750
 
                                    *writePtr++ = ((char *) &f)[i];
751
 
 
752
 
                                dMinX += 1;
753
 
                            }
754
 
                            break;
755
 
                            
756
 
                          default:
757
 
 
758
 
                            throw Iex::ArgExc ("Unknown pixel data type.");
759
 
                        }
760
 
                    }
761
 
                }
762
 
                else
763
 
                {
764
 
                    //
765
 
                    // If necessary, convert the pixel data to
766
 
                    // a machine-independent representation.
767
 
                    // Then store the pixel data in _data->lineBuffer.
768
 
                    //
769
 
 
770
 
                    const char *linePtr  = slice.base +
771
 
                                           divp (y, slice.ySampling) *
772
 
                                           slice.yStride;
773
 
 
774
 
                    const char *pixelPtr = linePtr + dMinX * slice.xStride;
775
 
                    const char *endPtr   = linePtr + dMaxX * slice.xStride;
776
 
 
777
 
                    if (_data->format == Compressor::XDR)
778
 
                    {
779
 
                        //
780
 
                        // The compressor expects data in Xdr format
781
 
                        //
782
 
 
783
 
                        switch (slice.type)
784
 
                        {
785
 
                          case UINT:
786
 
 
787
 
                            while (pixelPtr <= endPtr)
788
 
                            {
789
 
                                Xdr::write <CharPtrIO>
790
 
                                   (writePtr, *(const unsigned int *) pixelPtr);
791
 
                                pixelPtr += slice.xStride;
792
 
                            }
793
 
                            break;
794
 
 
795
 
                          case HALF:
796
 
 
797
 
                            while (pixelPtr <= endPtr)
798
 
                            {
799
 
                                Xdr::write <CharPtrIO>
800
 
                                    (writePtr, *(const half *) pixelPtr);
801
 
                                pixelPtr += slice.xStride;
802
 
                            }
803
 
                            break;
804
 
 
805
 
                          case FLOAT:
806
 
 
807
 
                            while (pixelPtr <= endPtr)
808
 
                            {
809
 
                                Xdr::write <CharPtrIO>
810
 
                                    (writePtr, *(const float *) pixelPtr);
811
 
                                pixelPtr += slice.xStride;
812
 
                            }
813
 
                            break;
814
 
                            
815
 
                          default:
816
 
 
817
 
                            throw Iex::ArgExc ("Unknown pixel data type.");
818
 
                        }
819
 
                    }
820
 
                    else
821
 
                    {
822
 
                        //
823
 
                        // The compressor expects data in the
824
 
                        // machine's native format.
825
 
                        //
826
 
 
827
 
                        switch (slice.type)
828
 
                        {
829
 
                          case UINT:
830
 
 
831
 
                            while (pixelPtr <= endPtr)
832
 
                            {
833
 
                                for (size_t i = 0;
834
 
                                     i < sizeof (unsigned int);
835
 
                                     ++i)
836
 
                                {
837
 
                                    *writePtr++ = pixelPtr[i];
838
 
                                }
839
 
 
840
 
                                pixelPtr += slice.xStride;
841
 
                            }
842
 
                            break;
843
 
 
844
 
                          case HALF:
845
 
 
846
 
                            while (pixelPtr <= endPtr)
847
 
                            {
848
 
                                *(half *) writePtr = *(const half *) pixelPtr;
849
 
                                writePtr += sizeof (half);
850
 
                                pixelPtr += slice.xStride;
851
 
                            }
852
 
                            break;
853
 
 
854
 
                          case FLOAT:
855
 
 
856
 
                            while (pixelPtr <= endPtr)
857
 
                            {
858
 
                                for (size_t i = 0; i < sizeof (float); ++i)
859
 
                                    *writePtr++ = pixelPtr[i];
860
 
 
861
 
                                pixelPtr += slice.xStride;
862
 
                            }
863
 
                            break;
864
 
                            
865
 
                          default:
866
 
 
867
 
                            throw Iex::ArgExc ("Unknown pixel data type.");
868
 
                        }
869
 
                    }
870
 
                }
871
 
            }
872
 
 
873
 
            if (_data->endOfLineBufferData < writePtr)
874
 
                _data->endOfLineBufferData = writePtr;
875
 
 
876
 
            #ifdef DEBUG
877
 
 
878
 
                assert (writePtr - (_data->lineBuffer +
879
 
                        _data->offsetInLineBuffer[y - _data->minY]) ==
880
 
                        (int) _data->bytesPerLine[y - _data->minY]);
881
 
 
882
 
            #endif
883
 
 
884
 
            //
885
 
            // If _data->lineBuffer is full, or if the current scan
886
 
            // line is the last one, then compress the contents of
887
 
            // _data->lineBuffer, and store the compressed data in
888
 
            // the output file.
889
 
            //
890
 
 
891
 
            int nextScanLine = _data->currentScanLine +
892
 
                               ((_data->lineOrder == INCREASING_Y)? 1: -1);
893
 
 
894
 
            if (nextScanLine < _data->lineBufferMinY ||
895
 
                nextScanLine > _data->lineBufferMaxY ||
896
 
                _data->missingScanLines <= 1)
897
 
            {
898
 
                int dataSize = _data->endOfLineBufferData - _data->lineBuffer;
899
 
                const char *dataPtr = _data->lineBuffer;
900
 
 
901
 
                if (_data->compressor)
902
 
                {
903
 
                    const char *compPtr;
904
 
 
905
 
                    int compSize = _data->compressor->compress
906
 
                                        (dataPtr, dataSize,
907
 
                                         _data->lineBufferMinY,
908
 
                                         compPtr);
909
 
 
910
 
                    if (compSize < dataSize)
911
 
                    {
912
 
                        dataSize = compSize;
913
 
                        dataPtr = compPtr;
914
 
                    }
915
 
                    else if (_data->format == Compressor::NATIVE)
916
 
                    {
917
 
                        //
918
 
                        // The data did not shrink during compression, but
919
 
                        // we cannot write to the file using the machine's
920
 
                        // native format, so we need to convert the lineBuffer
921
 
                        // to Xdr.
922
 
                        //
923
 
 
924
 
                        convertToXdr(_data, dataSize);
925
 
                    }
926
 
                }
927
 
 
928
 
                writePixelData (_data, dataPtr, dataSize);
929
 
 
930
 
                //
931
 
                // Clear _data->lineBuffer.
932
 
                //
933
 
 
934
 
                _data->endOfLineBufferData = _data->lineBuffer;
935
 
 
936
 
                _data->lineBufferMinY = lineBufferMinY (nextScanLine,
937
 
                                                        _data->minY,
938
 
                                                        _data->linesInBuffer);
939
 
 
940
 
                _data->lineBufferMaxY = lineBufferMaxY (nextScanLine,
941
 
                                                        _data->minY,
942
 
                                                        _data->linesInBuffer);
943
 
            }
944
 
 
945
 
            //
946
 
            // Advance to the next scan line.
947
 
            //
948
 
 
949
 
            numScanLines -= 1;
950
 
            _data->currentScanLine = nextScanLine;
951
 
            _data->missingScanLines -= 1;
 
1109
            LineBuffer *lineBuffer = _data->lineBuffers[i];
 
1110
 
 
1111
            if (lineBuffer->hasException && !exception)
 
1112
                exception = &lineBuffer->exception;
 
1113
 
 
1114
            lineBuffer->hasException = false;
952
1115
        }
 
1116
 
 
1117
        if (exception)
 
1118
            throw Iex::IoExc (*exception);
953
1119
    }
954
1120
    catch (Iex::BaseExc &e)
955
1121
    {
963
1129
int     
964
1130
OutputFile::currentScanLine () const
965
1131
{
 
1132
    Lock lock (*_data);
966
1133
    return _data->currentScanLine;
967
1134
}
968
1135
 
970
1137
void    
971
1138
OutputFile::copyPixels (InputFile &in)
972
1139
{
 
1140
    Lock lock (*_data);
 
1141
 
973
1142
    //
974
1143
    // Check if this file's and and the InputFile's
975
1144
    // headers are compatible.
976
1145
    //
977
1146
 
978
 
    const Header &hdr = header();
 
1147
    const Header &hdr = _data->header;
979
1148
    const Header &inHdr = in.header();
980
1149
 
981
1150
    if (inHdr.find("tiles") != inHdr.end())
982
 
    {
983
1151
        THROW (Iex::ArgExc, "Cannot copy pixels from image "
984
1152
                            "file \"" << in.fileName() << "\" to image "
985
 
                            "file \"" << fileName() << "\". The input file is "
986
 
                            "tiled, but the output file is not. Try using "
987
 
                            "TiledOutputFile::copyPixels instead.");
988
 
    }
 
1153
                            "file \"" << fileName() << "\". "
 
1154
                            "The input file is tiled, but the output file is "
 
1155
                            "not. Try using TiledOutputFile::copyPixels "
 
1156
                            "instead.");
989
1157
 
990
1158
    if (!(hdr.dataWindow() == inHdr.dataWindow()))
991
 
    {
992
1159
        THROW (Iex::ArgExc, "Cannot copy pixels from image "
993
1160
                            "file \"" << in.fileName() << "\" to image "
994
 
                            "file \"" << fileName() << "\". The files "
995
 
                            "have different data windows.");
996
 
    }
 
1161
                            "file \"" << fileName() << "\". "
 
1162
                            "The files have different data windows.");
997
1163
 
998
1164
    if (!(hdr.lineOrder() == inHdr.lineOrder()))
999
 
    {
1000
1165
        THROW (Iex::ArgExc, "Quick pixel copy from image "
1001
1166
                            "file \"" << in.fileName() << "\" to image "
1002
1167
                            "file \"" << fileName() << "\" failed. "
1003
1168
                            "The files have different line orders.");
1004
 
    }
1005
1169
 
1006
1170
    if (!(hdr.compression() == inHdr.compression()))
1007
 
    {
1008
1171
        THROW (Iex::ArgExc, "Quick pixel copy from image "
1009
1172
                            "file \"" << in.fileName() << "\" to image "
1010
1173
                            "file \"" << fileName() << "\" failed. "
1011
1174
                            "The files use different compression methods.");
1012
 
    }
1013
1175
 
1014
1176
    if (!(hdr.channels() == inHdr.channels()))
1015
 
    {
1016
1177
        THROW (Iex::ArgExc, "Quick pixel copy from image "
1017
1178
                            "file \"" << in.fileName() << "\" to image "
1018
1179
                            "file \"" << fileName() << "\" failed.  "
1019
1180
                            "The files have different channel lists.");
1020
 
    }
1021
1181
 
1022
1182
    //
1023
1183
    // Verify that no pixel data have been written to this file yet.
1026
1186
    const Box2i &dataWindow = hdr.dataWindow();
1027
1187
 
1028
1188
    if (_data->missingScanLines != dataWindow.max.y - dataWindow.min.y + 1)
1029
 
    {
1030
1189
        THROW (Iex::LogicExc, "Quick pixel copy from image "
1031
1190
                              "file \"" << in.fileName() << "\" to image "
1032
1191
                              "file \"" << fileName() << "\" failed. "
1033
1192
                              "\"" << fileName() << "\" already contains "
1034
1193
                              "pixel data.");
1035
 
    }
1036
1194
 
1037
1195
    //
1038
1196
    // Copy the pixel data.
1044
1202
        int pixelDataSize;
1045
1203
 
1046
1204
        in.rawPixelData (_data->currentScanLine, pixelData, pixelDataSize);
1047
 
        writePixelData (_data, pixelData, pixelDataSize);
 
1205
 
 
1206
        writePixelData (_data, lineBufferMinY (_data->currentScanLine,
 
1207
                                               _data->minY,
 
1208
                                               _data->linesInBuffer),
 
1209
                        pixelData, pixelDataSize);
1048
1210
 
1049
1211
        _data->currentScanLine += (_data->lineOrder == INCREASING_Y)?
1050
1212
                                   _data->linesInBuffer: -_data->linesInBuffer;
1051
1213
 
1052
 
        _data->lineBufferMinY = lineBufferMinY (_data->currentScanLine,
1053
 
                                                _data->minY,
1054
 
                                                _data->linesInBuffer);
1055
 
 
1056
1214
        _data->missingScanLines -= _data->linesInBuffer;
1057
1215
    }
1058
1216
}
1061
1219
void
1062
1220
OutputFile::updatePreviewImage (const PreviewRgba newPixels[])
1063
1221
{
 
1222
    Lock lock (*_data);
 
1223
 
1064
1224
    if (_data->previewPosition <= 0)
1065
 
    {
1066
1225
        THROW (Iex::LogicExc, "Cannot update preview image pixels. "
1067
1226
                              "File \"" << fileName() << "\" does not "
1068
1227
                              "contain a preview image.");
1069
 
    }
1070
1228
 
1071
1229
    //
1072
1230
    // Store the new pixels in the header's preview image attribute.
1105
1263
}
1106
1264
 
1107
1265
 
 
1266
void    
 
1267
OutputFile::breakScanLine  (int y, int offset, int length, char c)
 
1268
{
 
1269
    Lock lock (*_data);
 
1270
 
 
1271
    Int64 position = 
 
1272
        _data->lineOffsets[(y - _data->minY) / _data->linesInBuffer];
 
1273
 
 
1274
    if (!position)
 
1275
        THROW (Iex::ArgExc, "Cannot overwrite scan line " << y << ". "
 
1276
                            "The scan line has not yet been stored in "
 
1277
                            "file \"" << fileName() << "\".");
 
1278
 
 
1279
    _data->currentPosition = 0;
 
1280
    _data->os->seekp (position + offset);
 
1281
 
 
1282
    for (int i = 0; i < length; ++i)
 
1283
        _data->os->write (&c, 1);
 
1284
}
 
1285
 
 
1286
 
1108
1287
} // namespace Imf