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