~paparazzi-uav/paparazzi/v5.0-manual

« back to all changes in this revision

Viewing changes to sw/ext/opencv_bebop/opencv/3rdparty/openexr/IlmImf/ImfScanLineInputFile.cpp

  • Committer: Paparazzi buildbot
  • Date: 2016-05-18 15:00:29 UTC
  • Revision ID: felix.ruess+docbot@gmail.com-20160518150029-e8lgzi5kvb4p7un9
Manual import commit 4b8bbb730080dac23cf816b98908dacfabe2a8ec from v5.0 branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
///////////////////////////////////////////////////////////////////////////
 
2
//
 
3
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
 
4
// Digital Ltd. LLC
 
5
//
 
6
// All rights reserved.
 
7
//
 
8
// Redistribution and use in source and binary forms, with or without
 
9
// modification, are permitted provided that the following conditions are
 
10
// met:
 
11
// *       Redistributions of source code must retain the above copyright
 
12
// notice, this list of conditions and the following disclaimer.
 
13
// *       Redistributions in binary form must reproduce the above
 
14
// copyright notice, this list of conditions and the following disclaimer
 
15
// in the documentation and/or other materials provided with the
 
16
// distribution.
 
17
// *       Neither the name of Industrial Light & Magic nor the names of
 
18
// its contributors may be used to endorse or promote products derived
 
19
// from this software without specific prior written permission.
 
20
//
 
21
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 
22
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 
23
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 
24
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 
25
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
26
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 
27
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
28
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
29
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
30
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 
31
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
32
//
 
33
///////////////////////////////////////////////////////////////////////////
 
34
 
 
35
 
 
36
//-----------------------------------------------------------------------------
 
37
//
 
38
//      class ScanLineInputFile
 
39
//
 
40
//-----------------------------------------------------------------------------
 
41
 
 
42
#include <ImfScanLineInputFile.h>
 
43
#include <ImfChannelList.h>
 
44
#include <ImfMisc.h>
 
45
#include <ImfStdIO.h>
 
46
#include <ImfCompressor.h>
 
47
#include "ImathBox.h"
 
48
#include "ImathFun.h"
 
49
#include <ImfXdr.h>
 
50
#include <ImfConvert.h>
 
51
#include <ImfThreading.h>
 
52
#include "IlmThreadPool.h"
 
53
#include "IlmThreadSemaphore.h"
 
54
#include "IlmThreadMutex.h"
 
55
#include "Iex.h"
 
56
#include <string>
 
57
#include <vector>
 
58
#include <assert.h>
 
59
#include <algorithm> // for std::max()
 
