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
56OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
57
58
59struct PreviewRgba;
60
61
62class 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 TiledOutputFile (const char fileName[],
89 const Header &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 TiledOutputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os,
101 const Header &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 & 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 initialize (const Header &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
493OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
494
495#endif
496