/src/FreeImage/Source/OpenEXR/IlmImf/ImfHeader.cpp
C++ | 1106 lines | 749 code | 215 blank | 142 comment | 100 complexity | 82185b86a8a374a82711b5c49eeab256 MD5 | raw file
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 37//----------------------------------------------------------------------------- 38// 39// class Header 40// 41//----------------------------------------------------------------------------- 42 43#include <ImfHeader.h> 44#include <ImfStdIO.h> 45#include <ImfVersion.h> 46#include <ImfCompressor.h> 47#include <ImfMisc.h> 48#include <ImfBoxAttribute.h> 49#include <ImfChannelListAttribute.h> 50#include <ImfChromaticitiesAttribute.h> 51#include <ImfCompressionAttribute.h> 52#include <ImfDoubleAttribute.h> 53#include <ImfEnvmapAttribute.h> 54#include <ImfFloatAttribute.h> 55#include <ImfIntAttribute.h> 56#include <ImfKeyCodeAttribute.h> 57#include <ImfLineOrderAttribute.h> 58#include <ImfMatrixAttribute.h> 59#include <ImfOpaqueAttribute.h> 60#include <ImfPreviewImageAttribute.h> 61#include <ImfRationalAttribute.h> 62#include <ImfStringAttribute.h> 63#include <ImfStringVectorAttribute.h> 64#include <ImfTileDescriptionAttribute.h> 65#include <ImfTimeCodeAttribute.h> 66#include <ImfVecAttribute.h> 67#include "IlmThreadMutex.h" 68#include "Iex.h" 69#include <sstream> 70#include <stdlib.h> 71#include <time.h> 72 73 74namespace Imf { 75 76using namespace std; 77using Imath::Box2i; 78using Imath::V2i; 79using Imath::V2f; 80using IlmThread::Mutex; 81using IlmThread::Lock; 82 83 84namespace { 85 86int maxImageWidth = 0; 87int maxImageHeight = 0; 88int maxTileWidth = 0; 89int maxTileHeight = 0; 90 91 92void 93initialize (Header &header, 94 const Box2i &displayWindow, 95 const Box2i &dataWindow, 96 float pixelAspectRatio, 97 const V2f &screenWindowCenter, 98 float screenWindowWidth, 99 LineOrder lineOrder, 100 Compression compression) 101{ 102 header.insert ("displayWindow", Box2iAttribute (displayWindow)); 103 header.insert ("dataWindow", Box2iAttribute (dataWindow)); 104 header.insert ("pixelAspectRatio", FloatAttribute (pixelAspectRatio)); 105 header.insert ("screenWindowCenter", V2fAttribute (screenWindowCenter)); 106 header.insert ("screenWindowWidth", FloatAttribute (screenWindowWidth)); 107 header.insert ("lineOrder", LineOrderAttribute (lineOrder)); 108 header.insert ("compression", CompressionAttribute (compression)); 109 header.insert ("channels", ChannelListAttribute ()); 110} 111 112 113bool 114usesLongNames (const Header &header) 115{ 116 // 117 // If an OpenEXR file contains any attribute names, attribute type names 118 // or channel names longer than 31 characters, then the file cannot be 119 // read by older versions of the IlmImf library (up to OpenEXR 1.6.1). 120 // Before writing the file header, we check if the header contains 121 // any names longer than 31 characters; if it does, then we set the 122 // LONG_NAMES_FLAG in the file version number. Older versions of the 123 // IlmImf library will refuse to read files that have the LONG_NAMES_FLAG 124 // set. Without the flag, older versions of the library would mis- 125 // interpret the file as broken. 126 // 127 128 for (Header::ConstIterator i = header.begin(); 129 i != header.end(); 130 ++i) 131 { 132 if (strlen (i.name()) >= 32 || strlen (i.attribute().typeName()) >= 32) 133 return true; 134 } 135 136 const ChannelList &channels = header.channels(); 137 138 for (ChannelList::ConstIterator i = channels.begin(); 139 i != channels.end(); 140 ++i) 141 { 142 if (strlen (i.name()) >= 32) 143 return true; 144 } 145 146 return false; 147} 148 149template <size_t N> 150void checkIsNullTerminated (const char (&str)[N], const char *what) 151{ 152 for (int i = 0; i < N; ++i) { 153 if (str[i] == '\0') 154 return; 155 } 156 std::stringstream s; 157 s << "Invalid " << what << ": it is more than " << (N - 1) 158 << " characters long."; 159 throw Iex::InputExc(s); 160} 161 162} // namespace 163 164 165Header::Header (int width, 166 int height, 167 float pixelAspectRatio, 168 const V2f &screenWindowCenter, 169 float screenWindowWidth, 170 LineOrder lineOrder, 171 Compression compression) 172: 173 _map() 174{ 175 staticInitialize(); 176 177 Box2i displayWindow (V2i (0, 0), V2i (width - 1, height - 1)); 178 179 initialize (*this, 180 displayWindow, 181 displayWindow, 182 pixelAspectRatio, 183 screenWindowCenter, 184 screenWindowWidth, 185 lineOrder, 186 compression); 187} 188 189 190Header::Header (int width, 191 int height, 192 const Box2i &dataWindow, 193 float pixelAspectRatio, 194 const V2f &screenWindowCenter, 195 float screenWindowWidth, 196 LineOrder lineOrder, 197 Compression compression) 198: 199 _map() 200{ 201 staticInitialize(); 202 203 Box2i displayWindow (V2i (0, 0), V2i (width - 1, height - 1)); 204 205 initialize (*this, 206 displayWindow, 207 dataWindow, 208 pixelAspectRatio, 209 screenWindowCenter, 210 screenWindowWidth, 211 lineOrder, 212 compression); 213} 214 215 216Header::Header (const Box2i &displayWindow, 217 const Box2i &dataWindow, 218 float pixelAspectRatio, 219 const V2f &screenWindowCenter, 220 float screenWindowWidth, 221 LineOrder lineOrder, 222 Compression compression) 223: 224 _map() 225{ 226 staticInitialize(); 227 228 initialize (*this, 229 displayWindow, 230 dataWindow, 231 pixelAspectRatio, 232 screenWindowCenter, 233 screenWindowWidth, 234 lineOrder, 235 compression); 236} 237 238 239Header::Header (const Header &other): _map() 240{ 241 for (AttributeMap::const_iterator i = other._map.begin(); 242 i != other._map.end(); 243 ++i) 244 { 245 insert (*i->first, *i->second); 246 } 247} 248 249 250Header::~Header () 251{ 252 for (AttributeMap::iterator i = _map.begin(); 253 i != _map.end(); 254 ++i) 255 { 256 delete i->second; 257 } 258} 259 260 261Header & 262Header::operator = (const Header &other) 263{ 264 if (this != &other) 265 { 266 for (AttributeMap::iterator i = _map.begin(); 267 i != _map.end(); 268 ++i) 269 { 270 delete i->second; 271 } 272 273 _map.erase (_map.begin(), _map.end()); 274 275 for (AttributeMap::const_iterator i = other._map.begin(); 276 i != other._map.end(); 277 ++i) 278 { 279 insert (*i->first, *i->second); 280 } 281 } 282 283 return *this; 284} 285 286 287void 288Header::insert (const char name[], const Attribute &attribute) 289{ 290 if (name[0] == 0) 291 THROW (Iex::ArgExc, "Image attribute name cannot be an empty string."); 292 293 AttributeMap::iterator i = _map.find (name); 294 295 if (i == _map.end()) 296 { 297 Attribute *tmp = attribute.copy(); 298 299 try 300 { 301 _map[name] = tmp; 302 } 303 catch (...) 304 { 305 delete tmp; 306 throw; 307 } 308 } 309 else 310 { 311 if (strcmp (i->second->typeName(), attribute.typeName())) 312 THROW (Iex::TypeExc, "Cannot assign a value of " 313 "type \"" << attribute.typeName() << "\" " 314 "to image attribute \"" << name << "\" of " 315 "type \"" << i->second->typeName() << "\"."); 316 317 Attribute *tmp = attribute.copy(); 318 delete i->second; 319 i->second = tmp; 320 } 321} 322 323 324void 325Header::insert (const string &name, const Attribute &attribute) 326{ 327 insert (name.c_str(), attribute); 328} 329 330 331Attribute & 332Header::operator [] (const char name[]) 333{ 334 AttributeMap::iterator i = _map.find (name); 335 336 if (i == _map.end()) 337 THROW (Iex::ArgExc, "Cannot find image attribute \"" << name << "\"."); 338 339 return *i->second; 340} 341 342 343const Attribute & 344Header::operator [] (const char name[]) const 345{ 346 AttributeMap::const_iterator i = _map.find (name); 347 348 if (i == _map.end()) 349 THROW (Iex::ArgExc, "Cannot find image attribute \"" << name << "\"."); 350 351 return *i->second; 352} 353 354 355Attribute & 356Header::operator [] (const string &name) 357{ 358 return this->operator[] (name.c_str()); 359} 360 361 362const Attribute & 363Header::operator [] (const string &name) const 364{ 365 return this->operator[] (name.c_str()); 366} 367 368 369Header::Iterator 370Header::begin () 371{ 372 return _map.begin(); 373} 374 375 376Header::ConstIterator 377Header::begin () const 378{ 379 return _map.begin(); 380} 381 382 383Header::Iterator 384Header::end () 385{ 386 return _map.end(); 387} 388 389 390Header::ConstIterator 391Header::end () const 392{ 393 return _map.end(); 394} 395 396 397Header::Iterator 398Header::find (const char name[]) 399{ 400 return _map.find (name); 401} 402 403 404Header::ConstIterator 405Header::find (const char name[]) const 406{ 407 return _map.find (name); 408} 409 410 411Header::Iterator 412Header::find (const string &name) 413{ 414 return find (name.c_str()); 415} 416 417 418Header::ConstIterator 419Header::find (const string &name) const 420{ 421 return find (name.c_str()); 422} 423 424 425Imath::Box2i & 426Header::displayWindow () 427{ 428 return static_cast <Box2iAttribute &> 429 ((*this)["displayWindow"]).value(); 430} 431 432 433const Imath::Box2i & 434Header::displayWindow () const 435{ 436 return static_cast <const Box2iAttribute &> 437 ((*this)["displayWindow"]).value(); 438} 439 440 441Imath::Box2i & 442Header::dataWindow () 443{ 444 return static_cast <Box2iAttribute &> 445 ((*this)["dataWindow"]).value(); 446} 447 448 449const Imath::Box2i & 450Header::dataWindow () const 451{ 452 return static_cast <const Box2iAttribute &> 453 ((*this)["dataWindow"]).value(); 454} 455 456 457float & 458Header::pixelAspectRatio () 459{ 460 return static_cast <FloatAttribute &> 461 ((*this)["pixelAspectRatio"]).value(); 462} 463 464 465const float & 466Header::pixelAspectRatio () const 467{ 468 return static_cast <const FloatAttribute &> 469 ((*this)["pixelAspectRatio"]).value(); 470} 471 472 473Imath::V2f & 474Header::screenWindowCenter () 475{ 476 return static_cast <V2fAttribute &> 477 ((*this)["screenWindowCenter"]).value(); 478} 479 480 481const Imath::V2f & 482Header::screenWindowCenter () const 483{ 484 return static_cast <const V2fAttribute &> 485 ((*this)["screenWindowCenter"]).value(); 486} 487 488 489float & 490Header::screenWindowWidth () 491{ 492 return static_cast <FloatAttribute &> 493 ((*this)["screenWindowWidth"]).value(); 494} 495 496 497const float & 498Header::screenWindowWidth () const 499{ 500 return static_cast <const FloatAttribute &> 501 ((*this)["screenWindowWidth"]).value(); 502} 503 504 505ChannelList & 506Header::channels () 507{ 508 return static_cast <ChannelListAttribute &> 509 ((*this)["channels"]).value(); 510} 511 512 513const ChannelList & 514Header::channels () const 515{ 516 return static_cast <const ChannelListAttribute &> 517 ((*this)["channels"]).value(); 518} 519 520 521LineOrder & 522Header::lineOrder () 523{ 524 return static_cast <LineOrderAttribute &> 525 ((*this)["lineOrder"]).value(); 526} 527 528 529const LineOrder & 530Header::lineOrder () const 531{ 532 return static_cast <const LineOrderAttribute &> 533 ((*this)["lineOrder"]).value(); 534} 535 536 537Compression & 538Header::compression () 539{ 540 return static_cast <CompressionAttribute &> 541 ((*this)["compression"]).value(); 542} 543 544 545const Compression & 546Header::compression () const 547{ 548 return static_cast <const CompressionAttribute &> 549 ((*this)["compression"]).value(); 550} 551 552 553void 554Header::setTileDescription(const TileDescription& td) 555{ 556 insert ("tiles", TileDescriptionAttribute (td)); 557} 558 559 560bool 561Header::hasTileDescription() const 562{ 563 return findTypedAttribute <TileDescriptionAttribute> ("tiles") != 0; 564} 565 566 567TileDescription & 568Header::tileDescription () 569{ 570 return typedAttribute <TileDescriptionAttribute> ("tiles").value(); 571} 572 573 574const TileDescription & 575Header::tileDescription () const 576{ 577 return typedAttribute <TileDescriptionAttribute> ("tiles").value(); 578} 579 580void 581Header::setPreviewImage (const PreviewImage &pi) 582{ 583 insert ("preview", PreviewImageAttribute (pi)); 584} 585 586 587PreviewImage & 588Header::previewImage () 589{ 590 return typedAttribute <PreviewImageAttribute> ("preview").value(); 591} 592 593 594const PreviewImage & 595Header::previewImage () const 596{ 597 return typedAttribute <PreviewImageAttribute> ("preview").value(); 598} 599 600 601bool 602Header::hasPreviewImage () const 603{ 604 return findTypedAttribute <PreviewImageAttribute> ("preview") != 0; 605} 606 607 608void 609Header::sanityCheck (bool isTiled) const 610{ 611 // 612 // The display window and the data window must each 613 // contain at least one pixel. In addition, the 614 // coordinates of the window corners must be small 615 // enough to keep expressions like max-min+1 or 616 // max+min from overflowing. 617 // 618 619 const Box2i &displayWindow = this->displayWindow(); 620 621 if (displayWindow.min.x > displayWindow.max.x || 622 displayWindow.min.y > displayWindow.max.y || 623 displayWindow.min.x <= -(INT_MAX / 2) || 624 displayWindow.min.y <= -(INT_MAX / 2) || 625 displayWindow.max.x >= (INT_MAX / 2) || 626 displayWindow.max.y >= (INT_MAX / 2)) 627 { 628 throw Iex::ArgExc ("Invalid display window in image header."); 629 } 630 631 const Box2i &dataWindow = this->dataWindow(); 632 633 if (dataWindow.min.x > dataWindow.max.x || 634 dataWindow.min.y > dataWindow.max.y || 635 dataWindow.min.x <= -(INT_MAX / 2) || 636 dataWindow.min.y <= -(INT_MAX / 2) || 637 dataWindow.max.x >= (INT_MAX / 2) || 638 dataWindow.max.y >= (INT_MAX / 2)) 639 { 640 throw Iex::ArgExc ("Invalid data window in image header."); 641 } 642 643 if (maxImageWidth > 0 && 644 maxImageWidth < dataWindow.max.x - dataWindow.min.x + 1) 645 { 646 THROW (Iex::ArgExc, "The width of the data window exceeds the " 647 "maximum width of " << maxImageWidth << "pixels."); 648 } 649 650 if (maxImageHeight > 0 && 651 maxImageHeight < dataWindow.max.y - dataWindow.min.y + 1) 652 { 653 THROW (Iex::ArgExc, "The width of the data window exceeds the " 654 "maximum width of " << maxImageHeight << "pixels."); 655 } 656 657 // 658 // The pixel aspect ratio must be greater than 0. 659 // In applications, numbers like the the display or 660 // data window dimensions are likely to be multiplied 661 // or divided by the pixel aspect ratio; to avoid 662 // arithmetic exceptions, we limit the pixel aspect 663 // ratio to a range that is smaller than theoretically 664 // possible (real aspect ratios are likely to be close 665 // to 1.0 anyway). 666 // 667 668 float pixelAspectRatio = this->pixelAspectRatio(); 669 670 const float MIN_PIXEL_ASPECT_RATIO = 1e-6f; 671 const float MAX_PIXEL_ASPECT_RATIO = 1e+6f; 672 673 if (pixelAspectRatio < MIN_PIXEL_ASPECT_RATIO || 674 pixelAspectRatio > MAX_PIXEL_ASPECT_RATIO) 675 { 676 throw Iex::ArgExc ("Invalid pixel aspect ratio in image header."); 677 } 678 679 // 680 // The screen window width must not be less than 0. 681 // The size of the screen window can vary over a wide 682 // range (fish-eye lens to astronomical telescope), 683 // so we can't limit the screen window width to a 684 // small range. 685 // 686 687 float screenWindowWidth = this->screenWindowWidth(); 688 689 if (screenWindowWidth < 0) 690 throw Iex::ArgExc ("Invalid screen window width in image header."); 691 692 // 693 // If the file is tiled, verify that the tile description has resonable 694 // values and check to see if the lineOrder is one of the predefined 3. 695 // If the file is not tiled, then the lineOrder can only be INCREASING_Y 696 // or DECREASING_Y. 697 // 698 699 LineOrder lineOrder = this->lineOrder(); 700 701 if (isTiled) 702 { 703 if (!hasTileDescription()) 704 { 705 throw Iex::ArgExc ("Tiled image has no tile " 706 "description attribute."); 707 } 708 709 const TileDescription &tileDesc = tileDescription(); 710 711 if (tileDesc.xSize <= 0 || tileDesc.ySize <= 0) 712 throw Iex::ArgExc ("Invalid tile size in image header."); 713 714 if (maxTileWidth > 0 && 715 maxTileWidth < tileDesc.xSize) 716 { 717 THROW (Iex::ArgExc, "The width of the tiles exceeds the maximum " 718 "width of " << maxTileWidth << "pixels."); 719 } 720 721 if (maxTileHeight > 0 && 722 maxTileHeight < tileDesc.ySize) 723 { 724 THROW (Iex::ArgExc, "The width of the tiles exceeds the maximum " 725 "width of " << maxTileHeight << "pixels."); 726 } 727 728 if (tileDesc.mode != ONE_LEVEL && 729 tileDesc.mode != MIPMAP_LEVELS && 730 tileDesc.mode != RIPMAP_LEVELS) 731 throw Iex::ArgExc ("Invalid level mode in image header."); 732 733 if (tileDesc.roundingMode != ROUND_UP && 734 tileDesc.roundingMode != ROUND_DOWN) 735 throw Iex::ArgExc ("Invalid level rounding mode in image header."); 736 737 if (lineOrder != INCREASING_Y && 738 lineOrder != DECREASING_Y && 739 lineOrder != RANDOM_Y) 740 throw Iex::ArgExc ("Invalid line order in image header."); 741 } 742 else 743 { 744 if (lineOrder != INCREASING_Y && 745 lineOrder != DECREASING_Y) 746 throw Iex::ArgExc ("Invalid line order in image header."); 747 } 748 749 // 750 // The compression method must be one of the predefined values. 751 // 752 753 if (!isValidCompression (this->compression())) 754 throw Iex::ArgExc ("Unknown compression type in image header."); 755 756 // 757 // Check the channel list: 758 // 759 // If the file is tiled then for each channel, the type must be one of the 760 // predefined values, and the x and y sampling must both be 1. 761 // 762 // If the file is not tiled then for each channel, the type must be one 763 // of the predefined values, the x and y coordinates of the data window's 764 // upper left corner must be divisible by the x and y subsampling factors, 765 // and the width and height of the data window must be divisible by the 766 // x and y subsampling factors. 767 // 768 769 const ChannelList &channels = this->channels(); 770 771 if (isTiled) 772 { 773 for (ChannelList::ConstIterator i = channels.begin(); 774 i != channels.end(); 775 ++i) 776 { 777 if (i.channel().type != UINT && 778 i.channel().type != HALF && 779 i.channel().type != FLOAT) 780 { 781 THROW (Iex::ArgExc, "Pixel type of \"" << i.name() << "\" " 782 "image channel is invalid."); 783 } 784 785 if (i.channel().xSampling != 1) 786 { 787 THROW (Iex::ArgExc, "The x subsampling factor for the " 788 "\"" << i.name() << "\" channel " 789 "is not 1."); 790 } 791 792 if (i.channel().ySampling != 1) 793 { 794 THROW (Iex::ArgExc, "The y subsampling factor for the " 795 "\"" << i.name() << "\" channel " 796 "is not 1."); 797 } 798 } 799 } 800 else 801 { 802 for (ChannelList::ConstIterator i = channels.begin(); 803 i != channels.end(); 804 ++i) 805 { 806 if (i.channel().type != UINT && 807 i.channel().type != HALF && 808 i.channel().type != FLOAT) 809 { 810 THROW (Iex::ArgExc, "Pixel type of \"" << i.name() << "\" " 811 "image channel is invalid."); 812 } 813 814 if (i.channel().xSampling < 1) 815 { 816 THROW (Iex::ArgExc, "The x subsampling factor for the " 817 "\"" << i.name() << "\" channel " 818 "is invalid."); 819 } 820 821 if (i.channel().ySampling < 1) 822 { 823 THROW (Iex::ArgExc, "The y subsampling factor for the " 824 "\"" << i.name() << "\" channel " 825 "is invalid."); 826 } 827 828 if (dataWindow.min.x % i.channel().xSampling) 829 { 830 THROW (Iex::ArgExc, "The minimum x coordinate of the " 831 "image's data window is not a multiple " 832 "of the x subsampling factor of " 833 "the \"" << i.name() << "\" channel."); 834 } 835 836 if (dataWindow.min.y % i.channel().ySampling) 837 { 838 THROW (Iex::ArgExc, "The minimum y coordinate of the " 839 "image's data window is not a multiple " 840 "of the y subsampling factor of " 841 "the \"" << i.name() << "\" channel."); 842 } 843 844 if ((dataWindow.max.x - dataWindow.min.x + 1) % 845 i.channel().xSampling) 846 { 847 THROW (Iex::ArgExc, "Number of pixels per row in the " 848 "image's data window is not a multiple " 849 "of the x subsampling factor of " 850 "the \"" << i.name() << "\" channel."); 851 } 852 853 if ((dataWindow.max.y - dataWindow.min.y + 1) % 854 i.channel().ySampling) 855 { 856 THROW (Iex::ArgExc, "Number of pixels per column in the " 857 "image's data window is not a multiple " 858 "of the y subsampling factor of " 859 "the \"" << i.name() << "\" channel."); 860 } 861 } 862 } 863} 864 865 866void 867Header::setMaxImageSize (int maxWidth, int maxHeight) 868{ 869 maxImageWidth = maxWidth; 870 maxImageHeight = maxHeight; 871} 872 873 874void 875Header::setMaxTileSize (int maxWidth, int maxHeight) 876{ 877 maxTileWidth = maxWidth; 878 maxTileHeight = maxHeight; 879} 880 881 882Int64 883Header::writeTo (OStream &os, bool isTiled) const 884{ 885 // 886 // Write a "magic number" to identify the file as an image file. 887 // Write the current file format version number. 888 // 889 890 Xdr::write <StreamIO> (os, MAGIC); 891 892 int version = EXR_VERSION; 893 894 if (isTiled) 895 version |= TILED_FLAG; 896 897 if (usesLongNames (*this)) 898 version |= LONG_NAMES_FLAG; 899 900 Xdr::write <StreamIO> (os, version); 901 902 // 903 // Write all attributes. If we have a preview image attribute, 904 // keep track of its position in the file. 905 // 906 907 Int64 previewPosition = 0; 908 909 const Attribute *preview = 910 findTypedAttribute <PreviewImageAttribute> ("preview"); 911 912 for (ConstIterator i = begin(); i != end(); ++i) 913 { 914 // 915 // Write the attribute's name and type. 916 // 917 918 Xdr::write <StreamIO> (os, i.name()); 919 Xdr::write <StreamIO> (os, i.attribute().typeName()); 920 921 // 922 // Write the size of the attribute value, 923 // and the value itself. 924 // 925 926 StdOSStream oss; 927 i.attribute().writeValueTo (oss, version); 928 929 std::string s = oss.str(); 930 Xdr::write <StreamIO> (os, (int) s.length()); 931 932 if (&i.attribute() == preview) 933 previewPosition = os.tellp(); 934 935 os.write (s.data(), s.length()); 936 } 937 938 // 939 // Write zero-length attribute name to mark the end of the header. 940 // 941 942 Xdr::write <StreamIO> (os, ""); 943 944 return previewPosition; 945} 946 947 948void 949Header::readFrom (IStream &is, int &version) 950{ 951 // 952 // Read the magic number and the file format version number. 953 // Then check if we can read the rest of this file. 954 // 955 956 int magic; 957 958 Xdr::read <StreamIO> (is, magic); 959 Xdr::read <StreamIO> (is, version); 960 961 if (magic != MAGIC) 962 { 963 throw Iex::InputExc ("File is not an image file."); 964 } 965 966 if (getVersion (version) != EXR_VERSION) 967 { 968 THROW (Iex::InputExc, "Cannot read " 969 "version " << getVersion (version) << " " 970 "image files. Current file format version " 971 "is " << EXR_VERSION << "."); 972 } 973 974 if (!supportsFlags (getFlags (version))) 975 { 976 THROW (Iex::InputExc, "The file format version number's flag field " 977 "contains unrecognized flags."); 978 } 979 980 // 981 // Read all attributes. 982 // 983 984 while (true) 985 { 986 // 987 // Read the name of the attribute. 988 // A zero-length attribute name indicates the end of the header. 989 // 990 991 char name[Name::SIZE]; 992 Xdr::read <StreamIO> (is, Name::MAX_LENGTH, name); 993 994 if (name[0] == 0) 995 break; 996 997 checkIsNullTerminated (name, "attribute name"); 998 999 // 1000 // Read the attribute type and the size of the attribute value. 1001 // 1002 1003 char typeName[Name::SIZE]; 1004 int size; 1005 1006 Xdr::read <StreamIO> (is, Name::MAX_LENGTH, typeName); 1007 checkIsNullTerminated (typeName, "attribute type name"); 1008 Xdr::read <StreamIO> (is, size); 1009 1010 AttributeMap::iterator i = _map.find (name); 1011 1012 if (i != _map.end()) 1013 { 1014 // 1015 // The attribute already exists (for example, 1016 // because it is a predefined attribute). 1017 // Read the attribute's new value from the file. 1018 // 1019 1020 if (strncmp (i->second->typeName(), typeName, sizeof (typeName))) 1021 THROW (Iex::InputExc, "Unexpected type for image attribute " 1022 "\"" << name << "\"."); 1023 1024 i->second->readValueFrom (is, size, version); 1025 } 1026 else 1027 { 1028 // 1029 // The new attribute does not exist yet. 1030 // If the attribute type is of a known type, 1031 // read the attribute value. If the attribute 1032 // is of an unknown type, read its value and 1033 // store it as an OpaqueAttribute. 1034 // 1035 1036 Attribute *attr; 1037 1038 if (Attribute::knownType (typeName)) 1039 attr = Attribute::newAttribute (typeName); 1040 else 1041 attr = new OpaqueAttribute (typeName); 1042 1043 try 1044 { 1045 attr->readValueFrom (is, size, version); 1046 _map[name] = attr; 1047 } 1048 catch (...) 1049 { 1050 delete attr; 1051 throw; 1052 } 1053 } 1054 } 1055} 1056 1057 1058void 1059staticInitialize () 1060{ 1061 static Mutex criticalSection; 1062 Lock lock (criticalSection); 1063 1064 static bool initialized = false; 1065 1066 if (!initialized) 1067 { 1068 // 1069 // One-time initialization -- register 1070 // some predefined attribute types. 1071 // 1072 1073 Box2fAttribute::registerAttributeType(); 1074 Box2iAttribute::registerAttributeType(); 1075 ChannelListAttribute::registerAttributeType(); 1076 CompressionAttribute::registerAttributeType(); 1077 ChromaticitiesAttribute::registerAttributeType(); 1078 DoubleAttribute::registerAttributeType(); 1079 EnvmapAttribute::registerAttributeType(); 1080 FloatAttribute::registerAttributeType(); 1081 IntAttribute::registerAttributeType(); 1082 KeyCodeAttribute::registerAttributeType(); 1083 LineOrderAttribute::registerAttributeType(); 1084 M33dAttribute::registerAttributeType(); 1085 M33fAttribute::registerAttributeType(); 1086 M44dAttribute::registerAttributeType(); 1087 M44fAttribute::registerAttributeType(); 1088 PreviewImageAttribute::registerAttributeType(); 1089 RationalAttribute::registerAttributeType(); 1090 StringAttribute::registerAttributeType(); 1091 StringVectorAttribute::registerAttributeType(); 1092 TileDescriptionAttribute::registerAttributeType(); 1093 TimeCodeAttribute::registerAttributeType(); 1094 V2dAttribute::registerAttributeType(); 1095 V2fAttribute::registerAttributeType(); 1096 V2iAttribute::registerAttributeType(); 1097 V3dAttribute::registerAttributeType(); 1098 V3fAttribute::registerAttributeType(); 1099 V3iAttribute::registerAttributeType(); 1100 1101 initialized = true; 1102 } 1103} 1104 1105 1106} // namespace Imf