60
 
 
61
 
 
62
namespace Imf {
 
63
 
 
64
using Imath::Box2i;
 
65
using Imath::divp;
 
66
using Imath::modp;
 
67
using std::string;
 
68
using std::vector;
 
69
using std::ifstream;
 
70
using std::min;
 
71
using std::max;
 
72
using IlmThread::Mutex;
 
73
using IlmThread::Lock;
 
74
using IlmThread::Semaphore;
 
75
using IlmThread::Task;
 
76
using IlmThread::TaskGroup;
 
77
using IlmThread::ThreadPool;
 
78
 
 
79
namespace {
 
80
 
 
81
struct InSliceInfo
 
82
{
 
83
    PixelType   typeInFrameBuffer;
 
84
    PixelType   typeInFile;
 
85
    char *      base;
 
86
    size_t      xStride;
 
87
    size_t      yStride;
 
88
    int         xSampling;
 
89
    int         ySampling;
 
90
    bool        fill;
 
91
    bool        skip;
 
92
    double      fillValue;
 
93
 
 
94
    InSliceInfo (PixelType typeInFrameBuffer = HALF,
 
95
         PixelType typeInFile = HALF,
 
96
             char *base = 0,
 
97
             size_t xStride = 0,
 
98
             size_t yStride = 0,
 
99
             int xSampling = 1,
 
100
             int ySampling = 1,
 
101
             bool fill = false,
 
102
             bool skip = false,
 
103
             double fillValue = 0.0);
 
104
};
 
105
 
 
106
 
 
107
InSliceInfo::InSliceInfo (PixelType tifb,
 
108
              PixelType tifl,
 
109
              char *b,
 
110
              size_t xs, size_t ys,
 
111
              int xsm, int ysm,
 
112
              bool f, bool s,
 
113
              double fv)
 
114
:
 
115
    typeInFrameBuffer (tifb),
 
116
    typeInFile (tifl),
 
117
    base (b),
 
118
    xStride (xs),
 
119
    yStride (ys),
 
120
    xSampling (xsm),
 
121
    ySampling (ysm),
 
122
    fill (f),
 
123
    skip (s),
 
124
    fillValue (fv)
 
125
{
 
126
    // empty
 
127
}
 
128
 
 
129
 
 
130
struct LineBuffer
 
131
{
 
132
    const char *        uncompressedData;
 
133
    char *              buffer;
 
134
    int                 dataSize;
 
135
    int                 minY;
 
136
    int                 maxY;
 
137
    Compressor *        compressor;
 
138
    Compressor::Format  format;
 
139
    int                 number;
 
140
    bool                hasException;
 
141
    string              exception;
 
142
 
 
143
    LineBuffer (Compressor * const comp);
 
144
    ~LineBuffer ();
 
145
 
 
146
    inline void         wait () {_sem.wait();}
 
147
    inline void         post () {_sem.post();}
 
148
 
 
149
  private:
 
150
 
 
151
    Semaphore           _sem;
 
152
};
 
153
 
 
154
 
 
155
LineBuffer::LineBuffer (Compressor *comp):
 
156
    uncompressedData (0),
 
157
    buffer (0),
 
158
    dataSize (0),
 
159
    compressor (comp),
 
160
    format (defaultFormat(compressor)),
 
161
    number (-1),
 
162
    hasException (false),
 
163
    exception (),
 
164
    _sem (1)
 
165
{
 
166
    // empty
 
167
}
 
168
 
 
169
 
 
170
LineBuffer::~LineBuffer ()
 
171
{
 
172
    delete compressor;
 
173
}
 
174
 
 
175
} // namespace
 
176
 
 
177
 
 
178
struct ScanLineInputFile::Data: public Mutex
 
179
{
 
180
    Header              header;             // the image header
 
181
    int                 version;            // file's version
 
182
    FrameBuffer         frameBuffer;        // framebuffer to write into
 
183
    LineOrder           lineOrder;          // order of the scanlines in file
 
184
    int                 minX;               // data window's min x coord
 
185
    int                 maxX;               // data window's max x coord
 
186
    int                 minY;               // data window's min y coord
 
187
    int                 maxY;               // data window's max x coord
 
188
    vector<Int64>       lineOffsets;        // stores offsets in file for
 
189
                        // each line
 
190
    bool                fileIsComplete;     // True if no scanlines are missing
 
191
                            // in the file
 
192
    int                 nextLineBufferMinY; // minimum y of the next linebuffer
 
193
    vector<size_t>      bytesPerLine;       // combined size of a line over all
 
194
                                            // channels
 
195
    vector<size_t>      offsetInLineBuffer; // offset for each scanline in its
 
196
                                            // linebuffer
 
197
    vector<InSliceInfo> slices;             // info about channels in file
 
198
    IStream *           is;                 // file stream to read from
 
199
 
 
200
    vector<LineBuffer*> lineBuffers;        // each holds one line buffer
 
201
    int                 linesInBuffer;      // number of scanlines each buffer
 
202
                                            // holds
 
203
    size_t              lineBufferSize;     // size of the line buffer
 
204
 
 
205
     Data (IStream *is, int numThreads);
 
206
    ~Data ();
 
207
 
 
208
    inline LineBuffer * getLineBuffer (int number); // hash function from line
 
209
                                // buffer indices into our
 
210
                            // vector of line buffers
 
211
};
 
212
 
 
213
 
 
214
ScanLineInputFile::Data::Data (IStream *is, int numThreads):
 
215
    is (is)
 
216
{
 
217
    //
 
218
    // We need at least one lineBuffer, but if threading is used,
 
219
    // to keep n threads busy we need 2*n lineBuffers
 
220
    //
 
221
 
 
222
    lineBuffers.resize (max (1, 2 * numThreads));
 
223
}
 
224
 
 
225
 
 
226
ScanLineInputFile::Data::~Data ()
 
227
{
 
228
    for (size_t i = 0; i < lineBuffers.size(); i++)
 
229
        delete lineBuffers[i];
 
230
}
 
231
 
 
232
 
 
233
inline LineBuffer *
 
234
ScanLineInputFile::Data::getLineBuffer (int lineBufferNumber)
 
235
{
 
236
    return lineBuffers[lineBufferNumber % lineBuffers.size()];
 
237
}
 
238
 
 
239
 
 
240
namespace {
 
241
 
 
242
 
 
243
void
 
244
reconstructLineOffsets (IStream &is,
 
245
            LineOrder lineOrder,
 
246
            vector<Int64> &lineOffsets)
 
247
{
 
248
    Int64 position = is.tellg();
 
249
 
 
250
    try
 
251
    {
 
252
    for (unsigned int i = 0; i < lineOffsets.size(); i++)
 
253
    {
 
254
        Int64 lineOffset = is.tellg();
 
255
 
 
256
        int y;
 
257
        Xdr::read <StreamIO> (is, y);
 
258
 
 
259
        int dataSize;
 
260
        Xdr::read <StreamIO> (is, dataSize);
 
261
 
 
262
        Xdr::skip <StreamIO> (is, dataSize);
 
263
 
 
264
        if (lineOrder == INCREASING_Y)
 
265
        lineOffsets[i] = lineOffset;
 
266
        else
 
267
        lineOffsets[lineOffsets.size() - i - 1] = lineOffset;
 
268
    }
 
269
    }
 
270
    catch (...)
 
271
    {
 
272
    //
 
273
    // Suppress all exceptions.  This functions is
 
274
    // called only to reconstruct the line offset
 
275
    // table for incomplete files, and exceptions
 
276
    // are likely.
 
277
    //
 
278
    }
 
279
 
 
280
    is.clear();
 
281
    is.seekg (position);
 
282
}
 
283
 
 
284
 
 
285
void
 
286
readLineOffsets (IStream &is,
 
287
         LineOrder lineOrder,
 
288
         vector<Int64> &lineOffsets,
 
289
         bool &complete)
 
290
{
 
291
    for (unsigned int i = 0; i < lineOffsets.size(); i++)
 
292
    {
 
293
    Xdr::read <StreamIO> (is, lineOffsets[i]);
 
294
    }
 
295
 
 
296
    complete = true;
 
297
 
 
298
    for (unsigned int i = 0; i < lineOffsets.size(); i++)
 
299
    {
 
300
    if (lineOffsets[i] <= 0)
 
301
    {
 
302
        //
 
303
        // Invalid data in the line offset table mean that
 
304
        // the file is probably incomplete (the table is
 
305
        // the last thing written to the file).  Either
 
306
        // some process is still busy writing the file,
 
307
        // or writing the file was aborted.
 
308
        //
 
309
        // We should still be able to read the existing
 
310
        // parts of the file.  In order to do this, we
 
311
        // have to make a sequential scan over the scan
 
312
        // line data to reconstruct the line offset table.
 
313
        //
 
314
 
 
315
        complete = false;
 
316
        reconstructLineOffsets (is, lineOrder, lineOffsets);
 
317
        break;
 
318
    }
 
319
    }
 
320
}
 
321
 
 
322
 
 
323
void
 
324
readPixelData (ScanLineInputFile::Data *ifd,
 
325
           int minY,
 
326
           char *&buffer,
 
327
           int &dataSize)
 
328
{
 
329
    //
 
330
    // Read a single line buffer from the input file.
 
331
    //
 
332
    // If the input file is not memory-mapped, we copy the pixel data into
 
333
    // into the array pointed to by buffer.  If the file is memory-mapped,
 
334
    // then we change where buffer points to instead of writing into the
 
335
    // array (hence buffer needs to be a reference to a char *).
 
336
    //
 
337
 
 
338
    Int64 lineOffset =
 
339
    ifd->lineOffsets[(minY - ifd->minY) / ifd->linesInBuffer];
 
340
 
 
341
    if (lineOffset == 0)
 
342
    THROW (Iex::InputExc, "Scan line " << minY << " is missing.");
 
343
 
 
344
    //
 
345
    // Seek to the start of the scan line in the file,
 
346
    // if necessary.
 
347
    //
 
348
 
 
349
    if (ifd->nextLineBufferMinY != minY)
 
350
    ifd->is->seekg (lineOffset);
 
351
 
 
352
    //
 
353
    // Read the data block's header.
 
354
    //
 
355
 
 
356
    int yInFile;
 
357
 
 
358
    Xdr::read <StreamIO> (*ifd->is, yInFile);
 
359
    Xdr::read <StreamIO> (*ifd->is, dataSize);
 
360
 
 
361
    if (yInFile != minY)
 
362
        throw Iex::InputExc ("Unexpected data block y coordinate.");
 
363
 
 
364
    if (dataSize > (int) ifd->lineBufferSize)
 
365
    throw Iex::InputExc ("Unexpected data block length.");
 
366
 
 
367
    //
 
368
    // Read the pixel data.
 
369
    //
 
370
 
 
371
    if (ifd->is->isMemoryMapped ())
 
372
        buffer = ifd->is->readMemoryMapped (dataSize);
 
373
    else
 
374
        ifd->is->read (buffer, dataSize);
 
375
 
 
376
    //
 
377
    // Keep track of which scan line is the next one in
 
378
    // the file, so that we can avoid redundant seekg()
 
379
    // operations (seekg() can be fairly expensive).
 
380
    //
 
381
 
 
382
    if (ifd->lineOrder == INCREASING_Y)
 
383
    ifd->nextLineBufferMinY = minY + ifd->linesInBuffer;
 
384
    else
 
385
    ifd->nextLineBufferMinY = minY - ifd->linesInBuffer;
 
386
}
 
387
 
 
388
 
 
389
//
 
390
// A LineBufferTask encapsulates the task uncompressing a set of
 
391
// scanlines (line buffer) and copying them into the frame buffer.
 
392
//
 
393
 
 
394
class LineBufferTask : public Task
 
395
{
 
396
  public:
 
397
 
 
398
    LineBufferTask (TaskGroup *group,
 
399
                    ScanLineInputFile::Data *ifd,
 
400
            LineBuffer *lineBuffer,
 
401
                    int scanLineMin,
 
402
            int scanLineMax);
 
403
 
 
404
    virtual ~LineBufferTask ();
 
405
 
 
406
    virtual void                execute ();
 
407
 
 
408
  private:
 
409
 
 
410
    ScanLineInputFile::Data *   _ifd;
 
411
    LineBuffer *                _lineBuffer;
 
412
    int                         _scanLineMin;
 
413
    int                         _scanLineMax;
 
414
};
 
415
 
 
416
 
 
417
LineBufferTask::LineBufferTask
 
418
    (TaskGroup *group,
 
419
     ScanLineInputFile::Data *ifd,
 
420
     LineBuffer *lineBuffer,
 
421
     int scanLineMin,
 
422
     int scanLineMax)
 
423
:
 
424
    Task (group),
 
425
    _ifd (ifd),
 
426
    _lineBuffer (lineBuffer),
 
427
    _scanLineMin (scanLineMin),
 
428
    _scanLineMax (scanLineMax)
 
429
{
 
430
    // empty
 
431
}
 
432
 
 
433
 
 
434
LineBufferTask::~LineBufferTask ()
 
435
{
 
436
    //
 
437
    // Signal that the line buffer is now free
 
438
    //
 
439
 
 
440
    _lineBuffer->post ();
 
441
}
 
442
 
 
443
 
 
444
void
 
445
LineBufferTask::execute ()
 
446
{
 
447
    try
 
448
    {
 
449
        //
 
450
        // Uncompress the data, if necessary
 
451
        //
 
452
 
 
453
        if (_lineBuffer->uncompressedData == 0)
 
454
        {
 
455
            int uncompressedSize = 0;
 
456
            int maxY = min (_lineBuffer->maxY, _ifd->maxY);
 
457
 
 
458
            for (int i = _lineBuffer->minY - _ifd->minY;
 
459
                 i <= maxY - _ifd->minY;
 
460
         ++i)
 
461
        {
 
462
                uncompressedSize += (int) _ifd->bytesPerLine[i];
 
463
        }
 
464
 
 
465
            if (_lineBuffer->compressor &&
 
466
                _lineBuffer->dataSize < uncompressedSize)
 
467
            {
 
468
                _lineBuffer->format = _lineBuffer->compressor->format();
 
469
 
 
470
                _lineBuffer->dataSize = _lineBuffer->compressor->uncompress
 
471
                    (_lineBuffer->buffer, _lineBuffer->dataSize,
 
472
             _lineBuffer->minY, _lineBuffer->uncompressedData);
 
473
            }
 
474
            else
 
475
            {
 
476
                //
 
477
                // If the line is uncompressed, it's in XDR format,
 
478
                // regardless of the compressor's output format.
 
479
                //
 
480
 
 
481
                _lineBuffer->format = Compressor::XDR;
 
482
                _lineBuffer->uncompressedData = _lineBuffer->buffer;
 
483
            }
 
484
        }
 
485
 
 
486
        int yStart, yStop, dy;
 
487
 
 
488
        if (_ifd->lineOrder == INCREASING_Y)
 
489
        {
 
490
            yStart = _scanLineMin;
 
491
            yStop = _scanLineMax + 1;
 
492
            dy = 1;
 
493
        }
 
494
        else
 
495
        {
 
496
            yStart = _scanLineMax;
 
497
            yStop = _scanLineMin - 1;
 
498
            dy = -1;
 
499
        }
 
500
 
 
501
        for (int y = yStart; y != yStop; y += dy)
 
502
        {
 
503
            //
 
504
            // Convert one scan line's worth of pixel data back
 
505
            // from the machine-independent representation, and
 
506
            // store the result in the frame buffer.
 
507
            //
 
508
 
 
509
            const char *readPtr = _lineBuffer->uncompressedData +
 
510
                                  _ifd->offsetInLineBuffer[y - _ifd->minY];
 
511
 
 
512
            //
 
513
            // Iterate over all image channels.
 
514
            //
 
515
 
 
516
            for (unsigned int i = 0; i < _ifd->slices.size(); ++i)
 
517
            {
 
518
                //
 
519
                // Test if scan line y of this channel contains any data
 
520
        // (the scan line contains data only if y % ySampling == 0).
 
521
                //
 
522
 
 
523
                const InSliceInfo &slice = _ifd->slices[i];
 
524
 
 
525
                if (modp (y, slice.ySampling) != 0)
 
526
                    continue;
 
527
 
 
528
                //
 
529
                // Find the x coordinates of the leftmost and rightmost
 
530
                // sampled pixels (i.e. pixels within the data window
 
531
                // for which x % xSampling == 0).
 
532
                //
 
533
 
 
534
                int dMinX = divp (_ifd->minX, slice.xSampling);
 
535
                int dMaxX = divp (_ifd->maxX, slice.xSampling);
 
536
 
 
537
                //
 
538
        // Fill the frame buffer with pixel data.
 
539
                //
 
540
 
 
541
                if (slice.skip)
 
542
                {
 
543
                    //
 
544
                    // The file contains data for this channel, but
 
545
                    // the frame buffer contains no slice for this channel.
 
546
                    //
 
547
 
 
548
                    skipChannel (readPtr, slice.typeInFile, dMaxX - dMinX + 1);
 
549
                }
 
550
                else
 
551
                {
 
552
                    //
 
553
                    // The frame buffer contains a slice for this channel.
 
554
                    //
 
555
 
 
556
                    char *linePtr  = slice.base +
 
557
                                        divp (y, slice.ySampling) *
 
558
                                        slice.yStride;
 
559
 
 
560
                    char *writePtr = linePtr + dMinX * slice.xStride;
 
561
                    char *endPtr   = linePtr + dMaxX * slice.xStride;
 
562
 
 
563
                    copyIntoFrameBuffer (readPtr, writePtr, endPtr,
 
564
                                         slice.xStride, slice.fill,
 
565
                                         slice.fillValue, _lineBuffer->format,
 
566
                                         slice.typeInFrameBuffer,
 
567
                                         slice.typeInFile);
 
568
                }
 
569
            }
 
570
        }
 
571
    }
 
572
    catch (std::exception &e)
 
573
    {
 
574
        if (!_lineBuffer->hasException)
 
575
        {
 
576
            _lineBuffer->exception = e.what();
 
577
            _lineBuffer->hasException = true;
 
578
        }
 
579
    }
 
580
    catch (...)
 
581
    {
 
582
        if (!_lineBuffer->hasException)
 
583
        {
 
584
            _lineBuffer->exception = "unrecognized exception";
 
585
            _lineBuffer->hasException = true;
 
586
        }
 
587
    }
 
588
}
 
589
 
 
590
 
 
591
LineBufferTask *
 
592
newLineBufferTask
 
593
    (TaskGroup *group,
 
594
     ScanLineInputFile::Data *ifd,
 
595
     int number,
 
596
     int scanLineMin,
 
597
     int scanLineMax)
 
598
{
 
599
    //
 
600
    // Wait for a line buffer to become available, fill the line
 
601
    // buffer with raw data from the file if necessary, and create
 
602
    // a new LineBufferTask whose execute() method will uncompress
 
603
    // the contents of the buffer and copy the pixels into the
 
604
    // frame buffer.
 
605
    //
 
606
 
 
607
    LineBuffer *lineBuffer = ifd->getLineBuffer (number);
 
608
 
 
609
    try
 
610
    {
 
611
    lineBuffer->wait ();
 
612
 
 
613
    if (lineBuffer->number != number)
 
614
    {
 
615
        lineBuffer->minY = ifd->minY + number * ifd->linesInBuffer;
 
616
        lineBuffer->maxY = lineBuffer->minY + ifd->linesInBuffer - 1;
 
617
 
 
618
        lineBuffer->number = number;
 
619
        lineBuffer->uncompressedData = 0;
 
620
 
 
621
        readPixelData (ifd, lineBuffer->minY,
 
622
               lineBuffer->buffer,
 
623
               lineBuffer->dataSize);
 
624
    }
 
625
    }
 
626
    catch (std::exception &e)
 
627
    {
 
628
    if (!lineBuffer->hasException)
 
629
    {
 
630
        lineBuffer->exception = e.what();
 
631
        lineBuffer->hasException = true;
 
632
    }
 
633
    lineBuffer->number = -1;
 
634
    lineBuffer->post();\
 
635
    throw;
 
636
    }
 
637
    catch (...)
 
638
    {
 
639
    //
 
640
    // Reading from the file caused an exception.
 
641
    // Signal that the line buffer is free, and
 
642
    // re-throw the exception.
 
643
    //
 
644
 
 
645
    lineBuffer->exception = "unrecognized exception";
 
646
    lineBuffer->hasException = true;
 
647
    lineBuffer->number = -1;
 
648
    lineBuffer->post();
 
649
    throw;
 
650
    }
 
651
 
 
652
    scanLineMin = max (lineBuffer->minY, scanLineMin);
 
653
    scanLineMax = min (lineBuffer->maxY, scanLineMax);
 
654
 
 
655
    return new LineBufferTask (group, ifd, lineBuffer,
 
656
                   scanLineMin, scanLineMax);
 
657
}
 
658
 
 
659
} // namespace
 
660
 
 
661
 
 
662
ScanLineInputFile::ScanLineInputFile
 
663
    (const Header &header,
 
664
     IStream *is,
 
665
     int numThreads)
 
666
:
 
667
    _data (new Data (is, numThreads))
 
668
{
 
669
    try
 
670
    {
 
671
    _data->header = header;
 
672
 
 
673
    _data->lineOrder = _data->header.lineOrder();
 
674
 
 
675
    const Box2i &dataWindow = _data->header.dataWindow();
 
676
 
 
677
    _data->minX = dataWindow.min.x;
 
678
    _data->maxX = dataWindow.max.x;
 
679
    _data->minY = dataWindow.min.y;
 
680
    _data->maxY = dataWindow.max.y;
 
681
 
 
682
    size_t maxBytesPerLine = bytesPerLineTable (_data->header,
 
683
                                                    _data->bytesPerLine);
 
684
 
 
685
        for (size_t i = 0; i < _data->lineBuffers.size(); i++)
 
686
        {
 
687
            _data->lineBuffers[i] = new LineBuffer (newCompressor
 
688
                                                (_data->header.compression(),
 
689
                                                 maxBytesPerLine,
 
690
                                                 _data->header));
 
691
        }
 
692
 
 
693
        _data->linesInBuffer =
 
694
        numLinesInBuffer (_data->lineBuffers[0]->compressor);
 
695
 
 
696
        _data->lineBufferSize = maxBytesPerLine * _data->linesInBuffer;
 
697
 
 
698
        if (!_data->is->isMemoryMapped())
 
699
            for (size_t i = 0; i < _data->lineBuffers.size(); i++)
 
700
                _data->lineBuffers[i]->buffer = new char[_data->lineBufferSize];
 
701
 
 
702
    _data->nextLineBufferMinY = _data->minY - 1;
 
703
 
 
704
    offsetInLineBufferTable (_data->bytesPerLine,
 
705
                 _data->linesInBuffer,
 
706
                 _data->offsetInLineBuffer);
 
707
 
 
708
    int lineOffsetSize = (dataWindow.max.y - dataWindow.min.y +
 
709
                  _data->linesInBuffer) / _data->linesInBuffer;
 
710
 
 
711
    _data->lineOffsets.resize (lineOffsetSize);
 
712
 
 
713
    readLineOffsets (*_data->is,
 
714
             _data->lineOrder,
 
715
             _data->lineOffsets,
 
716
             _data->fileIsComplete);
 
717
    }
 
718
    catch (...)
 
719
    {
 
720
    delete _data;
 
721
    throw;
 
722
    }
 
723
}
 
724
 
 
725
 
 
726
ScanLineInputFile::~ScanLineInputFile ()
 
727
{
 
728
    if (!_data->is->isMemoryMapped())
 
729
        for (size_t i = 0; i < _data->lineBuffers.size(); i++)
 
730
            delete [] _data->lineBuffers[i]->buffer;
 
731
 
 
732
    delete _data;
 
733
}
 
734
 
 
735
 
 
736
const char *
 
737
ScanLineInputFile::fileName () const
 
738
{
 
739
    return _data->is->fileName();
 
740
}
 
741
 
 
742
 
 
743
const Header &
 
744
ScanLineInputFile::header () const
 
745
{
 
746
    return _data->header;
 
747
}
 
748
 
 
749
 
 
750
int
 
751
ScanLineInputFile::version () const
 
752
{
 
753
    return _data->version;
 
754
}
 
755
 
 
756
 
 
757
void
 
758
ScanLineInputFile::setFrameBuffer (const FrameBuffer &frameBuffer)
 
759
{
 
760
    Lock lock (*_data);
 
761
 
 
762
    //
 
763
    // Check if the new frame buffer descriptor is
 
764
    // compatible with the image file header.
 
765
    //
 
766
 
 
767
    const ChannelList &channels = _data->header.channels();
 
768
 
 
769
    for (FrameBuffer::ConstIterator j = frameBuffer.begin();
 
770
     j != frameBuffer.end();
 
771
     ++j)
 
772
    {
 
773
    ChannelList::ConstIterator i = channels.find (j.name());
 
774
 
 
775
    if (i == channels.end())
 
776
        continue;
 
777
 
 
778
    if (i.channel().xSampling != j.slice().xSampling ||
 
779
        i.channel().ySampling != j.slice().ySampling)
 
780
        THROW (Iex::ArgExc, "X and/or y subsampling factors "
 
781
                "of \"" << i.name() << "\" channel "
 
782
                "of input file \"" << fileName() << "\" are "
 
783
                "not compatible with the frame buffer's "
 
784
                "subsampling factors.");
 
785
    }
 
786
 
 
787
    //
 
788
    // Initialize the slice table for readPixels().
 
789
    //
 
790
 
 
791
    vector<InSliceInfo> slices;
 
792
    ChannelList::ConstIterator i = channels.begin();
 
793
 
 
794
    for (FrameBuffer::ConstIterator j = frameBuffer.begin();
 
795
     j != frameBuffer.end();
 
796
     ++j)
 
797
    {
 
798
    while (i != channels.end() && strcmp (i.name(), j.name()) < 0)
 
799
    {
 
800
        //
 
801
        // Channel i is present in the file but not
 
802
        // in the frame buffer; data for channel i
 
803
        // will be skipped during readPixels().
 
804
        //
 
805
 
 
806
        slices.push_back (InSliceInfo (i.channel().type,
 
807
                       i.channel().type,
 
808
                       0, // base
 
809
                       0, // xStride
 
810
                       0, // yStride
 
811
                       i.channel().xSampling,
 
812
                       i.channel().ySampling,
 
813
                       false,  // fill
 
814
                       true, // skip
 
815
                       0.0)); // fillValue
 
816
        ++i;
 
817
    }
 
818
 
 
819
    bool fill = false;
 
820
 
 
821
    if (i == channels.end() || strcmp (i.name(), j.name()) > 0)
 
822
    {
 
823
        //
 
824
        // Channel i is present in the frame buffer, but not in the file.
 
825
        // In the frame buffer, slice j will be filled with a default value.
 
826
        //
 
827
 
 
828
        fill = true;
 
829
    }
 
830
 
 
831
    slices.push_back (InSliceInfo (j.slice().type,
 
832
                       fill? j.slice().type:
 
833
                             i.channel().type,
 
834
                       j.slice().base,
 
835
                       j.slice().xStride,
 
836
                       j.slice().yStride,
 
837
                       j.slice().xSampling,
 
838
                       j.slice().ySampling,
 
839
                       fill,
 
840
                       false, // skip
 
841
                       j.slice().fillValue));
 
842
 
 
843
    if (i != channels.end() && !fill)
 
844
        ++i;
 
845
    }
 
846
 
 
847
    //
 
848
    // Store the new frame buffer.
 
849
    //
 
850
 
 
851
    _data->frameBuffer = frameBuffer;
 
852
    _data->slices = slices;
 
853
}
 
854
 
 
855
 
 
856
const FrameBuffer &
 
857
ScanLineInputFile::frameBuffer () const
 
858
{
 
859
    Lock lock (*_data);
 
860
    return _data->frameBuffer;
 
861
}
 
862
 
 
863
 
 
864
bool
 
865
ScanLineInputFile::isComplete () const
 
866
{
 
867
    return _data->fileIsComplete;
 
868
}
 
869
 
 
870
 
 
871
void
 
872
ScanLineInputFile::readPixels (int scanLine1, int scanLine2)
 
873
{
 
874
    try
 
875
    {
 
876
        Lock lock (*_data);
 
877
 
 
878
    if (_data->slices.size() == 0)
 
879
        throw Iex::ArgExc ("No frame buffer specified "
 
880
                   "as pixel data destination.");
 
881
 
 
882
    int scanLineMin = min (scanLine1, scanLine2);
 
883
    int scanLineMax = max (scanLine1, scanLine2);
 
884
 
 
885
    if (scanLineMin < _data->minY || scanLineMax > _data->maxY)
 
886
        throw Iex::ArgExc ("Tried to read scan line outside "
 
887
                   "the image file's data window.");
 
888
 
 
889
        //
 
890
        // We impose a numbering scheme on the lineBuffers where the first
 
891
        // scanline is contained in lineBuffer 1.
 
892
        //
 
893
        // Determine the first and last lineBuffer numbers in this scanline
 
894
        // range. We always attempt to read the scanlines in the order that
 
895
        // they are stored in the file.
 
896
        //
 
897
 
 
898
        int start, stop, dl;
 
899
 
 
900
        if (_data->lineOrder == INCREASING_Y)
 
901
        {
 
902
            start = (scanLineMin - _data->minY) / _data->linesInBuffer;
 
903
            stop  = (scanLineMax - _data->minY) / _data->linesInBuffer + 1;
 
904
            dl = 1;
 
905
        }
 
906
        else
 
907
        {
 
908
            start = (scanLineMax - _data->minY) / _data->linesInBuffer;
 
909
            stop  = (scanLineMin - _data->minY) / _data->linesInBuffer - 1;
 
910
            dl = -1;
 
911
        }
 
912
 
 
913
        //
 
914
        // Create a task group for all line buffer tasks.  When the
 
915
    // task group goes out of scope, the destructor waits until
 
916
    // all tasks are complete.
 
917
        //
 
918
 
 
919
        {
 
920
            TaskGroup taskGroup;
 
921
 
 
922
            //
 
923
            // Add the line buffer tasks.
 
924
            //
 
925
            // The tasks will execute in the order that they are created
 
926
            // because we lock the line buffers during construction and the
 
927
            // constructors are called by the main thread.  Hence, in order
 
928
        // for a successive task to execute the previous task which
 
929
        // used that line buffer must have completed already.
 
930
            //
 
931
 
 
932
            for (int l = start; l != stop; l += dl)
 
933
            {
 
934
                ThreadPool::addGlobalTask (newLineBufferTask (&taskGroup,
 
935
                                                              _data, l,
 
936
                                                              scanLineMin,
 
937
                                                              scanLineMax));
 
938
            }
 
939
 
 
940
        //
 
941
            // finish all tasks
 
942
        //
 
943
        }
 
944
 
 
945
    //
 
946
    // Exeption handling:
 
947
    //
 
948
    // LineBufferTask::execute() may have encountered exceptions, but
 
949
    // those exceptions occurred in another thread, not in the thread
 
950
    // that is executing this call to ScanLineInputFile::readPixels().
 
951
    // LineBufferTask::execute() has caught all exceptions and stored
 
952
    // the exceptions' what() strings in the line buffers.
 
953
    // Now we check if any line buffer contains a stored exception; if
 
954
    // this is the case then we re-throw the exception in this thread.
 
955
    // (It is possible that multiple line buffers contain stored
 
956
    // exceptions.  We re-throw the first exception we find and
 
957
    // ignore all others.)
 
958
    //
 
959
 
 
960
    const string *exception = 0;
 
961
 
 
962
        for (int i = 0; i < _data->lineBuffers.size(); ++i)
 
963
    {
 
964
            LineBuffer *lineBuffer = _data->lineBuffers[i];
 
965
 
 
966
        if (lineBuffer->hasException && !exception)
 
967
        exception = &lineBuffer->exception;
 
968
 
 
969
        lineBuffer->hasException = false;
 
970
    }
 
971
 
 
972
    if (exception)
 
973
        throw Iex::IoExc (*exception);
 
974
    }
 
975
    catch (Iex::BaseExc &e)
 
976
    {
 
977
    REPLACE_EXC (e, "Error reading pixel data from image "
 
978
                "file \"" << fileName() << "\". " << e);
 
979
    throw;
 
980
    }
 
981
}
 
982
 
 
983
 
 
984
void
 
985
ScanLineInputFile::readPixels (int scanLine)
 
986
{
 
987
    readPixels (scanLine, scanLine);
 
988
}
 
989
 
 
990
 
 
991
void
 
992
ScanLineInputFile::rawPixelData (int firstScanLine,
 
993
                 const char *&pixelData,
 
994
                 int &pixelDataSize)
 
995
{
 
996
    try
 
997
    {
 
998
        Lock lock (*_data);
 
999
 
 
1000
    if (firstScanLine < _data->minY || firstScanLine > _data->maxY)
 
1001
    {
 
1002
        throw Iex::ArgExc ("Tried to read scan line outside "
 
1003
                   "the image file's data window.");
 
1004
    }
 
1005
 
 
1006
        int minY = lineBufferMinY
 
1007
        (firstScanLine, _data->minY, _data->linesInBuffer);
 
1008
 
 
1009
    readPixelData
 
1010
        (_data, minY, _data->lineBuffers[0]->buffer, pixelDataSize);
 
1011
 
 
1012
    pixelData = _data->lineBuffers[0]->buffer;
 
1013
    }
 
1014
    catch (Iex::BaseExc &e)
 
1015
    {
 
1016
    REPLACE_EXC (e, "Error reading pixel data from image "
 
1017
                "file \"" << fileName() << "\". " << e);
 
1018
    throw;
 
1019
    }
 
1020
}
 
1021
 
 
1022
} // namespace Imf