59using std::ostringstream;
64 [[maybe_unused]]
Buffer file) {
65 const auto id = rootIFD->
getID();
66 const std::string& make =
id.
make;
70 return make ==
"NIKON CORPORATION" || make ==
"NIKON";
83 ThrowRDE(
"Image data outside of file.");
90 if (compression == 1 || (
hints.contains(
"force_uncompressed")) ||
101 if (offsets->
count != 1) {
106 "Byte count number does not match strip size: count:%u, strips:%u ",
110 ThrowRDE(
"Invalid strip byte count. File probably truncated.");
112 if (34713 != compression)
113 ThrowRDE(
"Unsupported compression");
126 ThrowRDE(
"Missing linearization table.");
146 const auto test =
mFile.getSubView(offset, 256);
147 for (
int i = 15; i < 256; i += 16)
163 if (!width || !height || !bitPerPixel)
166 const auto avaliableInputBytes = counts->
getU32(0);
167 const auto requiredPixels =
iPoint2D(width, height).
area();
173 const auto avaliablePixels = avaliableInputBits / bitPerPixel;
174 if (avaliablePixels < requiredPixels)
178 if (avaliablePixels == requiredPixels)
184 const auto requiredInputBits = bitPerPixel * requiredPixels;
189 assert(avaliableInputBytes >= requiredInputBytes);
190 const auto totalPadding = avaliableInputBytes - requiredInputBytes;
191 if (totalPadding % height != 0)
193 const auto perRowPadding = totalPadding / height;
194 return perRowPadding < 16;
205 if (byteCount % 3 != 0)
222 if (width == 0 || height == 0 || width > 8288 || height > 5520)
223 ThrowRDE(
"Unexpected image dimensions found: (%u; %u)", width, height);
226 ThrowRDE(
"Byte count number does not match strip size: "
227 "count:%u, stips:%u ",
231 if (yPerSlice == 0 || yPerSlice >
static_cast<uint32_t>(
mRaw->dim.y) ||
233 ThrowRDE(
"Invalid y per slice %u or strip count %u (height = %i)",
237 vector<NefSlice> slices;
238 slices.reserve(counts->
count);
249 if (offY + yPerSlice > height)
250 slice.
h = height - offY;
254 offY = min(height, offY + yPerSlice);
257 ThrowRDE(
"Slice offset/count invalid");
259 slices.push_back(slice);
263 ThrowRDE(
"No valid slices found. File probably truncated.");
268 if (bitPerPixel == 14 && width * slices[0].h * 2 == slices[0].count)
272 bitPerPixel =
hints.get(
"real_bpp", bitPerPixel);
274 switch (bitPerPixel) {
280 ThrowRDE(
"Invalid bpp found: %u", bitPerPixel);
284 for (
const NefSlice& slice : slices) {
290 if (
hints.contains(
"coolpixmangled")) {
293 u.readUncompressedRaw();
295 if (
hints.contains(
"coolpixsplit")) {
298 if (in.
getSize() % size.y != 0)
300 const auto inputPitchBytes = in.
getSize() / size.y;
302 hints.contains(
"msb_override")
306 inputPitchBytes, bitPerPixel, bo);
307 u.readUncompressedRaw();
317 int inputPitch)
const {
323 ThrowRDE(
"Column count isn't multiple of 8");
324 if (inputPitch != ((3 * size.x) / 2))
332 if (offset.x >
mRaw->dim.x || offset.y >
mRaw->dim.y)
333 ThrowRDE(
"All pixels outside of image");
334 if (offset.x + size.x >
mRaw->dim.x || offset.y + size.y >
mRaw->dim.y)
335 ThrowRDE(
"Output is partailly out of image");
339 const auto evenLinesInput = input.
getStream(size.y / 2, inputPitch)
342 const auto oddLinesInput = input.
getStream(size.y / 2, inputPitch)
348 for (
int row = offset.y; row < size.y;) {
349 for (
int col = offset.x; col < size.x; ++col)
352 for (
int col = offset.x; col < size.x; ++col)
357 "Should have run out of input");
389 if (width == 0 || height == 0 || width % 2 != 0 || width > 3680 ||
391 ThrowRDE(
"Unexpected image dimensions found: (%u; %u)", width, height);
407 if (meta->
hasCamera(
id.make,
id.model, extended_mode))
425 mode <<
"sNEF-uncompressed";
428 mode << bitPerPixel <<
"bit-uncompressed";
430 mode << bitPerPixel <<
"bit-compressed";
436 ostringstream extended_mode;
442 extended_mode << width <<
"x" << height <<
"-" << mode;
443 return extended_mode.str();
448 {0xc1, 0xbf, 0x6d, 0x0d, 0x59, 0xc5, 0x13, 0x9d, 0x83, 0x61, 0x6b, 0x4f,
449 0xc7, 0x7f, 0x3d, 0x3d, 0x53, 0x59, 0xe3, 0xc7, 0xe9, 0x2f, 0x95, 0xa7,
450 0x95, 0x1f, 0xdf, 0x7f, 0x2b, 0x29, 0xc7, 0x0d, 0xdf, 0x07, 0xef, 0x71,
451 0x89, 0x3d, 0x13, 0x3d, 0x3b, 0x13, 0xfb, 0x0d, 0x89, 0xc1, 0x65, 0x1f,
452 0xb3, 0x0d, 0x6b, 0x29, 0xe3, 0xfb, 0xef, 0xa3, 0x6b, 0x47, 0x7f, 0x95,
453 0x35, 0xa7, 0x47, 0x4f, 0xc7, 0xf1, 0x59, 0x95, 0x35, 0x11, 0x29, 0x61,
454 0xf1, 0x3d, 0xb3, 0x2b, 0x0d, 0x43, 0x89, 0xc1, 0x9d, 0x9d, 0x89, 0x65,
455 0xf1, 0xe9, 0xdf, 0xbf, 0x3d, 0x7f, 0x53, 0x97, 0xe5, 0xe9, 0x95, 0x17,
456 0x1d, 0x3d, 0x8b, 0xfb, 0xc7, 0xe3, 0x67, 0xa7, 0x07, 0xf1, 0x71, 0xa7,
457 0x53, 0xb5, 0x29, 0x89, 0xe5, 0x2b, 0xa7, 0x17, 0x29, 0xe9, 0x4f, 0xc5,
458 0x65, 0x6d, 0x6b, 0xef, 0x0d, 0x89, 0x49, 0x2f, 0xb3, 0x43, 0x53, 0x65,
459 0x1d, 0x49, 0xa3, 0x13, 0x89, 0x59, 0xef, 0x6b, 0xef, 0x65, 0x1d, 0x0b,
460 0x59, 0x13, 0xe3, 0x4f, 0x9d, 0xb3, 0x29, 0x43, 0x2b, 0x07, 0x1d, 0x95,
461 0x59, 0x59, 0x47, 0xfb, 0xe5, 0xe9, 0x61, 0x47, 0x2f, 0x35, 0x7f, 0x17,
462 0x7f, 0xef, 0x7f, 0x95, 0x95, 0x71, 0xd3, 0xa3, 0x0b, 0x71, 0xa3, 0xad,
463 0x0b, 0x3b, 0xb5, 0xfb, 0xa3, 0xbf, 0x4f, 0x83, 0x1d, 0xad, 0xe9, 0x2f,
464 0x71, 0x65, 0xa3, 0xe5, 0x07, 0x35, 0x3d, 0x0d, 0xb5, 0xe9, 0xe5, 0x47,
465 0x3b, 0x9d, 0xef, 0x35, 0xa3, 0xbf, 0xb3, 0xdf, 0x53, 0xd3, 0x97, 0x53,
466 0x49, 0x71, 0x07, 0x35, 0x61, 0x71, 0x2f, 0x43, 0x2f, 0x11, 0xdf, 0x17,
467 0x97, 0xfb, 0x95, 0x3b, 0x7f, 0x6b, 0xd3, 0x25, 0xbf, 0xad, 0xc7, 0xc5,
468 0xc5, 0xb5, 0x8b, 0xef, 0x2f, 0xd3, 0x07, 0x6b, 0x25, 0x49, 0x95, 0x25,
469 0x49, 0x6d, 0x71, 0xc7}};
471 {0xa7, 0xbc, 0xc9, 0xad, 0x91, 0xdf, 0x85, 0xe5, 0xd4, 0x78, 0xd5, 0x17,
472 0x46, 0x7c, 0x29, 0x4c, 0x4d, 0x03, 0xe9, 0x25, 0x68, 0x11, 0x86, 0xb3,
473 0xbd, 0xf7, 0x6f, 0x61, 0x22, 0xa2, 0x26, 0x34, 0x2a, 0xbe, 0x1e, 0x46,
474 0x14, 0x68, 0x9d, 0x44, 0x18, 0xc2, 0x40, 0xf4, 0x7e, 0x5f, 0x1b, 0xad,
475 0x0b, 0x94, 0xb6, 0x67, 0xb4, 0x0b, 0xe1, 0xea, 0x95, 0x9c, 0x66, 0xdc,
476 0xe7, 0x5d, 0x6c, 0x05, 0xda, 0xd5, 0xdf, 0x7a, 0xef, 0xf6, 0xdb, 0x1f,
477 0x82, 0x4c, 0xc0, 0x68, 0x47, 0xa1, 0xbd, 0xee, 0x39, 0x50, 0x56, 0x4a,
478 0xdd, 0xdf, 0xa5, 0xf8, 0xc6, 0xda, 0xca, 0x90, 0xca, 0x01, 0x42, 0x9d,
479 0x8b, 0x0c, 0x73, 0x43, 0x75, 0x05, 0x94, 0xde, 0x24, 0xb3, 0x80, 0x34,
480 0xe5, 0x2c, 0xdc, 0x9b, 0x3f, 0xca, 0x33, 0x45, 0xd0, 0xdb, 0x5f, 0xf5,
481 0x52, 0xc3, 0x21, 0xda, 0xe2, 0x22, 0x72, 0x6b, 0x3e, 0xd0, 0x5b, 0xa8,
482 0x87, 0x8c, 0x06, 0x5d, 0x0f, 0xdd, 0x09, 0x19, 0x93, 0xd0, 0xb9, 0xfc,
483 0x8b, 0x0f, 0x84, 0x60, 0x33, 0x1c, 0x9b, 0x45, 0xf1, 0xf0, 0xa3, 0x94,
484 0x3a, 0x12, 0x77, 0x33, 0x4d, 0x44, 0x78, 0x28, 0x3c, 0x9e, 0xfd, 0x65,
485 0x57, 0x16, 0x94, 0x6b, 0xfb, 0x59, 0xd0, 0xc8, 0x22, 0x36, 0xdb, 0xd2,
486 0x63, 0x98, 0x43, 0xa1, 0x04, 0x87, 0x86, 0xf7, 0xa6, 0x26, 0xbb, 0xd6,
487 0x59, 0x4d, 0xbf, 0x6a, 0x2e, 0xaa, 0x2b, 0xef, 0xe6, 0x78, 0xb6, 0x4e,
488 0xe0, 0x2f, 0xdc, 0x7c, 0xbe, 0x57, 0x19, 0x32, 0x7e, 0x2a, 0xd0, 0xb8,
489 0xba, 0x29, 0x00, 0x3c, 0x52, 0x7d, 0xa8, 0x49, 0x3b, 0x2d, 0xeb, 0x25,
490 0x49, 0xfa, 0xa3, 0xaa, 0x39, 0xa7, 0xc5, 0xa7, 0x50, 0x11, 0x36, 0xfb,
491 0xc6, 0x67, 0x4a, 0xf5, 0xa5, 0x12, 0x65, 0x7e, 0xb0, 0xdf, 0xaf, 0x4e,
492 0xb3, 0x61, 0x7f, 0x2f}};
499 if (wb->
count == 4) {
500 std::array<float, 4> wbCoeffs = {};
504 if (wbCoeffs[1] <= 0.0F)
506 mRaw->metadata.wbCoeffs = wbCoeffs;
508 }
else if (
mRootIFD->hasEntryRecursive(
static_cast<TiffTag>(0x0097))) {
515 if (v <
'0' || v >
'9')
516 ThrowRDE(
"Bad version component: %c - not a digit", v);
517 version = (version << 4) + v -
'0';
520 if (version == 0x100 && wb->
count >= 80 &&
522 std::array<float, 4> wbCoeffs = {};
523 wbCoeffs[0] =
static_cast<float>(wb->
getU16(36));
524 wbCoeffs[2] =
static_cast<float>(wb->
getU16(37));
525 wbCoeffs[1] =
static_cast<float>(wb->
getU16(38));
526 mRaw->metadata.wbCoeffs = wbCoeffs;
527 }
else if (version == 0x103 && wb->
count >= 26 &&
529 std::array<float, 4> wbCoeffs = {};
530 wbCoeffs[0] =
static_cast<float>(wb->
getU16(10));
531 wbCoeffs[1] =
static_cast<float>(wb->
getU16(11));
532 wbCoeffs[2] =
static_cast<float>(wb->
getU16(12));
533 mRaw->metadata.wbCoeffs = wbCoeffs;
534 }
else if (((version == 0x204 && wb->
count >= 564) ||
535 (version == 0x205 && wb->
count >= 284)) &&
542 if (serial.length() > 9)
543 ThrowRDE(
"Serial number is too long (%zu)", serial.length());
545 for (
unsigned char c : serial) {
546 if (c >=
'0' && c <=
'9')
547 serialno = serialno * 10 + c -
'0';
549 serialno = serialno * 10 + c % 10;
556 uint32_t keyno = keydata[0] ^ keydata[1] ^ keydata[2] ^ keydata[3];
560 uint8_t cj =
keymap[keyno & 0xff];
564 bs.
skipBytes(version == 0x204 ? 284 : 4);
566 std::array<uint8_t, 14 + 8>
buf;
567 for (
unsigned char& i :
buf) {
568 cj = uint8_t(cj + (ci * ck));
574 uint32_t off = (version == 0x204) ? 6 : 14;
575 std::array<float, 4> wbCoeffs = {};
577 wbCoeffs[0] =
static_cast<float>(
getU16BE(&
buf[off + 0]));
578 wbCoeffs[1] =
static_cast<float>(
getU16BE(&
buf[off + 2]));
579 wbCoeffs[2] =
static_cast<float>(
getU16BE(&
buf[off + 6]));
580 mRaw->metadata.wbCoeffs = wbCoeffs;
583 }
else if (
mRootIFD->hasEntryRecursive(
static_cast<TiffTag>(0x0014))) {
590 std::array<float, 4> wbCoeffs = {};
591 wbCoeffs[0] =
static_cast<float>(bs.
getU16()) / 256.0F;
593 wbCoeffs[2] =
static_cast<float>(bs.
getU16()) / 256.0F;
594 mRaw->metadata.wbCoeffs = wbCoeffs;
599 else if (wb->
count > 1572)
605 std::array<float, 4> wbCoeffs = {};
610 mRaw->metadata.wbCoeffs = wbCoeffs;
615 if (
hints.contains(
"nikon_wb_adjustment") &&
mRaw->metadata.wbCoeffs) {
616 (*
mRaw->metadata.wbCoeffs)[0] *= 256.0F / 527.0F;
617 (*
mRaw->metadata.wbCoeffs)[2] *= 256.0F / 317.0F;
626 auto makernotesWhite =
mRaw->whitePoint;
627 int makernotesBlack =
mRaw->blackLevel;
643 ThrowRDE(
"BlackLevel has %u entries instead of 4", bl->
count);
645 if (bitPerPixel != 12 && bitPerPixel != 14)
646 ThrowRDE(
"Bad bit per pixel: %u", bitPerPixel);
647 const int sh = 14 - bitPerPixel;
648 mRaw->blackLevelSeparate =
650 auto blackLevelSeparate1D = *
mRaw->blackLevelSeparate->getAsArray1DRef();
651 blackLevelSeparate1D(0) = bl->
getU16(0) >> sh;
652 blackLevelSeparate1D(1) = bl->
getU16(1) >> sh;
653 blackLevelSeparate1D(2) = bl->
getU16(2) >> sh;
654 blackLevelSeparate1D(3) = bl->
getU16(3) >> sh;
657 if (meta->
hasCamera(
id.make,
id.model, extended_mode)) {
659 }
else if (meta->
hasCamera(
id.make,
id.model, mode)) {
666 mRaw->whitePoint = *makernotesWhite;
667 if (makernotesBlack != -1)
668 mRaw->blackLevel = makernotesBlack;
683 ThrowRDE(
"Unable to locate whitebalance needed for decompression");
687 ThrowRDE(
"Whitebalance has unknown count or type");
693 if (
const auto lower_limit =
695 wb_r < lower_limit || wb_b < lower_limit || wb_r > 10.0F || wb_b > 10.0F)
696 ThrowRDE(
"Whitebalance has bad values (%f, %f)",
699 std::array<float, 4> wbCoeffs = {};
703 mRaw->metadata.wbCoeffs = wbCoeffs;
705 auto inv_wb_r =
static_cast<int>(1024.0F / wb_r);
706 auto inv_wb_b =
static_cast<int>(1024.0F / wb_b);
708 auto curve =
gammaCurve(1 / 2.4, 12.92, 4095);
711 for (
int i = 0; i < 4096; i++) {
712 curve[i] =
clampBits(
static_cast<int>(curve[i]) << 2, 16);
720 auto* tmpch =
reinterpret_cast<std::byte*
>(&tmp);
726 for (
int row = 0; row < out.
height(); row++) {
727 uint32_t random = in(row, 0) + (in(row, 1) << 8) + (in(row, 2) << 16);
728 for (
int col = 0; col < out.
width(); col += 6) {
736 auto y1 =
static_cast<float>(g1 | ((g2 & 0x0f) << 8));
737 auto y2 =
static_cast<float>((g2 >> 4) | (g3 << 4));
738 auto cb =
static_cast<float>(g4 | ((g5 & 0x0f) << 8));
739 auto cr =
static_cast<float>((g5 >> 4) | (g6 << 4));
745 if ((col + 6) < out.
width()) {
746 g4 = in(row, col + 6 + 3);
747 g5 = in(row, col + 6 + 4);
748 g6 = in(row, col + 6 + 5);
749 cb2 = (
static_cast<float>((g4 | ((g5 & 0x0f) << 8))) + cb) * 0.5F;
750 cr2 = (
static_cast<float>(((g5 >> 4) | (g6 << 4))) + cr) * 0.5F;
763 out(row, col) =
clampBits((inv_wb_r * tmp + (1 << 9)) >> 10, 15);
770 reinterpret_cast<std::byte*
>(&out(row, col + 1)), &random);
779 out(row, col + 2) =
clampBits((inv_wb_b * tmp + (1 << 9)) >> 10, 15);
786 out(row, col + 3) =
clampBits((inv_wb_r * tmp + (1 << 9)) >> 10, 15);
793 reinterpret_cast<std::byte*
>(&out(row, col + 4)), &random);
802 out(row, col + 5) =
clampBits((inv_wb_b * tmp + (1 << 9)) >> 10, 15);
808#define SQR(x) ((x) * (x))
810 std::vector<uint16_t> curve(65536);
813 std::array<double, 6> g;
814 std::array<double, 2> bnd = {{}};
817 g[2] = g[3] = g[4] = 0;
819 if (std::abs(g[1]) > 0 && (g[1] - 1) * (g[0] - 1) <= 0) {
820 for (i = 0; i < 48; i++) {
821 g[2] = (bnd[0] + bnd[1]) / 2;
822 if (std::abs(g[0]) > 0)
823 bnd[(pow(g[2] / g[1], -g[0]) - 1) / g[0] - 1 / g[2] > -1] = g[2];
825 bnd[g[2] / exp(1 - (1 / g[2])) < g[1]] = g[2];
828 if (std::abs(g[0]) > 0)
829 g[4] = g[2] * (1 / g[0] - 1);
831 if (std::abs(g[0]) > 0) {
832 g[5] = 1 / (g[1] *
SQR(g[3]) / 2 - g[4] * (1 - g[3]) +
833 (1 - pow(g[3], 1 + g[0])) * (1 + g[4]) / (1 + g[0])) -
836 g[5] = 1 / (g[1] *
SQR(g[3]) / 2 + 1 - g[2] - g[3] -
837 g[2] * g[3] * (log(g[3]) - 1)) -
841 for (i = 0; i < 0x10000; i++) {
843 const double r =
static_cast<double>(i) / imax;
850 if (std::abs(g[0]) > 0) {
851 v = pow((r + g[4]) / (1 + g[4]), 1 / g[0]);
853 v = exp((r - 1) / g[2]);
856 curve[i] =
static_cast<uint16_t>(0x10000 * v);
859 assert(curve.size() == 65536);
assert(dim.area() >=area)
bool checkCameraSupported(const CameraMetaData *meta, const TiffID &id, const std::string &mode)
void setMetaData(const CameraMetaData *meta, const TiffID &id, const std::string &mode, int iso_speed)
const TiffIFD * getIFDWithLargestImage(TiffTag filter=TiffTag::IMAGEWIDTH) const
TiffRootIFDOwner mRootIFD
int RAWSPEED_READONLY height() const
int RAWSPEED_READONLY width() const
size_type getRemainingSize() const
uint32_t getBits(int nbits)
Array1DRef< const uint8_t > getAsArray1DRef() const
size_type RAWSPEED_READONLY getSize() const
size_type RAWSPEED_READONLY getRemainSize() const
Buffer getBuffer(size_type size_)
ByteStream getStream(size_type size_)
void skipBytes(size_type nbytes)
const uint8_t * peekData(size_type count) const
bool hasPatternAt(std::string_view pattern, size_type relPos) const
Buffer peekRemainingBuffer() const
Endianness setByteOrder(Endianness endianness_)
std::string getExtendedMode(const std::string &mode) const
static bool NEFIsUncompressed(const TiffIFD *raw)
static std::vector< uint16_t > gammaCurve(double pwr, double ts, int imax)
static bool NEFIsUncompressedRGB(const TiffIFD *raw)
void DecodeNikonSNef(ByteStream input) const
std::string getMode() const
RawImage decodeRawInternal() override
void DecodeSNefUncompressed() const
void DecodeD100Uncompressed() const
void checkSupportInternal(const CameraMetaData *meta) override
void DecodeUncompressed() const
void decodeMetaDataInternal(const CameraMetaData *meta) override
static const std::array< uint8_t, 256 > serialmap
static bool isAppropriateDecoder(const TiffRootIFD *rootIFD, Buffer file)
bool D100IsCompressed(uint32_t offset) const
void readCoolpixSplitRaw(ByteStream input, const iPoint2D &size, const iPoint2D &offset, int inputPitch) const
static const std::array< uint8_t, 256 > keymap
int getBitPerSample() const
void parseWhiteBalance() const
void decompress(Array1DRef< const uint8_t > input, bool uncorrectedRawValues)
bool uncorrectedRawValues
float getFloat(uint32_t index=0) const
uint32_t getU32(uint32_t index=0) const
ByteStream getData() const
uint16_t getU16(uint32_t index=0) const
uint8_t getByte(uint32_t index=0) const
TiffEntry * getEntry(TiffTag tag) const
area_type RAWSPEED_READONLY area() const
constexpr uint64_t RAWSPEED_READNONE roundUpDivisionSafe(uint64_t value, uint64_t div)
constexpr RAWSPEED_READNONE Ttgt implicit_cast(Tsrc value)
uint16_t getU16BE(const void *data)
Array2DRef(Array1DRef< T > data, int width, int height, int pitch) -> Array2DRef< T >
void RAWSPEED_UNLIKELY_FUNCTION RAWSPEED_NOINLINE static char buf[bufSize]
constexpr auto RAWSPEED_READNONE clampBits(T value, unsigned int nBits)