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 | #ifndef INCLUDED_IMF_TILED_OUTPUT_FILE_H |
37 | #define INCLUDED_IMF_TILED_OUTPUT_FILE_H |
38 | |
39 | //----------------------------------------------------------------------------- |
40 | // |
41 | // class TiledOutputFile |
42 | // |
43 | //----------------------------------------------------------------------------- |
44 | |
45 | #include "ImfHeader.h" |
46 | #include "ImfFrameBuffer.h" |
47 | #include "ImathBox.h" |
48 | #include "ImfTileDescription.h" |
49 | #include "ImfThreading.h" |
50 | #include "ImfGenericOutputFile.h" |
51 | #include "ImfForward.h" |
52 | #include "ImfNamespace.h" |
53 | #include "ImfExport.h" |
54 | |
55 | |
56 | OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER |
57 | |
58 | |
59 | struct PreviewRgba; |
60 | |
61 | |
62 | class IMF_EXPORT TiledOutputFile : public GenericOutputFile |
63 | { |
64 | public: |
65 | |
66 | //------------------------------------------------------------------- |
67 | // A constructor that opens the file with the specified name, and |
68 | // writes the file header. The file header is also copied into the |
69 | // TiledOutputFile object, and can later be accessed via the header() |
70 | // method. |
71 | // |
72 | // Destroying TiledOutputFile constructed with this constructor |
73 | // automatically closes the corresponding files. |
74 | // |
75 | // The header must contain a TileDescriptionAttribute called "tiles". |
76 | // |
77 | // The x and y subsampling factors for all image channels must be 1; |
78 | // subsampling is not supported. |
79 | // |
80 | // Tiles can be written to the file in arbitrary order. The line |
81 | // order attribute can be used to cause the tiles to be sorted in |
82 | // the file. When the file is read later, reading the tiles in the |
83 | // same order as they are in the file tends to be significantly |
84 | // faster than reading the tiles in random order (see writeTile, |
85 | // below). |
86 | //------------------------------------------------------------------- |
87 | |
88 | (const char fileName[], |
89 | const Header &, |
90 | int numThreads = globalThreadCount ()); |
91 | |
92 | |
93 | // ---------------------------------------------------------------- |
94 | // A constructor that attaches the new TiledOutputFile object to |
95 | // a file that has already been opened. Destroying TiledOutputFile |
96 | // objects constructed with this constructor does not automatically |
97 | // close the corresponding files. |
98 | // ---------------------------------------------------------------- |
99 | |
100 | (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, |
101 | const Header &, |
102 | int numThreads = globalThreadCount ()); |
103 | |
104 | |
105 | //----------------------------------------------------- |
106 | // Destructor |
107 | // |
108 | // Destroying a TiledOutputFile object before all tiles |
109 | // have been written results in an incomplete file. |
110 | //----------------------------------------------------- |
111 | |
112 | virtual ~TiledOutputFile (); |
113 | |
114 | |
115 | //------------------------ |
116 | // Access to the file name |
117 | //------------------------ |
118 | |
119 | const char * fileName () const; |
120 | |
121 | |
122 | //-------------------------- |
123 | // Access to the file header |
124 | //-------------------------- |
125 | |
126 | const Header & () const; |
127 | |
128 | |
129 | //------------------------------------------------------- |
130 | // Set the current frame buffer -- copies the FrameBuffer |
131 | // object into the TiledOutputFile object. |
132 | // |
133 | // The current frame buffer is the source of the pixel |
134 | // data written to the file. The current frame buffer |
135 | // must be set at least once before writeTile() is |
136 | // called. The current frame buffer can be changed |
137 | // after each call to writeTile(). |
138 | //------------------------------------------------------- |
139 | |
140 | void setFrameBuffer (const FrameBuffer &frameBuffer); |
141 | |
142 | |
143 | //----------------------------------- |
144 | // Access to the current frame buffer |
145 | //----------------------------------- |
146 | |
147 | const FrameBuffer & frameBuffer () const; |
148 | |
149 | |
150 | //------------------- |
151 | // Utility functions: |
152 | //------------------- |
153 | |
154 | //--------------------------------------------------------- |
155 | // Multiresolution mode and tile size: |
156 | // The following functions return the xSize, ySize and mode |
157 | // fields of the file header's TileDescriptionAttribute. |
158 | //--------------------------------------------------------- |
159 | |
160 | unsigned int tileXSize () const; |
161 | unsigned int tileYSize () const; |
162 | LevelMode levelMode () const; |
163 | LevelRoundingMode levelRoundingMode () const; |
164 | |
165 | |
166 | //-------------------------------------------------------------------- |
167 | // Number of levels: |
168 | // |
169 | // numXLevels() returns the file's number of levels in x direction. |
170 | // |
171 | // if levelMode() == ONE_LEVEL: |
172 | // return value is: 1 |
173 | // |
174 | // if levelMode() == MIPMAP_LEVELS: |
175 | // return value is: rfunc (log (max (w, h)) / log (2)) + 1 |
176 | // |
177 | // if levelMode() == RIPMAP_LEVELS: |
178 | // return value is: rfunc (log (w) / log (2)) + 1 |
179 | // |
180 | // where |
181 | // w is the width of the image's data window, max.x - min.x + 1, |
182 | // y is the height of the image's data window, max.y - min.y + 1, |
183 | // and rfunc(x) is either floor(x), or ceil(x), depending on |
184 | // whether levelRoundingMode() returns ROUND_DOWN or ROUND_UP. |
185 | // |
186 | // numYLevels() returns the file's number of levels in y direction. |
187 | // |
188 | // if levelMode() == ONE_LEVEL or levelMode() == MIPMAP_LEVELS: |
189 | // return value is the same as for numXLevels() |
190 | // |
191 | // if levelMode() == RIPMAP_LEVELS: |
192 | // return value is: rfunc (log (h) / log (2)) + 1 |
193 | // |
194 | // |
195 | // numLevels() is a convenience function for use with MIPMAP_LEVELS |
196 | // files. |
197 | // |
198 | // if levelMode() == ONE_LEVEL or levelMode() == MIPMAP_LEVELS: |
199 | // return value is the same as for numXLevels() |
200 | // |
201 | // if levelMode() == RIPMAP_LEVELS: |
202 | // an IEX_NAMESPACE::LogicExc exception is thrown |
203 | // |
204 | // isValidLevel(lx, ly) returns true if the file contains |
205 | // a level with level number (lx, ly), false if not. |
206 | // |
207 | //-------------------------------------------------------------------- |
208 | |
209 | int numLevels () const; |
210 | int numXLevels () const; |
211 | int numYLevels () const; |
212 | bool isValidLevel (int lx, int ly) const; |
213 | |
214 | |
215 | //--------------------------------------------------------- |
216 | // Dimensions of a level: |
217 | // |
218 | // levelWidth(lx) returns the width of a level with level |
219 | // number (lx, *), where * is any number. |
220 | // |
221 | // return value is: |
222 | // max (1, rfunc (w / pow (2, lx))) |
223 | // |
224 | // |
225 | // levelHeight(ly) returns the height of a level with level |
226 | // number (*, ly), where * is any number. |
227 | // |
228 | // return value is: |
229 | // max (1, rfunc (h / pow (2, ly))) |
230 | // |
231 | //--------------------------------------------------------- |
232 | |
233 | int levelWidth (int lx) const; |
234 | int levelHeight (int ly) const; |
235 | |
236 | |
237 | //---------------------------------------------------------- |
238 | // Number of tiles: |
239 | // |
240 | // numXTiles(lx) returns the number of tiles in x direction |
241 | // that cover a level with level number (lx, *), where * is |
242 | // any number. |
243 | // |
244 | // return value is: |
245 | // (levelWidth(lx) + tileXSize() - 1) / tileXSize() |
246 | // |
247 | // |
248 | // numYTiles(ly) returns the number of tiles in y direction |
249 | // that cover a level with level number (*, ly), where * is |
250 | // any number. |
251 | // |
252 | // return value is: |
253 | // (levelHeight(ly) + tileXSize() - 1) / tileXSize() |
254 | // |
255 | //---------------------------------------------------------- |
256 | |
257 | int numXTiles (int lx = 0) const; |
258 | int numYTiles (int ly = 0) const; |
259 | |
260 | |
261 | //--------------------------------------------------------- |
262 | // Level pixel ranges: |
263 | // |
264 | // dataWindowForLevel(lx, ly) returns a 2-dimensional |
265 | // region of valid pixel coordinates for a level with |
266 | // level number (lx, ly) |
267 | // |
268 | // return value is a Box2i with min value: |
269 | // (dataWindow.min.x, dataWindow.min.y) |
270 | // |
271 | // and max value: |
272 | // (dataWindow.min.x + levelWidth(lx) - 1, |
273 | // dataWindow.min.y + levelHeight(ly) - 1) |
274 | // |
275 | // dataWindowForLevel(level) is a convenience function used |
276 | // for ONE_LEVEL and MIPMAP_LEVELS files. It returns |
277 | // dataWindowForLevel(level, level). |
278 | // |
279 | //--------------------------------------------------------- |
280 | |
281 | IMATH_NAMESPACE::Box2i dataWindowForLevel (int l = 0) const; |
282 | IMATH_NAMESPACE::Box2i dataWindowForLevel (int lx, int ly) const; |
283 | |
284 | |
285 | //------------------------------------------------------------------- |
286 | // Tile pixel ranges: |
287 | // |
288 | // dataWindowForTile(dx, dy, lx, ly) returns a 2-dimensional |
289 | // region of valid pixel coordinates for a tile with tile coordinates |
290 | // (dx,dy) and level number (lx, ly). |
291 | // |
292 | // return value is a Box2i with min value: |
293 | // (dataWindow.min.x + dx * tileXSize(), |
294 | // dataWindow.min.y + dy * tileYSize()) |
295 | // |
296 | // and max value: |
297 | // (dataWindow.min.x + (dx + 1) * tileXSize() - 1, |
298 | // dataWindow.min.y + (dy + 1) * tileYSize() - 1) |
299 | // |
300 | // dataWindowForTile(dx, dy, level) is a convenience function |
301 | // used for ONE_LEVEL and MIPMAP_LEVELS files. It returns |
302 | // dataWindowForTile(dx, dy, level, level). |
303 | // |
304 | //------------------------------------------------------------------- |
305 | |
306 | IMATH_NAMESPACE::Box2i dataWindowForTile (int dx, int dy, |
307 | int l = 0) const; |
308 | |
309 | IMATH_NAMESPACE::Box2i dataWindowForTile (int dx, int dy, |
310 | int lx, int ly) const; |
311 | |
312 | //------------------------------------------------------------------ |
313 | // Write pixel data: |
314 | // |
315 | // writeTile(dx, dy, lx, ly) writes the tile with tile |
316 | // coordinates (dx, dy), and level number (lx, ly) to |
317 | // the file. |
318 | // |
319 | // dx must lie in the interval [0, numXTiles(lx) - 1] |
320 | // dy must lie in the interval [0, numYTiles(ly) - 1] |
321 | // |
322 | // lx must lie in the interval [0, numXLevels() - 1] |
323 | // ly must lie in the inverval [0, numYLevels() - 1] |
324 | // |
325 | // writeTile(dx, dy, level) is a convenience function |
326 | // used for ONE_LEVEL and MIPMAP_LEVEL files. It calls |
327 | // writeTile(dx, dy, level, level). |
328 | // |
329 | // The two writeTiles(dx1, dx2, dy1, dy2, ...) functions allow |
330 | // writing multiple tiles at once. If multi-threading is used |
331 | // multiple tiles are written concurrently. The tile coordinates, |
332 | // dx1, dx2 and dy1, dy2, specify inclusive ranges of tile |
333 | // coordinates. It is valid for dx1 < dx2 or dy1 < dy2; the |
334 | // tiles are always written in the order specified by the line |
335 | // order attribute. Hence, it is not possible to specify an |
336 | // "invalid" or empty tile range. |
337 | // |
338 | // Pixels that are outside the pixel coordinate range for the tile's |
339 | // level, are never accessed by writeTile(). |
340 | // |
341 | // Each tile in the file must be written exactly once. |
342 | // |
343 | // The file's line order attribute determines the order of the tiles |
344 | // in the file: |
345 | // |
346 | // INCREASING_Y In the file, the tiles for each level are stored |
347 | // in a contiguous block. The levels are ordered |
348 | // like this: |
349 | // |
350 | // (0, 0) (1, 0) ... (nx-1, 0) |
351 | // (0, 1) (1, 1) ... (nx-1, 1) |
352 | // ... |
353 | // (0,ny-1) (1,ny-1) ... (nx-1,ny-1) |
354 | // |
355 | // where nx = numXLevels(), and ny = numYLevels(). |
356 | // In an individual level, (lx, ly), the tiles |
357 | // are stored in the following order: |
358 | // |
359 | // (0, 0) (1, 0) ... (tx-1, 0) |
360 | // (0, 1) (1, 1) ... (tx-1, 1) |
361 | // ... |
362 | // (0,ty-1) (1,ty-1) ... (tx-1,ty-1) |
363 | // |
364 | // where tx = numXTiles(lx), |
365 | // and ty = numYTiles(ly). |
366 | // |
367 | // DECREASING_Y As for INCREASING_Y, the tiles for each level |
368 | // are stored in a contiguous block. The levels |
369 | // are ordered the same way as for INCREASING_Y, |
370 | // but within an individual level, the tiles |
371 | // are stored in this order: |
372 | // |
373 | // (0,ty-1) (1,ty-1) ... (tx-1,ty-1) |
374 | // ... |
375 | // (0, 1) (1, 1) ... (tx-1, 1) |
376 | // (0, 0) (1, 0) ... (tx-1, 0) |
377 | // |
378 | // |
379 | // RANDOM_Y The order of the calls to writeTile() determines |
380 | // the order of the tiles in the file. |
381 | // |
382 | //------------------------------------------------------------------ |
383 | |
384 | void writeTile (int dx, int dy, int l = 0); |
385 | void writeTile (int dx, int dy, int lx, int ly); |
386 | |
387 | void writeTiles (int dx1, int dx2, int dy1, int dy2, |
388 | int lx, int ly); |
389 | |
390 | void writeTiles (int dx1, int dx2, int dy1, int dy2, |
391 | int l = 0); |
392 | |
393 | |
394 | //------------------------------------------------------------------ |
395 | // Shortcut to copy all pixels from a TiledInputFile into this file, |
396 | // without uncompressing and then recompressing the pixel data. |
397 | // This file's header must be compatible with the TiledInputFile's |
398 | // header: The two header's "dataWindow", "compression", |
399 | // "lineOrder", "channels", and "tiles" attributes must be the same. |
400 | //------------------------------------------------------------------ |
401 | |
402 | void copyPixels (TiledInputFile &in); |
403 | void copyPixels (TiledInputPart &in); |
404 | |
405 | |
406 | //------------------------------------------------------------------ |
407 | // Shortcut to copy all pixels from an InputFile into this file, |
408 | // without uncompressing and then recompressing the pixel data. |
409 | // This file's header must be compatible with the InputFile's |
410 | // header: The two header's "dataWindow", "compression", |
411 | // "lineOrder", "channels", and "tiles" attributes must be the same. |
412 | // |
413 | // To use this function, the InputFile must be tiled. |
414 | //------------------------------------------------------------------ |
415 | |
416 | void copyPixels (InputFile &in); |
417 | void copyPixels (InputPart &in); |
418 | |
419 | |
420 | |
421 | //-------------------------------------------------------------- |
422 | // Updating the preview image: |
423 | // |
424 | // updatePreviewImage() supplies a new set of pixels for the |
425 | // preview image attribute in the file's header. If the header |
426 | // does not contain a preview image, updatePreviewImage() throws |
427 | // an IEX_NAMESPACE::LogicExc. |
428 | // |
429 | // Note: updatePreviewImage() is necessary because images are |
430 | // often stored in a file incrementally, a few tiles at a time, |
431 | // while the image is being generated. Since the preview image |
432 | // is an attribute in the file's header, it gets stored in the |
433 | // file as soon as the file is opened, but we may not know what |
434 | // the preview image should look like until we have written the |
435 | // last tile of the main image. |
436 | // |
437 | //-------------------------------------------------------------- |
438 | |
439 | void updatePreviewImage (const PreviewRgba newPixels[]); |
440 | |
441 | |
442 | //------------------------------------------------------------- |
443 | // Break a tile -- for testing and debugging only: |
444 | // |
445 | // breakTile(dx,dy,lx,ly,p,n,c) introduces an error into the |
446 | // output file by writing n copies of character c, starting |
447 | // p bytes from the beginning of the tile with tile coordinates |
448 | // (dx, dy) and level number (lx, ly). |
449 | // |
450 | // Warning: Calling this function usually results in a broken |
451 | // image file. The file or parts of it may not be readable, |
452 | // or the file may contain bad data. |
453 | // |
454 | //------------------------------------------------------------- |
455 | |
456 | void breakTile (int dx, int dy, |
457 | int lx, int ly, |
458 | int offset, |
459 | int length, |
460 | char c); |
461 | struct Data; |
462 | |
463 | private: |
464 | |
465 | // ---------------------------------------------------------------- |
466 | // A constructor attaches the OutputStreamMutex to the |
467 | // given one from MultiPartOutputFile. Set the previewPosition |
468 | // and lineOffsetsPosition which have been acquired from |
469 | // the constructor of MultiPartOutputFile as well. |
470 | // ---------------------------------------------------------------- |
471 | TiledOutputFile (const OutputPartData* part); |
472 | |
473 | TiledOutputFile (const TiledOutputFile &); // not implemented |
474 | TiledOutputFile & operator = (const TiledOutputFile &); // not implemented |
475 | |
476 | void (const Header &); |
477 | |
478 | bool isValidTile (int dx, int dy, |
479 | int lx, int ly) const; |
480 | |
481 | size_t bytesPerLineForTile (int dx, int dy, |
482 | int lx, int ly) const; |
483 | |
484 | Data * _data; |
485 | |
486 | OutputStreamMutex* _streamData; |
487 | bool _deleteStream; |
488 | |
489 | friend class MultiPartOutputFile; |
490 | }; |
491 | |
492 | |
493 | OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT |
494 | |
495 | #endif |
496 | |