/src/freeimage-svn/FreeImage/trunk/Source/OpenEXR/IlmImf/ImfTiledMisc.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 | | // |
38 | | // Miscellaneous stuff related to tiled files |
39 | | // |
40 | | //----------------------------------------------------------------------------- |
41 | | |
42 | | #include <ImfTiledMisc.h> |
43 | | #include "Iex.h" |
44 | | #include <ImfMisc.h> |
45 | | #include <ImfChannelList.h> |
46 | | #include <ImfTileDescription.h> |
47 | | #include <algorithm> |
48 | | |
49 | | #include "ImfNamespace.h" |
50 | | |
51 | | OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER |
52 | | |
53 | | using IMATH_NAMESPACE::Box2i; |
54 | | using IMATH_NAMESPACE::V2i; |
55 | | |
56 | | |
57 | | int |
58 | | levelSize (int min, int max, int l, LevelRoundingMode rmode) |
59 | 0 | { |
60 | 0 | if (l < 0) |
61 | 0 | throw IEX_NAMESPACE::ArgExc ("Argument not in valid range."); |
62 | | |
63 | 0 | int a = max - min + 1; |
64 | 0 | int b = (1 << l); |
65 | 0 | int size = a / b; |
66 | |
|
67 | 0 | if (rmode == ROUND_UP && size * b < a) |
68 | 0 | size += 1; |
69 | |
|
70 | 0 | return std::max (size, 1); |
71 | 0 | } |
72 | | |
73 | | |
74 | | Box2i |
75 | | dataWindowForLevel (const TileDescription &tileDesc, |
76 | | int minX, int maxX, |
77 | | int minY, int maxY, |
78 | | int lx, int ly) |
79 | 0 | { |
80 | 0 | V2i levelMin = V2i (minX, minY); |
81 | |
|
82 | 0 | V2i levelMax = levelMin + |
83 | 0 | V2i (levelSize (minX, maxX, lx, tileDesc.roundingMode) - 1, |
84 | 0 | levelSize (minY, maxY, ly, tileDesc.roundingMode) - 1); |
85 | |
|
86 | 0 | return Box2i(levelMin, levelMax); |
87 | 0 | } |
88 | | |
89 | | |
90 | | Box2i |
91 | | dataWindowForTile (const TileDescription &tileDesc, |
92 | | int minX, int maxX, |
93 | | int minY, int maxY, |
94 | | int dx, int dy, |
95 | | int lx, int ly) |
96 | 0 | { |
97 | 0 | V2i tileMin = V2i (minX + dx * tileDesc.xSize, |
98 | 0 | minY + dy * tileDesc.ySize); |
99 | |
|
100 | 0 | V2i tileMax = tileMin + V2i (tileDesc.xSize - 1, tileDesc.ySize - 1); |
101 | |
|
102 | 0 | V2i levelMax = dataWindowForLevel |
103 | 0 | (tileDesc, minX, maxX, minY, maxY, lx, ly).max; |
104 | |
|
105 | 0 | tileMax = V2i (std::min (tileMax[0], levelMax[0]), |
106 | 0 | std::min (tileMax[1], levelMax[1])); |
107 | |
|
108 | 0 | return Box2i (tileMin, tileMax); |
109 | 0 | } |
110 | | |
111 | | |
112 | | size_t |
113 | | calculateBytesPerPixel (const Header &header) |
114 | 0 | { |
115 | 0 | const ChannelList &channels = header.channels(); |
116 | |
|
117 | 0 | size_t bytesPerPixel = 0; |
118 | |
|
119 | 0 | for (ChannelList::ConstIterator c = channels.begin(); |
120 | 0 | c != channels.end(); |
121 | 0 | ++c) |
122 | 0 | { |
123 | 0 | bytesPerPixel += pixelTypeSize (c.channel().type); |
124 | 0 | } |
125 | |
|
126 | 0 | return bytesPerPixel; |
127 | 0 | } |
128 | | |
129 | | |
130 | | void |
131 | | calculateBytesPerLine (const Header &header, |
132 | | char* sampleCountBase, |
133 | | int sampleCountXStride, |
134 | | int sampleCountYStride, |
135 | | int minX, int maxX, |
136 | | int minY, int maxY, |
137 | | std::vector<int>& xOffsets, |
138 | | std::vector<int>& yOffsets, |
139 | | std::vector<Int64>& bytesPerLine) |
140 | 0 | { |
141 | 0 | const ChannelList &channels = header.channels(); |
142 | |
|
143 | 0 | int pos = 0; |
144 | 0 | for (ChannelList::ConstIterator c = channels.begin(); |
145 | 0 | c != channels.end(); |
146 | 0 | ++c, ++pos) |
147 | 0 | { |
148 | 0 | int xOffset = xOffsets[pos]; |
149 | 0 | int yOffset = yOffsets[pos]; |
150 | 0 | int i = 0; |
151 | 0 | for (int y = minY - yOffset; y <= maxY - yOffset; y++, i++) |
152 | 0 | for (int x = minX - xOffset; x <= maxX - xOffset; x++) |
153 | 0 | { |
154 | 0 | bytesPerLine[i] += sampleCount(sampleCountBase, |
155 | 0 | sampleCountXStride, |
156 | 0 | sampleCountYStride, |
157 | 0 | x, y) |
158 | 0 | * pixelTypeSize (c.channel().type); |
159 | 0 | } |
160 | 0 | } |
161 | 0 | } |
162 | | |
163 | | |
164 | | namespace { |
165 | | |
166 | | int |
167 | | floorLog2 (int x) |
168 | 0 | { |
169 | | // |
170 | | // For x > 0, floorLog2(y) returns floor(log(x)/log(2)). |
171 | | // |
172 | |
|
173 | 0 | int y = 0; |
174 | |
|
175 | 0 | while (x > 1) |
176 | 0 | { |
177 | 0 | y += 1; |
178 | 0 | x >>= 1; |
179 | 0 | } |
180 | |
|
181 | 0 | return y; |
182 | 0 | } |
183 | | |
184 | | |
185 | | int |
186 | | ceilLog2 (int x) |
187 | 0 | { |
188 | | // |
189 | | // For x > 0, ceilLog2(y) returns ceil(log(x)/log(2)). |
190 | | // |
191 | |
|
192 | 0 | int y = 0; |
193 | 0 | int r = 0; |
194 | |
|
195 | 0 | while (x > 1) |
196 | 0 | { |
197 | 0 | if (x & 1) |
198 | 0 | r = 1; |
199 | |
|
200 | 0 | y += 1; |
201 | 0 | x >>= 1; |
202 | 0 | } |
203 | |
|
204 | 0 | return y + r; |
205 | 0 | } |
206 | | |
207 | | |
208 | | int |
209 | | roundLog2 (int x, LevelRoundingMode rmode) |
210 | 0 | { |
211 | 0 | return (rmode == ROUND_DOWN)? floorLog2 (x): ceilLog2 (x); |
212 | 0 | } |
213 | | |
214 | | |
215 | | int |
216 | | calculateNumXLevels (const TileDescription& tileDesc, |
217 | | int minX, int maxX, |
218 | | int minY, int maxY) |
219 | 0 | { |
220 | 0 | int num = 0; |
221 | |
|
222 | 0 | switch (tileDesc.mode) |
223 | 0 | { |
224 | 0 | case ONE_LEVEL: |
225 | |
|
226 | 0 | num = 1; |
227 | 0 | break; |
228 | | |
229 | 0 | case MIPMAP_LEVELS: |
230 | |
|
231 | 0 | { |
232 | 0 | int w = maxX - minX + 1; |
233 | 0 | int h = maxY - minY + 1; |
234 | 0 | num = roundLog2 (std::max (w, h), tileDesc.roundingMode) + 1; |
235 | 0 | } |
236 | 0 | break; |
237 | | |
238 | 0 | case RIPMAP_LEVELS: |
239 | |
|
240 | 0 | { |
241 | 0 | int w = maxX - minX + 1; |
242 | 0 | num = roundLog2 (w, tileDesc.roundingMode) + 1; |
243 | 0 | } |
244 | 0 | break; |
245 | | |
246 | 0 | default: |
247 | |
|
248 | 0 | throw IEX_NAMESPACE::ArgExc ("Unknown LevelMode format."); |
249 | 0 | } |
250 | | |
251 | 0 | return num; |
252 | 0 | } |
253 | | |
254 | | |
255 | | int |
256 | | calculateNumYLevels (const TileDescription& tileDesc, |
257 | | int minX, int maxX, |
258 | | int minY, int maxY) |
259 | 0 | { |
260 | 0 | int num = 0; |
261 | |
|
262 | 0 | switch (tileDesc.mode) |
263 | 0 | { |
264 | 0 | case ONE_LEVEL: |
265 | |
|
266 | 0 | num = 1; |
267 | 0 | break; |
268 | | |
269 | 0 | case MIPMAP_LEVELS: |
270 | |
|
271 | 0 | { |
272 | 0 | int w = maxX - minX + 1; |
273 | 0 | int h = maxY - minY + 1; |
274 | 0 | num = roundLog2 (std::max (w, h), tileDesc.roundingMode) + 1; |
275 | 0 | } |
276 | 0 | break; |
277 | | |
278 | 0 | case RIPMAP_LEVELS: |
279 | |
|
280 | 0 | { |
281 | 0 | int h = maxY - minY + 1; |
282 | 0 | num = roundLog2 (h, tileDesc.roundingMode) + 1; |
283 | 0 | } |
284 | 0 | break; |
285 | | |
286 | 0 | default: |
287 | |
|
288 | 0 | throw IEX_NAMESPACE::ArgExc ("Unknown LevelMode format."); |
289 | 0 | } |
290 | | |
291 | 0 | return num; |
292 | 0 | } |
293 | | |
294 | | |
295 | | void |
296 | | calculateNumTiles (int *numTiles, |
297 | | int numLevels, |
298 | | int min, int max, |
299 | | int size, |
300 | | LevelRoundingMode rmode) |
301 | 0 | { |
302 | 0 | for (int i = 0; i < numLevels; i++) |
303 | 0 | { |
304 | 0 | numTiles[i] = (levelSize (min, max, i, rmode) + size - 1) / size; |
305 | 0 | } |
306 | 0 | } |
307 | | |
308 | | } // namespace |
309 | | |
310 | | |
311 | | void |
312 | | precalculateTileInfo (const TileDescription& tileDesc, |
313 | | int minX, int maxX, |
314 | | int minY, int maxY, |
315 | | int *&numXTiles, int *&numYTiles, |
316 | | int &numXLevels, int &numYLevels) |
317 | 0 | { |
318 | 0 | numXLevels = calculateNumXLevels(tileDesc, minX, maxX, minY, maxY); |
319 | 0 | numYLevels = calculateNumYLevels(tileDesc, minX, maxX, minY, maxY); |
320 | | |
321 | 0 | numXTiles = new int[numXLevels]; |
322 | 0 | numYTiles = new int[numYLevels]; |
323 | |
|
324 | 0 | calculateNumTiles (numXTiles, |
325 | 0 | numXLevels, |
326 | 0 | minX, maxX, |
327 | 0 | tileDesc.xSize, |
328 | 0 | tileDesc.roundingMode); |
329 | |
|
330 | 0 | calculateNumTiles (numYTiles, |
331 | 0 | numYLevels, |
332 | 0 | minY, maxY, |
333 | 0 | tileDesc.ySize, |
334 | 0 | tileDesc.roundingMode); |
335 | 0 | } |
336 | | |
337 | | |
338 | | int |
339 | | getTiledChunkOffsetTableSize(const Header& header) |
340 | 0 | { |
341 | | // |
342 | | // Save the dataWindow information |
343 | | // |
344 | |
|
345 | 0 | const Box2i &dataWindow = header.dataWindow(); |
346 | | |
347 | | // |
348 | | // Precompute level and tile information. |
349 | | // |
350 | |
|
351 | 0 | int* numXTiles; |
352 | 0 | int* numYTiles; |
353 | 0 | int numXLevels; |
354 | 0 | int numYLevels; |
355 | 0 | precalculateTileInfo (header.tileDescription(), |
356 | 0 | dataWindow.min.x, dataWindow.max.x, |
357 | 0 | dataWindow.min.y, dataWindow.max.y, |
358 | 0 | numXTiles, numYTiles, |
359 | 0 | numXLevels, numYLevels); |
360 | | |
361 | | // |
362 | | // Calculate lineOffsetSize. |
363 | | // |
364 | 0 | int lineOffsetSize = 0; |
365 | 0 | const TileDescription &desc = header.tileDescription(); |
366 | 0 | switch (desc.mode) |
367 | 0 | { |
368 | 0 | case ONE_LEVEL: |
369 | 0 | case MIPMAP_LEVELS: |
370 | 0 | for (int i = 0; i < numXLevels; i++) |
371 | 0 | lineOffsetSize += numXTiles[i] * numYTiles[i]; |
372 | 0 | break; |
373 | 0 | case RIPMAP_LEVELS: |
374 | 0 | for (int i = 0; i < numXLevels; i++) |
375 | 0 | for (int j = 0; j < numYLevels; j++) |
376 | 0 | lineOffsetSize += numXTiles[i] * numYTiles[j]; |
377 | 0 | break; |
378 | 0 | case NUM_LEVELMODES : |
379 | 0 | throw IEX_NAMESPACE::LogicExc("Bad level mode getting chunk offset table size"); |
380 | 0 | } |
381 | | |
382 | 0 | delete[] numXTiles; |
383 | 0 | delete[] numYTiles; |
384 | |
|
385 | 0 | return lineOffsetSize; |
386 | 0 | } |
387 | | |
388 | | |
389 | | OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT |