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