Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/3rdparty/openexr/IlmImf/ImfInputFile.cpp
16337 views
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
// class InputFile
38
//
39
//-----------------------------------------------------------------------------
40
41
#include <ImfInputFile.h>
42
#include <ImfScanLineInputFile.h>
43
#include <ImfTiledInputFile.h>
44
#include <ImfChannelList.h>
45
#include <ImfMisc.h>
46
#include <ImfStdIO.h>
47
#include <ImfVersion.h>
48
#include "ImathFun.h"
49
#include "IlmThreadMutex.h"
50
#include "Iex.h"
51
#include "half.h"
52
#include <fstream>
53
#include <algorithm>
54
55
56
namespace Imf {
57
58
59
using Imath::Box2i;
60
using Imath::divp;
61
using Imath::modp;
62
using IlmThread::Mutex;
63
using IlmThread::Lock;
64
65
66
//
67
// Struct InputFile::Data stores things that will be
68
// needed between calls to readPixels
69
//
70
71
struct InputFile::Data: public Mutex
72
{
73
Header header;
74
int version;
75
IStream * is;
76
bool deleteStream;
77
78
TiledInputFile * tFile;
79
ScanLineInputFile * sFile;
80
81
LineOrder lineOrder; // the file's lineorder
82
int minY; // data window's min y coord
83
int maxY; // data window's max x coord
84
85
FrameBuffer tFileBuffer;
86
FrameBuffer * cachedBuffer;
87
88
int cachedTileY;
89
int offset;
90
91
int numThreads;
92
93
Data (bool del, int numThreads);
94
~Data ();
95
96
void deleteCachedBuffer();
97
};
98
99
100
InputFile::Data::Data (bool del, int numThreads):
101
is (0),
102
deleteStream (del),
103
tFile (0),
104
sFile (0),
105
cachedBuffer (0),
106
cachedTileY (-1),
107
numThreads (numThreads)
108
{
109
// empty
110
}
111
112
113
InputFile::Data::~Data ()
114
{
115
delete tFile;
116
delete sFile;
117
118
if (deleteStream)
119
delete is;
120
121
deleteCachedBuffer();
122
}
123
124
125
void
126
InputFile::Data::deleteCachedBuffer()
127
{
128
//
129
// Delete the cached frame buffer, and all memory
130
// allocated for the slices in the cached frameBuffer.
131
//
132
133
if (cachedBuffer)
134
{
135
for (FrameBuffer::Iterator k = cachedBuffer->begin();
136
k != cachedBuffer->end();
137
++k)
138
{
139
Slice &s = k.slice();
140
141
switch (s.type)
142
{
143
case UINT:
144
145
delete [] (((unsigned int *)s.base) + offset);
146
break;
147
148
case HALF:
149
150
delete [] ((half *)s.base + offset);
151
break;
152
153
case FLOAT:
154
155
delete [] (((float *)s.base) + offset);
156
break;
157
}
158
}
159
160
//
161
// delete the cached frame buffer
162
//
163
164
delete cachedBuffer;
165
cachedBuffer = 0;
166
}
167
}
168
169
170
namespace {
171
172
void
173
bufferedReadPixels (InputFile::Data* ifd, int scanLine1, int scanLine2)
174
{
175
//
176
// bufferedReadPixels reads each row of tiles that intersect the
177
// scan-line range (scanLine1 to scanLine2). The previous row of
178
// tiles is cached in order to prevent redundent tile reads when
179
// accessing scanlines sequentially.
180
//
181
182
int minY = std::min (scanLine1, scanLine2);
183
int maxY = std::max (scanLine1, scanLine2);
184
185
if (minY < ifd->minY || maxY > ifd->maxY)
186
{
187
throw Iex::ArgExc ("Tried to read scan line outside "
188
"the image file's data window.");
189
}
190
191
//
192
// The minimum and maximum y tile coordinates that intersect this
193
// scanline range
194
//
195
196
int minDy = (minY - ifd->minY) / ifd->tFile->tileYSize();
197
int maxDy = (maxY - ifd->minY) / ifd->tFile->tileYSize();
198
199
//
200
// Figure out which one is first in the file so we can read without seeking
201
//
202
203
int yStart, yEnd, yStep;
204
205
if (ifd->lineOrder == DECREASING_Y)
206
{
207
yStart = maxDy;
208
yEnd = minDy - 1;
209
yStep = -1;
210
}
211
else
212
{
213
yStart = minDy;
214
yEnd = maxDy + 1;
215
yStep = 1;
216
}
217
218
//
219
// the number of pixels in a row of tiles
220
//
221
222
Box2i levelRange = ifd->tFile->dataWindowForLevel(0);
223
224
//
225
// Read the tiles into our temporary framebuffer and copy them into
226
// the user's buffer
227
//
228
229
for (int j = yStart; j != yEnd; j += yStep)
230
{
231
Box2i tileRange = ifd->tFile->dataWindowForTile (0, j, 0);
232
233
int minYThisRow = std::max (minY, tileRange.min.y);
234
int maxYThisRow = std::min (maxY, tileRange.max.y);
235
236
if (j != ifd->cachedTileY)
237
{
238
//
239
// We don't have any valid buffered info, so we need to read in
240
// from the file.
241
//
242
243
ifd->tFile->readTiles (0, ifd->tFile->numXTiles (0) - 1, j, j);
244
ifd->cachedTileY = j;
245
}
246
247
//
248
// Copy the data from our cached framebuffer into the user's
249
// framebuffer.
250
//
251
252
for (FrameBuffer::ConstIterator k = ifd->cachedBuffer->begin();
253
k != ifd->cachedBuffer->end();
254
++k)
255
{
256
Slice fromSlice = k.slice(); // slice to write from
257
Slice toSlice = ifd->tFileBuffer[k.name()]; // slice to write to
258
259
char *fromPtr, *toPtr;
260
int size = pixelTypeSize (toSlice.type);
261
262
int xStart = levelRange.min.x;
263
int yStart = minYThisRow;
264
265
while (modp (xStart, toSlice.xSampling) != 0)
266
++xStart;
267
268
while (modp (yStart, toSlice.ySampling) != 0)
269
++yStart;
270
271
for (int y = yStart;
272
y <= maxYThisRow;
273
y += toSlice.ySampling)
274
{
275
//
276
// Set the pointers to the start of the y scanline in
277
// this row of tiles
278
//
279
280
fromPtr = fromSlice.base +
281
(y - tileRange.min.y) * fromSlice.yStride +
282
xStart * fromSlice.xStride;
283
284
toPtr = toSlice.base +
285
divp (y, toSlice.ySampling) * toSlice.yStride +
286
divp (xStart, toSlice.xSampling) * toSlice.xStride;
287
288
//
289
// Copy all pixels for the scanline in this row of tiles
290
//
291
292
for (int x = xStart;
293
x <= levelRange.max.x;
294
x += toSlice.xSampling)
295
{
296
for (size_t i = 0; i < size; ++i)
297
toPtr[i] = fromPtr[i];
298
299
fromPtr += fromSlice.xStride * toSlice.xSampling;
300
toPtr += toSlice.xStride;
301
}
302
}
303
}
304
}
305
}
306
307
} // namespace
308
309
310
311
InputFile::InputFile (const char fileName[], int numThreads):
312
_data (new Data (true, numThreads))
313
{
314
try
315
{
316
_data->is = new StdIFStream (fileName);
317
initialize();
318
}
319
catch (Iex::BaseExc &e)
320
{
321
delete _data;
322
323
REPLACE_EXC (e, "Cannot read image file "
324
"\"" << fileName << "\". " << e);
325
throw;
326
}
327
catch (...)
328
{
329
delete _data;
330
throw;
331
}
332
}
333
334
335
InputFile::InputFile (IStream &is, int numThreads):
336
_data (new Data (false, numThreads))
337
{
338
try
339
{
340
_data->is = &is;
341
initialize();
342
}
343
catch (Iex::BaseExc &e)
344
{
345
delete _data;
346
347
REPLACE_EXC (e, "Cannot read image file "
348
"\"" << is.fileName() << "\". " << e);
349
throw;
350
}
351
catch (...)
352
{
353
delete _data;
354
throw;
355
}
356
}
357
358
359
void
360
InputFile::initialize ()
361
{
362
_data->header.readFrom (*_data->is, _data->version);
363
_data->header.sanityCheck (isTiled (_data->version));
364
365
if (isTiled (_data->version))
366
{
367
_data->lineOrder = _data->header.lineOrder();
368
369
//
370
// Save the dataWindow information
371
//
372
373
const Box2i &dataWindow = _data->header.dataWindow();
374
_data->minY = dataWindow.min.y;
375
_data->maxY = dataWindow.max.y;
376
377
_data->tFile = new TiledInputFile (_data->header,
378
_data->is,
379
_data->version,
380
_data->numThreads);
381
}
382
else
383
{
384
_data->sFile = new ScanLineInputFile (_data->header,
385
_data->is,
386
_data->numThreads);
387
}
388
}
389
390
391
InputFile::~InputFile ()
392
{
393
delete _data;
394
}
395
396
397
const char *
398
InputFile::fileName () const
399
{
400
return _data->is->fileName();
401
}
402
403
404
const Header &
405
InputFile::header () const
406
{
407
return _data->header;
408
}
409
410
411
int
412
InputFile::version () const
413
{
414
return _data->version;
415
}
416
417
418
void
419
InputFile::setFrameBuffer (const FrameBuffer &frameBuffer)
420
{
421
if (isTiled (_data->version))
422
{
423
Lock lock (*_data);
424
425
//
426
// We must invalidate the cached buffer if the new frame
427
// buffer has a different set of channels than the old
428
// frame buffer, or if the type of a channel has changed.
429
//
430
431
const FrameBuffer &oldFrameBuffer = _data->tFileBuffer;
432
433
FrameBuffer::ConstIterator i = oldFrameBuffer.begin();
434
FrameBuffer::ConstIterator j = frameBuffer.begin();
435
436
while (i != oldFrameBuffer.end() && j != frameBuffer.end())
437
{
438
if (strcmp (i.name(), j.name()) || i.slice().type != j.slice().type)
439
break;
440
441
++i;
442
++j;
443
}
444
445
if (i != oldFrameBuffer.end() || j != frameBuffer.end())
446
{
447
//
448
// Invalidate the cached buffer.
449
//
450
451
_data->deleteCachedBuffer ();
452
_data->cachedTileY = -1;
453
454
//
455
// Create new a cached frame buffer. It can hold a single
456
// row of tiles. The cached buffer can be reused for each
457
// row of tiles because we set the yTileCoords parameter of
458
// each Slice to true.
459
//
460
461
const Box2i &dataWindow = _data->header.dataWindow();
462
_data->cachedBuffer = new FrameBuffer();
463
_data->offset = dataWindow.min.x;
464
465
int tileRowSize = (dataWindow.max.x - dataWindow.min.x + 1) *
466
_data->tFile->tileYSize();
467
468
for (FrameBuffer::ConstIterator k = frameBuffer.begin();
469
k != frameBuffer.end();
470
++k)
471
{
472
Slice s = k.slice();
473
474
switch (s.type)
475
{
476
case UINT:
477
478
_data->cachedBuffer->insert
479
(k.name(),
480
Slice (UINT,
481
(char *)(new unsigned int[tileRowSize] -
482
_data->offset),
483
sizeof (unsigned int),
484
sizeof (unsigned int) *
485
_data->tFile->levelWidth(0),
486
1, 1,
487
s.fillValue,
488
false, true));
489
break;
490
491
case HALF:
492
493
_data->cachedBuffer->insert
494
(k.name(),
495
Slice (HALF,
496
(char *)(new half[tileRowSize] -
497
_data->offset),
498
sizeof (half),
499
sizeof (half) *
500
_data->tFile->levelWidth(0),
501
1, 1,
502
s.fillValue,
503
false, true));
504
break;
505
506
case FLOAT:
507
508
_data->cachedBuffer->insert
509
(k.name(),
510
Slice (FLOAT,
511
(char *)(new float[tileRowSize] -
512
_data->offset),
513
sizeof(float),
514
sizeof(float) *
515
_data->tFile->levelWidth(0),
516
1, 1,
517
s.fillValue,
518
false, true));
519
break;
520
521
default:
522
523
throw Iex::ArgExc ("Unknown pixel data type.");
524
}
525
}
526
527
_data->tFile->setFrameBuffer (*_data->cachedBuffer);
528
}
529
530
_data->tFileBuffer = frameBuffer;
531
}
532
else
533
{
534
_data->sFile->setFrameBuffer (frameBuffer);
535
}
536
}
537
538
539
const FrameBuffer &
540
InputFile::frameBuffer () const
541
{
542
if (isTiled (_data->version))
543
{
544
Lock lock (*_data);
545
return _data->tFileBuffer;
546
}
547
else
548
{
549
return _data->sFile->frameBuffer();
550
}
551
}
552
553
554
bool
555
InputFile::isComplete () const
556
{
557
if (isTiled (_data->version))
558
return _data->tFile->isComplete();
559
else
560
return _data->sFile->isComplete();
561
}
562
563
564
void
565
InputFile::readPixels (int scanLine1, int scanLine2)
566
{
567
if (isTiled (_data->version))
568
{
569
Lock lock (*_data);
570
bufferedReadPixels (_data, scanLine1, scanLine2);
571
}
572
else
573
{
574
_data->sFile->readPixels (scanLine1, scanLine2);
575
}
576
}
577
578
579
void
580
InputFile::readPixels (int scanLine)
581
{
582
readPixels (scanLine, scanLine);
583
}
584
585
586
void
587
InputFile::rawPixelData (int firstScanLine,
588
const char *&pixelData,
589
int &pixelDataSize)
590
{
591
try
592
{
593
if (isTiled (_data->version))
594
{
595
throw Iex::ArgExc ("Tried to read a raw scanline "
596
"from a tiled image.");
597
}
598
599
_data->sFile->rawPixelData (firstScanLine, pixelData, pixelDataSize);
600
}
601
catch (Iex::BaseExc &e)
602
{
603
REPLACE_EXC (e, "Error reading pixel data from image "
604
"file \"" << fileName() << "\". " << e);
605
throw;
606
}
607
}
608
609
610
void
611
InputFile::rawTileData (int &dx, int &dy,
612
int &lx, int &ly,
613
const char *&pixelData,
614
int &pixelDataSize)
615
{
616
try
617
{
618
if (!isTiled (_data->version))
619
{
620
throw Iex::ArgExc ("Tried to read a raw tile "
621
"from a scanline-based image.");
622
}
623
624
_data->tFile->rawTileData (dx, dy, lx, ly, pixelData, pixelDataSize);
625
}
626
catch (Iex::BaseExc &e)
627
{
628
REPLACE_EXC (e, "Error reading tile data from image "
629
"file \"" << fileName() << "\". " << e);
630
throw;
631
}
632
}
633
634
635
TiledInputFile*
636
InputFile::tFile()
637
{
638
if (!isTiled (_data->version))
639
{
640
throw Iex::ArgExc ("Cannot get a TiledInputFile pointer "
641
"from an InputFile that is not tiled.");
642
}
643
644
return _data->tFile;
645
}
646
647
648
} // namespace Imf
649
650