diff options
Diffstat (limited to 'graphics/asymptote/cudareflect/tinyexr/examples/exr2fptiff/tiny_dng_writer.h')
-rw-r--r-- | graphics/asymptote/cudareflect/tinyexr/examples/exr2fptiff/tiny_dng_writer.h | 1356 |
1 files changed, 0 insertions, 1356 deletions
diff --git a/graphics/asymptote/cudareflect/tinyexr/examples/exr2fptiff/tiny_dng_writer.h b/graphics/asymptote/cudareflect/tinyexr/examples/exr2fptiff/tiny_dng_writer.h deleted file mode 100644 index 6156821f3c..0000000000 --- a/graphics/asymptote/cudareflect/tinyexr/examples/exr2fptiff/tiny_dng_writer.h +++ /dev/null @@ -1,1356 +0,0 @@ -// -// TinyDNGWriter, single header only DNG writer in C++11. -// - -/* -The MIT License (MIT) - -Copyright (c) 2016 - 2020 Syoyo Fujita. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#ifndef TINY_DNG_WRITER_H_ -#define TINY_DNG_WRITER_H_ - -#include <sstream> -#include <vector> - -namespace tinydngwriter { - -typedef enum { - TIFFTAG_SUB_FILETYPE = 254, - TIFFTAG_IMAGE_WIDTH = 256, - TIFFTAG_IMAGE_LENGTH = 257, - TIFFTAG_BITS_PER_SAMPLE = 258, - TIFFTAG_COMPRESSION = 259, - TIFFTAG_PHOTOMETRIC = 262, - TIFFTAG_IMAGEDESCRIPTION = 270, - TIFFTAG_STRIP_OFFSET = 273, - TIFFTAG_SAMPLES_PER_PIXEL = 277, - TIFFTAG_ROWS_PER_STRIP = 278, - TIFFTAG_STRIP_BYTE_COUNTS = 279, - TIFFTAG_PLANAR_CONFIG = 284, - TIFFTAG_ORIENTATION = 274, - - TIFFTAG_XRESOLUTION = 282, // rational - TIFFTAG_YRESOLUTION = 283, // rational - TIFFTAG_RESOLUTION_UNIT = 296, - - TIFFTAG_SAMPLEFORMAT = 339, - - // DNG extension - TIFFTAG_CFA_REPEAT_PATTERN_DIM = 33421, - TIFFTAG_CFA_PATTERN = 33422, - - TIFFTAG_DNG_VERSION = 50706, - TIFFTAG_DNG_BACKWARD_VERSION = 50707, - TIFFTAG_CHRROMA_BLUR_RADIUS = 50703, - TIFFTAG_BLACK_LEVEL = 50714, - TIFFTAG_WHITE_LEVEL = 50717, - TIFFTAG_COLOR_MATRIX1 = 50721, - TIFFTAG_COLOR_MATRIX2 = 50722, - TIFFTAG_EXTRA_CAMERA_PROFILES = 50933, - TIFFTAG_PROFILE_NAME = 50936, - TIFFTAG_AS_SHOT_PROFILE_NAME = 50934, - TIFFTAG_DEFAULT_BLACK_RENDER = 51110, - TIFFTAG_ACTIVE_AREA = 50829, - TIFFTAG_FORWARD_MATRIX1 = 50964, - TIFFTAG_FORWARD_MATRIX2 = 50965 -} Tag; - -// SUBFILETYPE(bit field) -static const int FILETYPE_REDUCEDIMAGE = 1; -static const int FILETYPE_PAGE = 2; -static const int FILETYPE_MASK = 4; - -// PLANARCONFIG -static const int PLANARCONFIG_CONTIG = 1; -static const int PLANARCONFIG_SEPARATE = 2; - -// COMPRESSION -// TODO(syoyo) more compressin types. -static const int COMPRESSION_NONE = 1; - -// ORIENTATION -static const int ORIENTATION_TOPLEFT = 1; -static const int ORIENTATION_TOPRIGHT = 2; -static const int ORIENTATION_BOTRIGHT = 3; -static const int ORIENTATION_BOTLEFT = 4; -static const int ORIENTATION_LEFTTOP = 5; -static const int ORIENTATION_RIGHTTOP = 6; -static const int ORIENTATION_RIGHTBOT = 7; -static const int ORIENTATION_LEFTBOT = 8; - -// RESOLUTIONUNIT -static const int RESUNIT_NONE = 1; -static const int RESUNIT_INCH = 2; -static const int RESUNIT_CENTIMETER = 2; - -// PHOTOMETRIC -// TODO(syoyo): more photometric types. -static const int PHOTOMETRIC_WHITE_IS_ZERO = 0; // For bilevel and grayscale -static const int PHOTOMETRIC_BLACK_IS_ZERO = 1; // For bilevel and grayscale -static const int PHOTOMETRIC_RGB = 2; // Default -static const int PHOTOMETRIC_CFA = 32893; // DNG ext -static const int PHOTOMETRIC_LINEARRAW = 34892; // DNG ext - -// Sample format -static const int SAMPLEFORMAT_UINT = 1; // Default -static const int SAMPLEFORMAT_INT = 2; -static const int SAMPLEFORMAT_IEEEFP = 3; // floating point - -struct IFDTag { - unsigned short tag; - unsigned short type; - unsigned int count; - unsigned int offset_or_value; -}; -// 12 bytes. - -class DNGImage { - public: - DNGImage(); - ~DNGImage() {} - - /// - /// Optional: Explicitly specify endian. - /// Must be called before calling other Set methods. - /// - void SetBigEndian(bool big_endian); - - /// - /// Default = 0 - /// - bool SetSubfileType(bool reduced_image = false, bool page = false, - bool mask = false); - - bool SetImageWidth(unsigned int value); - bool SetImageLength(unsigned int value); - bool SetRowsPerStrip(unsigned int value); - bool SetSamplesPerPixel(unsigned short value); - // Set bits for each samples - bool SetBitsPerSample(const unsigned int num_samples, - const unsigned short *values); - bool SetPhotometric(unsigned short value); - bool SetPlanarConfig(unsigned short value); - bool SetOrientation(unsigned short value); - bool SetCompression(unsigned short value); - bool SetSampleFormat(const unsigned int num_samples, - const unsigned short *values); - bool SetXResolution(double value); - bool SetYResolution(double value); - bool SetResolutionUnit(const unsigned short value); - - bool SetImageDescription(const std::string &ascii); - - bool SetActiveArea(const unsigned int values[4]); - - bool SetChromaBlurRadius(double value); - - /// Specify black level per sample. - bool SetBlackLevelRational(unsigned int num_samples, const double *values); - - /// Specify white level per sample. - bool SetWhiteLevelRational(unsigned int num_samples, const double *values); - - /// Set image data - bool SetImageData(const unsigned char *data, const size_t data_len); - - /// Set custom field - bool SetCustomFieldLong(const unsigned short tag, const int value); - bool SetCustomFieldULong(const unsigned short tag, const unsigned int value); - - size_t GetDataSize() const { return data_os_.str().length(); } - - size_t GetStripOffset() const { return data_strip_offset_; } - size_t GetStripBytes() const { return data_strip_bytes_; } - - /// Write aux IFD data and strip image data to stream - bool WriteDataToStream(std::ostream *ofs, std::string *err) const; - - /// - /// Write IFD to stream. - /// - /// @param[in] data_base_offset : Byte offset to data - /// @param[in] strip_offset : Byte offset to image strip data - /// - /// TODO(syoyo): Support multiple strips - /// - bool WriteIFDToStream(const unsigned int data_base_offset, - const unsigned int strip_offset, std::ostream *ofs, - std::string *err) const; - - std::string Error() const { return err_; } - - private: - std::ostringstream data_os_; - bool swap_endian_; - bool dng_big_endian_; - unsigned short num_fields_; - unsigned int samples_per_pixels_; - unsigned short bits_per_sample_; - - // TODO(syoyo): Support multiple strips - size_t data_strip_offset_{0}; - size_t data_strip_bytes_{0}; - - std::string err_; // Error message - - std::vector<IFDTag> ifd_tags_; -}; - -class DNGWriter { - public: - // TODO(syoyo): Use same endian setting with DNGImage. - DNGWriter(bool big_endian); - ~DNGWriter() {} - - /// - /// Add DNGImage. - /// It just retains the pointer of the image, thus - /// application must not free resources until `WriteToFile` has been called. - /// - bool AddImage(const DNGImage *image) { - images_.push_back(image); - - return true; - } - - /// Write DNG to a file. - /// Return error string to `err` when Write() returns false. - /// Returns true upon success. - bool WriteToFile(const char *filename, std::string *err) const; - - private: - bool swap_endian_; - bool dng_big_endian_; // Endianness of DNG file. - - std::vector<const DNGImage *> images_; -}; - -} // namespace tinydngwriter - -#endif // TINY_DNG_WRITER_H_ - -#ifdef TINY_DNG_WRITER_IMPLEMENTATION - -// -// TIFF format resources. -// -// http://c0de517e.blogspot.jp/2013/07/tiny-hdr-writer.html -// http://paulbourke.net/dataformats/tiff/ and -// http://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf -// - -#include <algorithm> -#include <cassert> -#include <cfloat> -#include <cmath> -#include <cstdint> -#include <cstdlib> -#include <cstring> -#include <fstream> -#include <iostream> -#include <sstream> - -namespace tinydngwriter { - -#ifdef __clang__ -#pragma clang diagnostic push -#if __has_warning("-Wzero-as-null-pointer-constant") -#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" -#endif -#endif - -// -// TinyDNGWriter stores IFD table in the end of file so that offset to -// image data can be easily computed. -// -// +----------------------+ -// | header | -// +----------------------+ -// | | -// | image & meta 0 | -// | | -// +----------------------+ -// | | -// | image & meta 1 | -// | | -// +----------------------+ -// ... -// +----------------------+ -// | | -// | image & meta N | -// | | -// +----------------------+ -// | | -// | IFD 0 | -// | | -// +----------------------+ -// | | -// | IFD 1 | -// | | -// +----------------------+ -// ... -// +----------------------+ -// | | -// | IFD 2 | -// | | -// +----------------------+ -// - -// From tiff.h -typedef enum { - TIFF_NOTYPE = 0, /* placeholder */ - TIFF_BYTE = 1, /* 8-bit unsigned integer */ - TIFF_ASCII = 2, /* 8-bit bytes w/ last byte null */ - TIFF_SHORT = 3, /* 16-bit unsigned integer */ - TIFF_LONG = 4, /* 32-bit unsigned integer */ - TIFF_RATIONAL = 5, /* 64-bit unsigned fraction */ - TIFF_SBYTE = 6, /* !8-bit signed integer */ - TIFF_UNDEFINED = 7, /* !8-bit untyped data */ - TIFF_SSHORT = 8, /* !16-bit signed integer */ - TIFF_SLONG = 9, /* !32-bit signed integer */ - TIFF_SRATIONAL = 10, /* !64-bit signed fraction */ - TIFF_FLOAT = 11, /* !32-bit IEEE floating point */ - TIFF_DOUBLE = 12, /* !64-bit IEEE floating point */ - TIFF_IFD = 13, /* %32-bit unsigned integer (offset) */ - TIFF_LONG8 = 16, /* BigTIFF 64-bit unsigned integer */ - TIFF_SLONG8 = 17, /* BigTIFF 64-bit signed integer */ - TIFF_IFD8 = 18 /* BigTIFF 64-bit unsigned integer (offset) */ -} DataType; - -const static int kHeaderSize = 8; // TIFF header size. - -// floating point to integer rational value conversion -// https://stackoverflow.com/questions/51142275/exact-value-of-a-floating-point-number-as-a-rational -// -// Return error flag -static int DoubleToRational(double x, double *numerator, double *denominator) { - if (!std::isfinite(x)) { - *numerator = *denominator = 0.0; - if (x > 0.0) *numerator = 1.0; - if (x < 0.0) *numerator = -1.0; - return 1; - } - - // TIFF Rational use two uint32's, so reduce the bits - int bdigits = FLT_MANT_DIG; - int expo; - *denominator = 1.0; - *numerator = std::frexp(x, &expo) * std::pow(2.0, bdigits); - expo -= bdigits; - if (expo > 0) { - *numerator *= std::pow(2.0, expo); - } else if (expo < 0) { - expo = -expo; - if (expo >= FLT_MAX_EXP - 1) { - *numerator /= std::pow(2.0, expo - (FLT_MAX_EXP - 1)); - *denominator *= std::pow(2.0, FLT_MAX_EXP - 1); - return fabs(*numerator) < 1.0; - } else { - *denominator *= std::pow(2.0, expo); - } - } - - while ((std::fabs(*numerator) > 0.0) && - (std::fabs(std::fmod(*numerator, 2)) < - std::numeric_limits<double>::epsilon()) && - (std::fabs(std::fmod(*denominator, 2)) < - std::numeric_limits<double>::epsilon())) { - *numerator /= 2.0; - *denominator /= 2.0; - } - return 0; -} - -static inline bool IsBigEndian() { - unsigned int i = 0x01020304; - char c[4]; - memcpy(c, &i, 4); - return (c[0] == 1); -} - -static void swap2(unsigned short *val) { - unsigned short tmp = *val; - unsigned char *dst = reinterpret_cast<unsigned char *>(val); - unsigned char *src = reinterpret_cast<unsigned char *>(&tmp); - - dst[0] = src[1]; - dst[1] = src[0]; -} - -static void swap4(unsigned int *val) { - unsigned int tmp = *val; - unsigned char *dst = reinterpret_cast<unsigned char *>(val); - unsigned char *src = reinterpret_cast<unsigned char *>(&tmp); - - dst[0] = src[3]; - dst[1] = src[2]; - dst[2] = src[1]; - dst[3] = src[0]; -} - -static void swap8(uint64_t *val) { - uint64_t tmp = *val; - unsigned char *dst = reinterpret_cast<unsigned char *>(val); - unsigned char *src = reinterpret_cast<unsigned char *>(&tmp); - - dst[0] = src[7]; - dst[1] = src[6]; - dst[2] = src[5]; - dst[3] = src[4]; - dst[4] = src[3]; - dst[5] = src[2]; - dst[6] = src[1]; - dst[7] = src[0]; -} - -static void Write1(const unsigned char c, std::ostringstream *out) { - unsigned char value = c; - out->write(reinterpret_cast<const char *>(&value), 1); -} - -static void Write2(const unsigned short c, std::ostringstream *out, - const bool swap_endian) { - unsigned short value = c; - if (swap_endian) { - swap2(&value); - } - - out->write(reinterpret_cast<const char *>(&value), 2); -} - -static void Write4(const unsigned int c, std::ostringstream *out, - const bool swap_endian) { - unsigned int value = c; - if (swap_endian) { - swap4(&value); - } - - out->write(reinterpret_cast<const char *>(&value), 4); -} - -static bool WriteTIFFTag(const unsigned short tag, const unsigned short type, - const unsigned int count, const unsigned char *data, - std::vector<IFDTag> *tags_out, - std::ostringstream *data_out) { - assert(sizeof(IFDTag) == - 12); // FIXME(syoyo): Use static_assert for C++11 compiler - - IFDTag ifd; - ifd.tag = tag; - ifd.type = type; - ifd.count = count; - - size_t typesize_table[] = {1, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8, 4}; - - size_t len = count * (typesize_table[(type) < 14 ? (type) : 0]); - if (len > 4) { - assert(data_out); - if (!data_out) { - return false; - } - - // Store offset value. - - unsigned int offset = - static_cast<unsigned int>(data_out->tellp()) + kHeaderSize; - ifd.offset_or_value = offset; - - data_out->write(reinterpret_cast<const char *>(data), - static_cast<std::streamsize>(len)); - - } else { - ifd.offset_or_value = 0; - - // less than 4 bytes = store data itself. - if (len == 1) { - unsigned char value = *(data); - memcpy(&(ifd.offset_or_value), &value, sizeof(unsigned char)); - } else if (len == 2) { - unsigned short value = *(reinterpret_cast<const unsigned short *>(data)); - memcpy(&(ifd.offset_or_value), &value, sizeof(unsigned short)); - } else if (len == 4) { - unsigned int value = *(reinterpret_cast<const unsigned int *>(data)); - ifd.offset_or_value = value; - } else { - assert(0); - } - } - - tags_out->push_back(ifd); - - return true; -} - -static bool WriteTIFFVersionHeader(std::ostringstream *out, bool big_endian) { - // TODO(syoyo): Support BigTIFF? - - // 4d 4d = Big endian. 49 49 = Little endian. - if (big_endian) { - Write1(0x4d, out); - Write1(0x4d, out); - Write1(0x0, out); - Write1(0x2a, out); // Tiff version ID - } else { - Write1(0x49, out); - Write1(0x49, out); - Write1(0x2a, out); // Tiff version ID - Write1(0x0, out); - } - - return true; -} - -DNGImage::DNGImage() - : dng_big_endian_(true), - num_fields_(0), - samples_per_pixels_(0), - bits_per_sample_(0), - data_strip_offset_{0}, - data_strip_bytes_{0} { - swap_endian_ = (IsBigEndian() != dng_big_endian_); -} - -void DNGImage::SetBigEndian(bool big_endian) { - dng_big_endian_ = big_endian; - swap_endian_ = (IsBigEndian() != dng_big_endian_); -} - -bool DNGImage::SetSubfileType(bool reduced_image, bool page, bool mask) { - unsigned int count = 1; - - unsigned int bits = 0; - if (reduced_image) { - bits |= FILETYPE_REDUCEDIMAGE; - } - if (page) { - bits |= FILETYPE_PAGE; - } - if (mask) { - bits |= FILETYPE_MASK; - } - - bool ret = WriteTIFFTag( - static_cast<unsigned short>(TIFFTAG_SUB_FILETYPE), TIFF_LONG, count, - reinterpret_cast<const unsigned char *>(&bits), &ifd_tags_, &data_os_); - - if (!ret) { - return false; - } - - num_fields_++; - return true; -} - -bool DNGImage::SetImageWidth(const unsigned int width) { - unsigned int count = 1; - - unsigned int data = width; - bool ret = WriteTIFFTag( - static_cast<unsigned short>(TIFFTAG_IMAGE_WIDTH), TIFF_LONG, count, - reinterpret_cast<const unsigned char *>(&data), &ifd_tags_, &data_os_); - - if (!ret) { - return false; - } - - num_fields_++; - return true; -} - -bool DNGImage::SetImageLength(const unsigned int length) { - unsigned int count = 1; - - const unsigned int data = length; - bool ret = WriteTIFFTag( - static_cast<unsigned short>(TIFFTAG_IMAGE_LENGTH), TIFF_LONG, count, - reinterpret_cast<const unsigned char *>(&data), &ifd_tags_, &data_os_); - - if (!ret) { - return false; - } - - num_fields_++; - return true; -} - -bool DNGImage::SetRowsPerStrip(const unsigned int rows) { - if (rows == 0) { - return false; - } - - unsigned int count = 1; - - const unsigned int data = rows; - bool ret = WriteTIFFTag( - static_cast<unsigned short>(TIFFTAG_ROWS_PER_STRIP), TIFF_LONG, count, - reinterpret_cast<const unsigned char *>(&data), &ifd_tags_, &data_os_); - - if (!ret) { - return false; - } - - num_fields_++; - return true; -} - -bool DNGImage::SetSamplesPerPixel(const unsigned short value) { - if (value > 4) { - return false; - } - - unsigned int count = 1; - - const unsigned short data = value; - bool ret = WriteTIFFTag( - static_cast<unsigned short>(TIFFTAG_SAMPLES_PER_PIXEL), TIFF_SHORT, count, - reinterpret_cast<const unsigned char *>(&data), &ifd_tags_, &data_os_); - - if (!ret) { - return false; - } - - samples_per_pixels_ = value; // Store SPP for later use. - - num_fields_++; - return true; -} - -bool DNGImage::SetBitsPerSample(const unsigned int num_samples, - const unsigned short *values) { - // `SetSamplesPerPixel()` must be called in advance and SPP shoud be equal to - // `num_samples`. - if ((num_samples > 0) && (num_samples == samples_per_pixels_)) { - // OK - } else { - err_ += "SetSamplesPerPixel() must be called before SetBitsPerSample().\n"; - return false; - } - - unsigned short bps = values[0]; - - std::vector<unsigned short> vs(num_samples); - for (size_t i = 0; i < vs.size(); i++) { - // FIXME(syoyo): Currently bps must be same for all samples - if (bps != values[i]) { - err_ += "BitsPerSample must be same among samples at the moment.\n"; - return false; - } - - vs[i] = values[i]; - - // TODO(syoyo): Swap values when writing IFD tag, not here. - if (swap_endian_) { - swap2(&vs[i]); - } - } - - unsigned int count = num_samples; - - bool ret = WriteTIFFTag(static_cast<unsigned short>(TIFFTAG_BITS_PER_SAMPLE), - TIFF_SHORT, count, - reinterpret_cast<const unsigned char *>(vs.data()), - &ifd_tags_, &data_os_); - - if (!ret) { - return false; - } - - // Store BPS for later use. - bits_per_sample_ = bps; - - num_fields_++; - return true; -} - -bool DNGImage::SetPhotometric(const unsigned short value) { - if ((value == PHOTOMETRIC_LINEARRAW) || (value == PHOTOMETRIC_RGB) || - (value == PHOTOMETRIC_WHITE_IS_ZERO) || - (value == PHOTOMETRIC_BLACK_IS_ZERO)) { - // OK - } else { - return false; - } - - unsigned int count = 1; - - const unsigned short data = value; - bool ret = WriteTIFFTag( - static_cast<unsigned short>(TIFFTAG_PHOTOMETRIC), TIFF_SHORT, count, - reinterpret_cast<const unsigned char *>(&data), &ifd_tags_, &data_os_); - - if (!ret) { - return false; - } - - num_fields_++; - return true; -} - -bool DNGImage::SetPlanarConfig(const unsigned short value) { - unsigned int count = 1; - - if ((value == PLANARCONFIG_CONTIG) || (value == PLANARCONFIG_SEPARATE)) { - // OK - } else { - return false; - } - - const unsigned short data = value; - bool ret = WriteTIFFTag( - static_cast<unsigned short>(TIFFTAG_PLANAR_CONFIG), TIFF_SHORT, count, - reinterpret_cast<const unsigned char *>(&data), &ifd_tags_, &data_os_); - - if (!ret) { - return false; - } - - num_fields_++; - return true; -} - -bool DNGImage::SetCompression(const unsigned short value) { - unsigned int count = 1; - - if ((value == COMPRESSION_NONE)) { - // OK - } else { - return false; - } - - const unsigned short data = value; - bool ret = WriteTIFFTag( - static_cast<unsigned short>(TIFFTAG_COMPRESSION), TIFF_SHORT, count, - reinterpret_cast<const unsigned char *>(&data), &ifd_tags_, &data_os_); - - if (!ret) { - return false; - } - - num_fields_++; - return true; -} - -bool DNGImage::SetSampleFormat(const unsigned int num_samples, - const unsigned short *values) { - // `SetSamplesPerPixel()` must be called in advance - if ((num_samples > 0) && (num_samples == samples_per_pixels_)) { - // OK - } else { - err_ += "SetSamplesPerPixel() must be called before SetSampleFormat().\n"; - return false; - } - - unsigned short format = values[0]; - - std::vector<unsigned short> vs(num_samples); - for (size_t i = 0; i < vs.size(); i++) { - // FIXME(syoyo): Currently format must be same for all samples - if (format != values[i]) { - err_ += "SampleFormat must be same among samples at the moment.\n"; - return false; - } - - if ((format == SAMPLEFORMAT_UINT) || (format == SAMPLEFORMAT_INT) || - (format == SAMPLEFORMAT_IEEEFP)) { - // OK - } else { - err_ += "Invalid format value specified for SetSampleFormat().\n"; - return false; - } - - vs[i] = values[i]; - - // TODO(syoyo): Swap values when writing IFD tag, not here. - if (swap_endian_) { - swap2(&vs[i]); - } - } - - unsigned int count = num_samples; - - bool ret = WriteTIFFTag(static_cast<unsigned short>(TIFFTAG_SAMPLEFORMAT), - TIFF_SHORT, count, - reinterpret_cast<const unsigned char *>(vs.data()), - &ifd_tags_, &data_os_); - - if (!ret) { - return false; - } - - num_fields_++; - return true; -} - -bool DNGImage::SetOrientation(const unsigned short value) { - unsigned int count = 1; - - if ((value == ORIENTATION_TOPLEFT) || (value == ORIENTATION_TOPRIGHT) || - (value == ORIENTATION_BOTRIGHT) || (value == ORIENTATION_BOTLEFT) || - (value == ORIENTATION_LEFTTOP) || (value == ORIENTATION_RIGHTTOP) || - (value == ORIENTATION_RIGHTBOT) || (value == ORIENTATION_LEFTBOT)) { - // OK - } else { - return false; - } - - const unsigned int data = value; - bool ret = WriteTIFFTag( - static_cast<unsigned short>(TIFFTAG_ORIENTATION), TIFF_SHORT, count, - reinterpret_cast<const unsigned char *>(&data), &ifd_tags_, &data_os_); - - if (!ret) { - return false; - } - - num_fields_++; - return true; -} - -bool DNGImage::SetBlackLevelRational(unsigned int num_samples, - const double *values) { - // `SetSamplesPerPixel()` must be called in advance and SPP shoud be equal to - // `num_samples`. - if ((num_samples > 0) && (num_samples == samples_per_pixels_)) { - // OK - } else { - return false; - } - - std::vector<unsigned int> vs(num_samples * 2); - for (size_t i = 0; i < vs.size(); i++) { - double numerator, denominator; - if (DoubleToRational(values[i], &numerator, &denominator) != 0) { - // Couldn't represent fp value as integer rational value. - return false; - } - - vs[2 * i + 0] = static_cast<unsigned int>(numerator); - vs[2 * i + 1] = static_cast<unsigned int>(denominator); - - // TODO(syoyo): Swap rational value(8 bytes) when writing IFD tag, not here. - if (swap_endian_) { - swap4(&vs[2 * i + 0]); - swap4(&vs[2 * i + 1]); - } - } - - unsigned int count = num_samples; - - bool ret = WriteTIFFTag(static_cast<unsigned short>(TIFFTAG_BLACK_LEVEL), - TIFF_RATIONAL, count, - reinterpret_cast<const unsigned char *>(vs.data()), - &ifd_tags_, &data_os_); - - if (!ret) { - return false; - } - - num_fields_++; - return true; -} - -bool DNGImage::SetWhiteLevelRational(unsigned int num_samples, - const double *values) { - // `SetSamplesPerPixel()` must be called in advance and SPP shoud be equal to - // `num_samples`. - if ((num_samples > 0) && (num_samples == samples_per_pixels_)) { - // OK - } else { - return false; - } - - std::vector<unsigned int> vs(num_samples * 2); - for (size_t i = 0; i < vs.size(); i++) { - double numerator, denominator; - if (DoubleToRational(values[i], &numerator, &denominator) != 0) { - // Couldn't represent fp value as integer rational value. - return false; - } - - vs[2 * i + 0] = static_cast<unsigned int>(numerator); - vs[2 * i + 1] = static_cast<unsigned int>(denominator); - - // TODO(syoyo): Swap rational value(8 bytes) when writing IFD tag, not here. - if (swap_endian_) { - swap4(&vs[2 * i + 0]); - swap4(&vs[2 * i + 1]); - } - } - - unsigned int count = num_samples; - - bool ret = WriteTIFFTag(static_cast<unsigned short>(TIFFTAG_WHITE_LEVEL), - TIFF_RATIONAL, count, - reinterpret_cast<const unsigned char *>(vs.data()), - &ifd_tags_, &data_os_); - - if (!ret) { - return false; - } - - num_fields_++; - return true; -} - -bool DNGImage::SetXResolution(const double value) { - double numerator, denominator; - if (DoubleToRational(value, &numerator, &denominator) != 0) { - // Couldn't represent fp value as integer rational value. - return false; - } - - unsigned int data[2]; - data[0] = static_cast<unsigned int>(numerator); - data[1] = static_cast<unsigned int>(denominator); - - // TODO(syoyo): Swap rational value(8 bytes) when writing IFD tag, not here. - if (swap_endian_) { - swap4(&data[0]); - swap4(&data[1]); - } - - bool ret = WriteTIFFTag( - static_cast<unsigned short>(TIFFTAG_XRESOLUTION), TIFF_RATIONAL, 1, - reinterpret_cast<const unsigned char *>(data), &ifd_tags_, &data_os_); - - if (!ret) { - return false; - } - - num_fields_++; - return true; -} - -bool DNGImage::SetYResolution(const double value) { - double numerator, denominator; - if (DoubleToRational(value, &numerator, &denominator) != 0) { - // Couldn't represent fp value as integer rational value. - return false; - } - - unsigned int data[2]; - data[0] = static_cast<unsigned int>(numerator); - data[1] = static_cast<unsigned int>(denominator); - - // TODO(syoyo): Swap rational value(8 bytes) when writing IFD tag, not here. - if (swap_endian_) { - swap4(&data[0]); - swap4(&data[1]); - } - - bool ret = WriteTIFFTag( - static_cast<unsigned short>(TIFFTAG_YRESOLUTION), TIFF_RATIONAL, 1, - reinterpret_cast<const unsigned char *>(data), &ifd_tags_, &data_os_); - - if (!ret) { - return false; - } - - num_fields_++; - return true; -} - -bool DNGImage::SetResolutionUnit(const unsigned short value) { - unsigned int count = 1; - - if ((value == RESUNIT_NONE) || (value == RESUNIT_INCH) || - (value == RESUNIT_CENTIMETER)) { - // OK - } else { - return false; - } - - const unsigned short data = value; - bool ret = WriteTIFFTag( - static_cast<unsigned short>(TIFFTAG_RESOLUTION_UNIT), TIFF_SHORT, count, - reinterpret_cast<const unsigned char *>(&data), &ifd_tags_, &data_os_); - - if (!ret) { - return false; - } - - num_fields_++; - return true; -} - -bool DNGImage::SetImageDescription(const std::string &ascii) { - unsigned int count = - static_cast<unsigned int>(ascii.length() + 1); // +1 for '\0' - - if (count < 2) { - // empty string - return false; - } - - if (count > (1024 * 1024)) { - // too large - return false; - } - - bool ret = WriteTIFFTag(static_cast<unsigned short>(TIFFTAG_IMAGEDESCRIPTION), - TIFF_ASCII, count, - reinterpret_cast<const unsigned char *>(ascii.data()), - &ifd_tags_, &data_os_); - - if (!ret) { - return false; - } - - num_fields_++; - return true; -} - -bool DNGImage::SetActiveArea(const unsigned int values[4]) { - unsigned int count = 4; - - const unsigned int *data = values; - bool ret = WriteTIFFTag( - static_cast<unsigned short>(TIFFTAG_ACTIVE_AREA), TIFF_LONG, count, - reinterpret_cast<const unsigned char *>(data), &ifd_tags_, &data_os_); - - if (!ret) { - return false; - } - - num_fields_++; - return true; -} - -bool DNGImage::SetImageData(const unsigned char *data, const size_t data_len) { - if ((data == NULL) || (data_len < 1)) { - return false; - } - - data_strip_offset_ = size_t(data_os_.tellp()); - data_strip_bytes_ = data_len; - - data_os_.write(reinterpret_cast<const char *>(data), - static_cast<std::streamsize>(data_len)); - - // NOTE: STRIP_OFFSET tag will be written at `WriteIFDToStream()`. - - { - unsigned int count = 1; - unsigned int bytes = static_cast<unsigned int>(data_len); - - bool ret = WriteTIFFTag( - static_cast<unsigned short>(TIFFTAG_STRIP_BYTE_COUNTS), TIFF_LONG, - count, reinterpret_cast<const unsigned char *>(&bytes), &ifd_tags_, - NULL); - - if (!ret) { - return false; - } - - num_fields_++; - } - - return true; -} - -bool DNGImage::SetCustomFieldLong(const unsigned short tag, const int value) { - unsigned int count = 1; - - // TODO(syoyo): Check if `tag` value does not conflict with existing TIFF tag - // value. - - bool ret = WriteTIFFTag(tag, TIFF_SLONG, count, - reinterpret_cast<const unsigned char *>(&value), - &ifd_tags_, &data_os_); - - if (!ret) { - return false; - } - - num_fields_++; - return true; -} - -bool DNGImage::SetCustomFieldULong(const unsigned short tag, - const unsigned int value) { - unsigned int count = 1; - - // TODO(syoyo): Check if `tag` value does not conflict with existing TIFF tag - // value. - - bool ret = WriteTIFFTag(tag, TIFF_LONG, count, - reinterpret_cast<const unsigned char *>(&value), - &ifd_tags_, &data_os_); - - if (!ret) { - return false; - } - - num_fields_++; - return true; -} - -static bool IFDComparator(const IFDTag &a, const IFDTag &b) { - return (a.tag < b.tag); -} - -bool DNGImage::WriteDataToStream(std::ostream *ofs, std::string *err) const { - if ((data_os_.str().length() == 0)) { - if (err) { - (*err) += "Empty IFD data and image data.\n"; - } - return false; - } - - if ((bits_per_sample_ == 0) || (samples_per_pixels_ == 0)) { - if (err) { - (*err) += "Both BitsPerSample and SamplesPerPixels must be set.\n"; - } - return false; - } - - std::vector<uint8_t> data(data_os_.str().length()); - memcpy(data.data(), data_os_.str().data(), data.size()); - - if (data_strip_bytes_ == 0) { - // May ok?. - } else { - // FIXME(syoyo): Assume all channels use sample bps - - // We may need to swap endian for pixel data. - if (swap_endian_) { - if (bits_per_sample_ == 16) { - size_t n = data_strip_bytes_ / sizeof(uint16_t); - uint16_t *ptr = - reinterpret_cast<uint16_t *>(data.data() + data_strip_offset_); - - for (size_t i = 0; i < n; i++) { - swap2(&ptr[i]); - } - - } else if (bits_per_sample_ == 32) { - size_t n = data_strip_bytes_ / sizeof(uint32_t); - uint32_t *ptr = - reinterpret_cast<uint32_t *>(data.data() + data_strip_offset_); - - for (size_t i = 0; i < n; i++) { - swap4(&ptr[i]); - } - - } else if (bits_per_sample_ == 64) { - size_t n = data_strip_bytes_ / sizeof(uint64_t); - uint64_t *ptr = - reinterpret_cast<uint64_t *>(data.data() + data_strip_offset_); - - for (size_t i = 0; i < n; i++) { - swap8(&ptr[i]); - } - } - } - } - - ofs->write(reinterpret_cast<const char *>(data.data()), - static_cast<std::streamsize>(data.size())); - - return true; -} - -bool DNGImage::WriteIFDToStream(const unsigned int data_base_offset, - const unsigned int strip_offset, - std::ostream *ofs, std::string *err) const { - if ((num_fields_ == 0) || (ifd_tags_.size() < 1)) { - if (err) { - (*err) += "No TIFF Tags.\n"; - } - return false; - } - - // add STRIP_OFFSET tag and sort IFD tags. - std::vector<IFDTag> tags = ifd_tags_; - { - // For STRIP_OFFSET we need the actual offset value to data(image), - // thus write STRIP_OFFSET here. - unsigned int offset = strip_offset + kHeaderSize; - IFDTag ifd; - ifd.tag = TIFFTAG_STRIP_OFFSET; - ifd.type = TIFF_LONG; - ifd.count = 1; - ifd.offset_or_value = offset; - tags.push_back(ifd); - } - - // TIFF expects IFD tags are sorted. - std::sort(tags.begin(), tags.end(), IFDComparator); - - std::ostringstream ifd_os; - - unsigned short num_fields = static_cast<unsigned short>(tags.size()); - - Write2(num_fields, &ifd_os, swap_endian_); - - { - size_t typesize_table[] = {1, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8, 4}; - - for (size_t i = 0; i < tags.size(); i++) { - const IFDTag &ifd = tags[i]; - Write2(ifd.tag, &ifd_os, swap_endian_); - Write2(ifd.type, &ifd_os, swap_endian_); - Write4(ifd.count, &ifd_os, swap_endian_); - - size_t len = - ifd.count * (typesize_table[(ifd.type) < 14 ? (ifd.type) : 0]); - if (len > 4) { - // Store offset value. - unsigned int ifd_offt = ifd.offset_or_value + data_base_offset; - Write4(ifd_offt, &ifd_os, swap_endian_); - } else { - // less than 4 bytes = store data itself. - - if (len == 1) { - const unsigned char value = - *(reinterpret_cast<const unsigned char *>(&ifd.offset_or_value)); - Write1(value, &ifd_os); - unsigned char pad = 0; - Write1(pad, &ifd_os); - Write1(pad, &ifd_os); - Write1(pad, &ifd_os); - } else if (len == 2) { - const unsigned short value = - *(reinterpret_cast<const unsigned short *>(&ifd.offset_or_value)); - Write2(value, &ifd_os, swap_endian_); - const unsigned short pad = 0; - Write2(pad, &ifd_os, swap_endian_); - } else if (len == 4) { - const unsigned int value = - *(reinterpret_cast<const unsigned int *>(&ifd.offset_or_value)); - Write4(value, &ifd_os, swap_endian_); - } else { - assert(0); - } - } - } - - ofs->write(ifd_os.str().c_str(), - static_cast<std::streamsize>(ifd_os.str().length())); - } - - return true; -} - -// ------------------------------------------- - -DNGWriter::DNGWriter(bool big_endian) : dng_big_endian_(big_endian) { - swap_endian_ = (IsBigEndian() != dng_big_endian_); -} - -bool DNGWriter::WriteToFile(const char *filename, std::string *err) const { - std::ofstream ofs(filename, std::ostream::binary); - - if (!ofs) { - if (err) { - (*err) = "Failed to open file.\n"; - } - - return false; - } - - std::ostringstream header; - bool ret = WriteTIFFVersionHeader(&header, dng_big_endian_); - if (!ret) { - return false; - } - - if (images_.size() == 0) { - if (err) { - (*err) = "No image added for writing.\n"; - } - - return false; - } - - // 1. Compute offset and data size(exclude TIFF header bytes) - size_t data_len = 0; - size_t strip_offset = 0; - std::vector<size_t> data_offset_table; - std::vector<size_t> strip_offset_table; - for (size_t i = 0; i < images_.size(); i++) { - strip_offset = data_len + images_[i]->GetStripOffset(); - data_offset_table.push_back(data_len); - strip_offset_table.push_back(strip_offset); - data_len += images_[i]->GetDataSize(); - } - - // 2. Write offset to ifd table. - const unsigned int ifd_offset = - kHeaderSize + static_cast<unsigned int>(data_len); - Write4(ifd_offset, &header, swap_endian_); - - assert(header.str().length() == 8); - - // std::cout << "ifd_offset " << ifd_offset << std::endl; - // std::cout << "data_len " << data_os_.str().length() << std::endl; - // std::cout << "ifd_len " << ifd_os_.str().length() << std::endl; - // std::cout << "swap endian " << swap_endian_ << std::endl; - - // 3. Write header - ofs.write(header.str().c_str(), - static_cast<std::streamsize>(header.str().length())); - - // 4. Write image and meta data - // TODO(syoyo): Write IFD first, then image/meta data - for (size_t i = 0; i < images_.size(); i++) { - bool ok = images_[i]->WriteDataToStream(&ofs, err); - if (!ok) { - return false; - } - } - - // 5. Write IFD entries; - for (size_t i = 0; i < images_.size(); i++) { - bool ok = images_[i]->WriteIFDToStream( - static_cast<unsigned int>(data_offset_table[i]), - static_cast<unsigned int>(strip_offset_table[i]), &ofs, err); - if (!ok) { - return false; - } - - unsigned int next_ifd_offset = - static_cast<unsigned int>(ofs.tellp()) + sizeof(unsigned int); - - if (i == (images_.size() - 1)) { - // Write zero as IFD offset(= end of data) - next_ifd_offset = 0; - } - - if (swap_endian_) { - swap4(&next_ifd_offset); - } - - ofs.write(reinterpret_cast<const char *>(&next_ifd_offset), 4); - } - - return true; -} - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -} // namespace tinydngwriter - -#endif // TINY_DNG_WRITER_IMPLEMENTATION |