ImfRgbaFile.cpp 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405
  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 RgbaOutputFile
  37. // class RgbaInputFile
  38. //
  39. //-----------------------------------------------------------------------------
  40. #include <ImfRgbaFile.h>
  41. #include <ImfOutputFile.h>
  42. #include <ImfInputFile.h>
  43. #include <ImfChannelList.h>
  44. #include <ImfRgbaYca.h>
  45. #include <ImfStandardAttributes.h>
  46. #include <ImathFun.h>
  47. #include <IlmThreadMutex.h>
  48. #include <Iex.h>
  49. #include <string.h>
  50. #include <algorithm>
  51. #include "ImfNamespace.h"
  52. OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
  53. using namespace std;
  54. using namespace IMATH_NAMESPACE;
  55. using namespace RgbaYca;
  56. using namespace ILMTHREAD_NAMESPACE;
  57. namespace {
  58. void
  59. insertChannels (Header &header, RgbaChannels rgbaChannels)
  60. {
  61. ChannelList ch;
  62. if (rgbaChannels & (WRITE_Y | WRITE_C))
  63. {
  64. if (rgbaChannels & WRITE_Y)
  65. {
  66. ch.insert ("Y", Channel (HALF, 1, 1));
  67. }
  68. if (rgbaChannels & WRITE_C)
  69. {
  70. ch.insert ("RY", Channel (HALF, 2, 2, true));
  71. ch.insert ("BY", Channel (HALF, 2, 2, true));
  72. }
  73. }
  74. else
  75. {
  76. if (rgbaChannels & WRITE_R)
  77. ch.insert ("R", Channel (HALF, 1, 1));
  78. if (rgbaChannels & WRITE_G)
  79. ch.insert ("G", Channel (HALF, 1, 1));
  80. if (rgbaChannels & WRITE_B)
  81. ch.insert ("B", Channel (HALF, 1, 1));
  82. }
  83. if (rgbaChannels & WRITE_A)
  84. ch.insert ("A", Channel (HALF, 1, 1));
  85. header.channels() = ch;
  86. }
  87. RgbaChannels
  88. rgbaChannels (const ChannelList &ch, const string &channelNamePrefix = "")
  89. {
  90. int i = 0;
  91. if (ch.findChannel (channelNamePrefix + "R"))
  92. i |= WRITE_R;
  93. if (ch.findChannel (channelNamePrefix + "G"))
  94. i |= WRITE_G;
  95. if (ch.findChannel (channelNamePrefix + "B"))
  96. i |= WRITE_B;
  97. if (ch.findChannel (channelNamePrefix + "A"))
  98. i |= WRITE_A;
  99. if (ch.findChannel (channelNamePrefix + "Y"))
  100. i |= WRITE_Y;
  101. if (ch.findChannel (channelNamePrefix + "RY") ||
  102. ch.findChannel (channelNamePrefix + "BY"))
  103. i |= WRITE_C;
  104. return RgbaChannels (i);
  105. }
  106. string
  107. prefixFromLayerName (const string &layerName, const Header &header)
  108. {
  109. if (layerName.empty())
  110. return "";
  111. if (hasMultiView (header) && multiView(header)[0] == layerName)
  112. return "";
  113. return layerName + ".";
  114. }
  115. V3f
  116. ywFromHeader (const Header &header)
  117. {
  118. Chromaticities cr;
  119. if (hasChromaticities (header))
  120. cr = chromaticities (header);
  121. return computeYw (cr);
  122. }
  123. ptrdiff_t
  124. cachePadding (ptrdiff_t size)
  125. {
  126. //
  127. // Some of the buffers that are allocated by classes ToYca and
  128. // FromYca, below, may need to be padded to avoid cache thrashing.
  129. // If the difference between the buffer size and the nearest power
  130. // of two is less than CACHE_LINE_SIZE, then we add an appropriate
  131. // amount of padding.
  132. //
  133. // CACHE_LINE_SIZE must be a power of two, and it must be at
  134. // least as big as the true size of a cache line on the machine
  135. // we are running on. (It is ok if CACHE_LINE_SIZE is larger
  136. // than a real cache line.)
  137. //
  138. static int LOG2_CACHE_LINE_SIZE = 8;
  139. static const ptrdiff_t CACHE_LINE_SIZE = (1 << LOG2_CACHE_LINE_SIZE);
  140. int i = LOG2_CACHE_LINE_SIZE + 2;
  141. while ((size >> i) > 1)
  142. ++i;
  143. if (size > (1 << (i + 1)) - 64)
  144. return 64 + ((1 << (i + 1)) - size);
  145. if (size < (1 << i) + 64)
  146. return 64 + ((1 << i) - size);
  147. return 0;
  148. }
  149. } // namespace
  150. class RgbaOutputFile::ToYca: public Mutex
  151. {
  152. public:
  153. ToYca (OutputFile &outputFile, RgbaChannels rgbaChannels);
  154. ~ToYca ();
  155. void setYCRounding (unsigned int roundY,
  156. unsigned int roundC);
  157. void setFrameBuffer (const Rgba *base,
  158. size_t xStride,
  159. size_t yStride);
  160. void writePixels (int numScanLines);
  161. int currentScanLine () const;
  162. private:
  163. void padTmpBuf ();
  164. void rotateBuffers ();
  165. void duplicateLastBuffer ();
  166. void duplicateSecondToLastBuffer ();
  167. void decimateChromaVertAndWriteScanLine ();
  168. OutputFile & _outputFile;
  169. bool _writeY;
  170. bool _writeC;
  171. bool _writeA;
  172. int _xMin;
  173. int _width;
  174. int _height;
  175. int _linesConverted;
  176. LineOrder _lineOrder;
  177. int _currentScanLine;
  178. V3f _yw;
  179. Rgba * _bufBase;
  180. Rgba * _buf[N];
  181. Rgba * _tmpBuf;
  182. const Rgba * _fbBase;
  183. size_t _fbXStride;
  184. size_t _fbYStride;
  185. int _roundY;
  186. int _roundC;
  187. };
  188. RgbaOutputFile::ToYca::ToYca (OutputFile &outputFile,
  189. RgbaChannels rgbaChannels)
  190. :
  191. _outputFile (outputFile)
  192. {
  193. _writeY = (rgbaChannels & WRITE_Y)? true: false;
  194. _writeC = (rgbaChannels & WRITE_C)? true: false;
  195. _writeA = (rgbaChannels & WRITE_A)? true: false;
  196. const Box2i dw = _outputFile.header().dataWindow();
  197. _xMin = dw.min.x;
  198. _width = dw.max.x - dw.min.x + 1;
  199. _height = dw.max.y - dw.min.y + 1;
  200. _linesConverted = 0;
  201. _lineOrder = _outputFile.header().lineOrder();
  202. if (_lineOrder == INCREASING_Y)
  203. _currentScanLine = dw.min.y;
  204. else
  205. _currentScanLine = dw.max.y;
  206. _yw = ywFromHeader (_outputFile.header());
  207. ptrdiff_t pad = cachePadding (_width * sizeof (Rgba)) / sizeof (Rgba);
  208. _bufBase = new Rgba[(_width + pad) * N];
  209. for (int i = 0; i < N; ++i)
  210. _buf[i] = _bufBase + (i * (_width + pad));
  211. _tmpBuf = new Rgba[_width + N - 1];
  212. _fbBase = 0;
  213. _fbXStride = 0;
  214. _fbYStride = 0;
  215. _roundY = 7;
  216. _roundC = 5;
  217. }
  218. RgbaOutputFile::ToYca::~ToYca ()
  219. {
  220. delete [] _bufBase;
  221. delete [] _tmpBuf;
  222. }
  223. void
  224. RgbaOutputFile::ToYca::setYCRounding (unsigned int roundY,
  225. unsigned int roundC)
  226. {
  227. _roundY = roundY;
  228. _roundC = roundC;
  229. }
  230. void
  231. RgbaOutputFile::ToYca::setFrameBuffer (const Rgba *base,
  232. size_t xStride,
  233. size_t yStride)
  234. {
  235. if (_fbBase == 0)
  236. {
  237. FrameBuffer fb;
  238. if (_writeY)
  239. {
  240. fb.insert ("Y",
  241. Slice (HALF, // type
  242. (char *) &_tmpBuf[-_xMin].g, // base
  243. sizeof (Rgba), // xStride
  244. 0, // yStride
  245. 1, // xSampling
  246. 1)); // ySampling
  247. }
  248. if (_writeC)
  249. {
  250. fb.insert ("RY",
  251. Slice (HALF, // type
  252. (char *) &_tmpBuf[-_xMin].r, // base
  253. sizeof (Rgba) * 2, // xStride
  254. 0, // yStride
  255. 2, // xSampling
  256. 2)); // ySampling
  257. fb.insert ("BY",
  258. Slice (HALF, // type
  259. (char *) &_tmpBuf[-_xMin].b, // base
  260. sizeof (Rgba) * 2, // xStride
  261. 0, // yStride
  262. 2, // xSampling
  263. 2)); // ySampling
  264. }
  265. if (_writeA)
  266. {
  267. fb.insert ("A",
  268. Slice (HALF, // type
  269. (char *) &_tmpBuf[-_xMin].a, // base
  270. sizeof (Rgba), // xStride
  271. 0, // yStride
  272. 1, // xSampling
  273. 1)); // ySampling
  274. }
  275. _outputFile.setFrameBuffer (fb);
  276. }
  277. _fbBase = base;
  278. _fbXStride = xStride;
  279. _fbYStride = yStride;
  280. }
  281. void
  282. RgbaOutputFile::ToYca::writePixels (int numScanLines)
  283. {
  284. if (_fbBase == 0)
  285. {
  286. THROW (IEX_NAMESPACE::ArgExc, "No frame buffer was specified as the "
  287. "pixel data source for image file "
  288. "\"" << _outputFile.fileName() << "\".");
  289. }
  290. if (_writeY && !_writeC)
  291. {
  292. //
  293. // We are writing only luminance; filtering
  294. // and subsampling are not necessary.
  295. //
  296. for (int i = 0; i < numScanLines; ++i)
  297. {
  298. //
  299. // Copy the next scan line from the caller's
  300. // frame buffer into _tmpBuf.
  301. //
  302. for (int j = 0; j < _width; ++j)
  303. {
  304. _tmpBuf[j] = _fbBase[_fbYStride * _currentScanLine +
  305. _fbXStride * (j + _xMin)];
  306. }
  307. //
  308. // Convert the scan line from RGB to luminance/chroma,
  309. // and store the result in the output file.
  310. //
  311. RGBAtoYCA (_yw, _width, _writeA, _tmpBuf, _tmpBuf);
  312. _outputFile.writePixels (1);
  313. ++_linesConverted;
  314. if (_lineOrder == INCREASING_Y)
  315. ++_currentScanLine;
  316. else
  317. --_currentScanLine;
  318. }
  319. }
  320. else
  321. {
  322. //
  323. // We are writing chroma; the pixels must be filtered and subsampled.
  324. //
  325. for (int i = 0; i < numScanLines; ++i)
  326. {
  327. //
  328. // Copy the next scan line from the caller's
  329. // frame buffer into _tmpBuf.
  330. //
  331. for (int j = 0; j < _width; ++j)
  332. {
  333. _tmpBuf[j + N2] = _fbBase[_fbYStride * _currentScanLine +
  334. _fbXStride * (j + _xMin)];
  335. }
  336. //
  337. // Convert the scan line from RGB to luminance/chroma.
  338. //
  339. RGBAtoYCA (_yw, _width, _writeA, _tmpBuf + N2, _tmpBuf + N2);
  340. //
  341. // Append N2 copies of the first and last pixel to the
  342. // beginning and end of the scan line.
  343. //
  344. padTmpBuf ();
  345. //
  346. // Filter and subsample the scan line's chroma channels
  347. // horizontally; store the result in _buf.
  348. //
  349. rotateBuffers();
  350. decimateChromaHoriz (_width, _tmpBuf, _buf[N - 1]);
  351. //
  352. // If this is the first scan line in the image,
  353. // store N2 more copies of the scan line in _buf.
  354. //
  355. if (_linesConverted == 0)
  356. {
  357. for (int j = 0; j < N2; ++j)
  358. duplicateLastBuffer();
  359. }
  360. ++_linesConverted;
  361. //
  362. // If we have have converted at least N2 scan lines from
  363. // RGBA to luminance/chroma, then we can start to filter
  364. // and subsample vertically, and store pixels in the
  365. // output file.
  366. //
  367. if (_linesConverted > N2)
  368. decimateChromaVertAndWriteScanLine();
  369. //
  370. // If we have already converted the last scan line in
  371. // the image to luminance/chroma, filter, subsample and
  372. // store the remaining scan lines in _buf.
  373. //
  374. if (_linesConverted >= _height)
  375. {
  376. for (int j = 0; j < N2 - _height; ++j)
  377. duplicateLastBuffer();
  378. duplicateSecondToLastBuffer();
  379. ++_linesConverted;
  380. decimateChromaVertAndWriteScanLine();
  381. for (int j = 1; j < min (_height, N2); ++j)
  382. {
  383. duplicateLastBuffer();
  384. ++_linesConverted;
  385. decimateChromaVertAndWriteScanLine();
  386. }
  387. }
  388. if (_lineOrder == INCREASING_Y)
  389. ++_currentScanLine;
  390. else
  391. --_currentScanLine;
  392. }
  393. }
  394. }
  395. int
  396. RgbaOutputFile::ToYca::currentScanLine () const
  397. {
  398. return _currentScanLine;
  399. }
  400. void
  401. RgbaOutputFile::ToYca::padTmpBuf ()
  402. {
  403. for (int i = 0; i < N2; ++i)
  404. {
  405. _tmpBuf[i] = _tmpBuf[N2];
  406. _tmpBuf[_width + N2 + i] = _tmpBuf[_width + N2 - 2];
  407. }
  408. }
  409. void
  410. RgbaOutputFile::ToYca::rotateBuffers ()
  411. {
  412. Rgba *tmp = _buf[0];
  413. for (int i = 0; i < N - 1; ++i)
  414. _buf[i] = _buf[i + 1];
  415. _buf[N - 1] = tmp;
  416. }
  417. void
  418. RgbaOutputFile::ToYca::duplicateLastBuffer ()
  419. {
  420. rotateBuffers();
  421. memcpy (_buf[N - 1], _buf[N - 2], _width * sizeof (Rgba));
  422. }
  423. void
  424. RgbaOutputFile::ToYca::duplicateSecondToLastBuffer ()
  425. {
  426. rotateBuffers();
  427. memcpy (_buf[N - 1], _buf[N - 3], _width * sizeof (Rgba));
  428. }
  429. void
  430. RgbaOutputFile::ToYca::decimateChromaVertAndWriteScanLine ()
  431. {
  432. if (_linesConverted & 1)
  433. memcpy (_tmpBuf, _buf[N2], _width * sizeof (Rgba));
  434. else
  435. decimateChromaVert (_width, _buf, _tmpBuf);
  436. if (_writeY && _writeC)
  437. roundYCA (_width, _roundY, _roundC, _tmpBuf, _tmpBuf);
  438. _outputFile.writePixels (1);
  439. }
  440. RgbaOutputFile::RgbaOutputFile (const char name[],
  441. const Header &header,
  442. RgbaChannels rgbaChannels,
  443. int numThreads):
  444. _outputFile (0),
  445. _toYca (0)
  446. {
  447. Header hd (header);
  448. insertChannels (hd, rgbaChannels);
  449. _outputFile = new OutputFile (name, hd, numThreads);
  450. if (rgbaChannels & (WRITE_Y | WRITE_C))
  451. _toYca = new ToYca (*_outputFile, rgbaChannels);
  452. }
  453. RgbaOutputFile::RgbaOutputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os,
  454. const Header &header,
  455. RgbaChannels rgbaChannels,
  456. int numThreads):
  457. _outputFile (0),
  458. _toYca (0)
  459. {
  460. Header hd (header);
  461. insertChannels (hd, rgbaChannels);
  462. _outputFile = new OutputFile (os, hd, numThreads);
  463. if (rgbaChannels & (WRITE_Y | WRITE_C))
  464. _toYca = new ToYca (*_outputFile, rgbaChannels);
  465. }
  466. RgbaOutputFile::RgbaOutputFile (const char name[],
  467. const IMATH_NAMESPACE::Box2i &displayWindow,
  468. const IMATH_NAMESPACE::Box2i &dataWindow,
  469. RgbaChannels rgbaChannels,
  470. float pixelAspectRatio,
  471. const IMATH_NAMESPACE::V2f screenWindowCenter,
  472. float screenWindowWidth,
  473. LineOrder lineOrder,
  474. Compression compression,
  475. int numThreads):
  476. _outputFile (0),
  477. _toYca (0)
  478. {
  479. Header hd (displayWindow,
  480. dataWindow.isEmpty()? displayWindow: dataWindow,
  481. pixelAspectRatio,
  482. screenWindowCenter,
  483. screenWindowWidth,
  484. lineOrder,
  485. compression);
  486. insertChannels (hd, rgbaChannels);
  487. _outputFile = new OutputFile (name, hd, numThreads);
  488. if (rgbaChannels & (WRITE_Y | WRITE_C))
  489. _toYca = new ToYca (*_outputFile, rgbaChannels);
  490. }
  491. RgbaOutputFile::RgbaOutputFile (const char name[],
  492. int width,
  493. int height,
  494. RgbaChannels rgbaChannels,
  495. float pixelAspectRatio,
  496. const IMATH_NAMESPACE::V2f screenWindowCenter,
  497. float screenWindowWidth,
  498. LineOrder lineOrder,
  499. Compression compression,
  500. int numThreads):
  501. _outputFile (0),
  502. _toYca (0)
  503. {
  504. Header hd (width,
  505. height,
  506. pixelAspectRatio,
  507. screenWindowCenter,
  508. screenWindowWidth,
  509. lineOrder,
  510. compression);
  511. insertChannels (hd, rgbaChannels);
  512. _outputFile = new OutputFile (name, hd, numThreads);
  513. if (rgbaChannels & (WRITE_Y | WRITE_C))
  514. _toYca = new ToYca (*_outputFile, rgbaChannels);
  515. }
  516. RgbaOutputFile::~RgbaOutputFile ()
  517. {
  518. delete _toYca;
  519. delete _outputFile;
  520. }
  521. void
  522. RgbaOutputFile::setFrameBuffer (const Rgba *base,
  523. size_t xStride,
  524. size_t yStride)
  525. {
  526. if (_toYca)
  527. {
  528. Lock lock (*_toYca);
  529. _toYca->setFrameBuffer (base, xStride, yStride);
  530. }
  531. else
  532. {
  533. size_t xs = xStride * sizeof (Rgba);
  534. size_t ys = yStride * sizeof (Rgba);
  535. FrameBuffer fb;
  536. fb.insert ("R", Slice (HALF, (char *) &base[0].r, xs, ys));
  537. fb.insert ("G", Slice (HALF, (char *) &base[0].g, xs, ys));
  538. fb.insert ("B", Slice (HALF, (char *) &base[0].b, xs, ys));
  539. fb.insert ("A", Slice (HALF, (char *) &base[0].a, xs, ys));
  540. _outputFile->setFrameBuffer (fb);
  541. }
  542. }
  543. void
  544. RgbaOutputFile::writePixels (int numScanLines)
  545. {
  546. if (_toYca)
  547. {
  548. Lock lock (*_toYca);
  549. _toYca->writePixels (numScanLines);
  550. }
  551. else
  552. {
  553. _outputFile->writePixels (numScanLines);
  554. }
  555. }
  556. int
  557. RgbaOutputFile::currentScanLine () const
  558. {
  559. if (_toYca)
  560. {
  561. Lock lock (*_toYca);
  562. return _toYca->currentScanLine();
  563. }
  564. else
  565. {
  566. return _outputFile->currentScanLine();
  567. }
  568. }
  569. const Header &
  570. RgbaOutputFile::header () const
  571. {
  572. return _outputFile->header();
  573. }
  574. const FrameBuffer &
  575. RgbaOutputFile::frameBuffer () const
  576. {
  577. return _outputFile->frameBuffer();
  578. }
  579. const IMATH_NAMESPACE::Box2i &
  580. RgbaOutputFile::displayWindow () const
  581. {
  582. return _outputFile->header().displayWindow();
  583. }
  584. const IMATH_NAMESPACE::Box2i &
  585. RgbaOutputFile::dataWindow () const
  586. {
  587. return _outputFile->header().dataWindow();
  588. }
  589. float
  590. RgbaOutputFile::pixelAspectRatio () const
  591. {
  592. return _outputFile->header().pixelAspectRatio();
  593. }
  594. const IMATH_NAMESPACE::V2f
  595. RgbaOutputFile::screenWindowCenter () const
  596. {
  597. return _outputFile->header().screenWindowCenter();
  598. }
  599. float
  600. RgbaOutputFile::screenWindowWidth () const
  601. {
  602. return _outputFile->header().screenWindowWidth();
  603. }
  604. LineOrder
  605. RgbaOutputFile::lineOrder () const
  606. {
  607. return _outputFile->header().lineOrder();
  608. }
  609. Compression
  610. RgbaOutputFile::compression () const
  611. {
  612. return _outputFile->header().compression();
  613. }
  614. RgbaChannels
  615. RgbaOutputFile::channels () const
  616. {
  617. return rgbaChannels (_outputFile->header().channels());
  618. }
  619. void
  620. RgbaOutputFile::updatePreviewImage (const PreviewRgba newPixels[])
  621. {
  622. _outputFile->updatePreviewImage (newPixels);
  623. }
  624. void
  625. RgbaOutputFile::setYCRounding (unsigned int roundY, unsigned int roundC)
  626. {
  627. if (_toYca)
  628. {
  629. Lock lock (*_toYca);
  630. _toYca->setYCRounding (roundY, roundC);
  631. }
  632. }
  633. void
  634. RgbaOutputFile::breakScanLine (int y, int offset, int length, char c)
  635. {
  636. _outputFile->breakScanLine (y, offset, length, c);
  637. }
  638. class RgbaInputFile::FromYca: public Mutex
  639. {
  640. public:
  641. FromYca (InputFile &inputFile, RgbaChannels rgbaChannels);
  642. ~FromYca ();
  643. void setFrameBuffer (Rgba *base,
  644. size_t xStride,
  645. size_t yStride,
  646. const string &channelNamePrefix);
  647. void readPixels (int scanLine1, int scanLine2);
  648. private:
  649. void readPixels (int scanLine);
  650. void rotateBuf1 (int d);
  651. void rotateBuf2 (int d);
  652. void readYCAScanLine (int y, Rgba buf[]);
  653. void padTmpBuf ();
  654. InputFile & _inputFile;
  655. bool _readC;
  656. int _xMin;
  657. int _yMin;
  658. int _yMax;
  659. int _width;
  660. int _height;
  661. int _currentScanLine;
  662. LineOrder _lineOrder;
  663. V3f _yw;
  664. Rgba * _bufBase;
  665. Rgba * _buf1[N + 2];
  666. Rgba * _buf2[3];
  667. Rgba * _tmpBuf;
  668. Rgba * _fbBase;
  669. size_t _fbXStride;
  670. size_t _fbYStride;
  671. };
  672. RgbaInputFile::FromYca::FromYca (InputFile &inputFile,
  673. RgbaChannels rgbaChannels)
  674. :
  675. _inputFile (inputFile)
  676. {
  677. _readC = (rgbaChannels & WRITE_C)? true: false;
  678. const Box2i dw = _inputFile.header().dataWindow();
  679. _xMin = dw.min.x;
  680. _yMin = dw.min.y;
  681. _yMax = dw.max.y;
  682. _width = dw.max.x - dw.min.x + 1;
  683. _height = dw.max.y - dw.min.y + 1;
  684. _currentScanLine = dw.min.y - N - 2;
  685. _lineOrder = _inputFile.header().lineOrder();
  686. _yw = ywFromHeader (_inputFile.header());
  687. ptrdiff_t pad = cachePadding (_width * sizeof (Rgba)) / sizeof (Rgba);
  688. _bufBase = new Rgba[(_width + pad) * (N + 2 + 3)];
  689. for (int i = 0; i < N + 2; ++i)
  690. _buf1[i] = _bufBase + (i * (_width + pad));
  691. for (int i = 0; i < 3; ++i)
  692. _buf2[i] = _bufBase + ((i + N + 2) * (_width + pad));
  693. _tmpBuf = new Rgba[_width + N - 1];
  694. _fbBase = 0;
  695. _fbXStride = 0;
  696. _fbYStride = 0;
  697. }
  698. RgbaInputFile::FromYca::~FromYca ()
  699. {
  700. delete [] _bufBase;
  701. delete [] _tmpBuf;
  702. }
  703. void
  704. RgbaInputFile::FromYca::setFrameBuffer (Rgba *base,
  705. size_t xStride,
  706. size_t yStride,
  707. const string &channelNamePrefix)
  708. {
  709. if (_fbBase == 0)
  710. {
  711. FrameBuffer fb;
  712. fb.insert (channelNamePrefix + "Y",
  713. Slice (HALF, // type
  714. (char *) &_tmpBuf[N2 - _xMin].g, // base
  715. sizeof (Rgba), // xStride
  716. 0, // yStride
  717. 1, // xSampling
  718. 1, // ySampling
  719. 0.5)); // fillValue
  720. if (_readC)
  721. {
  722. fb.insert (channelNamePrefix + "RY",
  723. Slice (HALF, // type
  724. (char *) &_tmpBuf[N2 - _xMin].r, // base
  725. sizeof (Rgba) * 2, // xStride
  726. 0, // yStride
  727. 2, // xSampling
  728. 2, // ySampling
  729. 0.0)); // fillValue
  730. fb.insert (channelNamePrefix + "BY",
  731. Slice (HALF, // type
  732. (char *) &_tmpBuf[N2 - _xMin].b, // base
  733. sizeof (Rgba) * 2, // xStride
  734. 0, // yStride
  735. 2, // xSampling
  736. 2, // ySampling
  737. 0.0)); // fillValue
  738. }
  739. fb.insert (channelNamePrefix + "A",
  740. Slice (HALF, // type
  741. (char *) &_tmpBuf[N2 - _xMin].a, // base
  742. sizeof (Rgba), // xStride
  743. 0, // yStride
  744. 1, // xSampling
  745. 1, // ySampling
  746. 1.0)); // fillValue
  747. _inputFile.setFrameBuffer (fb);
  748. }
  749. _fbBase = base;
  750. _fbXStride = xStride;
  751. _fbYStride = yStride;
  752. }
  753. void
  754. RgbaInputFile::FromYca::readPixels (int scanLine1, int scanLine2)
  755. {
  756. int minY = min (scanLine1, scanLine2);
  757. int maxY = max (scanLine1, scanLine2);
  758. if (_lineOrder == INCREASING_Y)
  759. {
  760. for (int y = minY; y <= maxY; ++y)
  761. readPixels (y);
  762. }
  763. else
  764. {
  765. for (int y = maxY; y >= minY; --y)
  766. readPixels (y);
  767. }
  768. }
  769. void
  770. RgbaInputFile::FromYca::readPixels (int scanLine)
  771. {
  772. if (_fbBase == 0)
  773. {
  774. THROW (IEX_NAMESPACE::ArgExc, "No frame buffer was specified as the "
  775. "pixel data destination for image file "
  776. "\"" << _inputFile.fileName() << "\".");
  777. }
  778. //
  779. // In order to convert one scan line to RGB format, we need that
  780. // scan line plus N2+1 extra scan lines above and N2+1 scan lines
  781. // below in luminance/chroma format.
  782. //
  783. // We allow random access to scan lines, but we buffer partially
  784. // processed luminance/chroma data in order to make reading pixels
  785. // in increasing y or decreasing y order reasonably efficient:
  786. //
  787. // _currentScanLine holds the y coordinate of the scan line
  788. // that was most recently read.
  789. //
  790. // _buf1 contains scan lines _currentScanLine-N2-1
  791. // through _currentScanLine+N2+1 in
  792. // luminance/chroma format. Odd-numbered
  793. // lines contain no chroma data. Even-numbered
  794. // lines have valid chroma data for all pixels.
  795. //
  796. // _buf2 contains scan lines _currentScanLine-1
  797. // through _currentScanLine+1, in RGB format.
  798. // Super-saturated pixels (see ImfRgbaYca.h)
  799. // have not yet been eliminated.
  800. //
  801. // If the scan line we are trying to read now is close enough to
  802. // _currentScanLine, we don't have to recompute the contents of _buf1
  803. // and _buf2 from scratch. We can rotate _buf1 and _buf2, and fill
  804. // in the missing data.
  805. //
  806. int dy = scanLine - _currentScanLine;
  807. if (abs (dy) < N + 2)
  808. rotateBuf1 (dy);
  809. if (abs (dy) < 3)
  810. rotateBuf2 (dy);
  811. if (dy < 0)
  812. {
  813. {
  814. int n = min (-dy, N + 2);
  815. int yMin = scanLine - N2 - 1;
  816. for (int i = n - 1; i >= 0; --i)
  817. readYCAScanLine (yMin + i, _buf1[i]);
  818. }
  819. {
  820. int n = min (-dy, 3);
  821. for (int i = 0; i < n; ++i)
  822. {
  823. if ((scanLine + i) & 1)
  824. {
  825. YCAtoRGBA (_yw, _width, _buf1[N2 + i], _buf2[i]);
  826. }
  827. else
  828. {
  829. reconstructChromaVert (_width, _buf1 + i, _buf2[i]);
  830. YCAtoRGBA (_yw, _width, _buf2[i], _buf2[i]);
  831. }
  832. }
  833. }
  834. }
  835. else
  836. {
  837. {
  838. int n = min (dy, N + 2);
  839. int yMax = scanLine + N2 + 1;
  840. for (int i = n - 1; i >= 0; --i)
  841. readYCAScanLine (yMax - i, _buf1[N + 1 - i]);
  842. }
  843. {
  844. int n = min (dy, 3);
  845. for (int i = 2; i > 2 - n; --i)
  846. {
  847. if ((scanLine + i) & 1)
  848. {
  849. YCAtoRGBA (_yw, _width, _buf1[N2 + i], _buf2[i]);
  850. }
  851. else
  852. {
  853. reconstructChromaVert (_width, _buf1 + i, _buf2[i]);
  854. YCAtoRGBA (_yw, _width, _buf2[i], _buf2[i]);
  855. }
  856. }
  857. }
  858. }
  859. fixSaturation (_yw, _width, _buf2, _tmpBuf);
  860. for (int i = 0; i < _width; ++i)
  861. _fbBase[_fbYStride * scanLine + _fbXStride * (i + _xMin)] = _tmpBuf[i];
  862. _currentScanLine = scanLine;
  863. }
  864. void
  865. RgbaInputFile::FromYca::rotateBuf1 (int d)
  866. {
  867. d = modp (d, N + 2);
  868. Rgba *tmp[N + 2];
  869. for (int i = 0; i < N + 2; ++i)
  870. tmp[i] = _buf1[i];
  871. for (int i = 0; i < N + 2; ++i)
  872. _buf1[i] = tmp[(i + d) % (N + 2)];
  873. }
  874. void
  875. RgbaInputFile::FromYca::rotateBuf2 (int d)
  876. {
  877. d = modp (d, 3);
  878. Rgba *tmp[3];
  879. for (int i = 0; i < 3; ++i)
  880. tmp[i] = _buf2[i];
  881. for (int i = 0; i < 3; ++i)
  882. _buf2[i] = tmp[(i + d) % 3];
  883. }
  884. void
  885. RgbaInputFile::FromYca::readYCAScanLine (int y, Rgba *buf)
  886. {
  887. //
  888. // Clamp y.
  889. //
  890. if (y < _yMin)
  891. y = _yMin;
  892. else if (y > _yMax)
  893. y = _yMax - 1;
  894. //
  895. // Read scan line y into _tmpBuf.
  896. //
  897. _inputFile.readPixels (y);
  898. //
  899. // Reconstruct missing chroma samples and copy
  900. // the scan line into buf.
  901. //
  902. if (!_readC)
  903. {
  904. for (int i = 0; i < _width; ++i)
  905. {
  906. _tmpBuf[i + N2].r = 0;
  907. _tmpBuf[i + N2].b = 0;
  908. }
  909. }
  910. if (y & 1)
  911. {
  912. memcpy (buf, _tmpBuf + N2, _width * sizeof (Rgba));
  913. }
  914. else
  915. {
  916. padTmpBuf();
  917. reconstructChromaHoriz (_width, _tmpBuf, buf);
  918. }
  919. }
  920. void
  921. RgbaInputFile::FromYca::padTmpBuf ()
  922. {
  923. for (int i = 0; i < N2; ++i)
  924. {
  925. _tmpBuf[i] = _tmpBuf[N2];
  926. _tmpBuf[_width + N2 + i] = _tmpBuf[_width + N2 - 2];
  927. }
  928. }
  929. RgbaInputFile::RgbaInputFile (const char name[], int numThreads):
  930. _inputFile (new InputFile (name, numThreads)),
  931. _fromYca (0),
  932. _channelNamePrefix ("")
  933. {
  934. RgbaChannels rgbaChannels = channels();
  935. if (rgbaChannels & (WRITE_Y | WRITE_C))
  936. _fromYca = new FromYca (*_inputFile, rgbaChannels);
  937. }
  938. RgbaInputFile::RgbaInputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int numThreads):
  939. _inputFile (new InputFile (is, numThreads)),
  940. _fromYca (0),
  941. _channelNamePrefix ("")
  942. {
  943. RgbaChannels rgbaChannels = channels();
  944. if (rgbaChannels & (WRITE_Y | WRITE_C))
  945. _fromYca = new FromYca (*_inputFile, rgbaChannels);
  946. }
  947. RgbaInputFile::RgbaInputFile (const char name[],
  948. const string &layerName,
  949. int numThreads)
  950. :
  951. _inputFile (new InputFile (name, numThreads)),
  952. _fromYca (0),
  953. _channelNamePrefix (prefixFromLayerName (layerName, _inputFile->header()))
  954. {
  955. RgbaChannels rgbaChannels = channels();
  956. if (rgbaChannels & (WRITE_Y | WRITE_C))
  957. _fromYca = new FromYca (*_inputFile, rgbaChannels);
  958. }
  959. RgbaInputFile::RgbaInputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is,
  960. const string &layerName,
  961. int numThreads)
  962. :
  963. _inputFile (new InputFile (is, numThreads)),
  964. _fromYca (0),
  965. _channelNamePrefix (prefixFromLayerName (layerName, _inputFile->header()))
  966. {
  967. RgbaChannels rgbaChannels = channels();
  968. if (rgbaChannels & (WRITE_Y | WRITE_C))
  969. _fromYca = new FromYca (*_inputFile, rgbaChannels);
  970. }
  971. RgbaInputFile::~RgbaInputFile ()
  972. {
  973. delete _inputFile;
  974. delete _fromYca;
  975. }
  976. void
  977. RgbaInputFile::setFrameBuffer (Rgba *base, size_t xStride, size_t yStride)
  978. {
  979. if (_fromYca)
  980. {
  981. Lock lock (*_fromYca);
  982. _fromYca->setFrameBuffer (base, xStride, yStride, _channelNamePrefix);
  983. }
  984. else
  985. {
  986. size_t xs = xStride * sizeof (Rgba);
  987. size_t ys = yStride * sizeof (Rgba);
  988. FrameBuffer fb;
  989. fb.insert (_channelNamePrefix + "R",
  990. Slice (HALF,
  991. (char *) &base[0].r,
  992. xs, ys,
  993. 1, 1, // xSampling, ySampling
  994. 0.0)); // fillValue
  995. fb.insert (_channelNamePrefix + "G",
  996. Slice (HALF,
  997. (char *) &base[0].g,
  998. xs, ys,
  999. 1, 1, // xSampling, ySampling
  1000. 0.0)); // fillValue
  1001. fb.insert (_channelNamePrefix + "B",
  1002. Slice (HALF,
  1003. (char *) &base[0].b,
  1004. xs, ys,
  1005. 1, 1, // xSampling, ySampling
  1006. 0.0)); // fillValue
  1007. fb.insert (_channelNamePrefix + "A",
  1008. Slice (HALF,
  1009. (char *) &base[0].a,
  1010. xs, ys,
  1011. 1, 1, // xSampling, ySampling
  1012. 1.0)); // fillValue
  1013. _inputFile->setFrameBuffer (fb);
  1014. }
  1015. }
  1016. void
  1017. RgbaInputFile::setLayerName (const string &layerName)
  1018. {
  1019. delete _fromYca;
  1020. _fromYca = 0;
  1021. _channelNamePrefix = prefixFromLayerName (layerName, _inputFile->header());
  1022. RgbaChannels rgbaChannels = channels();
  1023. if (rgbaChannels & (WRITE_Y | WRITE_C))
  1024. _fromYca = new FromYca (*_inputFile, rgbaChannels);
  1025. FrameBuffer fb;
  1026. _inputFile->setFrameBuffer (fb);
  1027. }
  1028. void
  1029. RgbaInputFile::readPixels (int scanLine1, int scanLine2)
  1030. {
  1031. if (_fromYca)
  1032. {
  1033. Lock lock (*_fromYca);
  1034. _fromYca->readPixels (scanLine1, scanLine2);
  1035. }
  1036. else
  1037. {
  1038. _inputFile->readPixels (scanLine1, scanLine2);
  1039. }
  1040. }
  1041. void
  1042. RgbaInputFile::readPixels (int scanLine)
  1043. {
  1044. readPixels (scanLine, scanLine);
  1045. }
  1046. bool
  1047. RgbaInputFile::isComplete () const
  1048. {
  1049. return _inputFile->isComplete();
  1050. }
  1051. const Header &
  1052. RgbaInputFile::header () const
  1053. {
  1054. return _inputFile->header();
  1055. }
  1056. const char *
  1057. RgbaInputFile::fileName () const
  1058. {
  1059. return _inputFile->fileName();
  1060. }
  1061. const FrameBuffer &
  1062. RgbaInputFile::frameBuffer () const
  1063. {
  1064. return _inputFile->frameBuffer();
  1065. }
  1066. const IMATH_NAMESPACE::Box2i &
  1067. RgbaInputFile::displayWindow () const
  1068. {
  1069. return _inputFile->header().displayWindow();
  1070. }
  1071. const IMATH_NAMESPACE::Box2i &
  1072. RgbaInputFile::dataWindow () const
  1073. {
  1074. return _inputFile->header().dataWindow();
  1075. }
  1076. float
  1077. RgbaInputFile::pixelAspectRatio () const
  1078. {
  1079. return _inputFile->header().pixelAspectRatio();
  1080. }
  1081. const IMATH_NAMESPACE::V2f
  1082. RgbaInputFile::screenWindowCenter () const
  1083. {
  1084. return _inputFile->header().screenWindowCenter();
  1085. }
  1086. float
  1087. RgbaInputFile::screenWindowWidth () const
  1088. {
  1089. return _inputFile->header().screenWindowWidth();
  1090. }
  1091. LineOrder
  1092. RgbaInputFile::lineOrder () const
  1093. {
  1094. return _inputFile->header().lineOrder();
  1095. }
  1096. Compression
  1097. RgbaInputFile::compression () const
  1098. {
  1099. return _inputFile->header().compression();
  1100. }
  1101. RgbaChannels
  1102. RgbaInputFile::channels () const
  1103. {
  1104. return rgbaChannels (_inputFile->header().channels(), _channelNamePrefix);
  1105. }
  1106. int
  1107. RgbaInputFile::version () const
  1108. {
  1109. return _inputFile->version();
  1110. }
  1111. OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT