🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1356 lines
36 KiB

  1. //
  2. // TinyDNGWriter, single header only DNG writer in C++11.
  3. //
  4. /*
  5. The MIT License (MIT)
  6. Copyright (c) 2016 - 2020 Syoyo Fujita.
  7. Permission is hereby granted, free of charge, to any person obtaining a copy
  8. of this software and associated documentation files (the "Software"), to deal
  9. in the Software without restriction, including without limitation the rights
  10. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. copies of the Software, and to permit persons to whom the Software is
  12. furnished to do so, subject to the following conditions:
  13. The above copyright notice and this permission notice shall be included in
  14. all copies or substantial portions of the Software.
  15. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. THE SOFTWARE.
  22. */
  23. #ifndef TINY_DNG_WRITER_H_
  24. #define TINY_DNG_WRITER_H_
  25. #include <sstream>
  26. #include <vector>
  27. namespace tinydngwriter {
  28. typedef enum {
  29. TIFFTAG_SUB_FILETYPE = 254,
  30. TIFFTAG_IMAGE_WIDTH = 256,
  31. TIFFTAG_IMAGE_LENGTH = 257,
  32. TIFFTAG_BITS_PER_SAMPLE = 258,
  33. TIFFTAG_COMPRESSION = 259,
  34. TIFFTAG_PHOTOMETRIC = 262,
  35. TIFFTAG_IMAGEDESCRIPTION = 270,
  36. TIFFTAG_STRIP_OFFSET = 273,
  37. TIFFTAG_SAMPLES_PER_PIXEL = 277,
  38. TIFFTAG_ROWS_PER_STRIP = 278,
  39. TIFFTAG_STRIP_BYTE_COUNTS = 279,
  40. TIFFTAG_PLANAR_CONFIG = 284,
  41. TIFFTAG_ORIENTATION = 274,
  42. TIFFTAG_XRESOLUTION = 282, // rational
  43. TIFFTAG_YRESOLUTION = 283, // rational
  44. TIFFTAG_RESOLUTION_UNIT = 296,
  45. TIFFTAG_SAMPLEFORMAT = 339,
  46. // DNG extension
  47. TIFFTAG_CFA_REPEAT_PATTERN_DIM = 33421,
  48. TIFFTAG_CFA_PATTERN = 33422,
  49. TIFFTAG_DNG_VERSION = 50706,
  50. TIFFTAG_DNG_BACKWARD_VERSION = 50707,
  51. TIFFTAG_CHRROMA_BLUR_RADIUS = 50703,
  52. TIFFTAG_BLACK_LEVEL = 50714,
  53. TIFFTAG_WHITE_LEVEL = 50717,
  54. TIFFTAG_COLOR_MATRIX1 = 50721,
  55. TIFFTAG_COLOR_MATRIX2 = 50722,
  56. TIFFTAG_EXTRA_CAMERA_PROFILES = 50933,
  57. TIFFTAG_PROFILE_NAME = 50936,
  58. TIFFTAG_AS_SHOT_PROFILE_NAME = 50934,
  59. TIFFTAG_DEFAULT_BLACK_RENDER = 51110,
  60. TIFFTAG_ACTIVE_AREA = 50829,
  61. TIFFTAG_FORWARD_MATRIX1 = 50964,
  62. TIFFTAG_FORWARD_MATRIX2 = 50965
  63. } Tag;
  64. // SUBFILETYPE(bit field)
  65. static const int FILETYPE_REDUCEDIMAGE = 1;
  66. static const int FILETYPE_PAGE = 2;
  67. static const int FILETYPE_MASK = 4;
  68. // PLANARCONFIG
  69. static const int PLANARCONFIG_CONTIG = 1;
  70. static const int PLANARCONFIG_SEPARATE = 2;
  71. // COMPRESSION
  72. // TODO(syoyo) more compressin types.
  73. static const int COMPRESSION_NONE = 1;
  74. // ORIENTATION
  75. static const int ORIENTATION_TOPLEFT = 1;
  76. static const int ORIENTATION_TOPRIGHT = 2;
  77. static const int ORIENTATION_BOTRIGHT = 3;
  78. static const int ORIENTATION_BOTLEFT = 4;
  79. static const int ORIENTATION_LEFTTOP = 5;
  80. static const int ORIENTATION_RIGHTTOP = 6;
  81. static const int ORIENTATION_RIGHTBOT = 7;
  82. static const int ORIENTATION_LEFTBOT = 8;
  83. // RESOLUTIONUNIT
  84. static const int RESUNIT_NONE = 1;
  85. static const int RESUNIT_INCH = 2;
  86. static const int RESUNIT_CENTIMETER = 2;
  87. // PHOTOMETRIC
  88. // TODO(syoyo): more photometric types.
  89. static const int PHOTOMETRIC_WHITE_IS_ZERO = 0; // For bilevel and grayscale
  90. static const int PHOTOMETRIC_BLACK_IS_ZERO = 1; // For bilevel and grayscale
  91. static const int PHOTOMETRIC_RGB = 2; // Default
  92. static const int PHOTOMETRIC_CFA = 32893; // DNG ext
  93. static const int PHOTOMETRIC_LINEARRAW = 34892; // DNG ext
  94. // Sample format
  95. static const int SAMPLEFORMAT_UINT = 1; // Default
  96. static const int SAMPLEFORMAT_INT = 2;
  97. static const int SAMPLEFORMAT_IEEEFP = 3; // floating point
  98. struct IFDTag {
  99. unsigned short tag;
  100. unsigned short type;
  101. unsigned int count;
  102. unsigned int offset_or_value;
  103. };
  104. // 12 bytes.
  105. class DNGImage {
  106. public:
  107. DNGImage();
  108. ~DNGImage() {}
  109. ///
  110. /// Optional: Explicitly specify endian.
  111. /// Must be called before calling other Set methods.
  112. ///
  113. void SetBigEndian(bool big_endian);
  114. ///
  115. /// Default = 0
  116. ///
  117. bool SetSubfileType(bool reduced_image = false, bool page = false,
  118. bool mask = false);
  119. bool SetImageWidth(unsigned int value);
  120. bool SetImageLength(unsigned int value);
  121. bool SetRowsPerStrip(unsigned int value);
  122. bool SetSamplesPerPixel(unsigned short value);
  123. // Set bits for each samples
  124. bool SetBitsPerSample(const unsigned int num_samples,
  125. const unsigned short *values);
  126. bool SetPhotometric(unsigned short value);
  127. bool SetPlanarConfig(unsigned short value);
  128. bool SetOrientation(unsigned short value);
  129. bool SetCompression(unsigned short value);
  130. bool SetSampleFormat(const unsigned int num_samples,
  131. const unsigned short *values);
  132. bool SetXResolution(double value);
  133. bool SetYResolution(double value);
  134. bool SetResolutionUnit(const unsigned short value);
  135. bool SetImageDescription(const std::string &ascii);
  136. bool SetActiveArea(const unsigned int values[4]);
  137. bool SetChromaBlurRadius(double value);
  138. /// Specify black level per sample.
  139. bool SetBlackLevelRational(unsigned int num_samples, const double *values);
  140. /// Specify white level per sample.
  141. bool SetWhiteLevelRational(unsigned int num_samples, const double *values);
  142. /// Set image data
  143. bool SetImageData(const unsigned char *data, const size_t data_len);
  144. /// Set custom field
  145. bool SetCustomFieldLong(const unsigned short tag, const int value);
  146. bool SetCustomFieldULong(const unsigned short tag, const unsigned int value);
  147. size_t GetDataSize() const { return data_os_.str().length(); }
  148. size_t GetStripOffset() const { return data_strip_offset_; }
  149. size_t GetStripBytes() const { return data_strip_bytes_; }
  150. /// Write aux IFD data and strip image data to stream
  151. bool WriteDataToStream(std::ostream *ofs, std::string *err) const;
  152. ///
  153. /// Write IFD to stream.
  154. ///
  155. /// @param[in] data_base_offset : Byte offset to data
  156. /// @param[in] strip_offset : Byte offset to image strip data
  157. ///
  158. /// TODO(syoyo): Support multiple strips
  159. ///
  160. bool WriteIFDToStream(const unsigned int data_base_offset,
  161. const unsigned int strip_offset, std::ostream *ofs,
  162. std::string *err) const;
  163. std::string Error() const { return err_; }
  164. private:
  165. std::ostringstream data_os_;
  166. bool swap_endian_;
  167. bool dng_big_endian_;
  168. unsigned short num_fields_;
  169. unsigned int samples_per_pixels_;
  170. unsigned short bits_per_sample_;
  171. // TODO(syoyo): Support multiple strips
  172. size_t data_strip_offset_{0};
  173. size_t data_strip_bytes_{0};
  174. std::string err_; // Error message
  175. std::vector<IFDTag> ifd_tags_;
  176. };
  177. class DNGWriter {
  178. public:
  179. // TODO(syoyo): Use same endian setting with DNGImage.
  180. DNGWriter(bool big_endian);
  181. ~DNGWriter() {}
  182. ///
  183. /// Add DNGImage.
  184. /// It just retains the pointer of the image, thus
  185. /// application must not free resources until `WriteToFile` has been called.
  186. ///
  187. bool AddImage(const DNGImage *image) {
  188. images_.push_back(image);
  189. return true;
  190. }
  191. /// Write DNG to a file.
  192. /// Return error string to `err` when Write() returns false.
  193. /// Returns true upon success.
  194. bool WriteToFile(const char *filename, std::string *err) const;
  195. private:
  196. bool swap_endian_;
  197. bool dng_big_endian_; // Endianness of DNG file.
  198. std::vector<const DNGImage *> images_;
  199. };
  200. } // namespace tinydngwriter
  201. #endif // TINY_DNG_WRITER_H_
  202. #ifdef TINY_DNG_WRITER_IMPLEMENTATION
  203. //
  204. // TIFF format resources.
  205. //
  206. // http://c0de517e.blogspot.jp/2013/07/tiny-hdr-writer.html
  207. // http://paulbourke.net/dataformats/tiff/ and
  208. // http://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf
  209. //
  210. #include <algorithm>
  211. #include <cassert>
  212. #include <cfloat>
  213. #include <cmath>
  214. #include <cstdint>
  215. #include <cstdlib>
  216. #include <cstring>
  217. #include <fstream>
  218. #include <iostream>
  219. #include <sstream>
  220. namespace tinydngwriter {
  221. #ifdef __clang__
  222. #pragma clang diagnostic push
  223. #if __has_warning("-Wzero-as-null-pointer-constant")
  224. #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
  225. #endif
  226. #endif
  227. //
  228. // TinyDNGWriter stores IFD table in the end of file so that offset to
  229. // image data can be easily computed.
  230. //
  231. // +----------------------+
  232. // | header |
  233. // +----------------------+
  234. // | |
  235. // | image & meta 0 |
  236. // | |
  237. // +----------------------+
  238. // | |
  239. // | image & meta 1 |
  240. // | |
  241. // +----------------------+
  242. // ...
  243. // +----------------------+
  244. // | |
  245. // | image & meta N |
  246. // | |
  247. // +----------------------+
  248. // | |
  249. // | IFD 0 |
  250. // | |
  251. // +----------------------+
  252. // | |
  253. // | IFD 1 |
  254. // | |
  255. // +----------------------+
  256. // ...
  257. // +----------------------+
  258. // | |
  259. // | IFD 2 |
  260. // | |
  261. // +----------------------+
  262. //
  263. // From tiff.h
  264. typedef enum {
  265. TIFF_NOTYPE = 0, /* placeholder */
  266. TIFF_BYTE = 1, /* 8-bit unsigned integer */
  267. TIFF_ASCII = 2, /* 8-bit bytes w/ last byte null */
  268. TIFF_SHORT = 3, /* 16-bit unsigned integer */
  269. TIFF_LONG = 4, /* 32-bit unsigned integer */
  270. TIFF_RATIONAL = 5, /* 64-bit unsigned fraction */
  271. TIFF_SBYTE = 6, /* !8-bit signed integer */
  272. TIFF_UNDEFINED = 7, /* !8-bit untyped data */
  273. TIFF_SSHORT = 8, /* !16-bit signed integer */
  274. TIFF_SLONG = 9, /* !32-bit signed integer */
  275. TIFF_SRATIONAL = 10, /* !64-bit signed fraction */
  276. TIFF_FLOAT = 11, /* !32-bit IEEE floating point */
  277. TIFF_DOUBLE = 12, /* !64-bit IEEE floating point */
  278. TIFF_IFD = 13, /* %32-bit unsigned integer (offset) */
  279. TIFF_LONG8 = 16, /* BigTIFF 64-bit unsigned integer */
  280. TIFF_SLONG8 = 17, /* BigTIFF 64-bit signed integer */
  281. TIFF_IFD8 = 18 /* BigTIFF 64-bit unsigned integer (offset) */
  282. } DataType;
  283. const static int kHeaderSize = 8; // TIFF header size.
  284. // floating point to integer rational value conversion
  285. // https://stackoverflow.com/questions/51142275/exact-value-of-a-floating-point-number-as-a-rational
  286. //
  287. // Return error flag
  288. static int DoubleToRational(double x, double *numerator, double *denominator) {
  289. if (!std::isfinite(x)) {
  290. *numerator = *denominator = 0.0;
  291. if (x > 0.0) *numerator = 1.0;
  292. if (x < 0.0) *numerator = -1.0;
  293. return 1;
  294. }
  295. // TIFF Rational use two uint32's, so reduce the bits
  296. int bdigits = FLT_MANT_DIG;
  297. int expo;
  298. *denominator = 1.0;
  299. *numerator = std::frexp(x, &expo) * std::pow(2.0, bdigits);
  300. expo -= bdigits;
  301. if (expo > 0) {
  302. *numerator *= std::pow(2.0, expo);
  303. } else if (expo < 0) {
  304. expo = -expo;
  305. if (expo >= FLT_MAX_EXP - 1) {
  306. *numerator /= std::pow(2.0, expo - (FLT_MAX_EXP - 1));
  307. *denominator *= std::pow(2.0, FLT_MAX_EXP - 1);
  308. return fabs(*numerator) < 1.0;
  309. } else {
  310. *denominator *= std::pow(2.0, expo);
  311. }
  312. }
  313. while ((std::fabs(*numerator) > 0.0) &&
  314. (std::fabs(std::fmod(*numerator, 2)) <
  315. std::numeric_limits<double>::epsilon()) &&
  316. (std::fabs(std::fmod(*denominator, 2)) <
  317. std::numeric_limits<double>::epsilon())) {
  318. *numerator /= 2.0;
  319. *denominator /= 2.0;
  320. }
  321. return 0;
  322. }
  323. static inline bool IsBigEndian() {
  324. unsigned int i = 0x01020304;
  325. char c[4];
  326. memcpy(c, &i, 4);
  327. return (c[0] == 1);
  328. }
  329. static void swap2(unsigned short *val) {
  330. unsigned short tmp = *val;
  331. unsigned char *dst = reinterpret_cast<unsigned char *>(val);
  332. unsigned char *src = reinterpret_cast<unsigned char *>(&tmp);
  333. dst[0] = src[1];
  334. dst[1] = src[0];
  335. }
  336. static void swap4(unsigned int *val) {
  337. unsigned int tmp = *val;
  338. unsigned char *dst = reinterpret_cast<unsigned char *>(val);
  339. unsigned char *src = reinterpret_cast<unsigned char *>(&tmp);
  340. dst[0] = src[3];
  341. dst[1] = src[2];
  342. dst[2] = src[1];
  343. dst[3] = src[0];
  344. }
  345. static void swap8(uint64_t *val) {
  346. uint64_t tmp = *val;
  347. unsigned char *dst = reinterpret_cast<unsigned char *>(val);
  348. unsigned char *src = reinterpret_cast<unsigned char *>(&tmp);
  349. dst[0] = src[7];
  350. dst[1] = src[6];
  351. dst[2] = src[5];
  352. dst[3] = src[4];
  353. dst[4] = src[3];
  354. dst[5] = src[2];
  355. dst[6] = src[1];
  356. dst[7] = src[0];
  357. }
  358. static void Write1(const unsigned char c, std::ostringstream *out) {
  359. unsigned char value = c;
  360. out->write(reinterpret_cast<const char *>(&value), 1);
  361. }
  362. static void Write2(const unsigned short c, std::ostringstream *out,
  363. const bool swap_endian) {
  364. unsigned short value = c;
  365. if (swap_endian) {
  366. swap2(&value);
  367. }
  368. out->write(reinterpret_cast<const char *>(&value), 2);
  369. }
  370. static void Write4(const unsigned int c, std::ostringstream *out,
  371. const bool swap_endian) {
  372. unsigned int value = c;
  373. if (swap_endian) {
  374. swap4(&value);
  375. }
  376. out->write(reinterpret_cast<const char *>(&value), 4);
  377. }
  378. static bool WriteTIFFTag(const unsigned short tag, const unsigned short type,
  379. const unsigned int count, const unsigned char *data,
  380. std::vector<IFDTag> *tags_out,
  381. std::ostringstream *data_out) {
  382. assert(sizeof(IFDTag) ==
  383. 12); // FIXME(syoyo): Use static_assert for C++11 compiler
  384. IFDTag ifd;
  385. ifd.tag = tag;
  386. ifd.type = type;
  387. ifd.count = count;
  388. size_t typesize_table[] = {1, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8, 4};
  389. size_t len = count * (typesize_table[(type) < 14 ? (type) : 0]);
  390. if (len > 4) {
  391. assert(data_out);
  392. if (!data_out) {
  393. return false;
  394. }
  395. // Store offset value.
  396. unsigned int offset =
  397. static_cast<unsigned int>(data_out->tellp()) + kHeaderSize;
  398. ifd.offset_or_value = offset;
  399. data_out->write(reinterpret_cast<const char *>(data),
  400. static_cast<std::streamsize>(len));
  401. } else {
  402. ifd.offset_or_value = 0;
  403. // less than 4 bytes = store data itself.
  404. if (len == 1) {
  405. unsigned char value = *(data);
  406. memcpy(&(ifd.offset_or_value), &value, sizeof(unsigned char));
  407. } else if (len == 2) {
  408. unsigned short value = *(reinterpret_cast<const unsigned short *>(data));
  409. memcpy(&(ifd.offset_or_value), &value, sizeof(unsigned short));
  410. } else if (len == 4) {
  411. unsigned int value = *(reinterpret_cast<const unsigned int *>(data));
  412. ifd.offset_or_value = value;
  413. } else {
  414. assert(0);
  415. }
  416. }
  417. tags_out->push_back(ifd);
  418. return true;
  419. }
  420. static bool WriteTIFFVersionHeader(std::ostringstream *out, bool big_endian) {
  421. // TODO(syoyo): Support BigTIFF?
  422. // 4d 4d = Big endian. 49 49 = Little endian.
  423. if (big_endian) {
  424. Write1(0x4d, out);
  425. Write1(0x4d, out);
  426. Write1(0x0, out);
  427. Write1(0x2a, out); // Tiff version ID
  428. } else {
  429. Write1(0x49, out);
  430. Write1(0x49, out);
  431. Write1(0x2a, out); // Tiff version ID
  432. Write1(0x0, out);
  433. }
  434. return true;
  435. }
  436. DNGImage::DNGImage()
  437. : dng_big_endian_(true),
  438. num_fields_(0),
  439. samples_per_pixels_(0),
  440. bits_per_sample_(0),
  441. data_strip_offset_{0},
  442. data_strip_bytes_{0} {
  443. swap_endian_ = (IsBigEndian() != dng_big_endian_);
  444. }
  445. void DNGImage::SetBigEndian(bool big_endian) {
  446. dng_big_endian_ = big_endian;
  447. swap_endian_ = (IsBigEndian() != dng_big_endian_);
  448. }
  449. bool DNGImage::SetSubfileType(bool reduced_image, bool page, bool mask) {
  450. unsigned int count = 1;
  451. unsigned int bits = 0;
  452. if (reduced_image) {
  453. bits |= FILETYPE_REDUCEDIMAGE;
  454. }
  455. if (page) {
  456. bits |= FILETYPE_PAGE;
  457. }
  458. if (mask) {
  459. bits |= FILETYPE_MASK;
  460. }
  461. bool ret = WriteTIFFTag(
  462. static_cast<unsigned short>(TIFFTAG_SUB_FILETYPE), TIFF_LONG, count,
  463. reinterpret_cast<const unsigned char *>(&bits), &ifd_tags_, &data_os_);
  464. if (!ret) {
  465. return false;
  466. }
  467. num_fields_++;
  468. return true;
  469. }
  470. bool DNGImage::SetImageWidth(const unsigned int width) {
  471. unsigned int count = 1;
  472. unsigned int data = width;
  473. bool ret = WriteTIFFTag(
  474. static_cast<unsigned short>(TIFFTAG_IMAGE_WIDTH), TIFF_LONG, count,
  475. reinterpret_cast<const unsigned char *>(&data), &ifd_tags_, &data_os_);
  476. if (!ret) {
  477. return false;
  478. }
  479. num_fields_++;
  480. return true;
  481. }
  482. bool DNGImage::SetImageLength(const unsigned int length) {
  483. unsigned int count = 1;
  484. const unsigned int data = length;
  485. bool ret = WriteTIFFTag(
  486. static_cast<unsigned short>(TIFFTAG_IMAGE_LENGTH), TIFF_LONG, count,
  487. reinterpret_cast<const unsigned char *>(&data), &ifd_tags_, &data_os_);
  488. if (!ret) {
  489. return false;
  490. }
  491. num_fields_++;
  492. return true;
  493. }
  494. bool DNGImage::SetRowsPerStrip(const unsigned int rows) {
  495. if (rows == 0) {
  496. return false;
  497. }
  498. unsigned int count = 1;
  499. const unsigned int data = rows;
  500. bool ret = WriteTIFFTag(
  501. static_cast<unsigned short>(TIFFTAG_ROWS_PER_STRIP), TIFF_LONG, count,
  502. reinterpret_cast<const unsigned char *>(&data), &ifd_tags_, &data_os_);
  503. if (!ret) {
  504. return false;
  505. }
  506. num_fields_++;
  507. return true;
  508. }
  509. bool DNGImage::SetSamplesPerPixel(const unsigned short value) {
  510. if (value > 4) {
  511. return false;
  512. }
  513. unsigned int count = 1;
  514. const unsigned short data = value;
  515. bool ret = WriteTIFFTag(
  516. static_cast<unsigned short>(TIFFTAG_SAMPLES_PER_PIXEL), TIFF_SHORT, count,
  517. reinterpret_cast<const unsigned char *>(&data), &ifd_tags_, &data_os_);
  518. if (!ret) {
  519. return false;
  520. }
  521. samples_per_pixels_ = value; // Store SPP for later use.
  522. num_fields_++;
  523. return true;
  524. }
  525. bool DNGImage::SetBitsPerSample(const unsigned int num_samples,
  526. const unsigned short *values) {
  527. // `SetSamplesPerPixel()` must be called in advance and SPP shoud be equal to
  528. // `num_samples`.
  529. if ((num_samples > 0) && (num_samples == samples_per_pixels_)) {
  530. // OK
  531. } else {
  532. err_ += "SetSamplesPerPixel() must be called before SetBitsPerSample().\n";
  533. return false;
  534. }
  535. unsigned short bps = values[0];
  536. std::vector<unsigned short> vs(num_samples);
  537. for (size_t i = 0; i < vs.size(); i++) {
  538. // FIXME(syoyo): Currently bps must be same for all samples
  539. if (bps != values[i]) {
  540. err_ += "BitsPerSample must be same among samples at the moment.\n";
  541. return false;
  542. }
  543. vs[i] = values[i];
  544. // TODO(syoyo): Swap values when writing IFD tag, not here.
  545. if (swap_endian_) {
  546. swap2(&vs[i]);
  547. }
  548. }
  549. unsigned int count = num_samples;
  550. bool ret = WriteTIFFTag(static_cast<unsigned short>(TIFFTAG_BITS_PER_SAMPLE),
  551. TIFF_SHORT, count,
  552. reinterpret_cast<const unsigned char *>(vs.data()),
  553. &ifd_tags_, &data_os_);
  554. if (!ret) {
  555. return false;
  556. }
  557. // Store BPS for later use.
  558. bits_per_sample_ = bps;
  559. num_fields_++;
  560. return true;
  561. }
  562. bool DNGImage::SetPhotometric(const unsigned short value) {
  563. if ((value == PHOTOMETRIC_LINEARRAW) || (value == PHOTOMETRIC_RGB) ||
  564. (value == PHOTOMETRIC_WHITE_IS_ZERO) ||
  565. (value == PHOTOMETRIC_BLACK_IS_ZERO)) {
  566. // OK
  567. } else {
  568. return false;
  569. }
  570. unsigned int count = 1;
  571. const unsigned short data = value;
  572. bool ret = WriteTIFFTag(
  573. static_cast<unsigned short>(TIFFTAG_PHOTOMETRIC), TIFF_SHORT, count,
  574. reinterpret_cast<const unsigned char *>(&data), &ifd_tags_, &data_os_);
  575. if (!ret) {
  576. return false;
  577. }
  578. num_fields_++;
  579. return true;
  580. }
  581. bool DNGImage::SetPlanarConfig(const unsigned short value) {
  582. unsigned int count = 1;
  583. if ((value == PLANARCONFIG_CONTIG) || (value == PLANARCONFIG_SEPARATE)) {
  584. // OK
  585. } else {
  586. return false;
  587. }
  588. const unsigned short data = value;
  589. bool ret = WriteTIFFTag(
  590. static_cast<unsigned short>(TIFFTAG_PLANAR_CONFIG), TIFF_SHORT, count,
  591. reinterpret_cast<const unsigned char *>(&data), &ifd_tags_, &data_os_);
  592. if (!ret) {
  593. return false;
  594. }
  595. num_fields_++;
  596. return true;
  597. }
  598. bool DNGImage::SetCompression(const unsigned short value) {
  599. unsigned int count = 1;
  600. if ((value == COMPRESSION_NONE)) {
  601. // OK
  602. } else {
  603. return false;
  604. }
  605. const unsigned short data = value;
  606. bool ret = WriteTIFFTag(
  607. static_cast<unsigned short>(TIFFTAG_COMPRESSION), TIFF_SHORT, count,
  608. reinterpret_cast<const unsigned char *>(&data), &ifd_tags_, &data_os_);
  609. if (!ret) {
  610. return false;
  611. }
  612. num_fields_++;
  613. return true;
  614. }
  615. bool DNGImage::SetSampleFormat(const unsigned int num_samples,
  616. const unsigned short *values) {
  617. // `SetSamplesPerPixel()` must be called in advance
  618. if ((num_samples > 0) && (num_samples == samples_per_pixels_)) {
  619. // OK
  620. } else {
  621. err_ += "SetSamplesPerPixel() must be called before SetSampleFormat().\n";
  622. return false;
  623. }
  624. unsigned short format = values[0];
  625. std::vector<unsigned short> vs(num_samples);
  626. for (size_t i = 0; i < vs.size(); i++) {
  627. // FIXME(syoyo): Currently format must be same for all samples
  628. if (format != values[i]) {
  629. err_ += "SampleFormat must be same among samples at the moment.\n";
  630. return false;
  631. }
  632. if ((format == SAMPLEFORMAT_UINT) || (format == SAMPLEFORMAT_INT) ||
  633. (format == SAMPLEFORMAT_IEEEFP)) {
  634. // OK
  635. } else {
  636. err_ += "Invalid format value specified for SetSampleFormat().\n";
  637. return false;
  638. }
  639. vs[i] = values[i];
  640. // TODO(syoyo): Swap values when writing IFD tag, not here.
  641. if (swap_endian_) {
  642. swap2(&vs[i]);
  643. }
  644. }
  645. unsigned int count = num_samples;
  646. bool ret = WriteTIFFTag(static_cast<unsigned short>(TIFFTAG_SAMPLEFORMAT),
  647. TIFF_SHORT, count,
  648. reinterpret_cast<const unsigned char *>(vs.data()),
  649. &ifd_tags_, &data_os_);
  650. if (!ret) {
  651. return false;
  652. }
  653. num_fields_++;
  654. return true;
  655. }
  656. bool DNGImage::SetOrientation(const unsigned short value) {
  657. unsigned int count = 1;
  658. if ((value == ORIENTATION_TOPLEFT) || (value == ORIENTATION_TOPRIGHT) ||
  659. (value == ORIENTATION_BOTRIGHT) || (value == ORIENTATION_BOTLEFT) ||
  660. (value == ORIENTATION_LEFTTOP) || (value == ORIENTATION_RIGHTTOP) ||
  661. (value == ORIENTATION_RIGHTBOT) || (value == ORIENTATION_LEFTBOT)) {
  662. // OK
  663. } else {
  664. return false;
  665. }
  666. const unsigned int data = value;
  667. bool ret = WriteTIFFTag(
  668. static_cast<unsigned short>(TIFFTAG_ORIENTATION), TIFF_SHORT, count,
  669. reinterpret_cast<const unsigned char *>(&data), &ifd_tags_, &data_os_);
  670. if (!ret) {
  671. return false;
  672. }
  673. num_fields_++;
  674. return true;
  675. }
  676. bool DNGImage::SetBlackLevelRational(unsigned int num_samples,
  677. const double *values) {
  678. // `SetSamplesPerPixel()` must be called in advance and SPP shoud be equal to
  679. // `num_samples`.
  680. if ((num_samples > 0) && (num_samples == samples_per_pixels_)) {
  681. // OK
  682. } else {
  683. return false;
  684. }
  685. std::vector<unsigned int> vs(num_samples * 2);
  686. for (size_t i = 0; i < vs.size(); i++) {
  687. double numerator, denominator;
  688. if (DoubleToRational(values[i], &numerator, &denominator) != 0) {
  689. // Couldn't represent fp value as integer rational value.
  690. return false;
  691. }
  692. vs[2 * i + 0] = static_cast<unsigned int>(numerator);
  693. vs[2 * i + 1] = static_cast<unsigned int>(denominator);
  694. // TODO(syoyo): Swap rational value(8 bytes) when writing IFD tag, not here.
  695. if (swap_endian_) {
  696. swap4(&vs[2 * i + 0]);
  697. swap4(&vs[2 * i + 1]);
  698. }
  699. }
  700. unsigned int count = num_samples;
  701. bool ret = WriteTIFFTag(static_cast<unsigned short>(TIFFTAG_BLACK_LEVEL),
  702. TIFF_RATIONAL, count,
  703. reinterpret_cast<const unsigned char *>(vs.data()),
  704. &ifd_tags_, &data_os_);
  705. if (!ret) {
  706. return false;
  707. }
  708. num_fields_++;
  709. return true;
  710. }
  711. bool DNGImage::SetWhiteLevelRational(unsigned int num_samples,
  712. const double *values) {
  713. // `SetSamplesPerPixel()` must be called in advance and SPP shoud be equal to
  714. // `num_samples`.
  715. if ((num_samples > 0) && (num_samples == samples_per_pixels_)) {
  716. // OK
  717. } else {
  718. return false;
  719. }
  720. std::vector<unsigned int> vs(num_samples * 2);
  721. for (size_t i = 0; i < vs.size(); i++) {
  722. double numerator, denominator;
  723. if (DoubleToRational(values[i], &numerator, &denominator) != 0) {
  724. // Couldn't represent fp value as integer rational value.
  725. return false;
  726. }
  727. vs[2 * i + 0] = static_cast<unsigned int>(numerator);
  728. vs[2 * i + 1] = static_cast<unsigned int>(denominator);
  729. // TODO(syoyo): Swap rational value(8 bytes) when writing IFD tag, not here.
  730. if (swap_endian_) {
  731. swap4(&vs[2 * i + 0]);
  732. swap4(&vs[2 * i + 1]);
  733. }
  734. }
  735. unsigned int count = num_samples;
  736. bool ret = WriteTIFFTag(static_cast<unsigned short>(TIFFTAG_WHITE_LEVEL),
  737. TIFF_RATIONAL, count,
  738. reinterpret_cast<const unsigned char *>(vs.data()),
  739. &ifd_tags_, &data_os_);
  740. if (!ret) {
  741. return false;
  742. }
  743. num_fields_++;
  744. return true;
  745. }
  746. bool DNGImage::SetXResolution(const double value) {
  747. double numerator, denominator;
  748. if (DoubleToRational(value, &numerator, &denominator) != 0) {
  749. // Couldn't represent fp value as integer rational value.
  750. return false;
  751. }
  752. unsigned int data[2];
  753. data[0] = static_cast<unsigned int>(numerator);
  754. data[1] = static_cast<unsigned int>(denominator);
  755. // TODO(syoyo): Swap rational value(8 bytes) when writing IFD tag, not here.
  756. if (swap_endian_) {
  757. swap4(&data[0]);
  758. swap4(&data[1]);
  759. }
  760. bool ret = WriteTIFFTag(
  761. static_cast<unsigned short>(TIFFTAG_XRESOLUTION), TIFF_RATIONAL, 1,
  762. reinterpret_cast<const unsigned char *>(data), &ifd_tags_, &data_os_);
  763. if (!ret) {
  764. return false;
  765. }
  766. num_fields_++;
  767. return true;
  768. }
  769. bool DNGImage::SetYResolution(const double value) {
  770. double numerator, denominator;
  771. if (DoubleToRational(value, &numerator, &denominator) != 0) {
  772. // Couldn't represent fp value as integer rational value.
  773. return false;
  774. }
  775. unsigned int data[2];
  776. data[0] = static_cast<unsigned int>(numerator);
  777. data[1] = static_cast<unsigned int>(denominator);
  778. // TODO(syoyo): Swap rational value(8 bytes) when writing IFD tag, not here.
  779. if (swap_endian_) {
  780. swap4(&data[0]);
  781. swap4(&data[1]);
  782. }
  783. bool ret = WriteTIFFTag(
  784. static_cast<unsigned short>(TIFFTAG_YRESOLUTION), TIFF_RATIONAL, 1,
  785. reinterpret_cast<const unsigned char *>(data), &ifd_tags_, &data_os_);
  786. if (!ret) {
  787. return false;
  788. }
  789. num_fields_++;
  790. return true;
  791. }
  792. bool DNGImage::SetResolutionUnit(const unsigned short value) {
  793. unsigned int count = 1;
  794. if ((value == RESUNIT_NONE) || (value == RESUNIT_INCH) ||
  795. (value == RESUNIT_CENTIMETER)) {
  796. // OK
  797. } else {
  798. return false;
  799. }
  800. const unsigned short data = value;
  801. bool ret = WriteTIFFTag(
  802. static_cast<unsigned short>(TIFFTAG_RESOLUTION_UNIT), TIFF_SHORT, count,
  803. reinterpret_cast<const unsigned char *>(&data), &ifd_tags_, &data_os_);
  804. if (!ret) {
  805. return false;
  806. }
  807. num_fields_++;
  808. return true;
  809. }
  810. bool DNGImage::SetImageDescription(const std::string &ascii) {
  811. unsigned int count =
  812. static_cast<unsigned int>(ascii.length() + 1); // +1 for '\0'
  813. if (count < 2) {
  814. // empty string
  815. return false;
  816. }
  817. if (count > (1024 * 1024)) {
  818. // too large
  819. return false;
  820. }
  821. bool ret = WriteTIFFTag(static_cast<unsigned short>(TIFFTAG_IMAGEDESCRIPTION),
  822. TIFF_ASCII, count,
  823. reinterpret_cast<const unsigned char *>(ascii.data()),
  824. &ifd_tags_, &data_os_);
  825. if (!ret) {
  826. return false;
  827. }
  828. num_fields_++;
  829. return true;
  830. }
  831. bool DNGImage::SetActiveArea(const unsigned int values[4]) {
  832. unsigned int count = 4;
  833. const unsigned int *data = values;
  834. bool ret = WriteTIFFTag(
  835. static_cast<unsigned short>(TIFFTAG_ACTIVE_AREA), TIFF_LONG, count,
  836. reinterpret_cast<const unsigned char *>(data), &ifd_tags_, &data_os_);
  837. if (!ret) {
  838. return false;
  839. }
  840. num_fields_++;
  841. return true;
  842. }
  843. bool DNGImage::SetImageData(const unsigned char *data, const size_t data_len) {
  844. if ((data == NULL) || (data_len < 1)) {
  845. return false;
  846. }
  847. data_strip_offset_ = size_t(data_os_.tellp());
  848. data_strip_bytes_ = data_len;
  849. data_os_.write(reinterpret_cast<const char *>(data),
  850. static_cast<std::streamsize>(data_len));
  851. // NOTE: STRIP_OFFSET tag will be written at `WriteIFDToStream()`.
  852. {
  853. unsigned int count = 1;
  854. unsigned int bytes = static_cast<unsigned int>(data_len);
  855. bool ret = WriteTIFFTag(
  856. static_cast<unsigned short>(TIFFTAG_STRIP_BYTE_COUNTS), TIFF_LONG,
  857. count, reinterpret_cast<const unsigned char *>(&bytes), &ifd_tags_,
  858. NULL);
  859. if (!ret) {
  860. return false;
  861. }
  862. num_fields_++;
  863. }
  864. return true;
  865. }
  866. bool DNGImage::SetCustomFieldLong(const unsigned short tag, const int value) {
  867. unsigned int count = 1;
  868. // TODO(syoyo): Check if `tag` value does not conflict with existing TIFF tag
  869. // value.
  870. bool ret = WriteTIFFTag(tag, TIFF_SLONG, count,
  871. reinterpret_cast<const unsigned char *>(&value),
  872. &ifd_tags_, &data_os_);
  873. if (!ret) {
  874. return false;
  875. }
  876. num_fields_++;
  877. return true;
  878. }
  879. bool DNGImage::SetCustomFieldULong(const unsigned short tag,
  880. const unsigned int value) {
  881. unsigned int count = 1;
  882. // TODO(syoyo): Check if `tag` value does not conflict with existing TIFF tag
  883. // value.
  884. bool ret = WriteTIFFTag(tag, TIFF_LONG, count,
  885. reinterpret_cast<const unsigned char *>(&value),
  886. &ifd_tags_, &data_os_);
  887. if (!ret) {
  888. return false;
  889. }
  890. num_fields_++;
  891. return true;
  892. }
  893. static bool IFDComparator(const IFDTag &a, const IFDTag &b) {
  894. return (a.tag < b.tag);
  895. }
  896. bool DNGImage::WriteDataToStream(std::ostream *ofs, std::string *err) const {
  897. if ((data_os_.str().length() == 0)) {
  898. if (err) {
  899. (*err) += "Empty IFD data and image data.\n";
  900. }
  901. return false;
  902. }
  903. if ((bits_per_sample_ == 0) || (samples_per_pixels_ == 0)) {
  904. if (err) {
  905. (*err) += "Both BitsPerSample and SamplesPerPixels must be set.\n";
  906. }
  907. return false;
  908. }
  909. std::vector<uint8_t> data(data_os_.str().length());
  910. memcpy(data.data(), data_os_.str().data(), data.size());
  911. if (data_strip_bytes_ == 0) {
  912. // May ok?.
  913. } else {
  914. // FIXME(syoyo): Assume all channels use sample bps
  915. // We may need to swap endian for pixel data.
  916. if (swap_endian_) {
  917. if (bits_per_sample_ == 16) {
  918. size_t n = data_strip_bytes_ / sizeof(uint16_t);
  919. uint16_t *ptr =
  920. reinterpret_cast<uint16_t *>(data.data() + data_strip_offset_);
  921. for (size_t i = 0; i < n; i++) {
  922. swap2(&ptr[i]);
  923. }
  924. } else if (bits_per_sample_ == 32) {
  925. size_t n = data_strip_bytes_ / sizeof(uint32_t);
  926. uint32_t *ptr =
  927. reinterpret_cast<uint32_t *>(data.data() + data_strip_offset_);
  928. for (size_t i = 0; i < n; i++) {
  929. swap4(&ptr[i]);
  930. }
  931. } else if (bits_per_sample_ == 64) {
  932. size_t n = data_strip_bytes_ / sizeof(uint64_t);
  933. uint64_t *ptr =
  934. reinterpret_cast<uint64_t *>(data.data() + data_strip_offset_);
  935. for (size_t i = 0; i < n; i++) {
  936. swap8(&ptr[i]);
  937. }
  938. }
  939. }
  940. }
  941. ofs->write(reinterpret_cast<const char *>(data.data()),
  942. static_cast<std::streamsize>(data.size()));
  943. return true;
  944. }
  945. bool DNGImage::WriteIFDToStream(const unsigned int data_base_offset,
  946. const unsigned int strip_offset,
  947. std::ostream *ofs, std::string *err) const {
  948. if ((num_fields_ == 0) || (ifd_tags_.size() < 1)) {
  949. if (err) {
  950. (*err) += "No TIFF Tags.\n";
  951. }
  952. return false;
  953. }
  954. // add STRIP_OFFSET tag and sort IFD tags.
  955. std::vector<IFDTag> tags = ifd_tags_;
  956. {
  957. // For STRIP_OFFSET we need the actual offset value to data(image),
  958. // thus write STRIP_OFFSET here.
  959. unsigned int offset = strip_offset + kHeaderSize;
  960. IFDTag ifd;
  961. ifd.tag = TIFFTAG_STRIP_OFFSET;
  962. ifd.type = TIFF_LONG;
  963. ifd.count = 1;
  964. ifd.offset_or_value = offset;
  965. tags.push_back(ifd);
  966. }
  967. // TIFF expects IFD tags are sorted.
  968. std::sort(tags.begin(), tags.end(), IFDComparator);
  969. std::ostringstream ifd_os;
  970. unsigned short num_fields = static_cast<unsigned short>(tags.size());
  971. Write2(num_fields, &ifd_os, swap_endian_);
  972. {
  973. size_t typesize_table[] = {1, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8, 4};
  974. for (size_t i = 0; i < tags.size(); i++) {
  975. const IFDTag &ifd = tags[i];
  976. Write2(ifd.tag, &ifd_os, swap_endian_);
  977. Write2(ifd.type, &ifd_os, swap_endian_);
  978. Write4(ifd.count, &ifd_os, swap_endian_);
  979. size_t len =
  980. ifd.count * (typesize_table[(ifd.type) < 14 ? (ifd.type) : 0]);
  981. if (len > 4) {
  982. // Store offset value.
  983. unsigned int ifd_offt = ifd.offset_or_value + data_base_offset;
  984. Write4(ifd_offt, &ifd_os, swap_endian_);
  985. } else {
  986. // less than 4 bytes = store data itself.
  987. if (len == 1) {
  988. const unsigned char value =
  989. *(reinterpret_cast<const unsigned char *>(&ifd.offset_or_value));
  990. Write1(value, &ifd_os);
  991. unsigned char pad = 0;
  992. Write1(pad, &ifd_os);
  993. Write1(pad, &ifd_os);
  994. Write1(pad, &ifd_os);
  995. } else if (len == 2) {
  996. const unsigned short value =
  997. *(reinterpret_cast<const unsigned short *>(&ifd.offset_or_value));
  998. Write2(value, &ifd_os, swap_endian_);
  999. const unsigned short pad = 0;
  1000. Write2(pad, &ifd_os, swap_endian_);
  1001. } else if (len == 4) {
  1002. const unsigned int value =
  1003. *(reinterpret_cast<const unsigned int *>(&ifd.offset_or_value));
  1004. Write4(value, &ifd_os, swap_endian_);
  1005. } else {
  1006. assert(0);
  1007. }
  1008. }
  1009. }
  1010. ofs->write(ifd_os.str().c_str(),
  1011. static_cast<std::streamsize>(ifd_os.str().length()));
  1012. }
  1013. return true;
  1014. }
  1015. // -------------------------------------------
  1016. DNGWriter::DNGWriter(bool big_endian) : dng_big_endian_(big_endian) {
  1017. swap_endian_ = (IsBigEndian() != dng_big_endian_);
  1018. }
  1019. bool DNGWriter::WriteToFile(const char *filename, std::string *err) const {
  1020. std::ofstream ofs(filename, std::ostream::binary);
  1021. if (!ofs) {
  1022. if (err) {
  1023. (*err) = "Failed to open file.\n";
  1024. }
  1025. return false;
  1026. }
  1027. std::ostringstream header;
  1028. bool ret = WriteTIFFVersionHeader(&header, dng_big_endian_);
  1029. if (!ret) {
  1030. return false;
  1031. }
  1032. if (images_.size() == 0) {
  1033. if (err) {
  1034. (*err) = "No image added for writing.\n";
  1035. }
  1036. return false;
  1037. }
  1038. // 1. Compute offset and data size(exclude TIFF header bytes)
  1039. size_t data_len = 0;
  1040. size_t strip_offset = 0;
  1041. std::vector<size_t> data_offset_table;
  1042. std::vector<size_t> strip_offset_table;
  1043. for (size_t i = 0; i < images_.size(); i++) {
  1044. strip_offset = data_len + images_[i]->GetStripOffset();
  1045. data_offset_table.push_back(data_len);
  1046. strip_offset_table.push_back(strip_offset);
  1047. data_len += images_[i]->GetDataSize();
  1048. }
  1049. // 2. Write offset to ifd table.
  1050. const unsigned int ifd_offset =
  1051. kHeaderSize + static_cast<unsigned int>(data_len);
  1052. Write4(ifd_offset, &header, swap_endian_);
  1053. assert(header.str().length() == 8);
  1054. // std::cout << "ifd_offset " << ifd_offset << std::endl;
  1055. // std::cout << "data_len " << data_os_.str().length() << std::endl;
  1056. // std::cout << "ifd_len " << ifd_os_.str().length() << std::endl;
  1057. // std::cout << "swap endian " << swap_endian_ << std::endl;
  1058. // 3. Write header
  1059. ofs.write(header.str().c_str(),
  1060. static_cast<std::streamsize>(header.str().length()));
  1061. // 4. Write image and meta data
  1062. // TODO(syoyo): Write IFD first, then image/meta data
  1063. for (size_t i = 0; i < images_.size(); i++) {
  1064. bool ok = images_[i]->WriteDataToStream(&ofs, err);
  1065. if (!ok) {
  1066. return false;
  1067. }
  1068. }
  1069. // 5. Write IFD entries;
  1070. for (size_t i = 0; i < images_.size(); i++) {
  1071. bool ok = images_[i]->WriteIFDToStream(
  1072. static_cast<unsigned int>(data_offset_table[i]),
  1073. static_cast<unsigned int>(strip_offset_table[i]), &ofs, err);
  1074. if (!ok) {
  1075. return false;
  1076. }
  1077. unsigned int next_ifd_offset =
  1078. static_cast<unsigned int>(ofs.tellp()) + sizeof(unsigned int);
  1079. if (i == (images_.size() - 1)) {
  1080. // Write zero as IFD offset(= end of data)
  1081. next_ifd_offset = 0;
  1082. }
  1083. if (swap_endian_) {
  1084. swap4(&next_ifd_offset);
  1085. }
  1086. ofs.write(reinterpret_cast<const char *>(&next_ifd_offset), 4);
  1087. }
  1088. return true;
  1089. }
  1090. #ifdef __clang__
  1091. #pragma clang diagnostic pop
  1092. #endif
  1093. } // namespace tinydngwriter
  1094. #endif // TINY_DNG_WRITER_IMPLEMENTATION