/src/freeimage-svn/FreeImage/trunk/Source/OpenEXR/IlmImf/ImfInputFile.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | |
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 | 0 | { |
135 | | // empty |
136 | 0 | } |
137 | | |
138 | | |
139 | | InputFile::Data::~Data () |
140 | 0 | { |
141 | 0 | if (tFile) |
142 | 0 | delete tFile; |
143 | 0 | if (sFile) |
144 | 0 | delete sFile; |
145 | 0 | if (dsFile) |
146 | 0 | delete dsFile; |
147 | 0 | if (compositor) |
148 | 0 | delete compositor; |
149 | |
|
150 | 0 | deleteCachedBuffer(); |
151 | |
|
152 | 0 | if (multiPartBackwardSupport && multiPartFile) |
153 | 0 | delete multiPartFile; |
154 | 0 | } |
155 | | |
156 | | |
157 | | void |
158 | | InputFile::Data::deleteCachedBuffer() |
159 | 0 | { |
160 | | // |
161 | | // Delete the cached frame buffer, and all memory |
162 | | // allocated for the slices in the cached frameBuffer. |
163 | | // |
164 | |
|
165 | 0 | if (cachedBuffer) |
166 | 0 | { |
167 | 0 | for (FrameBuffer::Iterator k = cachedBuffer->begin(); |
168 | 0 | k != cachedBuffer->end(); |
169 | 0 | ++k) |
170 | 0 | { |
171 | 0 | Slice &s = k.slice(); |
172 | |
|
173 | 0 | switch (s.type) |
174 | 0 | { |
175 | 0 | case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT: |
176 | |
|
177 | 0 | delete [] (((unsigned int *)s.base) + offset); |
178 | 0 | break; |
179 | | |
180 | 0 | case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF: |
181 | |
|
182 | 0 | delete [] ((half *)s.base + offset); |
183 | 0 | break; |
184 | | |
185 | 0 | case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT: |
186 | |
|
187 | 0 | delete [] (((float *)s.base) + offset); |
188 | 0 | break; |
189 | 0 | case NUM_PIXELTYPES : |
190 | 0 | throw(IEX_NAMESPACE::ArgExc("Invalid pixel type")); |
191 | 0 | } |
192 | 0 | } |
193 | | |
194 | | // |
195 | | // delete the cached frame buffer |
196 | | // |
197 | | |
198 | 0 | delete cachedBuffer; |
199 | 0 | cachedBuffer = 0; |
200 | 0 | } |
201 | 0 | } |
202 | | |
203 | | |
204 | | namespace { |
205 | | |
206 | | void |
207 | | bufferedReadPixels (InputFile::Data* ifd, int scanLine1, int scanLine2) |
208 | 0 | { |
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 | 0 | int minY = std::min (scanLine1, scanLine2); |
217 | 0 | int maxY = std::max (scanLine1, scanLine2); |
218 | |
|
219 | 0 | if (minY < ifd->minY || maxY > ifd->maxY) |
220 | 0 | { |
221 | 0 | throw IEX_NAMESPACE::ArgExc ("Tried to read scan line outside " |
222 | 0 | "the image file's data window."); |
223 | 0 | } |
224 | | |
225 | | // |
226 | | // The minimum and maximum y tile coordinates that intersect this |
227 | | // scanline range |
228 | | // |
229 | | |
230 | 0 | int minDy = (minY - ifd->minY) / ifd->tFile->tileYSize(); |
231 | 0 | 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 | 0 | int yStart, yEnd, yStep; |
238 | |
|
239 | 0 | if (ifd->lineOrder == DECREASING_Y) |
240 | 0 | { |
241 | 0 | yStart = maxDy; |
242 | 0 | yEnd = minDy - 1; |
243 | 0 | yStep = -1; |
244 | 0 | } |
245 | 0 | else |
246 | 0 | { |
247 | 0 | yStart = minDy; |
248 | 0 | yEnd = maxDy + 1; |
249 | 0 | yStep = 1; |
250 | 0 | } |
251 | | |
252 | | // |
253 | | // the number of pixels in a row of tiles |
254 | | // |
255 | |
|
256 | 0 | 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 | 0 | for (int j = yStart; j != yEnd; j += yStep) |
264 | 0 | { |
265 | 0 | Box2i tileRange = ifd->tFile->dataWindowForTile (0, j, 0); |
266 | |
|
267 | 0 | int minYThisRow = std::max (minY, tileRange.min.y); |
268 | 0 | int maxYThisRow = std::min (maxY, tileRange.max.y); |
269 | |
|
270 | 0 | if (j != ifd->cachedTileY) |
271 | 0 | { |
272 | | // |
273 | | // We don't have any valid buffered info, so we need to read in |
274 | | // from the file. |
275 | | // |
276 | |
|
277 | 0 | ifd->tFile->readTiles (0, ifd->tFile->numXTiles (0) - 1, j, j); |
278 | 0 | ifd->cachedTileY = j; |
279 | 0 | } |
280 | | |
281 | | // |
282 | | // Copy the data from our cached framebuffer into the user's |
283 | | // framebuffer. |
284 | | // |
285 | |
|
286 | 0 | for (FrameBuffer::ConstIterator k = ifd->cachedBuffer->begin(); |
287 | 0 | k != ifd->cachedBuffer->end(); |
288 | 0 | ++k) |
289 | 0 | { |
290 | 0 | Slice fromSlice = k.slice(); // slice to write from |
291 | 0 | Slice toSlice = ifd->tFileBuffer[k.name()]; // slice to write to |
292 | |
|
293 | 0 | char *fromPtr, *toPtr; |
294 | 0 | int size = pixelTypeSize (toSlice.type); |
295 | |
|
296 | 0 | int xStart = levelRange.min.x; |
297 | 0 | int yStart = minYThisRow; |
298 | |
|
299 | 0 | while (modp (xStart, toSlice.xSampling) != 0) |
300 | 0 | ++xStart; |
301 | |
|
302 | 0 | while (modp (yStart, toSlice.ySampling) != 0) |
303 | 0 | ++yStart; |
304 | |
|
305 | 0 | for (int y = yStart; |
306 | 0 | y <= maxYThisRow; |
307 | 0 | y += toSlice.ySampling) |
308 | 0 | { |
309 | | // |
310 | | // Set the pointers to the start of the y scanline in |
311 | | // this row of tiles |
312 | | // |
313 | | |
314 | 0 | fromPtr = fromSlice.base + |
315 | 0 | (y - tileRange.min.y) * fromSlice.yStride + |
316 | 0 | xStart * fromSlice.xStride; |
317 | |
|
318 | 0 | toPtr = toSlice.base + |
319 | 0 | divp (y, toSlice.ySampling) * toSlice.yStride + |
320 | 0 | divp (xStart, toSlice.xSampling) * toSlice.xStride; |
321 | | |
322 | | // |
323 | | // Copy all pixels for the scanline in this row of tiles |
324 | | // |
325 | |
|
326 | 0 | for (int x = xStart; |
327 | 0 | x <= levelRange.max.x; |
328 | 0 | x += toSlice.xSampling) |
329 | 0 | { |
330 | 0 | for (int i = 0; i < size; ++i) |
331 | 0 | toPtr[i] = fromPtr[i]; |
332 | |
|
333 | 0 | fromPtr += fromSlice.xStride * toSlice.xSampling; |
334 | 0 | toPtr += toSlice.xStride; |
335 | 0 | } |
336 | 0 | } |
337 | 0 | } |
338 | 0 | } |
339 | 0 | } |
340 | | |
341 | | } // namespace |
342 | | |
343 | | |
344 | | |
345 | | InputFile::InputFile (const char fileName[], int numThreads): |
346 | | _data (new Data (numThreads)) |
347 | 0 | { |
348 | 0 | _data->_streamData = NULL; |
349 | 0 | _data->_deleteStream=true; |
350 | | |
351 | 0 | OPENEXR_IMF_INTERNAL_NAMESPACE::IStream* is = 0; |
352 | 0 | try |
353 | 0 | { |
354 | 0 | is = new StdIFStream (fileName); |
355 | 0 | readMagicNumberAndVersionField(*is, _data->version); |
356 | | |
357 | | // |
358 | | // compatibility to read multipart file. |
359 | | // |
360 | 0 | if (isMultiPart(_data->version)) |
361 | 0 | { |
362 | 0 | compatibilityInitialize(*is); |
363 | 0 | } |
364 | 0 | else |
365 | 0 | { |
366 | 0 | _data->_streamData = new InputStreamMutex(); |
367 | 0 | _data->_streamData->is = is; |
368 | 0 | _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 | 0 | if(!isNonImage(_data->version) && |
374 | 0 | !isMultiPart(_data->version) && |
375 | 0 | _data->header.hasType()) |
376 | 0 | { |
377 | 0 | _data->header.setType(isTiled(_data->version) ? TILEDIMAGE : SCANLINEIMAGE); |
378 | 0 | } |
379 | | |
380 | 0 | _data->header.sanityCheck (isTiled (_data->version)); |
381 | |
|
382 | 0 | initialize(); |
383 | 0 | } |
384 | 0 | } |
385 | 0 | catch (IEX_NAMESPACE::BaseExc &e) |
386 | 0 | { |
387 | 0 | if (is) delete is; |
388 | | |
389 | 0 | if ( _data && !_data->multiPartBackwardSupport && _data->_streamData) |
390 | 0 | { |
391 | 0 | delete _data->_streamData; |
392 | 0 | _data->_streamData=NULL; |
393 | 0 | } |
394 | | |
395 | 0 | if (_data) delete _data; |
396 | 0 | _data=NULL; |
397 | |
|
398 | 0 | REPLACE_EXC (e, "Cannot read image file " |
399 | 0 | "\"" << fileName << "\". " << e); |
400 | 0 | throw; |
401 | 0 | } |
402 | 0 | catch (...) |
403 | 0 | { |
404 | 0 | if (is) delete is; |
405 | 0 | if (_data && !_data->multiPartBackwardSupport && _data->_streamData) |
406 | 0 | { |
407 | 0 | delete _data->_streamData; |
408 | 0 | } |
409 | 0 | if (_data) delete _data; |
410 | |
|
411 | 0 | throw; |
412 | 0 | } |
413 | 0 | } |
414 | | |
415 | | |
416 | | InputFile::InputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int numThreads): |
417 | | _data (new Data (numThreads)) |
418 | 0 | { |
419 | 0 | _data->_streamData=NULL; |
420 | 0 | _data->_deleteStream=false; |
421 | 0 | try |
422 | 0 | { |
423 | 0 | readMagicNumberAndVersionField(is, _data->version); |
424 | | |
425 | | // |
426 | | // Backward compatibility to read multpart file. |
427 | | // |
428 | 0 | if (isMultiPart(_data->version)) |
429 | 0 | { |
430 | 0 | compatibilityInitialize(is); |
431 | 0 | } |
432 | 0 | else |
433 | 0 | { |
434 | 0 | _data->_streamData = new InputStreamMutex(); |
435 | 0 | _data->_streamData->is = &is; |
436 | 0 | _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 | 0 | if(!isNonImage(_data->version) && |
442 | 0 | !isMultiPart(_data->version) && |
443 | 0 | _data->header.hasType()) |
444 | 0 | { |
445 | 0 | _data->header.setType(isTiled(_data->version) ? TILEDIMAGE : SCANLINEIMAGE); |
446 | 0 | } |
447 | | |
448 | 0 | _data->header.sanityCheck (isTiled (_data->version)); |
449 | |
|
450 | 0 | initialize(); |
451 | 0 | } |
452 | 0 | } |
453 | 0 | catch (IEX_NAMESPACE::BaseExc &e) |
454 | 0 | { |
455 | 0 | if (_data && !_data->multiPartBackwardSupport && _data->_streamData) delete _data->_streamData; |
456 | 0 | if (_data) delete _data; |
457 | 0 | _data=NULL; |
458 | |
|
459 | 0 | REPLACE_EXC (e, "Cannot read image file " |
460 | 0 | "\"" << is.fileName() << "\". " << e); |
461 | 0 | throw; |
462 | 0 | } |
463 | 0 | catch (...) |
464 | 0 | { |
465 | 0 | if (_data && !_data->multiPartBackwardSupport && _data->_streamData) delete _data->_streamData; |
466 | 0 | if (_data) delete _data; |
467 | 0 | _data=NULL; |
468 | 0 | throw; |
469 | 0 | } |
470 | 0 | } |
471 | | |
472 | | |
473 | | InputFile::InputFile (InputPartData* part) : |
474 | | _data (new Data (part->numThreads)) |
475 | 0 | { |
476 | 0 | _data->_deleteStream=false; |
477 | 0 | multiPartInitialize (part); |
478 | 0 | } |
479 | | |
480 | | |
481 | | void |
482 | | InputFile::compatibilityInitialize (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream& is) |
483 | 0 | { |
484 | 0 | 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 | 0 | _data->multiPartBackwardSupport = true; |
492 | 0 | _data->multiPartFile = new MultiPartInputFile(is, _data->numThreads); |
493 | 0 | InputPartData* part = _data->multiPartFile->getPart(0); |
494 | |
|
495 | 0 | multiPartInitialize (part); |
496 | 0 | } |
497 | | |
498 | | |
499 | | void |
500 | | InputFile::multiPartInitialize (InputPartData* part) |
501 | 0 | { |
502 | 0 | _data->_streamData = part->mutex; |
503 | 0 | _data->version = part->version; |
504 | 0 | _data->header = part->header; |
505 | 0 | _data->partNumber = part->partNumber; |
506 | 0 | _data->part = part; |
507 | |
|
508 | 0 | initialize(); |
509 | 0 | } |
510 | | |
511 | | |
512 | | void |
513 | | InputFile::initialize () |
514 | 0 | { |
515 | 0 | if (!_data->part) |
516 | 0 | { |
517 | 0 | if(_data->header.hasType() && _data->header.type()==DEEPSCANLINE) |
518 | 0 | { |
519 | 0 | _data->isTiled=false; |
520 | 0 | const Box2i &dataWindow = _data->header.dataWindow(); |
521 | 0 | _data->minY = dataWindow.min.y; |
522 | 0 | _data->maxY = dataWindow.max.y; |
523 | | |
524 | 0 | _data->dsFile = new DeepScanLineInputFile (_data->header, |
525 | 0 | _data->_streamData->is, |
526 | 0 | _data->version, |
527 | 0 | _data->numThreads); |
528 | 0 | _data->compositor = new CompositeDeepScanLine; |
529 | 0 | _data->compositor->addSource(_data->dsFile); |
530 | 0 | } |
531 | | |
532 | 0 | else if (isTiled (_data->version)) |
533 | 0 | { |
534 | 0 | _data->isTiled = true; |
535 | 0 | _data->lineOrder = _data->header.lineOrder(); |
536 | | |
537 | | // |
538 | | // Save the dataWindow information |
539 | | // |
540 | | |
541 | 0 | const Box2i &dataWindow = _data->header.dataWindow(); |
542 | 0 | _data->minY = dataWindow.min.y; |
543 | 0 | _data->maxY = dataWindow.max.y; |
544 | |
|
545 | 0 | _data->tFile = new TiledInputFile (_data->header, |
546 | 0 | _data->_streamData->is, |
547 | 0 | _data->version, |
548 | 0 | _data->numThreads); |
549 | 0 | } |
550 | | |
551 | 0 | else if(!_data->header.hasType() || _data->header.type()==SCANLINEIMAGE) |
552 | 0 | { |
553 | 0 | _data->sFile = new ScanLineInputFile (_data->header, |
554 | 0 | _data->_streamData->is, |
555 | 0 | _data->numThreads); |
556 | 0 | }else{ |
557 | | // type set but not recognised |
558 | | |
559 | 0 | THROW(IEX_NAMESPACE::ArgExc, "InputFile cannot handle parts of type " << _data->header.type()); |
560 | 0 | } |
561 | 0 | } |
562 | 0 | else |
563 | 0 | { |
564 | 0 | if(_data->header.hasType() && _data->header.type()==DEEPSCANLINE) |
565 | 0 | { |
566 | 0 | _data->isTiled=false; |
567 | 0 | const Box2i &dataWindow = _data->header.dataWindow(); |
568 | 0 | _data->minY = dataWindow.min.y; |
569 | 0 | _data->maxY = dataWindow.max.y; |
570 | | |
571 | 0 | _data->dsFile = new DeepScanLineInputFile (_data->part); |
572 | 0 | _data->compositor = new CompositeDeepScanLine; |
573 | 0 | _data->compositor->addSource(_data->dsFile); |
574 | 0 | } |
575 | 0 | else if (isTiled (_data->header.type())) |
576 | 0 | { |
577 | 0 | _data->isTiled = true; |
578 | 0 | _data->lineOrder = _data->header.lineOrder(); |
579 | | |
580 | | // |
581 | | // Save the dataWindow information |
582 | | // |
583 | |
|
584 | 0 | const Box2i &dataWindow = _data->header.dataWindow(); |
585 | 0 | _data->minY = dataWindow.min.y; |
586 | 0 | _data->maxY = dataWindow.max.y; |
587 | |
|
588 | 0 | _data->tFile = new TiledInputFile (_data->part); |
589 | 0 | } |
590 | 0 | else if(!_data->header.hasType() || _data->header.type()==SCANLINEIMAGE) |
591 | 0 | { |
592 | 0 | _data->sFile = new ScanLineInputFile (_data->part); |
593 | 0 | }else{ |
594 | 0 | THROW(IEX_NAMESPACE::ArgExc, "InputFile cannot handle parts of type " << _data->header.type()); |
595 | | |
596 | 0 | } |
597 | 0 | } |
598 | 0 | } |
599 | | |
600 | | #include <iostream> |
601 | | InputFile::~InputFile () |
602 | 0 | { |
603 | 0 | if (_data->_deleteStream) |
604 | 0 | delete _data->_streamData->is; |
605 | | |
606 | | // unless this file was opened via the multipart API, |
607 | | // delete the streamData object too |
608 | 0 | if (_data->partNumber==-1 && _data->_streamData) |
609 | 0 | delete _data->_streamData; |
610 | |
|
611 | 0 | if (_data) delete _data; |
612 | 0 | } |
613 | | |
614 | | const char * |
615 | | InputFile::fileName () const |
616 | 0 | { |
617 | 0 | return _data->_streamData->is->fileName(); |
618 | 0 | } |
619 | | |
620 | | |
621 | | const Header & |
622 | | InputFile::header () const |
623 | 0 | { |
624 | 0 | return _data->header; |
625 | 0 | } |
626 | | |
627 | | |
628 | | int |
629 | | InputFile::version () const |
630 | 0 | { |
631 | 0 | return _data->version; |
632 | 0 | } |
633 | | |
634 | | |
635 | | void |
636 | | InputFile::setFrameBuffer (const FrameBuffer &frameBuffer) |
637 | 0 | { |
638 | 0 | if (_data->isTiled) |
639 | 0 | { |
640 | 0 | 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 | 0 | const FrameBuffer &oldFrameBuffer = _data->tFileBuffer; |
649 | |
|
650 | 0 | FrameBuffer::ConstIterator i = oldFrameBuffer.begin(); |
651 | 0 | FrameBuffer::ConstIterator j = frameBuffer.begin(); |
652 | |
|
653 | 0 | while (i != oldFrameBuffer.end() && j != frameBuffer.end()) |
654 | 0 | { |
655 | 0 | if (strcmp (i.name(), j.name()) || i.slice().type != j.slice().type) |
656 | 0 | break; |
657 | | |
658 | 0 | ++i; |
659 | 0 | ++j; |
660 | 0 | } |
661 | |
|
662 | 0 | if (i != oldFrameBuffer.end() || j != frameBuffer.end()) |
663 | 0 | { |
664 | | // |
665 | | // Invalidate the cached buffer. |
666 | | // |
667 | |
|
668 | 0 | _data->deleteCachedBuffer (); |
669 | 0 | _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 | 0 | const Box2i &dataWindow = _data->header.dataWindow(); |
679 | 0 | _data->cachedBuffer = new FrameBuffer(); |
680 | 0 | _data->offset = dataWindow.min.x; |
681 | | |
682 | 0 | int tileRowSize = (dataWindow.max.x - dataWindow.min.x + 1) * |
683 | 0 | _data->tFile->tileYSize(); |
684 | |
|
685 | 0 | for (FrameBuffer::ConstIterator k = frameBuffer.begin(); |
686 | 0 | k != frameBuffer.end(); |
687 | 0 | ++k) |
688 | 0 | { |
689 | 0 | Slice s = k.slice(); |
690 | |
|
691 | 0 | switch (s.type) |
692 | 0 | { |
693 | 0 | case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT: |
694 | |
|
695 | 0 | _data->cachedBuffer->insert |
696 | 0 | (k.name(), |
697 | 0 | Slice (UINT, |
698 | 0 | (char *)(new unsigned int[tileRowSize] - |
699 | 0 | _data->offset), |
700 | 0 | sizeof (unsigned int), |
701 | 0 | sizeof (unsigned int) * |
702 | 0 | _data->tFile->levelWidth(0), |
703 | 0 | 1, 1, |
704 | 0 | s.fillValue, |
705 | 0 | false, true)); |
706 | 0 | break; |
707 | | |
708 | 0 | case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF: |
709 | |
|
710 | 0 | _data->cachedBuffer->insert |
711 | 0 | (k.name(), |
712 | 0 | Slice (HALF, |
713 | 0 | (char *)(new half[tileRowSize] - |
714 | 0 | _data->offset), |
715 | 0 | sizeof (half), |
716 | 0 | sizeof (half) * |
717 | 0 | _data->tFile->levelWidth(0), |
718 | 0 | 1, 1, |
719 | 0 | s.fillValue, |
720 | 0 | false, true)); |
721 | 0 | break; |
722 | | |
723 | 0 | case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT: |
724 | |
|
725 | 0 | _data->cachedBuffer->insert |
726 | 0 | (k.name(), |
727 | 0 | Slice (OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT, |
728 | 0 | (char *)(new float[tileRowSize] - |
729 | 0 | _data->offset), |
730 | 0 | sizeof(float), |
731 | 0 | sizeof(float) * |
732 | 0 | _data->tFile->levelWidth(0), |
733 | 0 | 1, 1, |
734 | 0 | s.fillValue, |
735 | 0 | false, true)); |
736 | 0 | break; |
737 | | |
738 | 0 | default: |
739 | |
|
740 | 0 | throw IEX_NAMESPACE::ArgExc ("Unknown pixel data type."); |
741 | 0 | } |
742 | 0 | } |
743 | | |
744 | 0 | _data->tFile->setFrameBuffer (*_data->cachedBuffer); |
745 | 0 | } |
746 | | |
747 | 0 | _data->tFileBuffer = frameBuffer; |
748 | 0 | } |
749 | 0 | else if(_data->compositor) |
750 | 0 | { |
751 | 0 | _data->compositor->setFrameBuffer(frameBuffer); |
752 | 0 | }else { |
753 | 0 | _data->sFile->setFrameBuffer(frameBuffer); |
754 | 0 | _data->tFileBuffer = frameBuffer; |
755 | 0 | } |
756 | 0 | } |
757 | | |
758 | | |
759 | | const FrameBuffer & |
760 | | InputFile::frameBuffer () const |
761 | 0 | { |
762 | 0 | if(_data->compositor) |
763 | 0 | { |
764 | 0 | return _data->compositor->frameBuffer(); |
765 | 0 | } |
766 | 0 | else if(_data->isTiled) |
767 | 0 | { |
768 | 0 | Lock lock (*_data); |
769 | 0 | return _data->tFileBuffer; |
770 | 0 | } |
771 | 0 | else |
772 | 0 | { |
773 | 0 | return _data->sFile->frameBuffer(); |
774 | 0 | } |
775 | 0 | } |
776 | | |
777 | | |
778 | | bool |
779 | | InputFile::isComplete () const |
780 | 0 | { |
781 | 0 | if (_data->dsFile) |
782 | 0 | return _data->dsFile->isComplete(); |
783 | 0 | else if (_data->isTiled) |
784 | 0 | return _data->tFile->isComplete(); |
785 | 0 | else |
786 | 0 | return _data->sFile->isComplete(); |
787 | 0 | } |
788 | | |
789 | | bool |
790 | | InputFile::isOptimizationEnabled() const |
791 | 0 | { |
792 | 0 | if(_data->sFile) |
793 | 0 | { |
794 | 0 | return _data->sFile->isOptimizationEnabled(); |
795 | 0 | }else{ |
796 | 0 | return false; |
797 | 0 | } |
798 | 0 | } |
799 | | |
800 | | |
801 | | void |
802 | | InputFile::readPixels (int scanLine1, int scanLine2) |
803 | 0 | { |
804 | 0 | if (_data->compositor) |
805 | 0 | { |
806 | 0 | _data->compositor->readPixels(scanLine1,scanLine2); |
807 | 0 | } |
808 | 0 | else if (_data->isTiled) |
809 | 0 | { |
810 | 0 | Lock lock (*_data); |
811 | 0 | bufferedReadPixels (_data, scanLine1, scanLine2); |
812 | 0 | } |
813 | 0 | else |
814 | 0 | { |
815 | 0 | _data->sFile->readPixels (scanLine1, scanLine2); |
816 | 0 | } |
817 | 0 | } |
818 | | |
819 | | |
820 | | void |
821 | | InputFile::readPixels (int scanLine) |
822 | 0 | { |
823 | 0 | readPixels (scanLine, scanLine); |
824 | 0 | } |
825 | | |
826 | | |
827 | | void |
828 | | InputFile::rawPixelData (int firstScanLine, |
829 | | const char *&pixelData, |
830 | | int &pixelDataSize) |
831 | 0 | { |
832 | 0 | try |
833 | 0 | { |
834 | 0 | if (_data->dsFile) |
835 | 0 | { |
836 | 0 | throw IEX_NAMESPACE::ArgExc ("Tried to read a raw scanline " |
837 | 0 | "from a deep image."); |
838 | 0 | } |
839 | | |
840 | 0 | else if (_data->isTiled) |
841 | 0 | { |
842 | 0 | throw IEX_NAMESPACE::ArgExc ("Tried to read a raw scanline " |
843 | 0 | "from a tiled image."); |
844 | 0 | } |
845 | | |
846 | 0 | _data->sFile->rawPixelData (firstScanLine, pixelData, pixelDataSize); |
847 | 0 | } |
848 | 0 | catch (IEX_NAMESPACE::BaseExc &e) |
849 | 0 | { |
850 | 0 | REPLACE_EXC (e, "Error reading pixel data from image " |
851 | 0 | "file \"" << fileName() << "\". " << e); |
852 | 0 | throw; |
853 | 0 | } |
854 | 0 | } |
855 | | |
856 | | |
857 | | void |
858 | | InputFile::rawTileData (int &dx, int &dy, |
859 | | int &lx, int &ly, |
860 | | const char *&pixelData, |
861 | | int &pixelDataSize) |
862 | 0 | { |
863 | 0 | try |
864 | 0 | { |
865 | 0 | if (!_data->isTiled) |
866 | 0 | { |
867 | 0 | throw IEX_NAMESPACE::ArgExc ("Tried to read a raw tile " |
868 | 0 | "from a scanline-based image."); |
869 | 0 | } |
870 | | |
871 | 0 | _data->tFile->rawTileData (dx, dy, lx, ly, pixelData, pixelDataSize); |
872 | 0 | } |
873 | 0 | catch (IEX_NAMESPACE::BaseExc &e) |
874 | 0 | { |
875 | 0 | REPLACE_EXC (e, "Error reading tile data from image " |
876 | 0 | "file \"" << fileName() << "\". " << e); |
877 | 0 | throw; |
878 | 0 | } |
879 | 0 | } |
880 | | |
881 | | |
882 | | TiledInputFile* |
883 | | InputFile::tFile() |
884 | 0 | { |
885 | 0 | if (!_data->isTiled) |
886 | 0 | { |
887 | 0 | throw IEX_NAMESPACE::ArgExc ("Cannot get a TiledInputFile pointer " |
888 | 0 | "from an InputFile that is not tiled."); |
889 | 0 | } |
890 | | |
891 | 0 | return _data->tFile; |
892 | 0 | } |
893 | | |
894 | | |
895 | | OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT |