1 /**
2  * @file
3  * @brief PFS library - core API interfaces
4  *
5  * Classes for reading and writing a stream of PFS frames.
6  *
7  * Note on the design of pfs library API: pfs library API makes
8  * extensive usage of interfaces - classes that have only virtual
9  * methods. This way no private fields are visible for the client
10  * programs. Everything that is private is hidden in .cpp file rather
11  * than the header .h. For example, pfs library uses STL to store some
12  * internal data, but no STL class can be found the header file
13  * pfs.h. Such design should hopefully give less problems when
14  * extending and updating the library.
15  *
16  * This file is a part of PFSTOOLS package.
17  * ----------------------------------------------------------------------
18  * Copyright (C) 2003,2004 Rafal Mantiuk and Grzegorz Krawczyk
19  *
20  *  This library is free software; you can redistribute it and/or
21  *  modify it under the terms of the GNU Lesser General Public
22  *  License as published by the Free Software Foundation; either
23  *  version 2.1 of the License, or (at your option) any later version.
24  *
25  *  This library is distributed in the hope that it will be useful,
26  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
27  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
28  *  Lesser General Public License for more details.
29  *
30  *  You should have received a copy of the GNU Lesser General Public
31  *  License along with this library; if not, write to the Free Software
32  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
33  * ----------------------------------------------------------------------
34  *
35  * @author Rafal Mantiuk, <mantiuk@mpi-sb.mpg.de>
36  *
37  * $Id: pfs.h,v 1.5 2014/04/05 22:04:13 rafm Exp $
38  */
39 
40 #ifndef PFS_H
41 #define PFS_H
42 
43 #include <stdio.h>
44 #include <string.h>
45 #include "array2d.h"
46 
47 #include <getopt.h>
48 
49 //struct option;
50 
51 /**
52  * All classes and function from PFS library reside in pfs namespace.
53  */
54 namespace pfs
55 {
56 
57   /**
58    * Utility class that keeps pointer and deletes pointed object
59    * when the class is deleted.
60    *
61    * Note that it is not a full implementation of the smart pointer
62    * and memory management is not fool proof. You should never store
63    * this object as a global variable or a field of a class. These
64    * objects should be used only as local variables.
65    */
66   template<class T>
67     class SelfDestructPtr
68     {
69       T *ptr;
70       mutable bool itsOwn;
71     public:
ptr(ptr)72       explicit SelfDestructPtr( T *ptr = 0 ): ptr(ptr), itsOwn(ptr!=0)
73         {
74         }
75 
SelfDestructPtr(const SelfDestructPtr & r)76       SelfDestructPtr( const SelfDestructPtr& r )
77         : itsOwn(r.itsOwn), ptr(r.release()) {}
78 
79       SelfDestructPtr& operator=( const SelfDestructPtr& r ) {
80         if (&r != this) {
81             if (ptr != r.ptr) {
82               if( itsOwn ) delete ptr;
83               itsOwn = r.itsOwn;
84             }
85             else if( r.itsOwn ) itsOwn = true;
86             ptr = r.release();
87         }
88         return *this;
89       }
90 
~SelfDestructPtr()91       ~SelfDestructPtr()
92         {
93           if( itsOwn )
94             delete ptr;
95         }
96 
97       bool operator==( const SelfDestructPtr &x ) const {
98         return *(ptr) == *(x.ptr);
99       }
100 
101       bool operator!=( const SelfDestructPtr &x ) const {
102         return *(ptr) != *(x.ptr);
103       }
104 
105       T& operator*()  const            {return *ptr;}
106       T* operator->() const            {return ptr;}
get()107       T* get()        const            {return ptr;}
release()108       T* release()    const  {itsOwn = false; return ptr;}
109 
110     };
111 
112 
113   /**
114    * Iterator that allows to get the list of available tags in a
115    * TagContainer.
116    */
117   class TagIterator
118     {
119     public:
120       /**
121        * Get next item on the list.
122        *
123        * @return name of the tag
124        */
125       virtual const char *getNext() = 0;
126       /**
127        * Returns true if there is still an item left on the list.
128        */
129       virtual bool hasNext() const = 0;
130 
~TagIterator()131       virtual ~TagIterator()
132 	{
133 	}
134     };
135 
136   typedef SelfDestructPtr<TagIterator> TagIteratorPtr;
137 
138 /**
139  * TagContainer interface allows to read and modify tags. A tag is "name"="value" pair.
140  */
141   class TagContainer
142     {
143     public:
~TagContainer()144       virtual ~TagContainer() {};
145       /**
146        * Get a string tag of the name tagName from the TagContainer.
147        * @param tagName name of the tag to retrieve
148        * @return tag value or NULL if tag was not found
149        */
150       virtual const char* getString( const char *tagName ) = 0;
151 
152       /**
153        * Set or add a string tag of the name tagName.
154        * @param tagName name of the tag to add or set
155        * @param tagValue value of the tag
156        */
157       virtual void setString( const char *tagName, const char *tagValue ) = 0;
158 
159       /**
160        * Removes (if exists) a tag of the name tagName from the TagContainer.
161        * @param tagName name of the tag to remove
162        */
163       virtual void removeTag( const char *tagName ) = 0;
164 
165       /**
166        * Use TagIterator to iterate over all tags in the TagContainer.
167        * TagIteratorPtr is a smart pointer, which destructs
168        * TagIterator when TagIteratorPtr is destructed. Use ->
169        * operator to access TagIterator members from a TagIteratorPtr
170        * object.
171        *
172        * To iterate over all tags, use the following code:
173        * <code>
174        * pfs::TagIteratorPtr it( frame->getTags()->getIterator() );
175        * while( it->hasNext() ) {
176        *   const char *tagName = it->getNext();
177        *   //Do something
178        * }
179        * </code>
180        */
181       virtual TagIteratorPtr getIterator() const = 0;
182     };
183 
184 
185 /**
186  * Channel interface represents a 2D rectangular array with
187  * associated tags.
188  */
189   class Channel : public Array2D {
190   public:
~Channel()191     virtual ~Channel() {};
192     /**
193      * Gets width of the channel (in pixels).
194      * This is a synonym for Array2D::getCols().
195      */
getWidth()196     int getWidth() const {
197       return getCols();
198     }
199 
200     /**
201      * Gets height of the channel (in pixels).
202      * This is a synonym for Array2D::getRows().
203      */
getHeight()204     virtual int getHeight() const
205       {
206         return getRows();
207       }
208 
209     /**
210      * Gets name of the channel.
211      */
212     virtual const char *getName() const = 0;
213 
214     /**
215      * Returns TagContainer that can be used to access or modify
216      * tags associated with this Channel object.
217      */
218     virtual TagContainer *getTags() = 0;
219 
220     /**
221      * For performance reasons, the channels can be accessed as a
222      * table of float values. Data is given in row-major order, i.e.
223      * it is indexed data[x+y*width]. If performance is not crucial,
224      * use Array2D interface instead.
225      *
226      * @return a table of floats of the size width*height
227      */
228     virtual float *getRawData() = 0;
229   };
230 
231   /**
232    * Iterator that allows to get the list of available channels in a frame.
233    */
234   class ChannelIterator
235     {
236     public:
237       /**
238        * Get next item on the list.
239        */
240       virtual Channel *getNext() = 0;
241       /**
242        * Returns true if there is still an item left on the list.
243        */
244       virtual bool hasNext() const = 0;
245 
~ChannelIterator()246       virtual ~ChannelIterator()
247 	{
248 	}
249     };
250 
251   typedef SelfDestructPtr<ChannelIterator> ChannelIteratorPtr;
252 
253 /**
254  * Interface representing a single PFS frame. Frame may contain 0
255  * or more channels (e.g. color XYZ, depth channel, alpha
256  * channnel). All the channels are of the same size. Frame can
257  * also contain additional information in tags (see getTags).
258  */
259   class Frame {
260   public:
261     /**
262      * Gets width of the channels (in pixels).
263      */
264     virtual int getWidth() const = 0;
265 
266     /**
267      * Gets height of the channels (in pixels).
268      */
269     virtual int getHeight() const = 0;
270 
271     /**
272      * Gets color channels in XYZ color space. May return NULLs
273      * if such channels do not exist. Values assigned to
274      * X, Y, Z are always either all NULLs or valid pointers to
275      * channels.
276      *
277      * @param X [out] a pointer to store X channel in
278      * @param Y [out] a pointer to store Y channel in
279      * @param Z [out] a pointer to store Z channel in
280      */
281     virtual void getXYZChannels( Channel* &X, Channel* &Y, Channel* &Z ) = 0;
282 
283     /**
284      * Creates color channels in XYZ color space. If such channels
285      * already exists, returns existing channels, rather than
286      * creating new ones.  Note, that nothing can be assumed about
287      * the content of each channel.
288      *
289      * @param X [out] a pointer to store X channel in
290      * @param Y [out] a pointer to store Y channel in
291      * @param Z [out] a pointer to store Z channel in
292      */
293     virtual void createXYZChannels( Channel* &X, Channel* &Y, Channel* &Z ) = 0;
294 
295     /**
296      * Gets a named channel.
297      *
298      * @param name [in] name of the channel. Name must be 8 or less
299      * character long.
300      * @return channel or NULL if the channel does not exist
301      */
302     virtual Channel* getChannel( const char *name ) = 0;
303 
304     /**
305      * Creates a named channel. If the channel already exists, returns
306      * existing channel.
307      *
308      * Note that new channels should be created only for the first
309      * frame. The channels should not changes for the subsequent
310      * frames of a sequence.
311      *
312      * @param name [in] name of the channel. Name must be 8 or less
313      * character long.
314      * @return existing or newly created channel
315      */
316     virtual Channel* createChannel( const char *name ) = 0;
317 
318 
319     /**
320      * Removes a channel and frees the memory allocated for it. It is
321      * safe to remove the channel pointed by the ChannelIterator.
322      *
323      * @param channel [in] channel that should be removed.
324      */
325     virtual void removeChannel( Channel *channel ) = 0;
326 
327     /**
328      * DEPRECIATED!!! Use getIterator instead.
329      *
330      * Returns iterator for all available channels.
331      *
332      * Note that only one iterator for particular frame can be used at
333      * a time. This method returns each time the same data structure,
334      * so the iterator from previous call is lost after the call. The
335      * iterator MUST NOT be deleted after use.
336      *
337      * Object ChannelIterator MUST NOT be freed. It's responsibility
338      * of a Frame object.
339      */
340     virtual ChannelIterator *getChannels() = 0;
341 
342     /**
343      * Use ChannelIterator to iterate over all Channels in the Frame.
344      * ChannelIteratorPtr is a smart pointer, which destructs
345      * ChannelIterator when ChannelIteratorPtr is destructed. Use ->
346      * operator to access ChannelIterator members from a
347      * ChannelIteratorPtr object.
348      *
349      * To iterate over all channels, use the following code:
350      * <code>
351      * pfs::ChannelIteratorPtr it( frame->getChannelIterator() );
352      * while( it->hasNext() ) {
353      *   pfs::Channel *ch = cit->getNext();
354      *   //Do whatever is needed
355      * }
356      * </code>
357      */
358     virtual ChannelIteratorPtr getChannelIterator() = 0;
359 
360     /**
361      * Returns TagContainer that can be used to access or modify
362      * tags associated with this Frame object.
363      */
364     virtual TagContainer *getTags() = 0;
365 
366     virtual ~Frame() = 0;
367 
368   };
369 
370   /**
371    * Copy all tags from both the frame and its channels to the
372    * destination frame. If there is no corresponding destination
373    * channel for a source channel, the tags from that source channel
374    * will not be copied. Note, that all tags in the destination
375    * channel will be removed before copying. Therefore after this
376    * operation, the destination will contain exactly the same tags as
377    * the source.
378    */
379   void copyTags( Frame *from, Frame *to );
380 
381   /**
382    * Copy all tags from one container into another. Note, that all
383    * tags in the destination channel will be removed before
384    * copying. Therefore after this operation, the destination will
385    * contain exactly the same tags as the source.
386    */
387   void copyTags( const TagContainer *from, TagContainer *to );
388 
389 
390   class DOMIOImpl;
391 
392 /**
393  * Reading and writing frames in PFS format from/to streams.
394  */
395   class DOMIO {
396     DOMIOImpl *impl;
397   public:
398     DOMIO();
399     ~DOMIO();
400 
401     /**
402      * Creates a frame that can be latter written to the stream
403      * using writeFrame method. This method and readFrame are the
404      * only way to create Frame objects.
405      *
406      * Note: Frame object must be released with freeFrame methods
407      * as soon as it is no longer needed. Otherwise the
408      * application will run out of memory.
409      *
410      * @param width width of the frame to create
411      * @param height height of the frame to create
412      * @return Frame object that can be modified and written back to PFS
413      * stream using writeFrame method
414      */
415     Frame *createFrame( int width, int height );
416 
417     /**
418      * Read PFS frame from the input Stream. This method and
419      * createFrame are the only way to create Frame objects.
420      *
421      * Note: Frame object must be released with freeFrame methods
422      * as soon as it is no longer needed. Otherwise the
423      * application will run out of memory.
424      *
425      * @param inputStream read frame from that stream
426      * @return Frame object that contains PFS frame read from
427      * the stream. NULL if there are no more frames.
428      */
429     Frame *readFrame( FILE *inputStream );
430 
431     /**
432      * Writes Frame object to outputStream in PFS format.
433      *
434      * @param frame Frame object to be written. This object
435      * must be created with readFrame or createFrame method.
436      * @param outputStream write frame to that stream
437      */
438     void writeFrame( Frame *frame, FILE *outputStream );
439 
440     /**
441      * Deallocated memory allocated with createFrame or readFrame. Must
442      * be called as soon as frame is not needed. Pointer to a frame is
443      * invalid after this method call.
444      *
445      * @param frame Frame object to be freed
446      */
447     void freeFrame( Frame *frame );
448   };
449 
450 
451 
452   /**
453    * A pair of a file name and file handler, returned from
454    * FrameFileIterator.
455    */
456   struct FrameFile
457   {
FrameFileFrameFile458     FrameFile( FILE *fh, const char* fileName ): fh(fh), fileName( fileName )
459     {
460     }
461 
462     /**
463      * File handler.
464      */
465     FILE *fh;
466 
467     /**
468      * File name.
469      */
470     const char *fileName;
471   };
472 
473 
474   class FrameFileIteratorImpl;
475 
476 /**
477  * Utility class that can be used to iterate over file names
478  * specified as command line arguments. It can handle patterns,
479  * like frame%04d.hdr, where %04d is replaced with specified
480  * range of frame numbers.
481  *
482  */
483   class FrameFileIterator
484     {
485       FrameFileIteratorImpl *impl;
486     public:
487       /**
488        * Creates new iterator over frame files. Command line
489        * arguments are parsed and all recognized arguments are
490        * removed.
491        *
492        * @param argc argument count passed to program's main function.
493        * @param argv argument values passed to program's main function.
494        * @param fopenMode mode used to fopen frame files, usually "rb" or "wb"
495        * @param fileNamePrefix each frame pattern must be preceded
496        * with this string (for example "-i'). If NULL, every argument that
497        * does not start with "-" is treated as a frame pattern.
498        * @param stdinout if set, treat '-' file name specially and instead
499        * of opening a named file, use filedescriptor passed as this parameter.
500        * It should be used to get or write data to stdin / stdout.
501        * @param optstring parameter string passed to getopt()
502        * function. When optstring != NULL, FrameFileIterator will skip
503        * all parameters and their required arguments. Optional
504        * arguments are not handled.
505        * @param getopt_long parameter structure passed to getopt_long()
506        * function. When getopt_long != NULL, FrameFileIterator will skip
507        * all parameters and their required arguments. Optional
508        * arguments are not handled.
509        * @throws CommandLineException on bad syntax of command line options
510        */
511       FrameFileIterator( int &argc, char* argv[], const char *fopenMode,
512         const char *fileNamePrefix = NULL, FILE *stdinout = NULL,
513         const char *optstring = NULL, const struct option *getopt_long = NULL );
514 
515       ~FrameFileIterator();
516 
517       /**
518        * Get the file handle FILE* and file name for the next
519        * frame. Note that fileName string is valid until next
520        * call to getNextFrameFile or closeFrameFile.
521        *
522        * When file handle is no longer needed, closeFileFile
523        * should be called.
524        *
525        * @return file handle FILE* and file name of the next frame.
526        * Returns file handle == NULL if there are no more frames.
527        *
528        * @throws Exception if the file is not found
529        */
530       FrameFile getNextFrameFile( );
531 
532       /**
533        * Close file openned with getNextFrameFile.
534        *
535        * @param frameFile FrameFile object returned from getNextFrameFile
536        */
537       void closeFrameFile( FrameFile &frameFile );
538 
539       static void printUsage( FILE *out, const char *progName );
540 
541     };
542 
543 
544 /// This enum is used to specify color spaces for transformColorSpace function
545   enum ColorSpace
546     {
547       CS_XYZ = 0,         ///< Absolute XYZ space, reference white - D65, Y is calibrated luminance in cd/m^2
548       CS_RGB,             ///< Absolute XYZ space, reference white - D65, Rec. 709
549       CS_SRGB,            ///< sRGB color space for LDR images (see
550                           ///www.srgb.com). The possible pixel values
551                           ///for R, G and B channel should be within
552                           ///range 0-1 (the values above or below this
553                           ///range will be clamped). Peak luminance
554                           ///level of the display is 80cd/m^2.
555       CS_YUV,             ///< Perceptually uniform u and v color coordinates, Y is calibrated luminance in cd/m^2
556       CS_Yxy,             ///< Luminance and normalized chromacities (x=X/(X+Y+Z), y=Y/(X+Y+Z))
557 	  CS_INVALID,         ///< For convenience
558 	  CS_PQYCbCr2020,	  ///< MPEG YCbCr with the PQ transfer function and Rec. 2020 colorspace
559 	  CS_YCbCr709,	      ///< MPEG YCbCr with the sRGB non-linearity and Rec. 709 colorspace
560 	  CS_HLGYCbCr2020,
561 	  CS_RGB2020,		  ///< Rec 2020 wide color gamut RGB colorspace
562       CS_LAST             ///< For internal purposes only
563     };
564 
565 /**
566  * Transform color channels from one color space into
567  * another. Input and output channels may point to the same data
568  * for in-memory transform.
569  *
570  * @param inCS input color space
571  * @param inC1 first color channel of the input image
572  * @param inC2 second color channel of the input image
573  * @param inC3 third color channel of the input image
574  * @param outCS output color space
575  * @param outC1 first color channel of the output image
576  * @param outC2 second color channel of the output image
577  * @param outC3 third color channel of the output image
578  */
579   void transformColorSpace( ColorSpace inCS,
580     const Array2D *inC1, const Array2D *inC2, const Array2D *inC3,
581     ColorSpace outCS,
582     Array2D *outC1, Array2D *outC2, Array2D *outC3 );
583 
584 
585 /**
586  * General exception class used to throw exceptions from pfs library.
587  */
588   class Exception
589     {
590       char msg[1024];
591     public:
592       /**
593        * Creates a new exception.
594        *
595        * @param message description of the cause for the
596        * exception. The copy of the message string is made, so it can
597        * be freed after creating Exception.
598        */
Exception(const char * const message)599       Exception( const char* const message )
600 	{
601           const size_t s = sizeof(msg)/sizeof(msg[0]) - 1;
602           strncpy( msg, message, s );
603           msg[s] = '\0';
604 	}
605 
~Exception()606       ~Exception() {};
607 
608       /**
609        * Returns the description of the problem.
610        *
611        * @return text description of the cause for the exception
612        */
getMessage()613       const char* getMessage() const throw()
614         {
615           return msg;
616 	}
617     };
618 
619 
620 /**
621  * Exception class used to throw exceptions from FileFileIterator class.
622  */
623   class CommandLineException: public Exception
624     {
625     public:
CommandLineException(const char * const message)626       CommandLineException( const char* const message ): Exception( message )
627 	{
628 	}
629     };
630 
631 
632 }
633 
634 
635 
636 #endif
637