1 // -*- mode: C++; tab-width: 4 -*-
2 // vi: ts=4
3
4 /*
5 * Copyright (c) 2010, Patrick A. Palmer and Leszek Godlewski.
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 #include <cassert>
39
40 #include "Cineon.h"
41 #include "EndianSwap.h"
42 #include "ReaderInternal.h"
43 #include "ElementReadStream.h"
44 #include "Codec.h"
45
46
Reader()47 cineon::Reader::Reader() : fd(0), rio(0)
48 {
49 // initialize all of the Codec* to NULL
50 this->codec = 0;
51 }
52
53
~Reader()54 cineon::Reader::~Reader()
55 {
56 this->Reset();
57 delete this->rio;
58 }
59
60
Reset()61 void cineon::Reader::Reset()
62 {
63 // delete all of the Codec * entries
64 delete this->codec;
65 this->codec = 0;
66
67 // Element Reader
68 if (this->rio)
69 {
70 delete rio;
71 this->rio = 0;
72 }
73 if (this->fd)
74 this->rio = new ElementReadStream(this->fd);
75 }
76
77
SetInStream(InStream * fd)78 void cineon::Reader::SetInStream(InStream *fd)
79 {
80 this->fd = fd;
81 this->Reset();
82 }
83
84
ReadHeader()85 bool cineon::Reader::ReadHeader()
86 {
87 return this->header.Read(this->fd);
88 }
89
90
ReadImage(void * data,const DataSize size)91 bool cineon::Reader::ReadImage(void *data, const DataSize size)
92 {
93 Block block(0, 0, this->header.Width()-1, this->header.Height()-1);
94 return this->ReadBlock(data, size, block);
95 }
96
97
98
99 /*
100 implementation notes:
101
102 cineon::readBlock reads in the image starting from the beginning of the channel. This can
103 be optimized if the image isn't encoded; we can skip forward in the file to close to the
104 start of (block.x1, block.y1) and determine exactly which bit will be the start. This
105 certainly will save some time for cases where we are only reading ROIs (regions of interest).
106
107 */
108
ReadBlock(void * data,const DataSize size,Block & block)109 bool cineon::Reader::ReadBlock(void *data, const DataSize size, Block &block)
110 {
111 int i;
112
113 // check the block coordinates
114 block.Check();
115
116 // get the number of components for this element descriptor
117 const int numberOfComponents = this->header.NumberOfElements();
118
119 // check the widths and bit depths of the image elements
120 bool consistentDepth = true;
121 bool consistentWidth = true;
122 const int bitDepth = this->header.BitDepth(0);
123 const int width = this->header.PixelsPerLine(0);
124 for (i = 1; i < numberOfComponents; i++) {
125 if (this->header.BitDepth(i) != bitDepth) {
126 consistentDepth = false;
127 if (!consistentWidth)
128 break;
129 }
130 if ((int)this->header.PixelsPerLine(i) != width) {
131 consistentWidth = false;
132 if (!consistentDepth)
133 break;
134 }
135 }
136
137 // lets see if this can be done in a single fast read
138 if (consistentDepth && consistentWidth && this->header.EndOfLinePadding() == 0 &&
139 ((bitDepth == 8 && size == cineon::kByte) ||
140 (bitDepth == 16 && size == cineon::kWord) ||
141 (bitDepth == 32 && size == cineon::kInt) ||
142 (bitDepth == 64 && size == cineon::kLongLong)) &&
143 block.x1 == 0 && block.x2 == (int)(this->header.Width()-1))
144 {
145 // seek to the beginning of the image block
146 if (this->fd->Seek((this->header.ImageOffset() + (block.y1 * this->header.Width() * (bitDepth / 8) * numberOfComponents)), InStream::kStart) == false)
147 return false;
148
149 // size of the image
150 const size_t imageSize = this->header.Width() * (block.y2 - block.y1 + 1) * numberOfComponents;
151 const size_t imageByteSize = imageSize * bitDepth / 8;
152
153 size_t rs = this->fd->ReadDirect(data, imageByteSize);
154 if (rs != imageByteSize)
155 return false;
156
157 // swap the bytes if different byte order
158 if (this->header.RequiresByteSwap())
159 cineon::EndianSwapImageBuffer(size, data, imageSize);
160
161 return true;
162 }
163
164
165 // determine if the encoding system is loaded
166 if (this->codec == 0)
167 // this element reader has not been used
168 this->codec = new Codec;
169
170 // read the image block
171 return this->codec->Read(this->header, this->rio, block, data, size);
172 }
173
174
175
ReadUserData(unsigned char * data)176 bool cineon::Reader::ReadUserData(unsigned char *data)
177 {
178 // check to make sure there is some user data
179 if (this->header.UserSize() == 0)
180 return true;
181
182 // seek to the beginning of the user data block
183 if (this->fd->Seek(sizeof(GenericHeader) + sizeof(IndustryHeader), InStream::kStart) == false)
184 return false;
185
186 size_t rs = this->fd->ReadDirect(data, this->header.UserSize());
187 if (rs != this->header.UserSize())
188 return false;
189
190 return true;
191 }
192
193
194
195