1 // -*- mode: C++; tab-width: 4 -*-
2 // vi: ts=4
3 
4 /*
5  * Copyright (c) 2009, Patrick A. Palmer.
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 met:
10  *
11  *   - Redistributions of source code must retain the above copyright notice,
12  *     this list of conditions and the following disclaimer.
13  *
14  *   - Redistributions in binary form must reproduce the above copyright
15  *     notice, this list of conditions and the following disclaimer in the
16  *     documentation and/or other materials provided with the distribution.
17  *
18  *   - Neither the name of Patrick A. Palmer nor the names of its
19  *     contributors may be used to endorse or promote products derived from
20  *     this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #include <cstdio>
36 #include <cstring>
37 #include <ctime>
38 
39 #include "DPX.h"
40 #include "EndianSwap.h"
41 #include "ReaderInternal.h"
42 #include "ElementReadStream.h"
43 #include "Codec.h"
44 #include "RunLengthEncoding.h"
45 
46 
47 
Reader()48 dpx::Reader::Reader() : fd(0), rio(0)
49 {
50 	// initialize all of the Codec* to NULL
51 	for (int i = 0; i < MAX_ELEMENTS; i++)
52 		this->codex[i] = 0;
53 }
54 
55 
~Reader()56 dpx::Reader::~Reader()
57 {
58 	this->Reset();
59     delete this->rio;
60 }
61 
62 
Reset()63 void dpx::Reader::Reset()
64 {
65 	// delete all of the Codec * entries
66 	for (int i = 0; i < MAX_ELEMENTS; i++)
67 		if (this->codex[i])
68 		{
69 			delete codex[i];
70 			this->codex[i] = 0;
71 		}
72 
73 	// Element Reader
74 	if (this->rio)
75 	{
76 		delete rio;
77 		this->rio = 0;
78 	}
79 	if (this->fd)
80 		this->rio = new ElementReadStream(this->fd);
81 }
82 
83 
SetInStream(InStream * fd)84 void dpx::Reader::SetInStream(InStream *fd)
85 {
86 	this->fd = fd;
87 	this->Reset();
88 }
89 
90 
ReadHeader()91 bool dpx::Reader::ReadHeader()
92 {
93 	return this->header.Read(this->fd);
94 }
95 
96 
ReadImage(const int element,void * data)97 bool dpx::Reader::ReadImage(const int element, void *data)
98 {
99     Block block(0, 0, this->header.Width()-1, this->header.Height()-1);
100     return this->ReadBlock(element, (unsigned char *)data, block);
101 }
102 
103 
104 
105 /*
106     implementation notes:
107 
108     dpx::readBlock reads in the image starting from the beginning of the channel.  This can
109     be optimized if the image isn't encoded; we can skip forward in the file to close to the
110     start of (block.x1, block.y1) and determine exactly which bit will be the start.  This
111     certainly will save some time for cases where we are only reading ROIs (regions of interest).
112 
113 */
ReadBlock(const int element,unsigned char * data,Block & block)114 bool dpx::Reader::ReadBlock(const int element, unsigned char *data, Block &block)
115 {
116 	// make sure the range is good
117 	if (element < 0 || element >= MAX_ELEMENTS)
118 		return false;
119 
120 	// make sure the entry is valid
121 	if (this->header.ImageDescriptor(element) == kUndefinedDescriptor)
122 		return false;
123 
124     // get the number of components for this element descriptor
125     const int numberOfComponents = this->header.ImageElementComponentCount(element);
126 
127     // bit depth of the image element
128     const int bitDepth = this->header.BitDepth(element);
129 
130     // rle encoding?
131     const bool rle = (this->header.ImageEncoding(element) == kRLE);
132 
133     // data size for the element
134     const DataSize size = this->header.ComponentDataSize(element);
135 
136     // lets see if this can be done in a single fast read
137     if (!rle && this->header.EndOfLinePadding(element) == 0 &&
138         ((bitDepth == 8 && size == dpx::kByte) ||
139          (bitDepth == 16 && size == dpx::kWord) ||
140          (bitDepth == 32 && size == dpx::kFloat) ||
141          (bitDepth == 64 && size == dpx::kDouble)) &&
142         block.x1 == 0 && block.x2 == (int)(this->header.Width()-1))
143     {
144         // seek to the beginning of the image block
145         if (this->fd->Seek((this->header.DataOffset(element) + (block.y1 * this->header.Width() * (bitDepth / 8) * numberOfComponents)), InStream::kStart) == false)
146             return false;
147 
148         // size of the image
149         const size_t imageSize = this->header.Width() * (block.y2 - block.y1 + 1) * numberOfComponents;
150         const size_t imageByteSize = imageSize * bitDepth / 8;
151 
152         size_t rs = this->fd->ReadDirect(data, imageByteSize);
153         if (rs != imageByteSize)
154             return false;
155 
156         // swap the bytes if different byte order
157         if (this->header.RequiresByteSwap())
158             dpx::EndianSwapImageBuffer(size, data, imageSize);
159 
160         return true;
161     }
162 
163     // determine if the encoding system is loaded
164     if (this->codex[element] == 0)
165     {
166         // this element reader has not been used
167         if (rle)
168             // TODO
169             //this->codex[element] = new RunLengthEncoding;
170             return false;
171         else
172             this->codex[element] = new Codec;
173     }
174 
175     // read the image block
176     return this->codex[element]->Read(this->header, this->rio, element, block, data, size);
177 }
178 
179 
180 
ReadUserData(unsigned char * data)181 bool dpx::Reader::ReadUserData(unsigned char *data)
182 {
183 	// check to make sure there is some user data
184 	if (this->header.UserSize() == 0)
185 		return true;
186 
187 	// seek to the beginning of the user data block
188 	if (this->fd->Seek(sizeof(GenericHeader) + sizeof(IndustryHeader), InStream::kStart) == false)
189 		return false;
190 
191 	size_t rs = this->fd->ReadDirect(data, this->header.UserSize());
192 	if (rs != this->header.UserSize())
193 		return false;
194 
195 	return true;
196 }
197 
198 
199 
200