ImfTiledOutputFile.cpp 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845
  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 TiledOutputFile
  37. //
  38. //-----------------------------------------------------------------------------
  39. #include <ImfTiledOutputFile.h>
  40. #include <ImfTiledInputFile.h>
  41. #include <ImfTiledInputPart.h>
  42. #include <ImfInputFile.h>
  43. #include <ImfInputPart.h>
  44. #include <ImfTileDescriptionAttribute.h>
  45. #include <ImfPreviewImageAttribute.h>
  46. #include <ImfChannelList.h>
  47. #include <ImfMisc.h>
  48. #include <ImfTiledMisc.h>
  49. #include <ImfStdIO.h>
  50. #include <ImfCompressor.h>
  51. #include "ImathBox.h"
  52. #include <ImfArray.h>
  53. #include <ImfXdr.h>
  54. #include <ImfVersion.h>
  55. #include <ImfTileOffsets.h>
  56. #include <ImfThreading.h>
  57. #include <ImfPartType.h>
  58. #include "IlmThreadPool.h"
  59. #include "IlmThreadSemaphore.h"
  60. #include "IlmThreadMutex.h"
  61. #include "ImfOutputStreamMutex.h"
  62. #include "ImfOutputPartData.h"
  63. #include "Iex.h"
  64. #include <string>
  65. #include <vector>
  66. #include <fstream>
  67. #include <assert.h>
  68. #include <map>
  69. #include <algorithm>
  70. #include "ImfNamespace.h"
  71. OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
  72. using IMATH_NAMESPACE::Box2i;
  73. using IMATH_NAMESPACE::V2i;
  74. using std::string;
  75. using std::vector;
  76. using std::ofstream;
  77. using std::map;
  78. using std::min;
  79. using std::max;
  80. using std::swap;
  81. using ILMTHREAD_NAMESPACE::Mutex;
  82. using ILMTHREAD_NAMESPACE::Lock;
  83. using ILMTHREAD_NAMESPACE::Semaphore;
  84. using ILMTHREAD_NAMESPACE::Task;
  85. using ILMTHREAD_NAMESPACE::TaskGroup;
  86. using ILMTHREAD_NAMESPACE::ThreadPool;
  87. namespace {
  88. struct TOutSliceInfo
  89. {
  90. PixelType type;
  91. const char * base;
  92. size_t xStride;
  93. size_t yStride;
  94. bool zero;
  95. int xTileCoords;
  96. int yTileCoords;
  97. TOutSliceInfo (PixelType type = HALF,
  98. const char *base = 0,
  99. size_t xStride = 0,
  100. size_t yStride = 0,
  101. bool zero = false,
  102. int xTileCoords = 0,
  103. int yTileCoords = 0);
  104. };
  105. TOutSliceInfo::TOutSliceInfo (PixelType t,
  106. const char *b,
  107. size_t xs, size_t ys,
  108. bool z,
  109. int xtc,
  110. int ytc)
  111. :
  112. type (t),
  113. base (b),
  114. xStride (xs),
  115. yStride (ys),
  116. zero (z),
  117. xTileCoords (xtc),
  118. yTileCoords (ytc)
  119. {
  120. // empty
  121. }
  122. struct TileCoord
  123. {
  124. int dx;
  125. int dy;
  126. int lx;
  127. int ly;
  128. TileCoord (int xTile = 0, int yTile = 0,
  129. int xLevel = 0, int yLevel = 0)
  130. :
  131. dx (xTile), dy (yTile),
  132. lx (xLevel), ly (yLevel)
  133. {
  134. // empty
  135. }
  136. bool
  137. operator < (const TileCoord &other) const
  138. {
  139. return (ly < other.ly) ||
  140. (ly == other.ly && lx < other.lx) ||
  141. ((ly == other.ly && lx == other.lx) &&
  142. ((dy < other.dy) || (dy == other.dy && dx < other.dx)));
  143. }
  144. bool
  145. operator == (const TileCoord &other) const
  146. {
  147. return lx == other.lx &&
  148. ly == other.ly &&
  149. dx == other.dx &&
  150. dy == other.dy;
  151. }
  152. };
  153. struct BufferedTile
  154. {
  155. char * pixelData;
  156. int pixelDataSize;
  157. BufferedTile (const char *data, int size):
  158. pixelData (0),
  159. pixelDataSize(size)
  160. {
  161. pixelData = new char[pixelDataSize];
  162. memcpy (pixelData, data, pixelDataSize);
  163. }
  164. ~BufferedTile()
  165. {
  166. delete [] pixelData;
  167. }
  168. };
  169. typedef map <TileCoord, BufferedTile *> TileMap;
  170. struct TileBuffer
  171. {
  172. Array<char> buffer;
  173. const char * dataPtr;
  174. int dataSize;
  175. Compressor * compressor;
  176. TileCoord tileCoord;
  177. bool hasException;
  178. string exception;
  179. TileBuffer (Compressor *comp);
  180. ~TileBuffer ();
  181. inline void wait () {_sem.wait();}
  182. inline void post () {_sem.post();}
  183. protected:
  184. Semaphore _sem;
  185. };
  186. TileBuffer::TileBuffer (Compressor *comp):
  187. dataPtr (0),
  188. dataSize (0),
  189. compressor (comp),
  190. hasException (false),
  191. exception (),
  192. _sem (1)
  193. {
  194. // empty
  195. }
  196. TileBuffer::~TileBuffer ()
  197. {
  198. delete compressor;
  199. }
  200. } // namespace
  201. struct TiledOutputFile::Data
  202. {
  203. Header header; // the image header
  204. int version; // file format version
  205. bool multipart; // part came from a multipart file
  206. TileDescription tileDesc; // describes the tile layout
  207. FrameBuffer frameBuffer; // framebuffer to write into
  208. Int64 previewPosition;
  209. LineOrder lineOrder; // the file's lineorder
  210. int minX; // data window's min x coord
  211. int maxX; // data window's max x coord
  212. int minY; // data window's min y coord
  213. int maxY; // data window's max x coord
  214. int numXLevels; // number of x levels
  215. int numYLevels; // number of y levels
  216. int * numXTiles; // number of x tiles at a level
  217. int * numYTiles; // number of y tiles at a level
  218. TileOffsets tileOffsets; // stores offsets in file for
  219. // each tile
  220. Compressor::Format format; // compressor's data format
  221. vector<TOutSliceInfo> slices; // info about channels in file
  222. size_t maxBytesPerTileLine; // combined size of a tile line
  223. // over all channels
  224. vector<TileBuffer*> tileBuffers;
  225. size_t tileBufferSize; // size of a tile buffer
  226. Int64 tileOffsetsPosition; // position of the tile index
  227. TileMap tileMap;
  228. TileCoord nextTileToWrite;
  229. int partNumber; // the output part number
  230. Data (int numThreads);
  231. ~Data ();
  232. inline TileBuffer * getTileBuffer (int number);
  233. // hash function from tile
  234. // buffer coords into our
  235. // vector of tile buffers
  236. TileCoord nextTileCoord (const TileCoord &a);
  237. };
  238. TiledOutputFile::Data::Data (int numThreads):
  239. multipart(false),
  240. numXTiles(0),
  241. numYTiles(0),
  242. tileOffsetsPosition (0),
  243. partNumber(-1)
  244. {
  245. //
  246. // We need at least one tileBuffer, but if threading is used,
  247. // to keep n threads busy we need 2*n tileBuffers
  248. //
  249. tileBuffers.resize (max (1, 2 * numThreads));
  250. }
  251. TiledOutputFile::Data::~Data ()
  252. {
  253. delete [] numXTiles;
  254. delete [] numYTiles;
  255. //
  256. // Delete all the tile buffers, if any still happen to exist
  257. //
  258. for (TileMap::iterator i = tileMap.begin(); i != tileMap.end(); ++i)
  259. delete i->second;
  260. for (size_t i = 0; i < tileBuffers.size(); i++)
  261. delete tileBuffers[i];
  262. }
  263. TileBuffer*
  264. TiledOutputFile::Data::getTileBuffer (int number)
  265. {
  266. return tileBuffers[number % tileBuffers.size()];
  267. }
  268. TileCoord
  269. TiledOutputFile::Data::nextTileCoord (const TileCoord &a)
  270. {
  271. TileCoord b = a;
  272. if (lineOrder == INCREASING_Y)
  273. {
  274. b.dx++;
  275. if (b.dx >= numXTiles[b.lx])
  276. {
  277. b.dx = 0;
  278. b.dy++;
  279. if (b.dy >= numYTiles[b.ly])
  280. {
  281. //
  282. // the next tile is in the next level
  283. //
  284. b.dy = 0;
  285. switch (tileDesc.mode)
  286. {
  287. case ONE_LEVEL:
  288. case MIPMAP_LEVELS:
  289. b.lx++;
  290. b.ly++;
  291. break;
  292. case RIPMAP_LEVELS:
  293. b.lx++;
  294. if (b.lx >= numXLevels)
  295. {
  296. b.lx = 0;
  297. b.ly++;
  298. #ifdef DEBUG
  299. assert (b.ly <= numYLevels);
  300. #endif
  301. }
  302. break;
  303. case NUM_LEVELMODES:
  304. throw(IEX_NAMESPACE::ArgExc("Invalid tile description"));
  305. }
  306. }
  307. }
  308. }
  309. else if (lineOrder == DECREASING_Y)
  310. {
  311. b.dx++;
  312. if (b.dx >= numXTiles[b.lx])
  313. {
  314. b.dx = 0;
  315. b.dy--;
  316. if (b.dy < 0)
  317. {
  318. //
  319. // the next tile is in the next level
  320. //
  321. switch (tileDesc.mode)
  322. {
  323. case ONE_LEVEL:
  324. case MIPMAP_LEVELS:
  325. b.lx++;
  326. b.ly++;
  327. break;
  328. case RIPMAP_LEVELS:
  329. b.lx++;
  330. if (b.lx >= numXLevels)
  331. {
  332. b.lx = 0;
  333. b.ly++;
  334. #ifdef DEBUG
  335. assert (b.ly <= numYLevels);
  336. #endif
  337. }
  338. break;
  339. case NUM_LEVELMODES:
  340. throw(IEX_NAMESPACE::ArgExc("Invalid tile description"));
  341. }
  342. if (b.ly < numYLevels)
  343. b.dy = numYTiles[b.ly] - 1;
  344. }
  345. }
  346. }
  347. return b;
  348. }
  349. namespace {
  350. void
  351. writeTileData (OutputStreamMutex *streamData,
  352. TiledOutputFile::Data *ofd,
  353. int dx, int dy,
  354. int lx, int ly,
  355. const char pixelData[],
  356. int pixelDataSize)
  357. {
  358. //
  359. // Store a block of pixel data in the output file, and try
  360. // to keep track of the current writing position the file,
  361. // without calling tellp() (tellp() can be fairly expensive).
  362. //
  363. Int64 currentPosition = streamData->currentPosition;
  364. streamData->currentPosition = 0;
  365. if (currentPosition == 0)
  366. currentPosition = streamData->os->tellp();
  367. ofd->tileOffsets (dx, dy, lx, ly) = currentPosition;
  368. #ifdef DEBUG
  369. assert (streamData->os->tellp() == currentPosition);
  370. #endif
  371. //
  372. // Write the tile header.
  373. //
  374. if (ofd->multipart)
  375. {
  376. Xdr::write <StreamIO> (*streamData->os, ofd->partNumber);
  377. }
  378. Xdr::write <StreamIO> (*streamData->os, dx);
  379. Xdr::write <StreamIO> (*streamData->os, dy);
  380. Xdr::write <StreamIO> (*streamData->os, lx);
  381. Xdr::write <StreamIO> (*streamData->os, ly);
  382. Xdr::write <StreamIO> (*streamData->os, pixelDataSize);
  383. streamData->os->write (pixelData, pixelDataSize);
  384. //
  385. // Keep current position in the file so that we can avoid
  386. // redundant seekg() operations (seekg() can be fairly expensive).
  387. //
  388. streamData->currentPosition = currentPosition +
  389. 5 * Xdr::size<int>() +
  390. pixelDataSize;
  391. if (ofd->multipart)
  392. {
  393. streamData->currentPosition += Xdr::size<int>();
  394. }
  395. }
  396. void
  397. bufferedTileWrite (OutputStreamMutex *streamData,
  398. TiledOutputFile::Data *ofd,
  399. int dx, int dy,
  400. int lx, int ly,
  401. const char pixelData[],
  402. int pixelDataSize)
  403. {
  404. //
  405. // Check if a tile with coordinates (dx,dy,lx,ly) has already been written.
  406. //
  407. if (ofd->tileOffsets (dx, dy, lx, ly))
  408. {
  409. THROW (IEX_NAMESPACE::ArgExc,
  410. "Attempt to write tile "
  411. "(" << dx << ", " << dy << ", " << lx << ", " << ly << ") "
  412. "more than once.");
  413. }
  414. //
  415. // If tiles can be written in random order, then don't buffer anything.
  416. //
  417. if (ofd->lineOrder == RANDOM_Y)
  418. {
  419. writeTileData (streamData, ofd, dx, dy, lx, ly, pixelData, pixelDataSize);
  420. return;
  421. }
  422. //
  423. // If the tiles cannot be written in random order, then check if a
  424. // tile with coordinates (dx,dy,lx,ly) has already been buffered.
  425. //
  426. TileCoord currentTile = TileCoord(dx, dy, lx, ly);
  427. if (ofd->tileMap.find (currentTile) != ofd->tileMap.end())
  428. {
  429. THROW (IEX_NAMESPACE::ArgExc,
  430. "Attempt to write tile "
  431. "(" << dx << ", " << dy << ", " << lx << ", " << ly << ") "
  432. "more than once.");
  433. }
  434. //
  435. // If all the tiles before this one have already been written to the file,
  436. // then write this tile immediately and check if we have buffered tiles
  437. // that can be written after this tile.
  438. //
  439. // Otherwise, buffer the tile so it can be written to file later.
  440. //
  441. if (ofd->nextTileToWrite == currentTile)
  442. {
  443. writeTileData (streamData, ofd, dx, dy, lx, ly, pixelData, pixelDataSize);
  444. ofd->nextTileToWrite = ofd->nextTileCoord (ofd->nextTileToWrite);
  445. TileMap::iterator i = ofd->tileMap.find (ofd->nextTileToWrite);
  446. //
  447. // Step through the tiles and write all successive buffered tiles after
  448. // the current one.
  449. //
  450. while(i != ofd->tileMap.end())
  451. {
  452. //
  453. // Write the tile, and then delete the tile's buffered data
  454. //
  455. writeTileData (streamData,
  456. ofd,
  457. i->first.dx, i->first.dy,
  458. i->first.lx, i->first.ly,
  459. i->second->pixelData,
  460. i->second->pixelDataSize);
  461. delete i->second;
  462. ofd->tileMap.erase (i);
  463. //
  464. // Proceed to the next tile
  465. //
  466. ofd->nextTileToWrite = ofd->nextTileCoord (ofd->nextTileToWrite);
  467. i = ofd->tileMap.find (ofd->nextTileToWrite);
  468. }
  469. }
  470. else
  471. {
  472. //
  473. // Create a new BufferedTile, copy the pixelData into it, and
  474. // insert it into the tileMap.
  475. //
  476. ofd->tileMap[currentTile] =
  477. new BufferedTile ((const char *)pixelData, pixelDataSize);
  478. }
  479. }
  480. void
  481. convertToXdr (TiledOutputFile::Data *ofd,
  482. Array<char>& tileBuffer,
  483. int numScanLines,
  484. int numPixelsPerScanLine)
  485. {
  486. //
  487. // Convert the contents of a TiledOutputFile's tileBuffer from the
  488. // machine's native representation to Xdr format. This function is called
  489. // by writeTile(), below, if the compressor wanted its input pixel data
  490. // in the machine's native format, but then failed to compress the data
  491. // (most compressors will expand rather than compress random input data).
  492. //
  493. // Note that this routine assumes that the machine's native representation
  494. // of the pixel data has the same size as the Xdr representation. This
  495. // makes it possible to convert the pixel data in place, without an
  496. // intermediate temporary buffer.
  497. //
  498. //
  499. // Set these to point to the start of the tile.
  500. // We will write to toPtr, and read from fromPtr.
  501. //
  502. char *writePtr = tileBuffer;
  503. const char *readPtr = writePtr;
  504. //
  505. // Iterate over all scan lines in the tile.
  506. //
  507. for (int y = 0; y < numScanLines; ++y)
  508. {
  509. //
  510. // Iterate over all slices in the file.
  511. //
  512. for (unsigned int i = 0; i < ofd->slices.size(); ++i)
  513. {
  514. const TOutSliceInfo &slice = ofd->slices[i];
  515. //
  516. // Convert the samples in place.
  517. //
  518. convertInPlace (writePtr, readPtr, slice.type,
  519. numPixelsPerScanLine);
  520. }
  521. }
  522. #ifdef DEBUG
  523. assert (writePtr == readPtr);
  524. #endif
  525. }
  526. //
  527. // A TileBufferTask encapsulates the task of copying a tile from
  528. // the user's framebuffer into a LineBuffer and compressing the data
  529. // if necessary.
  530. //
  531. class TileBufferTask: public Task
  532. {
  533. public:
  534. TileBufferTask (TaskGroup *group,
  535. TiledOutputFile::Data *ofd,
  536. int number,
  537. int dx, int dy,
  538. int lx, int ly);
  539. virtual ~TileBufferTask ();
  540. virtual void execute ();
  541. private:
  542. TiledOutputFile::Data * _ofd;
  543. TileBuffer * _tileBuffer;
  544. };
  545. TileBufferTask::TileBufferTask
  546. (TaskGroup *group,
  547. TiledOutputFile::Data *ofd,
  548. int number,
  549. int dx, int dy,
  550. int lx, int ly)
  551. :
  552. Task (group),
  553. _ofd (ofd),
  554. _tileBuffer (_ofd->getTileBuffer (number))
  555. {
  556. //
  557. // Wait for the tileBuffer to become available
  558. //
  559. _tileBuffer->wait ();
  560. _tileBuffer->tileCoord = TileCoord (dx, dy, lx, ly);
  561. }
  562. TileBufferTask::~TileBufferTask ()
  563. {
  564. //
  565. // Signal that the tile buffer is now free
  566. //
  567. _tileBuffer->post ();
  568. }
  569. void
  570. TileBufferTask::execute ()
  571. {
  572. try
  573. {
  574. //
  575. // First copy the pixel data from the frame buffer
  576. // into the tile buffer
  577. //
  578. // Convert one tile's worth of pixel data to
  579. // a machine-independent representation, and store
  580. // the result in _tileBuffer->buffer.
  581. //
  582. char *writePtr = _tileBuffer->buffer;
  583. Box2i tileRange = dataWindowForTile (_ofd->tileDesc,
  584. _ofd->minX, _ofd->maxX,
  585. _ofd->minY, _ofd->maxY,
  586. _tileBuffer->tileCoord.dx,
  587. _tileBuffer->tileCoord.dy,
  588. _tileBuffer->tileCoord.lx,
  589. _tileBuffer->tileCoord.ly);
  590. int numScanLines = tileRange.max.y - tileRange.min.y + 1;
  591. int numPixelsPerScanLine = tileRange.max.x - tileRange.min.x + 1;
  592. //
  593. // Iterate over the scan lines in the tile.
  594. //
  595. for (int y = tileRange.min.y; y <= tileRange.max.y; ++y)
  596. {
  597. //
  598. // Iterate over all image channels.
  599. //
  600. for (unsigned int i = 0; i < _ofd->slices.size(); ++i)
  601. {
  602. const TOutSliceInfo &slice = _ofd->slices[i];
  603. //
  604. // These offsets are used to facilitate both absolute
  605. // and tile-relative pixel coordinates.
  606. //
  607. int xOffset = slice.xTileCoords * tileRange.min.x;
  608. int yOffset = slice.yTileCoords * tileRange.min.y;
  609. //
  610. // Fill the tile buffer with pixel data.
  611. //
  612. if (slice.zero)
  613. {
  614. //
  615. // The frame buffer contains no data for this channel.
  616. // Store zeroes in _data->tileBuffer.
  617. //
  618. fillChannelWithZeroes (writePtr, _ofd->format, slice.type,
  619. numPixelsPerScanLine);
  620. }
  621. else
  622. {
  623. //
  624. // The frame buffer contains data for this channel.
  625. //
  626. const char *readPtr = slice.base +
  627. (y - yOffset) * slice.yStride +
  628. (tileRange.min.x - xOffset) *
  629. slice.xStride;
  630. const char *endPtr = readPtr +
  631. (numPixelsPerScanLine - 1) *
  632. slice.xStride;
  633. copyFromFrameBuffer (writePtr, readPtr, endPtr,
  634. slice.xStride, _ofd->format,
  635. slice.type);
  636. }
  637. }
  638. }
  639. //
  640. // Compress the contents of the tileBuffer,
  641. // and store the compressed data in the output file.
  642. //
  643. _tileBuffer->dataSize = writePtr - _tileBuffer->buffer;
  644. _tileBuffer->dataPtr = _tileBuffer->buffer;
  645. if (_tileBuffer->compressor)
  646. {
  647. const char *compPtr;
  648. int compSize = _tileBuffer->compressor->compressTile
  649. (_tileBuffer->dataPtr,
  650. _tileBuffer->dataSize,
  651. tileRange, compPtr);
  652. if (compSize < _tileBuffer->dataSize)
  653. {
  654. _tileBuffer->dataSize = compSize;
  655. _tileBuffer->dataPtr = compPtr;
  656. }
  657. else if (_ofd->format == Compressor::NATIVE)
  658. {
  659. //
  660. // The data did not shrink during compression, but
  661. // we cannot write to the file using native format,
  662. // so we need to convert the lineBuffer to Xdr.
  663. //
  664. convertToXdr (_ofd, _tileBuffer->buffer, numScanLines,
  665. numPixelsPerScanLine);
  666. }
  667. }
  668. }
  669. catch (std::exception &e)
  670. {
  671. if (!_tileBuffer->hasException)
  672. {
  673. _tileBuffer->exception = e.what ();
  674. _tileBuffer->hasException = true;
  675. }
  676. }
  677. catch (...)
  678. {
  679. if (!_tileBuffer->hasException)
  680. {
  681. _tileBuffer->exception = "unrecognized exception";
  682. _tileBuffer->hasException = true;
  683. }
  684. }
  685. }
  686. } // namespace
  687. TiledOutputFile::TiledOutputFile
  688. (const char fileName[],
  689. const Header &header,
  690. int numThreads)
  691. :
  692. _data (new Data (numThreads)),
  693. _streamData (new OutputStreamMutex()),
  694. _deleteStream (true)
  695. {
  696. try
  697. {
  698. header.sanityCheck (true);
  699. _streamData->os = new StdOFStream (fileName);
  700. _data->multipart=false; // since we opened with one header we can't be multipart
  701. initialize (header);
  702. _streamData->currentPosition = _streamData->os->tellp();
  703. // Write header and empty offset table to the file.
  704. writeMagicNumberAndVersionField(*_streamData->os, _data->header);
  705. _data->previewPosition = _data->header.writeTo (*_streamData->os, true);
  706. _data->tileOffsetsPosition = _data->tileOffsets.writeTo (*_streamData->os);
  707. }
  708. catch (IEX_NAMESPACE::BaseExc &e)
  709. {
  710. // ~TiledOutputFile will not run, so free memory here
  711. delete _streamData->os;
  712. delete _streamData;
  713. delete _data;
  714. REPLACE_EXC (e, "Cannot open image file "
  715. "\"" << fileName << "\". " << e.what());
  716. throw;
  717. }
  718. catch (...)
  719. {
  720. // ~TiledOutputFile will not run, so free memory here
  721. delete _streamData->os;
  722. delete _streamData;
  723. delete _data;
  724. throw;
  725. }
  726. }
  727. TiledOutputFile::TiledOutputFile
  728. (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os,
  729. const Header &header,
  730. int numThreads)
  731. :
  732. _data (new Data (numThreads)),
  733. _streamData (new OutputStreamMutex()),
  734. _deleteStream (false)
  735. {
  736. try
  737. {
  738. header.sanityCheck(true);
  739. _streamData->os = &os;
  740. _data->multipart=false; // since we opened with one header we can't be multipart
  741. initialize (header);
  742. _streamData->currentPosition = _streamData->os->tellp();
  743. // Write header and empty offset table to the file.
  744. writeMagicNumberAndVersionField(*_streamData->os, _data->header);
  745. _data->previewPosition = _data->header.writeTo (*_streamData->os, true);
  746. _data->tileOffsetsPosition = _data->tileOffsets.writeTo (*_streamData->os);
  747. }
  748. catch (IEX_NAMESPACE::BaseExc &e)
  749. {
  750. delete _streamData;
  751. delete _data;
  752. REPLACE_EXC (e, "Cannot open image file "
  753. "\"" << os.fileName() << "\". " << e.what());
  754. throw;
  755. }
  756. catch (...)
  757. {
  758. delete _streamData;
  759. delete _data;
  760. throw;
  761. }
  762. }
  763. TiledOutputFile::TiledOutputFile(const OutputPartData* part) :
  764. _deleteStream (false)
  765. {
  766. try
  767. {
  768. if (part->header.type() != TILEDIMAGE)
  769. throw IEX_NAMESPACE::ArgExc("Can't build a TiledOutputFile from a type-mismatched part.");
  770. _streamData = part->mutex;
  771. _data = new Data(part->numThreads);
  772. _data->multipart=part->multipart;
  773. initialize(part->header);
  774. _data->partNumber = part->partNumber;
  775. _data->tileOffsetsPosition = part->chunkOffsetTablePosition;
  776. _data->previewPosition = part->previewPosition;
  777. }
  778. catch (IEX_NAMESPACE::BaseExc &e)
  779. {
  780. delete _data;
  781. REPLACE_EXC (e, "Cannot initialize output part "
  782. "\"" << part->partNumber << "\". " << e.what());
  783. throw;
  784. }
  785. catch (...)
  786. {
  787. delete _data;
  788. throw;
  789. }
  790. }
  791. void
  792. TiledOutputFile::initialize (const Header &header)
  793. {
  794. _data->header = header;
  795. _data->lineOrder = _data->header.lineOrder();
  796. //
  797. // Check that the file is indeed tiled
  798. //
  799. _data->tileDesc = _data->header.tileDescription();
  800. //
  801. // 'Fix' the type attribute if it exists but is incorrectly set
  802. // (attribute is optional, but ensure it is correct if it exists)
  803. //
  804. if(_data->header.hasType())
  805. {
  806. _data->header.setType(TILEDIMAGE);
  807. }
  808. //
  809. // Save the dataWindow information
  810. //
  811. const Box2i &dataWindow = _data->header.dataWindow();
  812. _data->minX = dataWindow.min.x;
  813. _data->maxX = dataWindow.max.x;
  814. _data->minY = dataWindow.min.y;
  815. _data->maxY = dataWindow.max.y;
  816. //
  817. // Precompute level and tile information to speed up utility functions
  818. //
  819. precalculateTileInfo (_data->tileDesc,
  820. _data->minX, _data->maxX,
  821. _data->minY, _data->maxY,
  822. _data->numXTiles, _data->numYTiles,
  823. _data->numXLevels, _data->numYLevels);
  824. //
  825. // Determine the first tile coordinate that we will be writing
  826. // if the file is not RANDOM_Y.
  827. //
  828. _data->nextTileToWrite = (_data->lineOrder == INCREASING_Y)?
  829. TileCoord (0, 0, 0, 0):
  830. TileCoord (0, _data->numYTiles[0] - 1, 0, 0);
  831. _data->maxBytesPerTileLine =
  832. calculateBytesPerPixel (_data->header) * _data->tileDesc.xSize;
  833. _data->tileBufferSize = _data->maxBytesPerTileLine * _data->tileDesc.ySize;
  834. //
  835. // Create all the TileBuffers and allocate their internal buffers
  836. //
  837. for (size_t i = 0; i < _data->tileBuffers.size(); i++)
  838. {
  839. _data->tileBuffers[i] = new TileBuffer (newTileCompressor
  840. (_data->header.compression(),
  841. _data->maxBytesPerTileLine,
  842. _data->tileDesc.ySize,
  843. _data->header));
  844. _data->tileBuffers[i]->buffer.resizeErase(_data->tileBufferSize);
  845. }
  846. _data->format = defaultFormat (_data->tileBuffers[0]->compressor);
  847. _data->tileOffsets = TileOffsets (_data->tileDesc.mode,
  848. _data->numXLevels,
  849. _data->numYLevels,
  850. _data->numXTiles,
  851. _data->numYTiles);
  852. }
  853. TiledOutputFile::~TiledOutputFile ()
  854. {
  855. if (_data)
  856. {
  857. {
  858. Lock lock(*_streamData);
  859. Int64 originalPosition = _streamData->os->tellp();
  860. if (_data->tileOffsetsPosition > 0)
  861. {
  862. try
  863. {
  864. _streamData->os->seekp (_data->tileOffsetsPosition);
  865. _data->tileOffsets.writeTo (*_streamData->os);
  866. //
  867. // Restore the original position.
  868. //
  869. _streamData->os->seekp (originalPosition);
  870. }
  871. catch (...)
  872. {
  873. //
  874. // We cannot safely throw any exceptions from here.
  875. // This destructor may have been called because the
  876. // stack is currently being unwound for another
  877. // exception.
  878. //
  879. }
  880. }
  881. }
  882. if (_deleteStream && _streamData)
  883. delete _streamData->os;
  884. if (_data->partNumber == -1)
  885. delete _streamData;
  886. delete _data;
  887. }
  888. }
  889. const char *
  890. TiledOutputFile::fileName () const
  891. {
  892. return _streamData->os->fileName();
  893. }
  894. const Header &
  895. TiledOutputFile::header () const
  896. {
  897. return _data->header;
  898. }
  899. void
  900. TiledOutputFile::setFrameBuffer (const FrameBuffer &frameBuffer)
  901. {
  902. Lock lock (*_streamData);
  903. //
  904. // Check if the new frame buffer descriptor
  905. // is compatible with the image file header.
  906. //
  907. const ChannelList &channels = _data->header.channels();
  908. for (ChannelList::ConstIterator i = channels.begin();
  909. i != channels.end();
  910. ++i)
  911. {
  912. FrameBuffer::ConstIterator j = frameBuffer.find (i.name());
  913. if (j == frameBuffer.end())
  914. continue;
  915. if (i.channel().type != j.slice().type)
  916. THROW (IEX_NAMESPACE::ArgExc, "Pixel type of \"" << i.name() << "\" channel "
  917. "of output file \"" << fileName() << "\" is "
  918. "not compatible with the frame buffer's "
  919. "pixel type.");
  920. if (j.slice().xSampling != 1 || j.slice().ySampling != 1)
  921. THROW (IEX_NAMESPACE::ArgExc, "All channels in a tiled file must have"
  922. "sampling (1,1).");
  923. }
  924. //
  925. // Initialize slice table for writePixels().
  926. //
  927. vector<TOutSliceInfo> slices;
  928. for (ChannelList::ConstIterator i = channels.begin();
  929. i != channels.end();
  930. ++i)
  931. {
  932. FrameBuffer::ConstIterator j = frameBuffer.find (i.name());
  933. if (j == frameBuffer.end())
  934. {
  935. //
  936. // Channel i is not present in the frame buffer.
  937. // In the file, channel i will contain only zeroes.
  938. //
  939. slices.push_back (TOutSliceInfo (i.channel().type,
  940. 0, // base
  941. 0, // xStride,
  942. 0, // yStride,
  943. true)); // zero
  944. }
  945. else
  946. {
  947. //
  948. // Channel i is present in the frame buffer.
  949. //
  950. slices.push_back (TOutSliceInfo (j.slice().type,
  951. j.slice().base,
  952. j.slice().xStride,
  953. j.slice().yStride,
  954. false, // zero
  955. (j.slice().xTileCoords)? 1: 0,
  956. (j.slice().yTileCoords)? 1: 0));
  957. }
  958. }
  959. //
  960. // Store the new frame buffer.
  961. //
  962. _data->frameBuffer = frameBuffer;
  963. _data->slices = slices;
  964. }
  965. const FrameBuffer &
  966. TiledOutputFile::frameBuffer () const
  967. {
  968. Lock lock (*_streamData);
  969. return _data->frameBuffer;
  970. }
  971. void
  972. TiledOutputFile::writeTiles (int dx1, int dx2, int dy1, int dy2,
  973. int lx, int ly)
  974. {
  975. try
  976. {
  977. Lock lock (*_streamData);
  978. if (_data->slices.size() == 0)
  979. throw IEX_NAMESPACE::ArgExc ("No frame buffer specified "
  980. "as pixel data source.");
  981. if (!isValidTile (dx1, dy1, lx, ly) || !isValidTile (dx2, dy2, lx, ly))
  982. throw IEX_NAMESPACE::ArgExc ("Tile coordinates are invalid.");
  983. if (!isValidLevel (lx, ly))
  984. THROW (IEX_NAMESPACE::ArgExc,
  985. "Level coordinate "
  986. "(" << lx << ", " << ly << ") "
  987. "is invalid.");
  988. //
  989. // Determine the first and last tile coordinates in both dimensions
  990. // based on the file's lineOrder
  991. //
  992. if (dx1 > dx2)
  993. swap (dx1, dx2);
  994. if (dy1 > dy2)
  995. swap (dy1, dy2);
  996. int dyStart = dy1;
  997. int dyStop = dy2 + 1;
  998. int dY = 1;
  999. if (_data->lineOrder == DECREASING_Y)
  1000. {
  1001. dyStart = dy2;
  1002. dyStop = dy1 - 1;
  1003. dY = -1;
  1004. }
  1005. int numTiles = (dx2 - dx1 + 1) * (dy2 - dy1 + 1);
  1006. int numTasks = min ((int)_data->tileBuffers.size(), numTiles);
  1007. //
  1008. // Create a task group for all tile buffer tasks. When the
  1009. // task group goes out of scope, the destructor waits until
  1010. // all tasks are complete.
  1011. //
  1012. {
  1013. TaskGroup taskGroup;
  1014. //
  1015. // Add in the initial compression tasks to the thread pool
  1016. //
  1017. int nextCompBuffer = 0;
  1018. int dxComp = dx1;
  1019. int dyComp = dyStart;
  1020. while (nextCompBuffer < numTasks)
  1021. {
  1022. ThreadPool::addGlobalTask (new TileBufferTask (&taskGroup,
  1023. _data,
  1024. nextCompBuffer++,
  1025. dxComp, dyComp,
  1026. lx, ly));
  1027. dxComp++;
  1028. if (dxComp > dx2)
  1029. {
  1030. dxComp = dx1;
  1031. dyComp += dY;
  1032. }
  1033. }
  1034. //
  1035. // Write the compressed buffers and add in more compression
  1036. // tasks until done
  1037. //
  1038. int nextWriteBuffer = 0;
  1039. int dxWrite = dx1;
  1040. int dyWrite = dyStart;
  1041. while (nextWriteBuffer < numTiles)
  1042. {
  1043. //
  1044. // Wait until the nextWriteBuffer is ready to be written
  1045. //
  1046. TileBuffer* writeBuffer =
  1047. _data->getTileBuffer (nextWriteBuffer);
  1048. writeBuffer->wait();
  1049. //
  1050. // Write the tilebuffer
  1051. //
  1052. bufferedTileWrite (_streamData, _data, dxWrite, dyWrite, lx, ly,
  1053. writeBuffer->dataPtr,
  1054. writeBuffer->dataSize);
  1055. //
  1056. // Release the lock on nextWriteBuffer
  1057. //
  1058. writeBuffer->post();
  1059. //
  1060. // If there are no more tileBuffers to compress, then
  1061. // only continue to write out remaining tileBuffers,
  1062. // otherwise keep adding compression tasks.
  1063. //
  1064. if (nextCompBuffer < numTiles)
  1065. {
  1066. //
  1067. // add nextCompBuffer as a compression Task
  1068. //
  1069. ThreadPool::addGlobalTask
  1070. (new TileBufferTask (&taskGroup,
  1071. _data,
  1072. nextCompBuffer,
  1073. dxComp, dyComp,
  1074. lx, ly));
  1075. }
  1076. nextWriteBuffer++;
  1077. dxWrite++;
  1078. if (dxWrite > dx2)
  1079. {
  1080. dxWrite = dx1;
  1081. dyWrite += dY;
  1082. }
  1083. nextCompBuffer++;
  1084. dxComp++;
  1085. if (dxComp > dx2)
  1086. {
  1087. dxComp = dx1;
  1088. dyComp += dY;
  1089. }
  1090. }
  1091. //
  1092. // finish all tasks
  1093. //
  1094. }
  1095. //
  1096. // Exeption handling:
  1097. //
  1098. // TileBufferTask::execute() may have encountered exceptions, but
  1099. // those exceptions occurred in another thread, not in the thread
  1100. // that is executing this call to TiledOutputFile::writeTiles().
  1101. // TileBufferTask::execute() has caught all exceptions and stored
  1102. // the exceptions' what() strings in the tile buffers.
  1103. // Now we check if any tile buffer contains a stored exception; if
  1104. // this is the case then we re-throw the exception in this thread.
  1105. // (It is possible that multiple tile buffers contain stored
  1106. // exceptions. We re-throw the first exception we find and
  1107. // ignore all others.)
  1108. //
  1109. const string *exception = 0;
  1110. for (size_t i = 0; i < _data->tileBuffers.size(); ++i)
  1111. {
  1112. TileBuffer *tileBuffer = _data->tileBuffers[i];
  1113. if (tileBuffer->hasException && !exception)
  1114. exception = &tileBuffer->exception;
  1115. tileBuffer->hasException = false;
  1116. }
  1117. if (exception)
  1118. throw IEX_NAMESPACE::IoExc (*exception);
  1119. }
  1120. catch (IEX_NAMESPACE::BaseExc &e)
  1121. {
  1122. REPLACE_EXC (e, "Failed to write pixel data to image "
  1123. "file \"" << fileName() << "\". " << e.what());
  1124. throw;
  1125. }
  1126. }
  1127. void
  1128. TiledOutputFile::writeTiles (int dx1, int dxMax, int dyMin, int dyMax, int l)
  1129. {
  1130. writeTiles (dx1, dxMax, dyMin, dyMax, l, l);
  1131. }
  1132. void
  1133. TiledOutputFile::writeTile (int dx, int dy, int lx, int ly)
  1134. {
  1135. writeTiles (dx, dx, dy, dy, lx, ly);
  1136. }
  1137. void
  1138. TiledOutputFile::writeTile (int dx, int dy, int l)
  1139. {
  1140. writeTile(dx, dy, l, l);
  1141. }
  1142. void
  1143. TiledOutputFile::copyPixels (TiledInputFile &in)
  1144. {
  1145. Lock lock (*_streamData);
  1146. //
  1147. // Check if this file's and and the InputFile's
  1148. // headers are compatible.
  1149. //
  1150. const Header &hdr = _data->header;
  1151. const Header &inHdr = in.header();
  1152. if (!hdr.hasTileDescription() || !inHdr.hasTileDescription())
  1153. THROW (IEX_NAMESPACE::ArgExc, "Cannot perform a quick pixel copy from image "
  1154. "file \"" << in.fileName() << "\" to image "
  1155. "file \"" << fileName() << "\". The "
  1156. "output file is tiled, but the input file is not. "
  1157. "Try using OutputFile::copyPixels() instead.");
  1158. if (!(hdr.tileDescription() == inHdr.tileDescription()))
  1159. THROW (IEX_NAMESPACE::ArgExc, "Quick pixel copy from image "
  1160. "file \"" << in.fileName() << "\" to image "
  1161. "file \"" << fileName() << "\" failed. "
  1162. "The files have different tile descriptions.");
  1163. if (!(hdr.dataWindow() == inHdr.dataWindow()))
  1164. THROW (IEX_NAMESPACE::ArgExc, "Cannot copy pixels from image "
  1165. "file \"" << in.fileName() << "\" to image "
  1166. "file \"" << fileName() << "\". The "
  1167. "files have different data windows.");
  1168. if (!(hdr.lineOrder() == inHdr.lineOrder()))
  1169. THROW (IEX_NAMESPACE::ArgExc, "Quick pixel copy from image "
  1170. "file \"" << in.fileName() << "\" to image "
  1171. "file \"" << fileName() << "\" failed. "
  1172. "The files have different line orders.");
  1173. if (!(hdr.compression() == inHdr.compression()))
  1174. THROW (IEX_NAMESPACE::ArgExc, "Quick pixel copy from image "
  1175. "file \"" << in.fileName() << "\" to image "
  1176. "file \"" << fileName() << "\" failed. "
  1177. "The files use different compression methods.");
  1178. if (!(hdr.channels() == inHdr.channels()))
  1179. THROW (IEX_NAMESPACE::ArgExc, "Quick pixel copy from image "
  1180. "file \"" << in.fileName() << "\" to image "
  1181. "file \"" << fileName() << "\" "
  1182. "failed. The files have different channel "
  1183. "lists.");
  1184. //
  1185. // Verify that no pixel data have been written to this file yet.
  1186. //
  1187. if (!_data->tileOffsets.isEmpty())
  1188. THROW (IEX_NAMESPACE::LogicExc, "Quick pixel copy from image "
  1189. "file \"" << in.fileName() << "\" to image "
  1190. "file \"" << _streamData->os->fileName() << "\" "
  1191. "failed. \"" << fileName() << "\" "
  1192. "already contains pixel data.");
  1193. //
  1194. // Calculate the total number of tiles in the file
  1195. //
  1196. int numAllTiles = 0;
  1197. switch (levelMode ())
  1198. {
  1199. case ONE_LEVEL:
  1200. case MIPMAP_LEVELS:
  1201. for (int i_l = 0; i_l < numLevels (); ++i_l)
  1202. numAllTiles += numXTiles (i_l) * numYTiles (i_l);
  1203. break;
  1204. case RIPMAP_LEVELS:
  1205. for (int i_ly = 0; i_ly < numYLevels (); ++i_ly)
  1206. for (int i_lx = 0; i_lx < numXLevels (); ++i_lx)
  1207. numAllTiles += numXTiles (i_lx) * numYTiles (i_ly);
  1208. break;
  1209. default:
  1210. throw IEX_NAMESPACE::ArgExc ("Unknown LevelMode format.");
  1211. }
  1212. bool random_y = _data->lineOrder==RANDOM_Y;
  1213. std::vector<int> dx_table(random_y ? numAllTiles : 1);
  1214. std::vector<int> dy_table(random_y ? numAllTiles : 1);
  1215. std::vector<int> lx_table(random_y ? numAllTiles : 1);
  1216. std::vector<int> ly_table(random_y ? numAllTiles : 1);
  1217. if(random_y)
  1218. {
  1219. in.tileOrder(&dx_table[0],&dy_table[0],&lx_table[0],&ly_table[0]);
  1220. _data->nextTileToWrite.dx=dx_table[0];
  1221. _data->nextTileToWrite.dy=dy_table[0];
  1222. _data->nextTileToWrite.lx=lx_table[0];
  1223. _data->nextTileToWrite.ly=ly_table[0];
  1224. }
  1225. for (int i = 0; i < numAllTiles; ++i)
  1226. {
  1227. const char *pixelData;
  1228. int pixelDataSize;
  1229. int dx = _data->nextTileToWrite.dx;
  1230. int dy = _data->nextTileToWrite.dy;
  1231. int lx = _data->nextTileToWrite.lx;
  1232. int ly = _data->nextTileToWrite.ly;
  1233. in.rawTileData (dx, dy, lx, ly, pixelData, pixelDataSize);
  1234. writeTileData (_streamData, _data, dx, dy, lx, ly, pixelData, pixelDataSize);
  1235. if(random_y)
  1236. {
  1237. if(i<numAllTiles-1)
  1238. {
  1239. _data->nextTileToWrite.dx=dx_table[i+1];
  1240. _data->nextTileToWrite.dy=dy_table[i+1];
  1241. _data->nextTileToWrite.lx=lx_table[i+1];
  1242. _data->nextTileToWrite.ly=ly_table[i+1];
  1243. }
  1244. }else{
  1245. _data->nextTileToWrite=_data->nextTileCoord(_data->nextTileToWrite);
  1246. }
  1247. }
  1248. }
  1249. void
  1250. TiledOutputFile::copyPixels (InputFile &in)
  1251. {
  1252. copyPixels (*in.tFile());
  1253. }
  1254. void
  1255. TiledOutputFile::copyPixels (InputPart &in)
  1256. {
  1257. copyPixels (*in.file);
  1258. }
  1259. void
  1260. TiledOutputFile::copyPixels (TiledInputPart &in)
  1261. {
  1262. copyPixels (*in.file);
  1263. }
  1264. unsigned int
  1265. TiledOutputFile::tileXSize () const
  1266. {
  1267. return _data->tileDesc.xSize;
  1268. }
  1269. unsigned int
  1270. TiledOutputFile::tileYSize () const
  1271. {
  1272. return _data->tileDesc.ySize;
  1273. }
  1274. LevelMode
  1275. TiledOutputFile::levelMode () const
  1276. {
  1277. return _data->tileDesc.mode;
  1278. }
  1279. LevelRoundingMode
  1280. TiledOutputFile::levelRoundingMode () const
  1281. {
  1282. return _data->tileDesc.roundingMode;
  1283. }
  1284. int
  1285. TiledOutputFile::numLevels () const
  1286. {
  1287. if (levelMode() == RIPMAP_LEVELS)
  1288. THROW (IEX_NAMESPACE::LogicExc, "Error calling numLevels() on image "
  1289. "file \"" << fileName() << "\" "
  1290. "(numLevels() is not defined for RIPMAPs).");
  1291. return _data->numXLevels;
  1292. }
  1293. int
  1294. TiledOutputFile::numXLevels () const
  1295. {
  1296. return _data->numXLevels;
  1297. }
  1298. int
  1299. TiledOutputFile::numYLevels () const
  1300. {
  1301. return _data->numYLevels;
  1302. }
  1303. bool
  1304. TiledOutputFile::isValidLevel (int lx, int ly) const
  1305. {
  1306. if (lx < 0 || ly < 0)
  1307. return false;
  1308. if (levelMode() == MIPMAP_LEVELS && lx != ly)
  1309. return false;
  1310. if (lx >= numXLevels() || ly >= numYLevels())
  1311. return false;
  1312. return true;
  1313. }
  1314. int
  1315. TiledOutputFile::levelWidth (int lx) const
  1316. {
  1317. try
  1318. {
  1319. int retVal = levelSize (_data->minX, _data->maxX, lx,
  1320. _data->tileDesc.roundingMode);
  1321. return retVal;
  1322. }
  1323. catch (IEX_NAMESPACE::BaseExc &e)
  1324. {
  1325. REPLACE_EXC (e, "Error calling levelWidth() on image "
  1326. "file \"" << fileName() << "\". " << e.what());
  1327. throw;
  1328. }
  1329. }
  1330. int
  1331. TiledOutputFile::levelHeight (int ly) const
  1332. {
  1333. try
  1334. {
  1335. return levelSize (_data->minY, _data->maxY, ly,
  1336. _data->tileDesc.roundingMode);
  1337. }
  1338. catch (IEX_NAMESPACE::BaseExc &e)
  1339. {
  1340. REPLACE_EXC (e, "Error calling levelHeight() on image "
  1341. "file \"" << fileName() << "\". " << e.what());
  1342. throw;
  1343. }
  1344. }
  1345. int
  1346. TiledOutputFile::numXTiles (int lx) const
  1347. {
  1348. if (lx < 0 || lx >= _data->numXLevels)
  1349. THROW (IEX_NAMESPACE::LogicExc, "Error calling numXTiles() on image "
  1350. "file \"" << _streamData->os->fileName() << "\" "
  1351. "(Argument is not in valid range).");
  1352. return _data->numXTiles[lx];
  1353. }
  1354. int
  1355. TiledOutputFile::numYTiles (int ly) const
  1356. {
  1357. if (ly < 0 || ly >= _data->numYLevels)
  1358. THROW (IEX_NAMESPACE::LogicExc, "Error calling numXTiles() on image "
  1359. "file \"" << _streamData->os->fileName() << "\" "
  1360. "(Argument is not in valid range).");
  1361. return _data->numYTiles[ly];
  1362. }
  1363. Box2i
  1364. TiledOutputFile::dataWindowForLevel (int l) const
  1365. {
  1366. return dataWindowForLevel (l, l);
  1367. }
  1368. Box2i
  1369. TiledOutputFile::dataWindowForLevel (int lx, int ly) const
  1370. {
  1371. try
  1372. {
  1373. return OPENEXR_IMF_INTERNAL_NAMESPACE::dataWindowForLevel (
  1374. _data->tileDesc,
  1375. _data->minX, _data->maxX,
  1376. _data->minY, _data->maxY,
  1377. lx, ly);
  1378. }
  1379. catch (IEX_NAMESPACE::BaseExc &e)
  1380. {
  1381. REPLACE_EXC (e, "Error calling dataWindowForLevel() on image "
  1382. "file \"" << fileName() << "\". " << e.what());
  1383. throw;
  1384. }
  1385. }
  1386. Box2i
  1387. TiledOutputFile::dataWindowForTile (int dx, int dy, int l) const
  1388. {
  1389. return dataWindowForTile (dx, dy, l, l);
  1390. }
  1391. Box2i
  1392. TiledOutputFile::dataWindowForTile (int dx, int dy, int lx, int ly) const
  1393. {
  1394. try
  1395. {
  1396. if (!isValidTile (dx, dy, lx, ly))
  1397. throw IEX_NAMESPACE::ArgExc ("Arguments not in valid range.");
  1398. return OPENEXR_IMF_INTERNAL_NAMESPACE::dataWindowForTile (
  1399. _data->tileDesc,
  1400. _data->minX, _data->maxX,
  1401. _data->minY, _data->maxY,
  1402. dx, dy,
  1403. lx, ly);
  1404. }
  1405. catch (IEX_NAMESPACE::BaseExc &e)
  1406. {
  1407. REPLACE_EXC (e, "Error calling dataWindowForTile() on image "
  1408. "file \"" << fileName() << "\". " << e.what());
  1409. throw;
  1410. }
  1411. }
  1412. bool
  1413. TiledOutputFile::isValidTile (int dx, int dy, int lx, int ly) const
  1414. {
  1415. return ((lx < _data->numXLevels && lx >= 0) &&
  1416. (ly < _data->numYLevels && ly >= 0) &&
  1417. (dx < _data->numXTiles[lx] && dx >= 0) &&
  1418. (dy < _data->numYTiles[ly] && dy >= 0));
  1419. }
  1420. void
  1421. TiledOutputFile::updatePreviewImage (const PreviewRgba newPixels[])
  1422. {
  1423. Lock lock (*_streamData);
  1424. if (_data->previewPosition <= 0)
  1425. THROW (IEX_NAMESPACE::LogicExc, "Cannot update preview image pixels. "
  1426. "File \"" << fileName() << "\" does not "
  1427. "contain a preview image.");
  1428. //
  1429. // Store the new pixels in the header's preview image attribute.
  1430. //
  1431. PreviewImageAttribute &pia =
  1432. _data->header.typedAttribute <PreviewImageAttribute> ("preview");
  1433. PreviewImage &pi = pia.value();
  1434. PreviewRgba *pixels = pi.pixels();
  1435. int numPixels = pi.width() * pi.height();
  1436. for (int i = 0; i < numPixels; ++i)
  1437. pixels[i] = newPixels[i];
  1438. //
  1439. // Save the current file position, jump to the position in
  1440. // the file where the preview image starts, store the new
  1441. // preview image, and jump back to the saved file position.
  1442. //
  1443. Int64 savedPosition = _streamData->os->tellp();
  1444. try
  1445. {
  1446. _streamData->os->seekp (_data->previewPosition);
  1447. pia.writeValueTo (*_streamData->os, _data->version);
  1448. _streamData->os->seekp (savedPosition);
  1449. }
  1450. catch (IEX_NAMESPACE::BaseExc &e)
  1451. {
  1452. REPLACE_EXC (e, "Cannot update preview image pixels for "
  1453. "file \"" << fileName() << "\". " << e.what());
  1454. throw;
  1455. }
  1456. }
  1457. void
  1458. TiledOutputFile::breakTile
  1459. (int dx, int dy,
  1460. int lx, int ly,
  1461. int offset,
  1462. int length,
  1463. char c)
  1464. {
  1465. Lock lock (*_streamData);
  1466. Int64 position = _data->tileOffsets (dx, dy, lx, ly);
  1467. if (!position)
  1468. THROW (IEX_NAMESPACE::ArgExc,
  1469. "Cannot overwrite tile "
  1470. "(" << dx << ", " << dy << ", " << lx << "," << ly << "). "
  1471. "The tile has not yet been stored in "
  1472. "file \"" << fileName() << "\".");
  1473. _streamData->currentPosition = 0;
  1474. _streamData->os->seekp (position + offset);
  1475. for (int i = 0; i < length; ++i)
  1476. _streamData->os->write (&c, 1);
  1477. }
  1478. OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT