/src/FreeImage/Source/OpenEXR/IlmImf/ImfHeader.cpp

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