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