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 "ImfPartType.h"
49 #include "ImfInputPartData.h"
50 #include "ImfMultiPartInputFile.h"
51
52 #include <ImfCompositeDeepScanLine.h>
53 #include <ImfDeepScanLineInputFile.h>
54
55 #include "ImathFun.h"
56 #include "IlmThreadMutex.h"
57 #include "Iex.h"
58 #include "half.h"
59
60 #include <fstream>
61 #include <algorithm>
62
63 #include "ImfNamespace.h"
64
65 OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
66
67
68 using IMATH_NAMESPACE::Box2i;
69 using IMATH_NAMESPACE::divp;
70 using IMATH_NAMESPACE::modp;
71 using ILMTHREAD_NAMESPACE::Mutex;
72 using ILMTHREAD_NAMESPACE::Lock;
73
74
75 //
76 // Struct InputFile::Data stores things that will be
77 // needed between calls to readPixels
78 //
79
80 struct InputFile::Data : public Mutex
81 {
82 Header header;
83 int version;
84 bool isTiled;
85
86 TiledInputFile * tFile;
87 ScanLineInputFile * sFile;
88 DeepScanLineInputFile * dsFile;
89
90 LineOrder lineOrder; // the file's lineorder
91 int minY; // data window's min y coord
92 int maxY; // data window's max x coord
93
94 FrameBuffer tFileBuffer;
95 FrameBuffer * cachedBuffer;
96 CompositeDeepScanLine * compositor; // for loading deep files
97
98 int cachedTileY;
99 int offset;
100
101 int numThreads;
102
103 int partNumber;
104 InputPartData* part;
105
106 bool multiPartBackwardSupport;
107 MultiPartInputFile* multiPartFile;
108 InputStreamMutex * _streamData;
109 bool _deleteStream;
110
111 Data (int numThreads);
112 ~Data ();
113
114 void deleteCachedBuffer();
115 };
116
117
Data(int numThreads)118 InputFile::Data::Data (int numThreads):
119 isTiled (false),
120 tFile (0),
121 sFile (0),
122 dsFile(0),
123 cachedBuffer (0),
124 compositor(0),
125 cachedTileY (-1),
126 numThreads (numThreads),
127 partNumber (-1),
128 part(NULL),
129 multiPartBackwardSupport (false),
130 multiPartFile (0),
131 _streamData(0),
132 _deleteStream(false)
133
134 {
135 // empty
136 }
137
138
~Data()139 InputFile::Data::~Data ()
140 {
141 if (tFile)
142 delete tFile;
143 if (sFile)
144 delete sFile;
145 if (dsFile)
146 delete dsFile;
147 if (compositor)
148 delete compositor;
149
150 deleteCachedBuffer();
151
152 if (multiPartBackwardSupport && multiPartFile)
153 delete multiPartFile;
154 }
155
156
157 void
deleteCachedBuffer()158 InputFile::Data::deleteCachedBuffer()
159 {
160 //
161 // Delete the cached frame buffer, and all memory
162 // allocated for the slices in the cached frameBuffer.
163 //
164
165 if (cachedBuffer)
166 {
167 for (FrameBuffer::Iterator k = cachedBuffer->begin();
168 k != cachedBuffer->end();
169 ++k)
170 {
171 Slice &s = k.slice();
172
173 switch (s.type)
174 {
175 case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
176
177 delete [] (((unsigned int *)s.base) + offset);
178 break;
179
180 case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
181
182 delete [] ((half *)s.base + offset);
183 break;
184
185 case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
186
187 delete [] (((float *)s.base) + offset);
188 break;
189 case NUM_PIXELTYPES :
190 throw(IEX_NAMESPACE::ArgExc("Invalid pixel type"));
191 }
192 }
193
194 //
195 // delete the cached frame buffer
196 //
197
198 delete cachedBuffer;
199 cachedBuffer = 0;
200 }
201 }
202
203
204 namespace {
205
206 void
bufferedReadPixels(InputFile::Data * ifd,int scanLine1,int scanLine2)207 bufferedReadPixels (InputFile::Data* ifd, int scanLine1, int scanLine2)
208 {
209 //
210 // bufferedReadPixels reads each row of tiles that intersect the
211 // scan-line range (scanLine1 to scanLine2). The previous row of
212 // tiles is cached in order to prevent redundent tile reads when
213 // accessing scanlines sequentially.
214 //
215
216 int minY = std::min (scanLine1, scanLine2);
217 int maxY = std::max (scanLine1, scanLine2);
218
219 if (minY < ifd->minY || maxY > ifd->maxY)
220 {
221 throw IEX_NAMESPACE::ArgExc ("Tried to read scan line outside "
222 "the image file's data window.");
223 }
224
225 //
226 // The minimum and maximum y tile coordinates that intersect this
227 // scanline range
228 //
229
230 int minDy = (minY - ifd->minY) / ifd->tFile->tileYSize();
231 int maxDy = (maxY - ifd->minY) / ifd->tFile->tileYSize();
232
233 //
234 // Figure out which one is first in the file so we can read without seeking
235 //
236
237 int yStart, yEnd, yStep;
238
239 if (ifd->lineOrder == DECREASING_Y)
240 {
241 yStart = maxDy;
242 yEnd = minDy - 1;
243 yStep = -1;
244 }
245 else
246 {
247 yStart = minDy;
248 yEnd = maxDy + 1;
249 yStep = 1;
250 }
251
252 //
253 // the number of pixels in a row of tiles
254 //
255
256 Box2i levelRange = ifd->tFile->dataWindowForLevel(0);
257
258 //
259 // Read the tiles into our temporary framebuffer and copy them into
260 // the user's buffer
261 //
262
263 for (int j = yStart; j != yEnd; j += yStep)
264 {
265 Box2i tileRange = ifd->tFile->dataWindowForTile (0, j, 0);
266
267 int minYThisRow = std::max (minY, tileRange.min.y);
268 int maxYThisRow = std::min (maxY, tileRange.max.y);
269
270 if (j != ifd->cachedTileY)
271 {
272 //
273 // We don't have any valid buffered info, so we need to read in
274 // from the file.
275 //
276
277 ifd->tFile->readTiles (0, ifd->tFile->numXTiles (0) - 1, j, j);
278 ifd->cachedTileY = j;
279 }
280
281 //
282 // Copy the data from our cached framebuffer into the user's
283 // framebuffer.
284 //
285
286 for (FrameBuffer::ConstIterator k = ifd->cachedBuffer->begin();
287 k != ifd->cachedBuffer->end();
288 ++k)
289 {
290 Slice fromSlice = k.slice(); // slice to write from
291 Slice toSlice = ifd->tFileBuffer[k.name()]; // slice to write to
292
293 char *fromPtr, *toPtr;
294 int size = pixelTypeSize (toSlice.type);
295
296 int xStart = levelRange.min.x;
297 int yStart = minYThisRow;
298
299 while (modp (xStart, toSlice.xSampling) != 0)
300 ++xStart;
301
302 while (modp (yStart, toSlice.ySampling) != 0)
303 ++yStart;
304
305 for (int y = yStart;
306 y <= maxYThisRow;
307 y += toSlice.ySampling)
308 {
309 //
310 // Set the pointers to the start of the y scanline in
311 // this row of tiles
312 //
313
314 fromPtr = fromSlice.base +
315 (y - tileRange.min.y) * fromSlice.yStride +
316 xStart * fromSlice.xStride;
317
318 toPtr = toSlice.base +
319 divp (y, toSlice.ySampling) * toSlice.yStride +
320 divp (xStart, toSlice.xSampling) * toSlice.xStride;
321
322 //
323 // Copy all pixels for the scanline in this row of tiles
324 //
325
326 for (int x = xStart;
327 x <= levelRange.max.x;
328 x += toSlice.xSampling)
329 {
330 for (int i = 0; i < size; ++i)
331 toPtr[i] = fromPtr[i];
332
333 fromPtr += fromSlice.xStride * toSlice.xSampling;
334 toPtr += toSlice.xStride;
335 }
336 }
337 }
338 }
339 }
340
341 } // namespace
342
343
344
InputFile(const char fileName[],int numThreads)345 InputFile::InputFile (const char fileName[], int numThreads):
346 _data (new Data (numThreads))
347 {
348 _data->_streamData = NULL;
349 _data->_deleteStream=true;
350
351 OPENEXR_IMF_INTERNAL_NAMESPACE::IStream* is = 0;
352 try
353 {
354 is = new StdIFStream (fileName);
355 readMagicNumberAndVersionField(*is, _data->version);
356
357 //
358 // compatibility to read multipart file.
359 //
360 if (isMultiPart(_data->version))
361 {
362 compatibilityInitialize(*is);
363 }
364 else
365 {
366 _data->_streamData = new InputStreamMutex();
367 _data->_streamData->is = is;
368 _data->header.readFrom (*_data->_streamData->is, _data->version);
369
370 // fix type attribute in single part regular image types
371 // (may be wrong if an old version of OpenEXR converts
372 // a tiled image to scanline or vice versa)
373 if(!isNonImage(_data->version) &&
374 !isMultiPart(_data->version) &&
375 _data->header.hasType())
376 {
377 _data->header.setType(isTiled(_data->version) ? TILEDIMAGE : SCANLINEIMAGE);
378 }
379
380 _data->header.sanityCheck (isTiled (_data->version));
381
382 initialize();
383 }
384 }
385 catch (IEX_NAMESPACE::BaseExc &e)
386 {
387 if (is) delete is;
388
389 if ( _data && !_data->multiPartBackwardSupport && _data->_streamData)
390 {
391 delete _data->_streamData;
392 _data->_streamData=NULL;
393 }
394
395 if (_data) delete _data;
396 _data=NULL;
397
398 REPLACE_EXC (e, "Cannot read image file "
399 "\"" << fileName << "\". " << e);
400 throw;
401 }
402 catch (...)
403 {
404 if (is) delete is;
405 if (_data && !_data->multiPartBackwardSupport && _data->_streamData)
406 {
407 delete _data->_streamData;
408 }
409 if (_data) delete _data;
410
411 throw;
412 }
413 }
414
415
InputFile(OPENEXR_IMF_INTERNAL_NAMESPACE::IStream & is,int numThreads)416 InputFile::InputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int numThreads):
417 _data (new Data (numThreads))
418 {
419 _data->_streamData=NULL;
420 _data->_deleteStream=false;
421 try
422 {
423 readMagicNumberAndVersionField(is, _data->version);
424
425 //
426 // Backward compatibility to read multpart file.
427 //
428 if (isMultiPart(_data->version))
429 {
430 compatibilityInitialize(is);
431 }
432 else
433 {
434 _data->_streamData = new InputStreamMutex();
435 _data->_streamData->is = &is;
436 _data->header.readFrom (*_data->_streamData->is, _data->version);
437
438 // fix type attribute in single part regular image types
439 // (may be wrong if an old version of OpenEXR converts
440 // a tiled image to scanline or vice versa)
441 if(!isNonImage(_data->version) &&
442 !isMultiPart(_data->version) &&
443 _data->header.hasType())
444 {
445 _data->header.setType(isTiled(_data->version) ? TILEDIMAGE : SCANLINEIMAGE);
446 }
447
448 _data->header.sanityCheck (isTiled (_data->version));
449
450 initialize();
451 }
452 }
453 catch (IEX_NAMESPACE::BaseExc &e)
454 {
455 if (_data && !_data->multiPartBackwardSupport && _data->_streamData) delete _data->_streamData;
456 if (_data) delete _data;
457 _data=NULL;
458
459 REPLACE_EXC (e, "Cannot read image file "
460 "\"" << is.fileName() << "\". " << e);
461 throw;
462 }
463 catch (...)
464 {
465 if (_data && !_data->multiPartBackwardSupport && _data->_streamData) delete _data->_streamData;
466 if (_data) delete _data;
467 _data=NULL;
468 throw;
469 }
470 }
471
472
InputFile(InputPartData * part)473 InputFile::InputFile (InputPartData* part) :
474 _data (new Data (part->numThreads))
475 {
476 _data->_deleteStream=false;
477 multiPartInitialize (part);
478 }
479
480
481 void
compatibilityInitialize(OPENEXR_IMF_INTERNAL_NAMESPACE::IStream & is)482 InputFile::compatibilityInitialize (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream& is)
483 {
484 is.seekg(0);
485
486 //
487 // Construct a MultiPartInputFile, initialize InputFile
488 // with the part 0 data.
489 // (TODO) may want to have a way to set the reconstruction flag.
490 //
491 _data->multiPartBackwardSupport = true;
492 _data->multiPartFile = new MultiPartInputFile(is, _data->numThreads);
493 InputPartData* part = _data->multiPartFile->getPart(0);
494
495 multiPartInitialize (part);
496 }
497
498
499 void
multiPartInitialize(InputPartData * part)500 InputFile::multiPartInitialize (InputPartData* part)
501 {
502 _data->_streamData = part->mutex;
503 _data->version = part->version;
504 _data->header = part->header;
505 _data->partNumber = part->partNumber;
506 _data->part = part;
507
508 initialize();
509 }
510
511
512 void
initialize()513 InputFile::initialize ()
514 {
515 if (!_data->part)
516 {
517 if(_data->header.hasType() && _data->header.type()==DEEPSCANLINE)
518 {
519 _data->isTiled=false;
520 const Box2i &dataWindow = _data->header.dataWindow();
521 _data->minY = dataWindow.min.y;
522 _data->maxY = dataWindow.max.y;
523
524 _data->dsFile = new DeepScanLineInputFile (_data->header,
525 _data->_streamData->is,
526 _data->version,
527 _data->numThreads);
528 _data->compositor = new CompositeDeepScanLine;
529 _data->compositor->addSource(_data->dsFile);
530 }
531
532 else if (isTiled (_data->version))
533 {
534 _data->isTiled = true;
535 _data->lineOrder = _data->header.lineOrder();
536
537 //
538 // Save the dataWindow information
539 //
540
541 const Box2i &dataWindow = _data->header.dataWindow();
542 _data->minY = dataWindow.min.y;
543 _data->maxY = dataWindow.max.y;
544
545 _data->tFile = new TiledInputFile (_data->header,
546 _data->_streamData->is,
547 _data->version,
548 _data->numThreads);
549 }
550
551 else if(!_data->header.hasType() || _data->header.type()==SCANLINEIMAGE)
552 {
553 _data->sFile = new ScanLineInputFile (_data->header,
554 _data->_streamData->is,
555 _data->numThreads);
556 }else{
557 // type set but not recognised
558
559 THROW(IEX_NAMESPACE::ArgExc, "InputFile cannot handle parts of type " << _data->header.type());
560 }
561 }
562 else
563 {
564 if(_data->header.hasType() && _data->header.type()==DEEPSCANLINE)
565 {
566 _data->isTiled=false;
567 const Box2i &dataWindow = _data->header.dataWindow();
568 _data->minY = dataWindow.min.y;
569 _data->maxY = dataWindow.max.y;
570
571 _data->dsFile = new DeepScanLineInputFile (_data->part);
572 _data->compositor = new CompositeDeepScanLine;
573 _data->compositor->addSource(_data->dsFile);
574 }
575 else if (isTiled (_data->header.type()))
576 {
577 _data->isTiled = true;
578 _data->lineOrder = _data->header.lineOrder();
579
580 //
581 // Save the dataWindow information
582 //
583
584 const Box2i &dataWindow = _data->header.dataWindow();
585 _data->minY = dataWindow.min.y;
586 _data->maxY = dataWindow.max.y;
587
588 _data->tFile = new TiledInputFile (_data->part);
589 }
590 else if(!_data->header.hasType() || _data->header.type()==SCANLINEIMAGE)
591 {
592 _data->sFile = new ScanLineInputFile (_data->part);
593 }else{
594 THROW(IEX_NAMESPACE::ArgExc, "InputFile cannot handle parts of type " << _data->header.type());
595
596 }
597 }
598 }
599
600 #include <iostream>
~InputFile()601 InputFile::~InputFile ()
602 {
603 if (_data->_deleteStream)
604 delete _data->_streamData->is;
605
606 // unless this file was opened via the multipart API,
607 // delete the streamData object too
608 if (_data->partNumber==-1 && _data->_streamData)
609 delete _data->_streamData;
610
611 if (_data) delete _data;
612 }
613
614 const char *
fileName() const615 InputFile::fileName () const
616 {
617 return _data->_streamData->is->fileName();
618 }
619
620
621 const Header &
header() const622 InputFile::header () const
623 {
624 return _data->header;
625 }
626
627
628 int
version() const629 InputFile::version () const
630 {
631 return _data->version;
632 }
633
634
635 void
setFrameBuffer(const FrameBuffer & frameBuffer)636 InputFile::setFrameBuffer (const FrameBuffer &frameBuffer)
637 {
638 if (_data->isTiled)
639 {
640 Lock lock (*_data);
641
642 //
643 // We must invalidate the cached buffer if the new frame
644 // buffer has a different set of channels than the old
645 // frame buffer, or if the type of a channel has changed.
646 //
647
648 const FrameBuffer &oldFrameBuffer = _data->tFileBuffer;
649
650 FrameBuffer::ConstIterator i = oldFrameBuffer.begin();
651 FrameBuffer::ConstIterator j = frameBuffer.begin();
652
653 while (i != oldFrameBuffer.end() && j != frameBuffer.end())
654 {
655 if (strcmp (i.name(), j.name()) || i.slice().type != j.slice().type)
656 break;
657
658 ++i;
659 ++j;
660 }
661
662 if (i != oldFrameBuffer.end() || j != frameBuffer.end())
663 {
664 //
665 // Invalidate the cached buffer.
666 //
667
668 _data->deleteCachedBuffer ();
669 _data->cachedTileY = -1;
670
671 //
672 // Create new a cached frame buffer. It can hold a single
673 // row of tiles. The cached buffer can be reused for each
674 // row of tiles because we set the yTileCoords parameter of
675 // each Slice to true.
676 //
677
678 const Box2i &dataWindow = _data->header.dataWindow();
679 _data->cachedBuffer = new FrameBuffer();
680 _data->offset = dataWindow.min.x;
681
682 int tileRowSize = (dataWindow.max.x - dataWindow.min.x + 1) *
683 _data->tFile->tileYSize();
684
685 for (FrameBuffer::ConstIterator k = frameBuffer.begin();
686 k != frameBuffer.end();
687 ++k)
688 {
689 Slice s = k.slice();
690
691 switch (s.type)
692 {
693 case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
694
695 _data->cachedBuffer->insert
696 (k.name(),
697 Slice (UINT,
698 (char *)(new unsigned int[tileRowSize] -
699 _data->offset),
700 sizeof (unsigned int),
701 sizeof (unsigned int) *
702 _data->tFile->levelWidth(0),
703 1, 1,
704 s.fillValue,
705 false, true));
706 break;
707
708 case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
709
710 _data->cachedBuffer->insert
711 (k.name(),
712 Slice (HALF,
713 (char *)(new half[tileRowSize] -
714 _data->offset),
715 sizeof (half),
716 sizeof (half) *
717 _data->tFile->levelWidth(0),
718 1, 1,
719 s.fillValue,
720 false, true));
721 break;
722
723 case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
724
725 _data->cachedBuffer->insert
726 (k.name(),
727 Slice (OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT,
728 (char *)(new float[tileRowSize] -
729 _data->offset),
730 sizeof(float),
731 sizeof(float) *
732 _data->tFile->levelWidth(0),
733 1, 1,
734 s.fillValue,
735 false, true));
736 break;
737
738 default:
739
740 throw IEX_NAMESPACE::ArgExc ("Unknown pixel data type.");
741 }
742 }
743
744 _data->tFile->setFrameBuffer (*_data->cachedBuffer);
745 }
746
747 _data->tFileBuffer = frameBuffer;
748 }
749 else if(_data->compositor)
750 {
751 _data->compositor->setFrameBuffer(frameBuffer);
752 }else {
753 _data->sFile->setFrameBuffer(frameBuffer);
754 _data->tFileBuffer = frameBuffer;
755 }
756 }
757
758
759 const FrameBuffer &
frameBuffer() const760 InputFile::frameBuffer () const
761 {
762 if(_data->compositor)
763 {
764 return _data->compositor->frameBuffer();
765 }
766 else if(_data->isTiled)
767 {
768 Lock lock (*_data);
769 return _data->tFileBuffer;
770 }
771 else
772 {
773 return _data->sFile->frameBuffer();
774 }
775 }
776
777
778 bool
isComplete() const779 InputFile::isComplete () const
780 {
781 if (_data->dsFile)
782 return _data->dsFile->isComplete();
783 else if (_data->isTiled)
784 return _data->tFile->isComplete();
785 else
786 return _data->sFile->isComplete();
787 }
788
789 bool
isOptimizationEnabled() const790 InputFile::isOptimizationEnabled() const
791 {
792 if(_data->sFile)
793 {
794 return _data->sFile->isOptimizationEnabled();
795 }else{
796 return false;
797 }
798 }
799
800
801 void
readPixels(int scanLine1,int scanLine2)802 InputFile::readPixels (int scanLine1, int scanLine2)
803 {
804 if (_data->compositor)
805 {
806 _data->compositor->readPixels(scanLine1,scanLine2);
807 }
808 else if (_data->isTiled)
809 {
810 Lock lock (*_data);
811 bufferedReadPixels (_data, scanLine1, scanLine2);
812 }
813 else
814 {
815 _data->sFile->readPixels (scanLine1, scanLine2);
816 }
817 }
818
819
820 void
readPixels(int scanLine)821 InputFile::readPixels (int scanLine)
822 {
823 readPixels (scanLine, scanLine);
824 }
825
826
827 void
rawPixelData(int firstScanLine,const char * & pixelData,int & pixelDataSize)828 InputFile::rawPixelData (int firstScanLine,
829 const char *&pixelData,
830 int &pixelDataSize)
831 {
832 try
833 {
834 if (_data->dsFile)
835 {
836 throw IEX_NAMESPACE::ArgExc ("Tried to read a raw scanline "
837 "from a deep image.");
838 }
839
840 else if (_data->isTiled)
841 {
842 throw IEX_NAMESPACE::ArgExc ("Tried to read a raw scanline "
843 "from a tiled image.");
844 }
845
846 _data->sFile->rawPixelData (firstScanLine, pixelData, pixelDataSize);
847 }
848 catch (IEX_NAMESPACE::BaseExc &e)
849 {
850 REPLACE_EXC (e, "Error reading pixel data from image "
851 "file \"" << fileName() << "\". " << e);
852 throw;
853 }
854 }
855
856
857 void
rawTileData(int & dx,int & dy,int & lx,int & ly,const char * & pixelData,int & pixelDataSize)858 InputFile::rawTileData (int &dx, int &dy,
859 int &lx, int &ly,
860 const char *&pixelData,
861 int &pixelDataSize)
862 {
863 try
864 {
865 if (!_data->isTiled)
866 {
867 throw IEX_NAMESPACE::ArgExc ("Tried to read a raw tile "
868 "from a scanline-based image.");
869 }
870
871 _data->tFile->rawTileData (dx, dy, lx, ly, pixelData, pixelDataSize);
872 }
873 catch (IEX_NAMESPACE::BaseExc &e)
874 {
875 REPLACE_EXC (e, "Error reading tile data from image "
876 "file \"" << fileName() << "\". " << e);
877 throw;
878 }
879 }
880
881
882 TiledInputFile*
tFile()883 InputFile::tFile()
884 {
885 if (!_data->isTiled)
886 {
887 throw IEX_NAMESPACE::ArgExc ("Cannot get a TiledInputFile pointer "
888 "from an InputFile that is not tiled.");
889 }
890
891 return _data->tFile;
892 }
893
894
895 OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
896