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