diff --git a/rtdata/options/options.lin b/rtdata/options/options.lin
index 1d2f9faac..580390b28 100644
--- a/rtdata/options/options.lin
+++ b/rtdata/options/options.lin
@@ -12,8 +12,8 @@ MultiUser=true
[File Browser]
# Image filename extensions to be looked for, and their corresponding search state (0/1 -> skip/include)
-ParseExtensions=3fr;arw;arq;cr2;crf;crw;dcr;dng;fff;iiq;jpg;jpeg;kdc;mef;mos;mrw;nef;nrw;orf;pef;png;raf;raw;rw2;rwl;rwz;sr2;srf;srw;tif;tiff;x3f;
-ParseExtensionsEnabled=1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1;
+ParseExtensions=3fr;arw;arq;cr2;cr3;crf;crw;dcr;dng;fff;iiq;jpg;jpeg;kdc;mef;mos;mrw;nef;nrw;orf;pef;png;raf;raw;rw2;rwl;rwz;sr2;srf;srw;tif;tiff;x3f;
+ParseExtensionsEnabled=1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1;
[Output]
PathTemplate=%p1/converted/%f
diff --git a/rtdata/options/options.osx b/rtdata/options/options.osx
index 11c5da4c8..58e0a5604 100644
--- a/rtdata/options/options.osx
+++ b/rtdata/options/options.osx
@@ -12,8 +12,8 @@ MultiUser=true
[File Browser]
# Image filename extensions to be looked for, and their corresponding search state (0/1 -> skip/include)
-ParseExtensions=3fr;arw;arq;cr2;crf;crw;dcr;dng;fff;iiq;jpg;jpeg;kdc;mef;mos;mrw;nef;nrw;orf;pef;png;raf;raw;rw2;rwl;rwz;sr2;srf;srw;tif;tiff;x3f;
-ParseExtensionsEnabled=1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1;
+ParseExtensions=3fr;arw;arq;cr2;cr3;crf;crw;dcr;dng;fff;iiq;jpg;jpeg;kdc;mef;mos;mrw;nef;nrw;orf;pef;png;raf;raw;rw2;rwl;rwz;sr2;srf;srw;tif;tiff;x3f;
+ParseExtensionsEnabled=1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1;
[Output]
PathTemplate=%p1/converted/%f
diff --git a/rtdata/options/options.win b/rtdata/options/options.win
index a4a767bf4..a54e021b1 100644
--- a/rtdata/options/options.win
+++ b/rtdata/options/options.win
@@ -14,8 +14,8 @@ UseSystemTheme=false
[File Browser]
# Image filename extensions to be looked for, and their corresponding search state (0/1 -> skip/include)
-ParseExtensions=3fr;arw;arq;cr2;crf;crw;dcr;dng;fff;iiq;jpg;jpeg;kdc;mef;mos;mrw;nef;nrw;orf;pef;png;raf;raw;rw2;rwl;rwz;sr2;srf;srw;tif;tiff;x3f;
-ParseExtensionsEnabled=1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1;
+ParseExtensions=3fr;arw;arq;cr2;cr3;crf;crw;dcr;dng;fff;iiq;jpg;jpeg;kdc;mef;mos;mrw;nef;nrw;orf;pef;png;raf;raw;rw2;rwl;rwz;sr2;srf;srw;tif;tiff;x3f;
+ParseExtensionsEnabled=1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1;
[Output]
PathTemplate=%p1/converted/%f
diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt
index c37341c8b..f58afde5e 100644
--- a/rtengine/CMakeLists.txt
+++ b/rtengine/CMakeLists.txt
@@ -34,6 +34,7 @@ set(RTENGINESOURCEFILES
amaze_demosaic_RT.cc
badpixels.cc
boxblur.cc
+ canon_cr3_decoder.cc
CA_correct_RT.cc
calc_distort.cc
camconst.cc
diff --git a/rtengine/camconst.json b/rtengine/camconst.json
index f2db455a3..45233fc16 100644
--- a/rtengine/camconst.json
+++ b/rtengine/camconst.json
@@ -1138,6 +1138,11 @@ Camera constants:
}
},
+ { // Quality C, only raw crop
+ "make_model": [ "Canon EOS M6 Mark II", "Canon EOS 90D" ],
+ "raw_crop": [ 144, 72, 6984, 4660 ]
+ },
+
// Canon Powershot
{ // Quality C, CHDK DNGs, raw frame correction
"make_model": "Canon PowerShot A3100 IS",
diff --git a/rtengine/canon_cr3_decoder.cc b/rtengine/canon_cr3_decoder.cc
new file mode 100644
index 000000000..9d3e0a62d
--- /dev/null
+++ b/rtengine/canon_cr3_decoder.cc
@@ -0,0 +1,3120 @@
+/* -*- C++ -*-
+ *
+ * This file is part of ART.
+ *
+ * ART is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * ART is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with ART. If not, see .
+*/
+
+#include
+#include "dcraw.h"
+
+#ifdef __GNUC__ // silence warning
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wsign-compare"
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
+#endif
+
+// Code adapted from libraw
+/* -*- C++ -*-
+ * Copyright 2019 LibRaw LLC (info@libraw.org)
+ *
+ LibRaw is free software; you can redistribute it and/or modify
+ it under the terms of the one of two licenses as you choose:
+
+1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1
+ (See file LICENSE.LGPL provided in LibRaw distribution archive for details).
+
+2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
+ (See file LICENSE.CDDL provided in LibRaw distribution archive for details).
+
+*/
+
+
+void DCraw::parse_canon_cr3()
+{
+ int err;
+ unsigned long long szAtomList;
+ short nesting = -1;
+ short nTrack = -1;
+ short TrackType;
+ char AtomNameStack[128];
+ strcpy(make, "Canon");
+
+ szAtomList = ifp->size;
+ err = parseCR3(0ULL, szAtomList, nesting, AtomNameStack, nTrack, TrackType);
+ if ((err == 0 || err == -14) &&
+ nTrack >= 0) // no error, or too deep nesting
+ selectCRXTrack(nTrack);
+}
+
+#define LIBRAW_CRXTRACKS_MAXCOUNT RT_canon_CR3_data.CRXTRACKS_MAXCOUNT
+
+void DCraw::selectCRXTrack(short maxTrack)
+{
+ if (maxTrack < 0)
+ return;
+ INT64 bitcounts[LIBRAW_CRXTRACKS_MAXCOUNT], maxbitcount = 0;
+ uint32_t maxjpegbytes = 0;
+ memset(bitcounts, 0, sizeof(bitcounts));
+ for (int i = 0; i <= maxTrack && i < LIBRAW_CRXTRACKS_MAXCOUNT; i++)
+ {
+ CanonCR3Data::crx_data_header_t *d = &RT_canon_CR3_data.crx_header[i];
+ if (d->MediaType == 1) // RAW
+ {
+ bitcounts[i] = INT64(d->nBits) * INT64(d->f_width) * INT64(d->f_height);
+ if (bitcounts[i] > maxbitcount)
+ maxbitcount = bitcounts[i];
+ }
+ else if (d->MediaType == 2) // JPEG
+ {
+ if (d->MediaSize > maxjpegbytes)
+ {
+ maxjpegbytes = d->MediaSize;
+ thumb_offset = d->MediaOffset;
+ thumb_length = d->MediaSize;
+ }
+ }
+ }
+ if (maxbitcount < 8)
+ return;
+ int framei = -1, framecnt = 0;
+ for (int i = 0; i <= maxTrack && i < LIBRAW_CRXTRACKS_MAXCOUNT; i++)
+ {
+ if (bitcounts[i] == maxbitcount)
+ {
+ if (framecnt <= shot_select)
+ framei = i;
+ framecnt++;
+ }
+ }
+ is_raw = framecnt;
+ if (framei >= 0 && framei < LIBRAW_CRXTRACKS_MAXCOUNT)
+ {
+ CanonCR3Data::crx_data_header_t *d =
+ &RT_canon_CR3_data.crx_header[framei];
+ data_offset = d->MediaOffset;
+ //data_size = d->MediaSize;
+ raw_width = d->f_width;
+ raw_height = d->f_height;
+ load_raw = &DCraw::crxLoadRaw;
+ switch (d->cfaLayout)
+ {
+ case 0:
+ filters = 0x94949494;
+ break;
+ case 1:
+ filters = 0x61616161;
+ break;
+ case 2:
+ filters = 0x49494949;
+ break;
+ case 3:
+ filters = 0x16161616;
+ break;
+ }
+
+ RT_canon_CR3_data.crx_track_selected = framei;
+
+ int tiff_idx = -1;
+ INT64 tpixels = 0;
+ for (int i = 0; i < tiff_nifds; i++)
+ if (INT64(tiff_ifd[i].height) * INT64(tiff_ifd[i].height) > tpixels)
+ {
+ tpixels = INT64(tiff_ifd[i].height) * INT64(tiff_ifd[i].height);
+ tiff_idx = i;
+ }
+ if (tiff_idx >= 0)
+ flip = tiff_ifd[tiff_idx].flip;
+ }
+}
+
+#define FORC4 for (c=0; c < 4; c++)
+
+#define bad_hdr \
+ (((order != 0x4d4d) && (order != 0x4949)) || (get2() != 0x002a) || \
+ (get4() != 0x00000008))
+int DCraw::parseCR3(unsigned long long oAtomList,
+ unsigned long long szAtomList, short &nesting,
+ char *AtomNameStack, short &nTrack, short &TrackType)
+{
+ /*
+ Atom starts with 4 bytes for Atom size and 4 bytes containing Atom name
+ Atom size includes the length of the header and the size of all "contained"
+ Atoms if Atom size == 1, Atom has the extended size stored in 8 bytes located
+ after the Atom name if Atom size == 0, it is the last top-level Atom extending
+ to the end of the file Atom name is often a 4 symbol mnemonic, but can be a
+ 4-byte integer
+ */
+ const char UIID_Canon[17] =
+ "\x85\xc0\xb6\x87\x82\x0f\x11\xe0\x81\x11\xf4\xce\x46\x2b\x6a\x48";
+ const char UIID_Preview[17] =
+ "\xea\xf4\x2b\x5e\x1c\x98\x4b\x88\xb9\xfb\xb7\xdc\x40\x6e\x4d\x16";
+
+ /*
+ AtomType = 0 - unknown: "unk."
+ AtomType = 1 - container atom: "cont"
+ AtomType = 2 - leaf atom: "leaf"
+ AtomType = 3 - can be container, can be leaf: "both"
+ */
+ const char sAtomeType[4][5] = {"unk.", "cont", "leaf", "both"};
+ short AtomType;
+ static const struct
+ {
+ char AtomName[5];
+ short AtomType;
+ } AtomNamesList[] = {
+ {"dinf", 1},
+ {"edts", 1},
+ {"fiin", 1},
+ {"ipro", 1},
+ {"iprp", 1},
+ {"mdia", 1},
+ {"meco", 1},
+ {"mere", 1},
+ {"mfra", 1},
+ {"minf", 1},
+ {"moof", 1},
+ {"moov", 1},
+ {"mvex", 1},
+ {"paen", 1},
+ {"schi", 1},
+ {"sinf", 1},
+ {"skip", 1},
+ {"stbl", 1},
+ {"stsd", 1},
+ {"strk", 1},
+ {"tapt", 1},
+ {"traf", 1},
+ {"trak", 1},
+
+ {"cdsc", 2},
+ {"colr", 2},
+ {"dimg", 2},
+ // {"dref", 2},
+ {"free", 2},
+ {"frma", 2},
+ {"ftyp", 2},
+ {"hdlr", 2},
+ {"hvcC", 2},
+ {"iinf", 2},
+ {"iloc", 2},
+ {"infe", 2},
+ {"ipco", 2},
+ {"ipma", 2},
+ {"iref", 2},
+ {"irot", 2},
+ {"ispe", 2},
+ {"meta", 2},
+ {"mvhd", 2},
+ {"pitm", 2},
+ {"pixi", 2},
+ {"schm", 2},
+ {"thmb", 2},
+ {"tkhd", 2},
+ {"url ", 2},
+ {"urn ", 2},
+
+ {"CCTP", 1},
+ {"CRAW", 1},
+
+ {"JPEG", 2},
+ {"CDI1", 2},
+ {"CMP1", 2},
+
+ {"CNCV", 2},
+ {"CCDT", 2},
+ {"CTBO", 2},
+ {"CMT1", 2},
+ {"CMT2", 2},
+ {"CMT3", 2},
+ {"CMT4", 2},
+ {"THMB", 2},
+ {"co64", 2},
+ {"mdat", 2},
+ {"mdhd", 2},
+ {"nmhd", 2},
+ {"stsc", 2},
+ {"stsz", 2},
+ {"stts", 2},
+ {"vmhd", 2},
+
+ {"dref", 3},
+ {"uuid", 3},
+ };
+
+ const char sHandlerType[5][5] = {"unk.", "soun", "vide", "hint", "meta"};
+
+ int c, err = 0;
+
+ ushort tL; // Atom length represented in 4 or 8 bytes
+ char nmAtom[5]; // Atom name
+ unsigned long long oAtom, szAtom; // Atom offset and Atom size
+ unsigned long long oAtomContent,
+ szAtomContent; // offset and size of Atom content
+ unsigned long long lHdr;
+
+ char UIID[16];
+ uchar CMP1[36];
+ char HandlerType[5], MediaFormatID[5];
+ unsigned ImageWidth, ImageHeight;
+ long relpos_inDir, relpos_inBox;
+ unsigned szItem, Tag, lTag;
+ ushort tItem;
+
+ nmAtom[0] = MediaFormatID[0] = nmAtom[4] = MediaFormatID[4] = '\0';
+ strcpy(HandlerType, sHandlerType[0]);
+ ImageWidth = ImageHeight = 0U;
+ oAtom = oAtomList;
+ nesting++;
+ if (nesting > 31)
+ return -14; // too deep nesting
+ short s_order = order;
+
+ while ((oAtom + 8ULL) <= (oAtomList + szAtomList))
+ {
+ lHdr = 0ULL;
+ err = 0;
+ order = 0x4d4d;
+ fseek(ifp, oAtom, SEEK_SET);
+ szAtom = get4();
+ FORC4 nmAtom[c] = AtomNameStack[nesting * 4 + c] = fgetc(ifp);
+ AtomNameStack[(nesting + 1) * 4] = '\0';
+ tL = 4;
+ AtomType = 0;
+
+ for (c = 0; c < sizeof AtomNamesList / sizeof *AtomNamesList; c++)
+ if (!strcmp(nmAtom, AtomNamesList[c].AtomName))
+ {
+ AtomType = AtomNamesList[c].AtomType;
+ break;
+ }
+
+ if (!AtomType)
+ {
+ err = 1;
+ }
+
+ if (szAtom == 0ULL)
+ {
+ if (nesting != 0)
+ {
+ err = -2;
+ goto fin;
+ }
+ szAtom = szAtomList - oAtom;
+ oAtomContent = oAtom + 8ULL;
+ szAtomContent = szAtom - 8ULL;
+ }
+ else if (szAtom == 1ULL)
+ {
+ if ((oAtom + 16ULL) > (oAtomList + szAtomList))
+ {
+ err = -3;
+ goto fin;
+ }
+ tL = 8;
+ szAtom = (((unsigned long long)get4()) << 32) | get4();
+ oAtomContent = oAtom + 16ULL;
+ szAtomContent = szAtom - 16ULL;
+ }
+ else
+ {
+ oAtomContent = oAtom + 8ULL;
+ szAtomContent = szAtom - 8ULL;
+ }
+
+ if (!strcmp(nmAtom, "trak"))
+ {
+ nTrack++;
+ TrackType = 0;
+ if (nTrack >= LIBRAW_CRXTRACKS_MAXCOUNT)
+ break;
+ }
+ if (!strcmp(AtomNameStack, "moovuuid"))
+ {
+ lHdr = 16ULL;
+ fread(UIID, 1, lHdr, ifp);
+ if (!strncmp(UIID, UIID_Canon, lHdr))
+ {
+ AtomType = 1;
+ }
+ else
+ fseek(ifp, -lHdr, SEEK_CUR);
+ }
+ else if (!strcmp(AtomNameStack, "moovuuidCCTP"))
+ {
+ lHdr = 12ULL;
+ }
+ else if (!strcmp(AtomNameStack, "moovuuidCMT1"))
+ {
+ short q_order = order;
+ order = get2();
+ if ((tL != 4) || bad_hdr)
+ {
+ err = -4;
+ goto fin;
+ }
+ parse_tiff_ifd(oAtomContent);
+ order = q_order;
+ }
+ else if (!strcmp(AtomNameStack, "moovuuidCMT2"))
+ {
+ short q_order = order;
+ order = get2();
+ if ((tL != 4) || bad_hdr)
+ {
+ err = -5;
+ goto fin;
+ }
+ parse_exif(oAtomContent);
+ order = q_order;
+ }
+ else if (!strcmp(AtomNameStack, "moovuuidCMT3"))
+ {
+ short q_order = order;
+ order = get2();
+ if ((tL != 4) || bad_hdr)
+ {
+ err = -6;
+ goto fin;
+ }
+ fseek(ifp, -12L, SEEK_CUR);
+ parse_makernote(oAtomContent, 0);
+ order = q_order;
+ }
+ else if (!strcmp(AtomNameStack, "moovuuidCMT4"))
+ {
+ short q_order = order;
+ order = get2();
+ if ((tL != 4) || bad_hdr)
+ {
+ err = -6;
+ goto fin;
+ }
+ INT64 off = ftell(ifp);
+ parse_gps(oAtomContent);
+ fseek(ifp, off, SEEK_SET);
+// parse_gps_libraw(oAtomContent);
+ order = q_order;
+ }
+ else if (!strcmp(AtomNameStack, "moovtrakmdiahdlr"))
+ {
+ fseek(ifp, 8L, SEEK_CUR);
+ FORC4 HandlerType[c] = fgetc(ifp);
+ for (c = 1; c < sizeof sHandlerType / sizeof *sHandlerType; c++)
+ if (!strcmp(HandlerType, sHandlerType[c]))
+ {
+ TrackType = c;
+ break;
+ }
+ }
+ else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsd"))
+ {
+ if (szAtomContent >= 16)
+ {
+ fseek(ifp, 12L, SEEK_CUR);
+ lHdr = 8;
+ }
+ else
+ {
+ err = -7;
+ goto fin;
+ }
+ FORC4 MediaFormatID[c] = fgetc(ifp);
+ if ((TrackType == 2) && (!strcmp(MediaFormatID, "CRAW")))
+ {
+ if (szAtomContent >= 44)
+ fseek(ifp, 24L, SEEK_CUR);
+ else
+ {
+ err = -8;
+ goto fin;
+ }
+ }
+ else
+ {
+ AtomType = 2; // only continue for CRAW
+ lHdr = 0;
+ }
+#define current_track RT_canon_CR3_data.crx_header[nTrack]
+
+ ImageWidth = get2();
+ ImageHeight = get2();
+ }
+ else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAW"))
+ {
+ lHdr = 82;
+ }
+ else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAWCMP1"))
+ {
+ if (szAtomContent >= 40)
+ fread(CMP1, 1, 36, ifp);
+ else
+ {
+ err = -7;
+ goto fin;
+ }
+ if (!crxParseImageHeader(CMP1, nTrack))
+ current_track.MediaType = 1;
+ }
+ else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAWJPEG"))
+ {
+ current_track.MediaType = 2;
+ }
+ else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsz"))
+ {
+ if (szAtomContent == 12)
+ fseek(ifp, 4L, SEEK_CUR);
+ else if (szAtomContent == 16)
+ fseek(ifp, 12L, SEEK_CUR);
+ else
+ {
+ err = -9;
+ goto fin;
+ }
+ current_track.MediaSize = get4();
+ }
+ else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblco64"))
+ {
+ if (szAtomContent == 16)
+ fseek(ifp, 8L, SEEK_CUR);
+ else
+ {
+ err = -10;
+ goto fin;
+ }
+ current_track.MediaOffset = (((unsigned long long)get4()) << 32) | get4();
+ }
+
+ if (current_track.MediaSize && current_track.MediaOffset &&
+ ((oAtom + szAtom) >= (oAtomList + szAtomList)) &&
+ !strncmp(AtomNameStack, "moovtrakmdiaminfstbl", 20))
+ {
+ if ((TrackType == 4) && (!strcmp(MediaFormatID, "CTMD")))
+ {
+ order = 0x4949;
+ relpos_inDir = 0L;
+ while (relpos_inDir + 6 < current_track.MediaSize)
+ {
+ fseek(ifp, current_track.MediaOffset + relpos_inDir, SEEK_SET);
+ szItem = get4();
+ tItem = get2();
+ if ((relpos_inDir + szItem) > current_track.MediaSize)
+ {
+ err = -11;
+ goto fin;
+ }
+ if ((tItem == 7) || (tItem == 8) || (tItem == 9))
+ {
+ relpos_inBox = relpos_inDir + 12L;
+ while (relpos_inBox + 8 < relpos_inDir + szItem)
+ {
+ fseek(ifp, current_track.MediaOffset + relpos_inBox, SEEK_SET);
+ lTag = get4();
+ Tag = get4();
+ if (lTag < 8)
+ {
+ err = -12;
+ goto fin;
+ }
+ else if ((relpos_inBox + lTag) > (relpos_inDir + szItem))
+ {
+ err = -11;
+ goto fin;
+ }
+ if ((Tag == 0x927c) && ((tItem == 7) || (tItem == 8)))
+ {
+ fseek(ifp, current_track.MediaOffset + relpos_inBox + 8L,
+ SEEK_SET);
+ short q_order = order;
+ order = get2();
+ if (bad_hdr)
+ {
+ err = -13;
+ goto fin;
+ }
+ fseek(ifp, -8L, SEEK_CUR);
+ RT_canon_CR3_data.CR3_CTMDtag = 1;
+ parse_makernote(current_track.MediaOffset + relpos_inBox + 8,
+ 0);
+ RT_canon_CR3_data.CR3_CTMDtag = 0;
+ order = q_order;
+ }
+ relpos_inBox += lTag;
+ }
+ }
+ relpos_inDir += szItem;
+ }
+ order = 0x4d4d;
+ }
+ }
+#undef current_track
+ if (AtomType == 1)
+ {
+ err = parseCR3(oAtomContent + lHdr, szAtomContent - lHdr, nesting,
+ AtomNameStack, nTrack, TrackType);
+ if (err)
+ goto fin;
+ }
+ oAtom += szAtom;
+ }
+
+fin:
+ nesting--;
+ if (nesting >= 0)
+ AtomNameStack[nesting * 4] = '\0';
+ order = s_order;
+ return err;
+}
+#undef bad_hdr
+
+
+//-----------------------------------------------------------------------------
+
+#ifdef _abs
+#undef _abs
+#undef _min
+#undef _constrain
+#endif
+#define _abs(x) (((x) ^ ((int32_t)(x) >> 31)) - ((int32_t)(x) >> 31))
+#define _min(a, b) ((a) < (b) ? (a) : (b))
+#define _constrain(x, l, u) ((x) < (l) ? (l) : ((x) > (u) ? (u) : (x)))
+
+#if defined(__clang__) || defined(__GNUG__)
+#define libraw_inline inline __attribute__((always_inline))
+#elif defined(_MSC_VER) && _MSC_VER > 1400
+#define libraw_inline __forceinline
+#else
+#define libraw_inline inline
+#endif
+
+namespace {
+
+static unsigned sgetn (int n, unsigned char *s)
+{
+ unsigned result = 0;
+
+ while (n-- > 0) {
+ result = (result << 8) | (*s++);
+ }
+
+ return result;
+}
+
+// this should be divisible by 4
+#define CRX_BUF_SIZE 0x10000
+#if !defined(_WIN32) || (defined (__GNUC__) && !defined(__INTRINSIC_SPECIAL__BitScanReverse))
+/* __INTRINSIC_SPECIAL__BitScanReverse found in MinGW32-W64 v7.30 headers, may be there is a better solution? */
+typedef uint32_t DWORD;
+typedef uint8_t byte;
+libraw_inline void _BitScanReverse(DWORD *Index, unsigned long Mask)
+{
+ *Index = sizeof(unsigned long) * 8 - 1 - __builtin_clzl(Mask);
+}
+#define _byteswap_ulong(x) __builtin_bswap32(x)
+#endif
+
+#ifdef LIBRAW_USE_OPENMP
+# undef LIBRAW_USE_OPENMP
+#endif
+
+#define LIBRAW_EXCEPTION_IO_EOF std::exception()
+
+struct LibRaw_abstract_datastream {
+ IMFILE *ifp;
+
+ void lock() {}
+ void unlock() {}
+ void seek(int p, int how) { fseek(ifp, p, how); }
+ int read(void* dst, int es, int count)
+ { return fread(dst, es, count, ifp); }
+};
+
+struct CrxBitstream
+{
+ uint8_t mdatBuf[CRX_BUF_SIZE];
+ uint64_t mdatSize;
+ uint64_t curBufOffset;
+ uint32_t curPos;
+ uint32_t curBufSize;
+ uint32_t bitData;
+ int32_t bitsLeft;
+ LibRaw_abstract_datastream *input;
+};
+
+struct CrxBandParam
+{
+ CrxBitstream bitStream;
+ int16_t subbandWidth;
+ int16_t subbandHeight;
+ int32_t roundedBitsMask;
+ int32_t roundedBits;
+ int16_t curLine;
+ int32_t *lineBuf0;
+ int32_t *lineBuf1;
+ int32_t *lineBuf2;
+ int32_t sParam;
+ int32_t kParam;
+ int32_t *paramData;
+ int32_t *nonProgrData;
+ int8_t supportsPartial;
+};
+
+struct CrxWaveletTransform
+{
+ int32_t *subband0Buf;
+ int32_t *subband1Buf;
+ int32_t *subband2Buf;
+ int32_t *subband3Buf;
+ int32_t *lineBuf[8];
+ int16_t curLine;
+ int16_t curH;
+ int8_t fltTapH;
+ int16_t height;
+ int16_t width;
+};
+
+struct CrxSubband
+{
+ CrxBandParam *bandParam;
+ uint64_t mdatOffset;
+ uint8_t *bandBuf;
+ int32_t bandSize;
+ uint64_t dataSize;
+ int8_t supportsPartial;
+ int32_t quantValue;
+ uint16_t width;
+ uint16_t height;
+ int32_t paramK;
+ int64_t dataOffset;
+};
+
+struct CrxPlaneComp
+{
+ byte *compBuf;
+ CrxSubband *subBands;
+ CrxWaveletTransform *waveletTransform;
+ int8_t compNumber;
+ int64_t dataOffset;
+ int32_t compSize;
+ int8_t supportsPartial;
+ int32_t roundedBitsMask;
+ int8_t tileFlag;
+};
+
+struct CrxTile
+{
+ CrxPlaneComp *comps;
+ int8_t tileFlag;
+ int8_t tileNumber;
+ int64_t dataOffset;
+ int32_t tileSize;
+ uint16_t width;
+ uint16_t height;
+};
+
+struct CrxImage
+{
+ uint8_t nPlanes;
+ uint16_t planeWidth;
+ uint16_t planeHeight;
+ uint8_t samplePrecision;
+ uint8_t subbandCount;
+ uint8_t levels;
+ uint8_t nBits;
+ uint8_t encType;
+ uint8_t tileCols;
+ uint8_t tileRows;
+ CrxTile *tiles;
+ uint64_t mdatOffset;
+ uint64_t mdatSize;
+ int16_t *outBufs[4]; // one per plane
+ int16_t *planeBuf;
+ LibRaw_abstract_datastream *input;
+};
+
+enum TileFlags
+{
+ E_HAS_TILES_ON_THE_RIGHT = 1,
+ E_HAS_TILES_ON_THE_LEFT = 2,
+ E_HAS_TILES_ON_THE_BOTTOM = 4,
+ E_HAS_TILES_ON_THE_TOP = 8
+};
+
+int32_t exCoefNumTbl[0x120] = {
+ // level 1
+ 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ // level 2
+ 1, 1, 3, 3, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 3, 2, 1, 0, 1, 0, 0, 0, 0, 0, 1,
+ 2, 4, 4, 2, 1, 2, 1, 0, 0, 0, 0, 1, 1, 4, 3, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1,
+ 3, 3, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 3, 2, 1, 0, 1, 0, 0, 0, 0, 0, 1, 2, 4,
+ 4, 2, 1, 2, 1, 0, 0, 0, 0, 1, 1, 4, 3, 1, 1, 1, 1, 0, 0, 0, 0,
+
+ // level 3
+ 1, 1, 7, 7, 1, 1, 3, 3, 1, 1, 1, 1, 1, 0, 7, 6, 1, 0, 3, 2, 1, 0, 1, 0, 1,
+ 2, 10, 10, 2, 2, 5, 4, 2, 1, 2, 1, 1, 1, 10, 9, 1, 2, 4, 4, 2, 1, 2, 1, 1,
+ 1, 9, 9, 1, 2, 4, 4, 2, 1, 2, 1, 1, 0, 9, 8, 1, 1, 4, 3, 1, 1, 1, 1, 1, 2,
+ 8, 8, 2, 1, 4, 3, 1, 1, 1, 1, 1, 1, 8, 7, 1, 1, 3, 3, 1, 1, 1, 1};
+
+uint32_t JS[32] = {1, 1, 1, 1, 2, 2, 2, 2,
+ 4, 4, 4, 4, 8, 8, 8, 8,
+ 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x80, 0x80,
+ 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000};
+
+uint32_t J[32] = {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2,
+ 2, 3, 3, 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 9, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
+
+static inline void crxFillBuffer(CrxBitstream *bitStrm)
+{
+ if (bitStrm->curPos >= bitStrm->curBufSize && bitStrm->mdatSize)
+ {
+ bitStrm->curPos = 0;
+ bitStrm->curBufOffset += bitStrm->curBufSize;
+#ifdef LIBRAW_USE_OPENMP
+#pragma omp critical
+#endif
+ {
+#ifndef LIBRAW_USE_OPENMP
+ bitStrm->input->lock();
+#endif
+ bitStrm->input->seek(bitStrm->curBufOffset, SEEK_SET);
+ bitStrm->curBufSize = bitStrm->input->read(
+ bitStrm->mdatBuf, 1, _min(bitStrm->mdatSize, CRX_BUF_SIZE));
+#ifndef LIBRAW_USE_OPENMP
+ bitStrm->input->unlock();
+#endif
+ if (bitStrm->curBufSize < 1) // nothing read
+ throw LIBRAW_EXCEPTION_IO_EOF;
+ bitStrm->mdatSize -= bitStrm->curBufSize;
+ }
+ }
+}
+
+libraw_inline int crxBitstreamGetZeros(CrxBitstream *bitStrm)
+{
+ uint32_t bitData = bitStrm->bitData;
+ uint32_t nonZeroBit = 0;
+ uint64_t nextData = 0;
+ int32_t result = 0;
+
+ if (bitStrm->bitData)
+ {
+ _BitScanReverse((DWORD *)&nonZeroBit, (DWORD)bitStrm->bitData);
+ result = 31 - nonZeroBit;
+ bitStrm->bitData <<= 32 - nonZeroBit;
+ bitStrm->bitsLeft -= 32 - nonZeroBit;
+ }
+ else
+ {
+ uint32_t bitsLeft = bitStrm->bitsLeft;
+ while (1)
+ {
+ while (bitStrm->curPos + 4 <= bitStrm->curBufSize)
+ {
+ nextData =
+ _byteswap_ulong(*(uint32_t *)(bitStrm->mdatBuf + bitStrm->curPos));
+ bitStrm->curPos += 4;
+ crxFillBuffer(bitStrm);
+ if (nextData)
+ {
+ _BitScanReverse((DWORD *)&nonZeroBit, (DWORD)nextData);
+ result = bitsLeft + 31 - nonZeroBit;
+ bitStrm->bitData = nextData << (32 - nonZeroBit);
+ bitStrm->bitsLeft = nonZeroBit;
+ return result;
+ }
+ bitsLeft += 32;
+ }
+ if (bitStrm->curBufSize < bitStrm->curPos + 1)
+ break; // error
+ nextData = bitStrm->mdatBuf[bitStrm->curPos++];
+ crxFillBuffer(bitStrm);
+ if (nextData)
+ break;
+ bitsLeft += 8;
+ }
+ _BitScanReverse((DWORD *)&nonZeroBit, (DWORD)nextData);
+ result = (uint32_t)(bitsLeft + 7 - nonZeroBit);
+ bitStrm->bitData = nextData << (32 - nonZeroBit);
+ bitStrm->bitsLeft = nonZeroBit;
+ }
+ return result;
+}
+
+libraw_inline uint32_t crxBitstreamGetBits(CrxBitstream *bitStrm, int bits)
+{
+ int bitsLeft = bitStrm->bitsLeft;
+ uint32_t bitData = bitStrm->bitData;
+ uint32_t nextWord;
+ uint8_t nextByte;
+ uint32_t result;
+
+ if (bitsLeft < bits)
+ {
+ // get them from stream
+ if (bitStrm->curPos + 4 <= bitStrm->curBufSize)
+ {
+ nextWord =
+ _byteswap_ulong(*(uint32_t *)(bitStrm->mdatBuf + bitStrm->curPos));
+ bitStrm->curPos += 4;
+ crxFillBuffer(bitStrm);
+ bitStrm->bitsLeft = 32 - (bits - bitsLeft);
+ result = ((nextWord >> bitsLeft) | bitData) >> (32 - bits);
+ bitStrm->bitData = nextWord << (bits - bitsLeft);
+ return result;
+ }
+ // less than a word left - read byte at a time
+ do
+ {
+ if (bitStrm->curPos >= bitStrm->curBufSize)
+ break; // error
+ bitsLeft += 8;
+ nextByte = bitStrm->mdatBuf[bitStrm->curPos++];
+ crxFillBuffer(bitStrm);
+ bitData |= nextByte << (32 - bitsLeft);
+ } while (bitsLeft < bits);
+ }
+ result = bitData >> (32 - bits); // 32-bits
+ bitStrm->bitData = bitData << bits;
+ bitStrm->bitsLeft = bitsLeft - bits;
+ return result;
+}
+
+libraw_inline int crxPredictKParameter(int32_t prevK, int32_t bitCode,
+ int32_t maxVal = 0)
+{
+ int32_t newKParam = prevK - (bitCode < (1 << prevK >> 1)) +
+ ((bitCode >> prevK) > 2) + ((bitCode >> prevK) > 5);
+
+ return !maxVal || newKParam < maxVal ? newKParam : maxVal;
+}
+
+libraw_inline void crxDecodeSymbolL1(CrxBandParam *param,
+ int32_t doMedianPrediction,
+ int32_t notEOL = 0)
+{
+ if (doMedianPrediction)
+ {
+ int32_t symb[4];
+
+ int32_t delta = param->lineBuf0[1] - param->lineBuf0[0];
+ symb[2] = param->lineBuf1[0];
+ symb[0] = symb[1] = delta + symb[2];
+ symb[3] = param->lineBuf0[1];
+
+ param->lineBuf1[1] =
+ symb[(((param->lineBuf0[0] < param->lineBuf1[0]) ^ (delta < 0)) << 1) +
+ ((param->lineBuf1[0] < param->lineBuf0[1]) ^ (delta < 0))];
+ }
+ else
+ param->lineBuf1[1] = param->lineBuf0[1];
+
+ // get next error symbol
+ uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
+ if (bitCode >= 41)
+ bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
+ else if (param->kParam)
+ bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) |
+ (bitCode << param->kParam);
+
+ // add converted (+/-) error code to predicted value
+ param->lineBuf1[1] += -(bitCode & 1) ^ (bitCode >> 1);
+
+ // for not end of the line - use one symbol ahead to estimate next K
+ if (notEOL)
+ {
+ int32_t nextDelta = (param->lineBuf0[2] - param->lineBuf0[1]) << 1;
+ bitCode = (bitCode + _abs(nextDelta)) >> 1;
+ ++param->lineBuf0;
+ }
+
+ // update K parameter
+ param->kParam = crxPredictKParameter(param->kParam, bitCode, 15);
+
+ ++param->lineBuf1;
+}
+
+int crxDecodeLine(CrxBandParam *param)
+{
+ int length = param->subbandWidth;
+
+ param->lineBuf1[0] = param->lineBuf0[1];
+ for (; length > 1; --length)
+ {
+ if (param->lineBuf1[0] != param->lineBuf0[1] ||
+ param->lineBuf1[0] != param->lineBuf0[2])
+ {
+ crxDecodeSymbolL1(param, 1, 1);
+ }
+ else
+ {
+ int nSyms = 0;
+ if (crxBitstreamGetBits(¶m->bitStream, 1))
+ {
+ nSyms = 1;
+ while (crxBitstreamGetBits(¶m->bitStream, 1))
+ {
+ nSyms += JS[param->sParam];
+ if (nSyms > length)
+ {
+ nSyms = length;
+ break;
+ }
+ if (param->sParam < 31)
+ ++param->sParam;
+ if (nSyms == length)
+ break;
+ }
+
+ if (nSyms < length)
+ {
+ if (J[param->sParam])
+ nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]);
+ if (param->sParam > 0)
+ --param->sParam;
+ if (nSyms > length)
+ return -1;
+ }
+
+ length -= nSyms;
+
+ // copy symbol nSyms times
+ param->lineBuf0 += nSyms;
+
+ // copy symbol nSyms times
+ while (nSyms-- > 0)
+ {
+ param->lineBuf1[1] = param->lineBuf1[0];
+ ++param->lineBuf1;
+ }
+ }
+
+ if (length > 0)
+ crxDecodeSymbolL1(param, 0, (length > 1));
+ }
+ }
+
+ if (length == 1)
+ crxDecodeSymbolL1(param, 1, 0);
+
+ param->lineBuf1[1] = param->lineBuf1[0] + 1;
+
+ return 0;
+}
+
+libraw_inline void crxDecodeSymbolL1Rounded(CrxBandParam *param,
+ int32_t doSym = 1,
+ int32_t doCode = 1)
+{
+ int32_t sym = param->lineBuf0[1];
+
+ if (doSym)
+ {
+ // calculate the next symbol gradient
+ int32_t symb[4];
+ int32_t deltaH = param->lineBuf0[1] - param->lineBuf0[0];
+ symb[2] = param->lineBuf1[0];
+ symb[0] = symb[1] = deltaH + symb[2];
+ symb[3] = param->lineBuf0[1];
+ sym =
+ symb[(((param->lineBuf0[0] < param->lineBuf1[0]) ^ (deltaH < 0)) << 1) +
+ ((param->lineBuf1[0] < param->lineBuf0[1]) ^ (deltaH < 0))];
+ }
+
+ uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
+ if (bitCode >= 41)
+ bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
+ else if (param->kParam)
+ bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) |
+ (bitCode << param->kParam);
+ int32_t code = -(bitCode & 1) ^ (bitCode >> 1);
+ param->lineBuf1[1] = param->roundedBitsMask * 2 * code + (code >> 31) + sym;
+
+ if (doCode)
+ {
+ if (param->lineBuf0[2] > param->lineBuf0[1])
+ code = (param->lineBuf0[2] - param->lineBuf0[1] + param->roundedBitsMask -
+ 1) >>
+ param->roundedBits;
+ else
+ code = -(
+ (param->lineBuf0[1] - param->lineBuf0[2] + param->roundedBitsMask) >>
+ param->roundedBits);
+
+ param->kParam = crxPredictKParameter(param->kParam,
+ (bitCode + 2 * _abs(code)) >> 1, 15);
+ }
+ else
+ param->kParam = crxPredictKParameter(param->kParam, bitCode, 15);
+
+ ++param->lineBuf1;
+}
+
+int crxDecodeLineRounded(CrxBandParam *param)
+{
+ int32_t valueReached = 0;
+
+ param->lineBuf0[0] = param->lineBuf0[1];
+ param->lineBuf1[0] = param->lineBuf0[1];
+ int32_t length = param->subbandWidth;
+
+ for (; length > 1; --length)
+ {
+ if (_abs(param->lineBuf0[2] - param->lineBuf0[1]) > param->roundedBitsMask)
+ {
+ crxDecodeSymbolL1Rounded(param);
+ ++param->lineBuf0;
+ valueReached = 1;
+ }
+ else if (valueReached || _abs(param->lineBuf0[0] - param->lineBuf1[0]) >
+ param->roundedBitsMask)
+ {
+ crxDecodeSymbolL1Rounded(param);
+ ++param->lineBuf0;
+ valueReached = 0;
+ }
+ else
+ {
+ int nSyms = 0;
+ if (crxBitstreamGetBits(¶m->bitStream, 1))
+ {
+ nSyms = 1;
+ while (crxBitstreamGetBits(¶m->bitStream, 1))
+ {
+ nSyms += JS[param->sParam];
+ if (nSyms > length)
+ {
+ nSyms = length;
+ break;
+ }
+ if (param->sParam < 31)
+ ++param->sParam;
+ if (nSyms == length)
+ break;
+ }
+ if (nSyms < length)
+ {
+ if (J[param->sParam])
+ nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]);
+ if (param->sParam > 0)
+ --param->sParam;
+ }
+ if (nSyms > length)
+ return -1;
+ }
+ length -= nSyms;
+
+ // copy symbol nSyms times
+ param->lineBuf0 += nSyms;
+
+ // copy symbol nSyms times
+ while (nSyms-- > 0)
+ {
+ param->lineBuf1[1] = param->lineBuf1[0];
+ ++param->lineBuf1;
+ }
+
+ if (length > 1)
+ {
+ crxDecodeSymbolL1Rounded(param, 0);
+ ++param->lineBuf0;
+ valueReached = _abs(param->lineBuf0[1] - param->lineBuf0[0]) >
+ param->roundedBitsMask;
+ }
+ else if (length == 1)
+ crxDecodeSymbolL1Rounded(param, 0, 0);
+ }
+ }
+ if (length == 1)
+ crxDecodeSymbolL1Rounded(param, 1, 0);
+
+ param->lineBuf1[1] = param->lineBuf1[0] + 1;
+
+ return 0;
+}
+
+int crxDecodeLineNoRefPrevLine(CrxBandParam *param)
+{
+ int32_t i = 0;
+
+ for (; i < param->subbandWidth - 1; i++)
+ {
+ if (param->lineBuf0[i + 2] | param->lineBuf0[i + 1] | param->lineBuf1[i])
+ {
+ uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
+ if (bitCode >= 41)
+ bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
+ else if (param->kParam)
+ bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) |
+ (bitCode << param->kParam);
+ param->lineBuf1[i + 1] = -(bitCode & 1) ^ (bitCode >> 1);
+ param->kParam = crxPredictKParameter(param->kParam, bitCode);
+ if (param->lineBuf2[i + 1] - param->kParam <= 1)
+ {
+ if (param->kParam >= 15)
+ param->kParam = 15;
+ }
+ else
+ ++param->kParam;
+ }
+ else
+ {
+ int nSyms = 0;
+ if (crxBitstreamGetBits(¶m->bitStream, 1))
+ {
+ nSyms = 1;
+ if (i != param->subbandWidth - 1)
+ {
+ while (crxBitstreamGetBits(¶m->bitStream, 1))
+ {
+ nSyms += JS[param->sParam];
+ if (i + nSyms > param->subbandWidth)
+ {
+ nSyms = param->subbandWidth - i;
+ break;
+ }
+ if (param->sParam < 31)
+ ++param->sParam;
+ if (i + nSyms == param->subbandWidth)
+ break;
+ }
+ if (i + nSyms < param->subbandWidth)
+ {
+ if (J[param->sParam])
+ nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]);
+ if (param->sParam > 0)
+ --param->sParam;
+ }
+ if (i + nSyms > param->subbandWidth)
+ return -1;
+ }
+ }
+ else if (i > param->subbandWidth)
+ return -1;
+
+ if (nSyms > 0)
+ {
+ memset(param->lineBuf1 + i + 1, 0, nSyms * sizeof(int32_t));
+ memset(param->lineBuf2 + i, 0, nSyms * sizeof(int32_t));
+ i += nSyms;
+ }
+
+ if (i >= param->subbandWidth - 1)
+ {
+ if (i == param->subbandWidth - 1)
+ {
+ uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
+ if (bitCode >= 41)
+ bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
+ else if (param->kParam)
+ bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) |
+ (bitCode << param->kParam);
+ param->lineBuf1[i + 1] = -((bitCode + 1) & 1) ^ ((bitCode + 1) >> 1);
+ param->kParam = crxPredictKParameter(param->kParam, bitCode, 15);
+ param->lineBuf2[i] = param->kParam;
+ }
+ continue;
+ }
+ else
+ {
+ uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
+ if (bitCode >= 41)
+ bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
+ else if (param->kParam)
+ bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) |
+ (bitCode << param->kParam);
+ param->lineBuf1[i + 1] = -((bitCode + 1) & 1) ^ ((bitCode + 1) >> 1);
+ param->kParam = crxPredictKParameter(param->kParam, bitCode);
+ if (param->lineBuf2[i + 1] - param->kParam <= 1)
+ {
+ if (param->kParam >= 15)
+ param->kParam = 15;
+ }
+ else
+ ++param->kParam;
+ }
+ }
+ param->lineBuf2[i] = param->kParam;
+ }
+ if (i == param->subbandWidth - 1)
+ {
+ int32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
+ if (bitCode >= 41)
+ bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
+ else if (param->kParam)
+ bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) |
+ (bitCode << param->kParam);
+ param->lineBuf1[i + 1] = -(bitCode & 1) ^ (bitCode >> 1);
+ param->kParam = crxPredictKParameter(param->kParam, bitCode, 15);
+ param->lineBuf2[i] = param->kParam;
+ }
+
+ return 0;
+}
+
+int crxDecodeTopLine(CrxBandParam *param)
+{
+ param->lineBuf1[0] = 0;
+
+ int32_t length = param->subbandWidth;
+
+ // read the line from bitstream
+ for (; length > 1; --length)
+ {
+ if (param->lineBuf1[0])
+ param->lineBuf1[1] = param->lineBuf1[0];
+ else
+ {
+ int nSyms = 0;
+ if (crxBitstreamGetBits(¶m->bitStream, 1))
+ {
+ nSyms = 1;
+ while (crxBitstreamGetBits(¶m->bitStream, 1))
+ {
+ nSyms += JS[param->sParam];
+ if (nSyms > length)
+ {
+ nSyms = length;
+ break;
+ }
+ if (param->sParam < 31)
+ ++param->sParam;
+ if (nSyms == length)
+ break;
+ }
+ if (nSyms < length)
+ {
+ if (J[param->sParam])
+ nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]);
+ if (param->sParam > 0)
+ --param->sParam;
+ if (nSyms > length)
+ return -1;
+ }
+
+ length -= nSyms;
+
+ // copy symbol nSyms times
+ while (nSyms-- > 0)
+ {
+ param->lineBuf1[1] = param->lineBuf1[0];
+ ++param->lineBuf1;
+ }
+
+ if (length <= 0)
+ break;
+ }
+
+ param->lineBuf1[1] = 0;
+ }
+
+ uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
+ if (bitCode >= 41)
+ bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
+ else if (param->kParam)
+ bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) |
+ (bitCode << param->kParam);
+ param->lineBuf1[1] += -(bitCode & 1) ^ (bitCode >> 1);
+ param->kParam = crxPredictKParameter(param->kParam, bitCode, 15);
+ ++param->lineBuf1;
+ }
+
+ if (length == 1)
+ {
+ param->lineBuf1[1] = param->lineBuf1[0];
+ uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
+ if (bitCode >= 41)
+ bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
+ else if (param->kParam)
+ bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) |
+ (bitCode << param->kParam);
+ param->lineBuf1[1] += -(bitCode & 1) ^ (bitCode >> 1);
+ param->kParam = crxPredictKParameter(param->kParam, bitCode, 15);
+ ++param->lineBuf1;
+ }
+
+ param->lineBuf1[1] = param->lineBuf1[0] + 1;
+
+ return 0;
+}
+
+int crxDecodeTopLineRounded(CrxBandParam *param)
+{
+ param->lineBuf1[0] = 0;
+
+ int32_t length = param->subbandWidth;
+
+ // read the line from bitstream
+ for (; length > 1; --length)
+ {
+ if (_abs(param->lineBuf1[0]) > param->roundedBitsMask)
+ param->lineBuf1[1] = param->lineBuf1[0];
+ else
+ {
+ int nSyms = 0;
+ if (crxBitstreamGetBits(¶m->bitStream, 1))
+ {
+ nSyms = 1;
+ while (crxBitstreamGetBits(¶m->bitStream, 1))
+ {
+ nSyms += JS[param->sParam];
+ if (nSyms > length)
+ {
+ nSyms = length;
+ break;
+ }
+ if (param->sParam < 31)
+ ++param->sParam;
+ if (nSyms == length)
+ break;
+ }
+ if (nSyms < length)
+ {
+ if (J[param->sParam])
+ nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]);
+ if (param->sParam > 0)
+ --param->sParam;
+ if (nSyms > length)
+ return -1;
+ }
+ }
+
+ length -= nSyms;
+
+ // copy symbol nSyms times
+ while (nSyms-- > 0)
+ {
+ param->lineBuf1[1] = param->lineBuf1[0];
+ ++param->lineBuf1;
+ }
+
+ if (length <= 0)
+ break;
+
+ param->lineBuf1[1] = 0;
+ }
+
+ uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
+ if (bitCode >= 41)
+ bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
+ else if (param->kParam)
+ bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) |
+ (bitCode << param->kParam);
+
+ int32_t sVal = -(bitCode & 1) ^ (bitCode >> 1);
+ param->lineBuf1[1] += param->roundedBitsMask * 2 * sVal + (sVal >> 31);
+ param->kParam = crxPredictKParameter(param->kParam, bitCode, 15);
+ ++param->lineBuf1;
+ }
+
+ if (length == 1)
+ {
+ uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
+ if (bitCode >= 41)
+ bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
+ else if (param->kParam)
+ bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) |
+ (bitCode << param->kParam);
+ int32_t sVal = -(bitCode & 1) ^ (bitCode >> 1);
+ param->lineBuf1[1] += param->roundedBitsMask * 2 * sVal + (sVal >> 31);
+ param->kParam = crxPredictKParameter(param->kParam, bitCode, 15);
+ ++param->lineBuf1;
+ }
+
+ param->lineBuf1[1] = param->lineBuf1[0] + 1;
+
+ return 0;
+}
+
+int crxDecodeTopLineNoRefPrevLine(CrxBandParam *param)
+{
+ param->lineBuf0[0] = 0;
+ param->lineBuf1[0] = 0;
+ int32_t length = param->subbandWidth;
+ for (; length > 1; --length)
+ {
+ if (param->lineBuf1[0])
+ {
+ uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
+ if (bitCode >= 41)
+ bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
+ else if (param->kParam)
+ bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) |
+ (bitCode << param->kParam);
+ param->lineBuf1[1] = -(bitCode & 1) ^ (bitCode >> 1);
+ param->kParam = crxPredictKParameter(param->kParam, bitCode, 15);
+ }
+ else
+ {
+ int nSyms = 0;
+ if (crxBitstreamGetBits(¶m->bitStream, 1))
+ {
+ nSyms = 1;
+ while (crxBitstreamGetBits(¶m->bitStream, 1))
+ {
+ nSyms += JS[param->sParam];
+ if (nSyms > length)
+ {
+ nSyms = length;
+ break;
+ }
+ if (param->sParam < 31)
+ ++param->sParam;
+ if (nSyms == length)
+ break;
+ }
+ if (nSyms < length)
+ {
+ if (J[param->sParam])
+ nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]);
+ if (param->sParam > 0)
+ --param->sParam;
+ if (nSyms > length)
+ return -1;
+ }
+ }
+
+ length -= nSyms;
+
+ // copy symbol nSyms times
+ while (nSyms-- > 0)
+ {
+ param->lineBuf2[0] = 0;
+ param->lineBuf1[1] = 0;
+ ++param->lineBuf1;
+ ++param->lineBuf2;
+ }
+
+ if (length <= 0)
+ break;
+ uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
+ if (bitCode >= 41)
+ bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
+ else if (param->kParam)
+ bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) |
+ (bitCode << param->kParam);
+ param->lineBuf1[1] = -((bitCode + 1) & 1) ^ ((bitCode + 1) >> 1);
+ param->kParam = crxPredictKParameter(param->kParam, bitCode, 15);
+ }
+ param->lineBuf2[0] = param->kParam;
+ ++param->lineBuf2;
+ ++param->lineBuf1;
+ }
+
+ if (length == 1)
+ {
+ uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
+ if (bitCode >= 41)
+ bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
+ else if (param->kParam)
+ bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) |
+ (bitCode << param->kParam);
+ param->lineBuf1[1] = -(bitCode & 1) ^ (bitCode >> 1);
+ param->kParam = crxPredictKParameter(param->kParam, bitCode, 15);
+ param->lineBuf2[0] = param->kParam;
+ ++param->lineBuf1;
+ }
+
+ param->lineBuf1[1] = 0;
+
+ return 0;
+}
+
+int crxDecodeLine(CrxBandParam *param, uint8_t *bandBuf)
+{
+ if (!param || !bandBuf)
+ return -1;
+ if (param->curLine >= param->subbandHeight)
+ return -1;
+
+ if (param->curLine == 0)
+ {
+ int32_t lineLength = param->subbandWidth + 2;
+
+ param->sParam = 0;
+ param->kParam = 0;
+ if (param->supportsPartial)
+ {
+ if (param->roundedBitsMask <= 0)
+ {
+ param->lineBuf0 = (int32_t *)param->paramData;
+ param->lineBuf1 = param->lineBuf0 + lineLength;
+ int32_t *lineBuf = param->lineBuf1 + 1;
+ if (crxDecodeTopLine(param))
+ return -1;
+ memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(int32_t));
+ ++param->curLine;
+ }
+ else
+ {
+ param->roundedBits = 1;
+ if (param->roundedBitsMask & ~1)
+ {
+ while (param->roundedBitsMask >> param->roundedBits)
+ ++param->roundedBits;
+ }
+ param->lineBuf0 = (int32_t *)param->paramData;
+ param->lineBuf1 = param->lineBuf0 + lineLength;
+ int32_t *lineBuf = param->lineBuf1 + 1;
+ if (crxDecodeTopLineRounded(param))
+ return -1;
+ memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(int32_t));
+ ++param->curLine;
+ }
+ }
+ else
+ {
+ param->lineBuf2 = (int32_t *)param->nonProgrData;
+ param->lineBuf0 = (int32_t *)param->paramData;
+ param->lineBuf1 = param->lineBuf0 + lineLength;
+ int32_t *lineBuf = param->lineBuf1 + 1;
+ if (crxDecodeTopLineNoRefPrevLine(param))
+ return -1;
+ memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(int32_t));
+ ++param->curLine;
+ }
+ }
+ else if (!param->supportsPartial)
+ {
+ int32_t lineLength = param->subbandWidth + 2;
+ param->lineBuf2 = (int32_t *)param->nonProgrData;
+ if (param->curLine & 1)
+ {
+ param->lineBuf1 = (int32_t *)param->paramData;
+ param->lineBuf0 = param->lineBuf1 + lineLength;
+ }
+ else
+ {
+ param->lineBuf0 = (int32_t *)param->paramData;
+ param->lineBuf1 = param->lineBuf0 + lineLength;
+ }
+ int32_t *lineBuf = param->lineBuf1 + 1;
+ if (crxDecodeLineNoRefPrevLine(param))
+ return -1;
+ memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(int32_t));
+ ++param->curLine;
+ }
+ else if (param->roundedBitsMask <= 0)
+ {
+ int32_t lineLength = param->subbandWidth + 2;
+ if (param->curLine & 1)
+ {
+ param->lineBuf1 = (int32_t *)param->paramData;
+ param->lineBuf0 = param->lineBuf1 + lineLength;
+ }
+ else
+ {
+ param->lineBuf0 = (int32_t *)param->paramData;
+ param->lineBuf1 = param->lineBuf0 + lineLength;
+ }
+ int32_t *lineBuf = param->lineBuf1 + 1;
+ if (crxDecodeLine(param))
+ return -1;
+ memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(int32_t));
+ ++param->curLine;
+ }
+ else
+ {
+ int32_t lineLength = param->subbandWidth + 2;
+ if (param->curLine & 1)
+ {
+ param->lineBuf1 = (int32_t *)param->paramData;
+ param->lineBuf0 = param->lineBuf1 + lineLength;
+ }
+ else
+ {
+ param->lineBuf0 = (int32_t *)param->paramData;
+ param->lineBuf1 = param->lineBuf0 + lineLength;
+ }
+ int32_t *lineBuf = param->lineBuf1 + 1;
+ if (crxDecodeLineRounded(param))
+ return -1;
+ memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(int32_t));
+ ++param->curLine;
+ }
+ return 0;
+}
+
+int crxDecodeLineWithIQuantization(CrxSubband *subband)
+{
+ int32_t q_step_tbl[6] = {0x28, 0x2D, 0x33, 0x39, 0x40, 0x48};
+
+ if (!subband->dataSize)
+ {
+ memset(subband->bandBuf, 0, subband->bandSize);
+ return 0;
+ }
+
+ if (subband->supportsPartial)
+ {
+ uint32_t bitCode = crxBitstreamGetZeros(&subband->bandParam->bitStream);
+ if (bitCode >= 23)
+ bitCode = crxBitstreamGetBits(&subband->bandParam->bitStream, 8);
+ else if (subband->paramK)
+ bitCode =
+ crxBitstreamGetBits(&subband->bandParam->bitStream, subband->paramK) |
+ (bitCode << subband->paramK);
+
+ subband->quantValue +=
+ -(bitCode & 1) ^ (bitCode >> 1); // converting encoded to signed integer
+ subband->paramK = crxPredictKParameter(subband->paramK, bitCode);
+ if (subband->paramK > 7)
+ return -1;
+ }
+ if (crxDecodeLine(subband->bandParam, subband->bandBuf))
+ return -1;
+
+ if (subband->width <= 0)
+ return 0LL;
+
+ // update subband buffers
+ int32_t *bandBuf = (int32_t *)subband->bandBuf;
+ int32_t qScale =
+ q_step_tbl[subband->quantValue % 6] >> (6 - subband->quantValue / 6);
+ if (subband->quantValue / 6 >= 6)
+ qScale = q_step_tbl[subband->quantValue % 6] *
+ (1 << (subband->quantValue / 6 + 26));
+
+ if (qScale != 1)
+ for (int32_t i = 0; i < subband->width; i++)
+ bandBuf[i] *= qScale;
+
+ return 0;
+}
+
+void crxHorizontal53(int32_t *lineBufLA, int32_t *lineBufLB,
+ CrxWaveletTransform *wavelet, uint32_t tileFlag)
+{
+ int32_t *band0Buf = wavelet->subband0Buf;
+ int32_t *band1Buf = wavelet->subband1Buf;
+ int32_t *band2Buf = wavelet->subband2Buf;
+ int32_t *band3Buf = wavelet->subband3Buf;
+
+ if (wavelet->width <= 1)
+ {
+ lineBufLA[0] = band0Buf[0];
+ lineBufLB[0] = band2Buf[0];
+ }
+ else
+ {
+ if (tileFlag & E_HAS_TILES_ON_THE_LEFT)
+ {
+ lineBufLA[0] = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2);
+ lineBufLB[0] = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2);
+ ++band1Buf;
+ ++band3Buf;
+ }
+ else
+ {
+ lineBufLA[0] = band0Buf[0] - ((band1Buf[0] + 1) >> 1);
+ lineBufLB[0] = band2Buf[0] - ((band3Buf[0] + 1) >> 1);
+ }
+ ++band0Buf;
+ ++band2Buf;
+
+ for (int i = 0; i < wavelet->width - 3; i += 2)
+ {
+ int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2);
+ lineBufLA[1] = band1Buf[0] + ((delta + lineBufLA[0]) >> 1);
+ lineBufLA[2] = delta;
+
+ delta = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2);
+ lineBufLB[1] = band3Buf[0] + ((delta + lineBufLB[0]) >> 1);
+ lineBufLB[2] = delta;
+
+ ++band0Buf;
+ ++band1Buf;
+ ++band2Buf;
+ ++band3Buf;
+ lineBufLA += 2;
+ lineBufLB += 2;
+ }
+ if (tileFlag & E_HAS_TILES_ON_THE_RIGHT)
+ {
+ int32_t deltaA = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2);
+ lineBufLA[1] = band1Buf[0] + ((deltaA + lineBufLA[0]) >> 1);
+
+ int32_t deltaB = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2);
+ lineBufLB[1] = band3Buf[0] + ((deltaB + lineBufLB[0]) >> 1);
+
+ if (wavelet->width & 1)
+ {
+ lineBufLA[2] = deltaA;
+ lineBufLB[2] = deltaB;
+ }
+ }
+ else if (wavelet->width & 1)
+ {
+ lineBufLA[1] =
+ band1Buf[0] +
+ ((lineBufLA[0] + band0Buf[0] - ((band1Buf[0] + 1) >> 1)) >> 1);
+ lineBufLA[2] = band0Buf[0] - ((band1Buf[0] + 1) >> 1);
+
+ lineBufLB[1] =
+ band3Buf[0] +
+ ((lineBufLB[0] + band2Buf[0] - ((band3Buf[0] + 1) >> 1)) >> 1);
+ lineBufLB[2] = band2Buf[0] - ((band3Buf[0] + 1) >> 1);
+ }
+ else
+ {
+ lineBufLA[1] = lineBufLA[0] + band1Buf[0];
+ lineBufLB[1] = lineBufLB[0] + band3Buf[0];
+ }
+ }
+}
+
+int32_t *crxIdwt53FilterGetLine(CrxPlaneComp *comp, int32_t level)
+{
+ int32_t *result = comp->waveletTransform[level]
+ .lineBuf[(comp->waveletTransform[level].fltTapH -
+ comp->waveletTransform[level].curH + 5) %
+ 5 +
+ 3];
+ comp->waveletTransform[level].curH--;
+ return result;
+}
+
+int crxIdwt53FilterDecode(CrxPlaneComp *comp, int32_t level)
+{
+ if (comp->waveletTransform[level].curH)
+ return 0;
+
+ CrxSubband *sband = comp->subBands + 3 * level;
+
+ if (comp->waveletTransform[level].height - 3 <=
+ comp->waveletTransform[level].curLine &&
+ !(comp->tileFlag & E_HAS_TILES_ON_THE_BOTTOM))
+ {
+ if (comp->waveletTransform[level].height & 1)
+ {
+ if (level)
+ {
+ if (crxIdwt53FilterDecode(comp, level - 1))
+ return -1;
+ }
+ else if (crxDecodeLineWithIQuantization(sband))
+ return -1;
+
+ if (crxDecodeLineWithIQuantization(sband + 1))
+ return -1;
+ }
+ }
+ else
+ {
+ if (level)
+ {
+ if (crxIdwt53FilterDecode(comp, level - 1))
+ return -1;
+ }
+ else if (crxDecodeLineWithIQuantization(sband)) // LL band
+ return -1;
+
+ if (crxDecodeLineWithIQuantization(sband + 1) || // HL band
+ crxDecodeLineWithIQuantization(sband + 2) || // LH band
+ crxDecodeLineWithIQuantization(sband + 3)) // HH band
+ return -1;
+ }
+
+ return 0;
+}
+
+int crxIdwt53FilterTransform(CrxPlaneComp *comp, uint32_t level)
+{
+ CrxWaveletTransform *wavelet = comp->waveletTransform + level;
+
+ if (wavelet->curH)
+ return 0;
+
+ if (wavelet->curLine >= wavelet->height - 3)
+ {
+ if (!(comp->tileFlag & E_HAS_TILES_ON_THE_BOTTOM))
+ {
+ if (wavelet->height & 1)
+ {
+ if (level)
+ {
+ if (!wavelet[-1].curH)
+ if (crxIdwt53FilterTransform(comp, level - 1))
+ return -1;
+ wavelet->subband0Buf = crxIdwt53FilterGetLine(comp, level - 1);
+ }
+ int32_t *band0Buf = wavelet->subband0Buf;
+ int32_t *band1Buf = wavelet->subband1Buf;
+ int32_t *lineBufH0 = wavelet->lineBuf[wavelet->fltTapH + 3];
+ int32_t *lineBufH1 = wavelet->lineBuf[(wavelet->fltTapH + 1) % 5 + 3];
+ int32_t *lineBufH2 = wavelet->lineBuf[(wavelet->fltTapH + 2) % 5 + 3];
+
+ int32_t *lineBufL0 = wavelet->lineBuf[0];
+ int32_t *lineBufL1 = wavelet->lineBuf[1];
+ wavelet->lineBuf[1] = wavelet->lineBuf[2];
+ wavelet->lineBuf[2] = lineBufL1;
+
+ // process L bands
+ if (wavelet->width <= 1)
+ {
+ lineBufL0[0] = band0Buf[0];
+ }
+ else
+ {
+ if (comp->tileFlag & E_HAS_TILES_ON_THE_LEFT)
+ {
+ lineBufL0[0] = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2);
+ ++band1Buf;
+ }
+ else
+ {
+ lineBufL0[0] = band0Buf[0] - ((band1Buf[0] + 1) >> 1);
+ }
+ ++band0Buf;
+ for (int i = 0; i < wavelet->width - 3; i += 2)
+ {
+ int32_t delta =
+ band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2);
+ lineBufL0[1] = band1Buf[0] + ((lineBufL0[0] + delta) >> 1);
+ lineBufL0[2] = delta;
+ ++band0Buf;
+ ++band1Buf;
+ lineBufL0 += 2;
+ }
+ if (comp->tileFlag & E_HAS_TILES_ON_THE_RIGHT)
+ {
+ int32_t delta =
+ band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2);
+ lineBufL0[1] = band1Buf[0] + ((lineBufL0[0] + delta) >> 1);
+ if (wavelet->width & 1)
+ lineBufL0[2] = delta;
+ }
+ else if (wavelet->width & 1)
+ {
+ int32_t delta = band0Buf[0] - ((band1Buf[0] + 1) >> 1);
+ lineBufL0[1] = band1Buf[0] + ((lineBufL0[0] + delta) >> 1);
+ lineBufL0[2] = delta;
+ }
+ else
+ lineBufL0[1] = band1Buf[0] + lineBufL0[0];
+ }
+
+ // process H bands
+ lineBufL0 = wavelet->lineBuf[0];
+ lineBufL1 = wavelet->lineBuf[1];
+ for (int32_t i = 0; i < wavelet->width; i++)
+ {
+ int32_t delta = lineBufL0[i] - ((lineBufL1[i] + 1) >> 1);
+ lineBufH1[i] = lineBufL1[i] + ((delta + lineBufH0[i]) >> 1);
+ lineBufH2[i] = delta;
+ }
+ wavelet->curH += 3;
+ wavelet->curLine += 3;
+ wavelet->fltTapH = (wavelet->fltTapH + 3) % 5;
+ }
+ else
+ {
+ int32_t *lineBufL2 = wavelet->lineBuf[2];
+ int32_t *lineBufH0 = wavelet->lineBuf[wavelet->fltTapH + 3];
+ int32_t *lineBufH1 = wavelet->lineBuf[(wavelet->fltTapH + 1) % 5 + 3];
+ wavelet->lineBuf[1] = lineBufL2;
+ wavelet->lineBuf[2] = wavelet->lineBuf[1];
+
+ for (int32_t i = 0; i < wavelet->width; i++)
+ lineBufH1[i] = lineBufH0[i] + lineBufL2[i];
+
+ wavelet->curH += 2;
+ wavelet->curLine += 2;
+ wavelet->fltTapH = (wavelet->fltTapH + 2) % 5;
+ }
+ }
+ }
+ else
+ {
+ if (level)
+ {
+ if (!wavelet[-1].curH && crxIdwt53FilterTransform(comp, level - 1))
+ return -1;
+ wavelet->subband0Buf = crxIdwt53FilterGetLine(comp, level - 1);
+ }
+
+ int32_t *band0Buf = wavelet->subband0Buf;
+ int32_t *band1Buf = wavelet->subband1Buf;
+ int32_t *band2Buf = wavelet->subband2Buf;
+ int32_t *band3Buf = wavelet->subband3Buf;
+
+ int32_t *lineBufL0 = wavelet->lineBuf[0];
+ int32_t *lineBufL1 = wavelet->lineBuf[1];
+ int32_t *lineBufL2 = wavelet->lineBuf[2];
+ int32_t *lineBufH0 = wavelet->lineBuf[wavelet->fltTapH + 3];
+ int32_t *lineBufH1 = wavelet->lineBuf[(wavelet->fltTapH + 1) % 5 + 3];
+ int32_t *lineBufH2 = wavelet->lineBuf[(wavelet->fltTapH + 2) % 5 + 3];
+
+ wavelet->lineBuf[1] = wavelet->lineBuf[2];
+ wavelet->lineBuf[2] = lineBufL1;
+
+ // process L bands
+ if (wavelet->width <= 1)
+ {
+ lineBufL0[0] = band0Buf[0];
+ lineBufL1[0] = band2Buf[0];
+ }
+ else
+ {
+ if (comp->tileFlag & E_HAS_TILES_ON_THE_LEFT)
+ {
+ lineBufL0[0] = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2);
+ lineBufL1[0] = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2);
+ ++band1Buf;
+ ++band3Buf;
+ }
+ else
+ {
+ lineBufL0[0] = band0Buf[0] - ((band1Buf[0] + 1) >> 1);
+ lineBufL1[0] = band2Buf[0] - ((band3Buf[0] + 1) >> 1);
+ }
+ ++band0Buf;
+ ++band2Buf;
+ for (int i = 0; i < wavelet->width - 3; i += 2)
+ {
+ int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2);
+ lineBufL0[1] = band1Buf[0] + ((delta + lineBufL0[0]) >> 1);
+ lineBufL0[2] = delta;
+
+ delta = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2);
+ lineBufL1[1] = band3Buf[0] + ((delta + lineBufL1[0]) >> 1);
+ lineBufL1[2] = delta;
+
+ ++band0Buf;
+ ++band1Buf;
+ ++band2Buf;
+ ++band3Buf;
+ lineBufL0 += 2;
+ lineBufL1 += 2;
+ }
+ if (comp->tileFlag & E_HAS_TILES_ON_THE_RIGHT)
+ {
+ int32_t deltaA = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2);
+ lineBufL0[1] = band1Buf[0] + ((deltaA + lineBufL0[0]) >> 1);
+
+ int32_t deltaB = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2);
+ lineBufL1[1] = band3Buf[0] + ((deltaB + lineBufL1[0]) >> 1);
+
+ if (wavelet->width & 1)
+ {
+ lineBufL0[2] = deltaA;
+ lineBufL1[2] = deltaB;
+ }
+ }
+ else if (wavelet->width & 1)
+ {
+ int32_t delta = band0Buf[0] - ((band1Buf[0] + 1) >> 1);
+ lineBufL0[1] = band1Buf[0] + ((delta + lineBufL0[0]) >> 1);
+ lineBufL0[2] = delta;
+
+ delta = band2Buf[0] - ((band3Buf[0] + 1) >> 1);
+ lineBufL1[1] = band3Buf[0] + ((delta + lineBufL1[0]) >> 1);
+ lineBufL1[2] = delta;
+ }
+ else
+ {
+ lineBufL0[1] = lineBufL0[0] + band1Buf[0];
+ lineBufL1[1] = lineBufL1[0] + band3Buf[0];
+ }
+ }
+
+ // process H bands
+ lineBufL0 = wavelet->lineBuf[0];
+ lineBufL1 = wavelet->lineBuf[1];
+ lineBufL2 = wavelet->lineBuf[2];
+ for (int32_t i = 0; i < wavelet->width; i++)
+ {
+ int32_t delta = lineBufL0[i] - ((lineBufL2[i] + lineBufL1[i] + 2) >> 2);
+ lineBufH1[i] = lineBufL1[i] + ((delta + lineBufH0[i]) >> 1);
+ lineBufH2[i] = delta;
+ }
+ if (wavelet->curLine >= wavelet->height - 3 && wavelet->height & 1)
+ {
+ wavelet->curH += 3;
+ wavelet->curLine += 3;
+ wavelet->fltTapH = (wavelet->fltTapH + 3) % 5;
+ }
+ else
+ {
+ wavelet->curH += 2;
+ wavelet->curLine += 2;
+ wavelet->fltTapH = (wavelet->fltTapH + 2) % 5;
+ }
+ }
+
+ return 0;
+}
+
+int crxIdwt53FilterInitialize(CrxPlaneComp *comp, int32_t prevLevel)
+{
+ if (prevLevel < 0)
+ return 0;
+
+ for (int curLevel = 0, curBand = 0; curLevel < prevLevel + 1;
+ curLevel++, curBand += 3)
+ {
+ CrxWaveletTransform *wavelet = comp->waveletTransform + curLevel;
+ if (curLevel)
+ wavelet[0].subband0Buf = crxIdwt53FilterGetLine(comp, curLevel - 1);
+ else if (crxDecodeLineWithIQuantization(comp->subBands + curBand))
+ return -1;
+
+ int32_t *lineBufH0 = wavelet->lineBuf[wavelet->fltTapH + 3];
+ if (wavelet->height > 1)
+ {
+ if (crxDecodeLineWithIQuantization(comp->subBands + curBand + 1) ||
+ crxDecodeLineWithIQuantization(comp->subBands + curBand + 2) ||
+ crxDecodeLineWithIQuantization(comp->subBands + curBand + 3))
+ return -1;
+
+ int32_t *lineBufL0 = wavelet->lineBuf[0];
+ int32_t *lineBufL1 = wavelet->lineBuf[1];
+ int32_t *lineBufL2 = wavelet->lineBuf[2];
+
+ if (comp->tileFlag & E_HAS_TILES_ON_THE_TOP)
+ {
+ crxHorizontal53(lineBufL0, wavelet->lineBuf[1], wavelet,
+ comp->tileFlag);
+ if (crxDecodeLineWithIQuantization(comp->subBands + curBand + 3) ||
+ crxDecodeLineWithIQuantization(comp->subBands + curBand + 2))
+ return -1;
+
+ int32_t *band2Buf = wavelet->subband2Buf;
+ int32_t *band3Buf = wavelet->subband3Buf;
+
+ // process L band
+ if (wavelet->width <= 1)
+ lineBufL2[0] = band2Buf[0];
+ else
+ {
+ if (comp->tileFlag & E_HAS_TILES_ON_THE_LEFT)
+ {
+ lineBufL2[0] = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2);
+ ++band3Buf;
+ }
+ else
+ lineBufL2[0] = band2Buf[0] - ((band3Buf[0] + 1) >> 1);
+
+ ++band2Buf;
+
+ for (int i = 0; i < wavelet->width - 3; i += 2)
+ {
+ int32_t delta =
+ band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2);
+ lineBufL2[1] = band3Buf[0] + ((lineBufL2[0] + delta) >> 1);
+ lineBufL2[2] = delta;
+
+ ++band2Buf;
+ ++band3Buf;
+ lineBufL2 += 2;
+ }
+ if (comp->tileFlag & E_HAS_TILES_ON_THE_RIGHT)
+ {
+ int32_t delta =
+ band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2);
+ lineBufL2[1] = band3Buf[0] + ((lineBufL2[0] + delta) >> 1);
+ if (wavelet->width & 1)
+ lineBufL2[2] = delta;
+ }
+ else if (wavelet->width & 1)
+ {
+ int32_t delta = band2Buf[0] - ((band3Buf[0] + 1) >> 1);
+
+ lineBufL2[1] = band3Buf[0] + ((lineBufL2[0] + delta) >> 1);
+ lineBufL2[2] = delta;
+ }
+ else
+ {
+ lineBufL2[1] = band3Buf[0] + lineBufL2[0];
+ }
+ }
+
+ // process H band
+ for (int32_t i = 0; i < wavelet->width; i++)
+ lineBufH0[i] =
+ lineBufL0[i] - ((lineBufL1[i] + lineBufL2[i] + 2) >> 2);
+ }
+ else
+ {
+ crxHorizontal53(lineBufL0, wavelet->lineBuf[2], wavelet,
+ comp->tileFlag);
+ for (int i = 0; i < wavelet->width; i++)
+ lineBufH0[i] = lineBufL0[i] - ((lineBufL2[i] + 1) >> 1);
+ }
+
+ if (crxIdwt53FilterDecode(comp, curLevel) ||
+ crxIdwt53FilterTransform(comp, curLevel))
+ return -1;
+ }
+ else
+ {
+ if (crxDecodeLineWithIQuantization(comp->subBands + curBand + 1))
+ return -1;
+
+ int32_t *band0Buf = wavelet->subband0Buf;
+ int32_t *band1Buf = wavelet->subband1Buf;
+
+ // process H band
+ if (wavelet->width <= 1)
+ lineBufH0[0] = band0Buf[0];
+ else
+ {
+ if (comp->tileFlag & E_HAS_TILES_ON_THE_LEFT)
+ {
+ lineBufH0[0] = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2);
+ ++band1Buf;
+ }
+ else
+ lineBufH0[0] = band0Buf[0] - ((band1Buf[0] + 1) >> 1);
+
+ ++band0Buf;
+
+ for (int i = 0; i < wavelet->width - 3; i += 2)
+ {
+ int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2);
+ lineBufH0[1] = band1Buf[0] + ((lineBufH0[0] + delta) >> 1);
+ lineBufH0[2] = delta;
+
+ ++band0Buf;
+ ++band1Buf;
+ lineBufH0 += 2;
+ }
+
+ if (comp->tileFlag & E_HAS_TILES_ON_THE_RIGHT)
+ {
+ int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2);
+ lineBufH0[1] = band1Buf[0] + ((lineBufH0[0] + delta) >> 1);
+ lineBufH0[2] = delta;
+ }
+ else if (wavelet->width & 1)
+ {
+ int32_t delta = band0Buf[0] - ((band1Buf[0] + 1) >> 1);
+ lineBufH0[1] = band1Buf[0] + ((lineBufH0[0] + delta) >> 1);
+ lineBufH0[2] = delta;
+ }
+ else
+ {
+ lineBufH0[1] = band1Buf[0] + lineBufH0[0];
+ }
+ }
+ ++wavelet->curLine;
+ ++wavelet->curH;
+ wavelet->fltTapH = (wavelet->fltTapH + 1) % 5;
+ }
+ }
+
+ return 0;
+}
+
+void crxFreeSubbandData(CrxImage *image, CrxPlaneComp *comp)
+{
+ if (comp->compBuf)
+ {
+ free(comp->compBuf);
+ comp->compBuf = 0;
+ }
+
+ if (!comp->subBands)
+ return;
+
+ for (int32_t i = 0; i < image->subbandCount; i++)
+ {
+ if (comp->subBands[i].bandParam)
+ {
+ free(comp->subBands[i].bandParam);
+ comp->subBands[i].bandParam = 0LL;
+ }
+ comp->subBands[i].bandBuf = 0;
+ comp->subBands[i].bandSize = 0;
+ }
+}
+
+void crxConvertPlaneLine(CrxImage *img, int imageRow, int imageCol = 0,
+ int plane = 0, int32_t *lineData = 0,
+ int lineLength = 0)
+{
+ if (lineData)
+ {
+ uint64_t rawOffset = 4 * img->planeWidth * imageRow + 2 * imageCol;
+ if (img->encType == 1)
+ {
+ int32_t maxVal = 1 << (img->nBits - 1);
+ int32_t minVal = -maxVal;
+ --maxVal;
+ for (int i = 0; i < lineLength; i++)
+ img->outBufs[plane][rawOffset + 2 * i] =
+ _constrain(lineData[i], minVal, maxVal);
+ }
+ else if (img->encType == 3)
+ {
+ // copy to intermediate planeBuf
+ rawOffset = plane * img->planeWidth * img->planeHeight +
+ img->planeWidth * imageRow + imageCol;
+ for (int i = 0; i < lineLength; i++)
+ img->planeBuf[rawOffset + i] = lineData[i];
+ }
+ else if (img->nPlanes == 4)
+ {
+ int32_t median = 1 << (img->nBits - 1);
+ int32_t maxVal = (1 << img->nBits) - 1;
+ for (int i = 0; i < lineLength; i++)
+ img->outBufs[plane][rawOffset + 2 * i] =
+ _constrain(median + lineData[i], 0, maxVal);
+ }
+ else if (img->nPlanes == 1)
+ {
+ int32_t maxVal = (1 << img->nBits) - 1;
+ int32_t median = 1 << (img->nBits - 1);
+ rawOffset = img->planeWidth * imageRow + imageCol;
+ for (int i = 0; i < lineLength; i++)
+ img->outBufs[0][rawOffset + i] =
+ _constrain(median + lineData[i], 0, maxVal);
+ }
+ }
+ else if (img->encType == 3 && img->planeBuf)
+ {
+ int32_t planeSize = img->planeWidth * img->planeHeight;
+ int16_t *plane0 = img->planeBuf + imageRow * img->planeWidth;
+ int16_t *plane1 = plane0 + planeSize;
+ int16_t *plane2 = plane1 + planeSize;
+ int16_t *plane3 = plane2 + planeSize;
+
+ int32_t median = 1 << (img->nBits - 1) << 10;
+ int32_t maxVal = (1 << img->nBits) - 1;
+ uint32_t rawLineOffset = 4 * img->planeWidth * imageRow;
+
+ // for this stage - all except imageRow is ignored
+ for (int i = 0; i < img->planeWidth; i++)
+ {
+ int32_t gr =
+ median + (plane0[i] << 10) - 168 * plane1[i] - 585 * plane3[i];
+ int32_t val = 0;
+ if (gr < 0)
+ gr = -(((_abs(gr) + 512) >> 9) & ~1);
+ else
+ gr = ((_abs(gr) + 512) >> 9) & ~1;
+
+ // Essentially R = round(median + P0 + 1.474*P3)
+ val = (median + (plane0[i] << 10) + 1510 * plane3[i] + 512) >> 10;
+ img->outBufs[0][rawLineOffset + 2 * i] = _constrain(val, 0, maxVal);
+ // Essentially G1 = round(median + P0 + P2 - 0.164*P1 - 0.571*P3)
+ val = (plane2[i] + gr + 1) >> 1;
+ img->outBufs[1][rawLineOffset + 2 * i] = _constrain(val, 0, maxVal);
+ // Essentially G1 = round(median + P0 - P2 - 0.164*P1 - 0.571*P3)
+ val = (gr - plane2[i] + 1) >> 1;
+ img->outBufs[2][rawLineOffset + 2 * i] = _constrain(val, 0, maxVal);
+ // Essentially B = round(median + P0 + 1.881*P1)
+ val = (median + (plane0[i] << 10) + 1927 * plane1[i] + 512) >> 10;
+ img->outBufs[3][rawLineOffset + 2 * i] = _constrain(val, 0, maxVal);
+ }
+ }
+}
+
+int crxParamInit(CrxBandParam **param, uint64_t subbandMdatOffset,
+ uint64_t subbandDataSize, uint32_t subbandWidth,
+ uint32_t subbandHeight, int32_t supportsPartial,
+ uint32_t roundedBitsMask, LibRaw_abstract_datastream *input)
+{
+ int32_t progrDataSize = supportsPartial ? 0 : sizeof(int32_t) * subbandWidth;
+ int32_t paramLength = 2 * subbandWidth + 4;
+ uint8_t *paramBuf = (uint8_t *)calloc(
+ 1, sizeof(CrxBandParam) + sizeof(int32_t) * paramLength + progrDataSize);
+
+ if (!paramBuf)
+ return -1;
+
+ *param = (CrxBandParam *)paramBuf;
+
+ paramBuf += sizeof(CrxBandParam);
+
+ (*param)->paramData = (int32_t *)paramBuf;
+ (*param)->nonProgrData =
+ progrDataSize ? (*param)->paramData + paramLength : 0;
+ (*param)->subbandWidth = subbandWidth;
+ (*param)->subbandHeight = subbandHeight;
+ (*param)->roundedBits = 0;
+ (*param)->curLine = 0;
+ (*param)->roundedBitsMask = roundedBitsMask;
+ (*param)->supportsPartial = supportsPartial;
+ (*param)->bitStream.bitData = 0;
+ (*param)->bitStream.bitsLeft = 0;
+ (*param)->bitStream.mdatSize = subbandDataSize;
+ (*param)->bitStream.curPos = 0;
+ (*param)->bitStream.curBufSize = 0;
+ (*param)->bitStream.curBufOffset = subbandMdatOffset;
+ (*param)->bitStream.input = input;
+
+ crxFillBuffer(&(*param)->bitStream);
+
+ return 0;
+}
+
+int crxSetupSubbandData(CrxImage *img, CrxPlaneComp *planeComp,
+ const CrxTile *tile, uint32_t mdatOffset)
+{
+ long compDataSize = 0;
+ long waveletDataOffset = 0;
+ long compCoeffDataOffset = 0;
+ int32_t toSubbands = 3 * img->levels + 1;
+ int32_t transformWidth = 0;
+
+ CrxSubband *subbands = planeComp->subBands;
+
+ // calculate sizes
+ for (int32_t subbandNum = 0; subbandNum < toSubbands; subbandNum++)
+ {
+ subbands[subbandNum].bandSize =
+ subbands[subbandNum].width * sizeof(int32_t); // 4bytes
+ compDataSize += subbands[subbandNum].bandSize;
+ }
+
+ if (img->levels)
+ {
+ int32_t encLevels = img->levels ? img->levels : 1;
+ waveletDataOffset = (compDataSize + 7) & ~7;
+ compDataSize =
+ (sizeof(CrxWaveletTransform) * encLevels + waveletDataOffset + 7) & ~7;
+ compCoeffDataOffset = compDataSize;
+
+ // calc wavelet line buffer sizes (always at one level up from current)
+ for (int level = 0; level < img->levels; ++level)
+ if (level < img->levels - 1)
+ compDataSize += 8 * sizeof(int32_t) *
+ planeComp->subBands[3 * (level + 1) + 2].width;
+ else
+ compDataSize += 8 * sizeof(int32_t) * tile->width;
+ }
+
+ // buffer allocation
+ planeComp->compBuf = (uint8_t *)malloc(compDataSize);
+ if (!planeComp->compBuf)
+ return -1;
+
+ // subbands buffer and sizes initialisation
+ uint64_t subbandMdatOffset = img->mdatOffset + mdatOffset;
+ uint8_t *subbandBuf = planeComp->compBuf;
+
+ for (int32_t subbandNum = 0; subbandNum < toSubbands; subbandNum++)
+ {
+ subbands[subbandNum].bandBuf = subbandBuf;
+ subbandBuf += subbands[subbandNum].bandSize;
+ subbands[subbandNum].mdatOffset =
+ subbandMdatOffset + subbands[subbandNum].dataOffset;
+ }
+
+ // wavelet data initialisation
+ if (img->levels)
+ {
+ CrxWaveletTransform *waveletTransforms =
+ (CrxWaveletTransform *)(planeComp->compBuf + waveletDataOffset);
+ int32_t *paramData = (int32_t *)(planeComp->compBuf + compCoeffDataOffset);
+
+ planeComp->waveletTransform = waveletTransforms;
+ waveletTransforms[0].subband0Buf = (int32_t *)subbands->bandBuf;
+
+ for (int level = 0; level < img->levels; ++level)
+ {
+ int32_t band = 3 * level + 1;
+
+ if (level >= img->levels - 1)
+ {
+ waveletTransforms[level].height = tile->height;
+ transformWidth = tile->width;
+ }
+ else
+ {
+ waveletTransforms[level].height = subbands[band + 3].height;
+ transformWidth = subbands[band + 4].width;
+ }
+ waveletTransforms[level].width = transformWidth;
+ waveletTransforms[level].lineBuf[0] = paramData;
+ waveletTransforms[level].lineBuf[1] =
+ waveletTransforms[level].lineBuf[0] + transformWidth;
+ waveletTransforms[level].lineBuf[2] =
+ waveletTransforms[level].lineBuf[1] + transformWidth;
+ waveletTransforms[level].lineBuf[3] =
+ waveletTransforms[level].lineBuf[2] + transformWidth;
+ waveletTransforms[level].lineBuf[4] =
+ waveletTransforms[level].lineBuf[3] + transformWidth;
+ waveletTransforms[level].lineBuf[5] =
+ waveletTransforms[level].lineBuf[4] + transformWidth;
+ waveletTransforms[level].lineBuf[6] =
+ waveletTransforms[level].lineBuf[5] + transformWidth;
+ waveletTransforms[level].lineBuf[7] =
+ waveletTransforms[level].lineBuf[6] + transformWidth;
+ waveletTransforms[level].curLine = 0;
+ waveletTransforms[level].curH = 0;
+ waveletTransforms[level].fltTapH = 0;
+ waveletTransforms[level].subband1Buf = (int32_t *)subbands[band].bandBuf;
+ waveletTransforms[level].subband2Buf =
+ (int32_t *)subbands[band + 1].bandBuf;
+ waveletTransforms[level].subband3Buf =
+ (int32_t *)subbands[band + 2].bandBuf;
+
+ paramData = waveletTransforms[level].lineBuf[7] + transformWidth;
+ }
+ }
+
+ // decoding params and bitstream initialisation
+ for (int32_t subbandNum = 0; subbandNum < toSubbands; subbandNum++)
+ {
+ if (subbands[subbandNum].dataSize)
+ {
+ int32_t supportsPartial = 0;
+ uint32_t roundedBitsMask = 0;
+
+ if (planeComp->supportsPartial && subbandNum == 0)
+ {
+ roundedBitsMask = planeComp->roundedBitsMask;
+ supportsPartial = 1;
+ }
+ if (crxParamInit(&subbands[subbandNum].bandParam,
+ subbands[subbandNum].mdatOffset,
+ subbands[subbandNum].dataSize,
+ subbands[subbandNum].width, subbands[subbandNum].height,
+ supportsPartial, roundedBitsMask, img->input))
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+} // namespace
+
+
+int DCraw::crxDecodePlane(void *p, uint32_t planeNumber)
+{
+ CrxImage *img = (CrxImage *)p;
+ int imageRow = 0;
+ for (int tRow = 0; tRow < img->tileRows; tRow++)
+ {
+ int imageCol = 0;
+ for (int tCol = 0; tCol < img->tileCols; tCol++)
+ {
+ CrxTile *tile = img->tiles + tRow * img->tileRows + tCol;
+ CrxPlaneComp *planeComp = tile->comps + planeNumber;
+ uint64_t tileMdatOffset = tile->dataOffset + planeComp->dataOffset;
+
+ // decode single tile
+ if (crxSetupSubbandData(img, planeComp, tile, tileMdatOffset))
+ return -1;
+
+ if (img->levels)
+ {
+ if (crxIdwt53FilterInitialize(planeComp, img->levels - 1))
+ return -1;
+ for (int i = 0; i < tile->height; ++i)
+ {
+ if (crxIdwt53FilterDecode(planeComp, img->levels - 1) ||
+ crxIdwt53FilterTransform(planeComp, img->levels - 1))
+ return -1;
+ int32_t *lineData =
+ crxIdwt53FilterGetLine(planeComp, img->levels - 1);
+ crxConvertPlaneLine(img, imageRow + i, imageCol, planeNumber,
+ lineData, tile->width);
+ }
+ }
+ else
+ {
+ // we have the only subband in this case
+ if (!planeComp->subBands->dataSize)
+ {
+ memset(planeComp->subBands->bandBuf, 0,
+ planeComp->subBands->bandSize);
+ return 0;
+ }
+
+ for (int i = 0; i < tile->height; ++i)
+ {
+ if (crxDecodeLine(planeComp->subBands->bandParam,
+ planeComp->subBands->bandBuf))
+ return -1;
+ int32_t *lineData = (int32_t *)planeComp->subBands->bandBuf;
+ crxConvertPlaneLine(img, imageRow + i, imageCol, planeNumber,
+ lineData, tile->width);
+ }
+ }
+ imageCol += tile->width;
+ }
+ imageRow += img->tiles[tRow * img->tileRows].height;
+ }
+
+ return 0;
+}
+
+
+namespace {
+
+typedef DCraw::CanonCR3Data::crx_data_header_t crx_data_header_t;
+
+
+int crxReadSubbandHeaders(crx_data_header_t *hdr, CrxImage *img, CrxTile *tile,
+ CrxPlaneComp *comp, uint8_t **subbandMdatPtr,
+ uint32_t *mdatSize)
+{
+ CrxSubband *band = comp->subBands + img->subbandCount - 1; // set to last band
+ uint32_t bandHeight = tile->height;
+ uint32_t bandWidth = tile->width;
+ int32_t bandWidthExCoef = 0;
+ int32_t bandHeightExCoef = 0;
+ if (img->levels)
+ {
+ // Build up subband sequences to crxDecode to a level in a header
+
+ // Coefficient structure is a bit unclear and convoluted:
+ // 3 levels max - 8 groups (for tile width rounded to 8 bytes)
+ // of 3 band per level 4 sets of coefficients for each
+ int32_t *rowExCoef =
+ exCoefNumTbl + 0x60 * (img->levels - 1) + 12 * (tile->width & 7);
+ int32_t *colExCoef =
+ exCoefNumTbl + 0x60 * (img->levels - 1) + 12 * (tile->height & 7);
+ for (int level = 0; level < img->levels; ++level)
+ {
+ int32_t widthOddPixel = bandWidth & 1;
+ int32_t heightOddPixel = bandHeight & 1;
+ bandWidth = (widthOddPixel + bandWidth) >> 1;
+ bandHeight = (heightOddPixel + bandHeight) >> 1;
+
+ int32_t bandWidthExCoef0 = 0;
+ int32_t bandWidthExCoef1 = 0;
+ int32_t bandHeightExCoef0 = 0;
+ int32_t bandHeightExCoef1 = 0;
+ if (tile->tileFlag & E_HAS_TILES_ON_THE_RIGHT)
+ {
+ bandWidthExCoef0 = rowExCoef[0];
+ bandWidthExCoef1 = rowExCoef[1];
+ }
+ if (tile->tileFlag & E_HAS_TILES_ON_THE_LEFT)
+ ++bandWidthExCoef0;
+ if (tile->tileFlag & E_HAS_TILES_ON_THE_BOTTOM)
+ {
+ bandHeightExCoef0 = colExCoef[0];
+ bandHeightExCoef1 = colExCoef[1];
+ }
+ if (tile->tileFlag & E_HAS_TILES_ON_THE_TOP)
+ ++bandHeightExCoef0;
+
+ band[0].width = bandWidth + bandWidthExCoef0 - widthOddPixel;
+ band[0].height = bandHeight + bandHeightExCoef0 - heightOddPixel;
+
+ band[-1].width = bandWidth + bandWidthExCoef1;
+ band[-1].height = bandHeight + bandHeightExCoef0 - heightOddPixel;
+
+ band[-2].width = bandWidth + bandWidthExCoef0 - widthOddPixel;
+ band[-2].height = bandHeight + bandHeightExCoef1;
+
+ rowExCoef += 4;
+ colExCoef += 4;
+ band -= 3;
+ }
+ bandWidthExCoef = bandHeightExCoef = 0;
+ if (tile->tileFlag & E_HAS_TILES_ON_THE_RIGHT)
+ bandWidthExCoef =
+ exCoefNumTbl[0x60 * (img->levels - 1) + 12 * (tile->width & 7) +
+ 4 * (img->levels - 1) + 1];
+ if (tile->tileFlag & E_HAS_TILES_ON_THE_BOTTOM)
+ bandHeightExCoef =
+ exCoefNumTbl[0x60 * (img->levels - 1) + 12 * (tile->height & 7) +
+ 4 * (img->levels - 1) + 1];
+ }
+ band->width = bandWidthExCoef + bandWidth;
+ band->height = bandHeightExCoef + bandHeight;
+
+ if (!img->subbandCount)
+ return 0;
+ int32_t curSubband = 0;
+ int32_t subbandOffset = 0;
+ band = comp->subBands;
+ for (int curSubband = 0; curSubband < img->subbandCount; curSubband++, band++)
+ {
+ if (*mdatSize < 0xC)
+ return -1;
+
+ if (sgetn(2, *subbandMdatPtr) != 0xFF03)
+ return -1;
+
+ uint32_t bitData = sgetn(4, *subbandMdatPtr + 8);
+ uint32_t subbandSize = sgetn(4, *subbandMdatPtr + 4);
+
+ if (curSubband != bitData >> 28)
+ {
+ band->dataSize = subbandSize;
+ return -1;
+ }
+ band->dataSize = subbandSize - (bitData & 0x7FF);
+ band->supportsPartial = bitData & 0x8000 ? 1 : 0;
+ band->dataOffset = subbandOffset;
+ band->quantValue = (bitData >> 19) & 0xFF;
+ band->paramK = 0;
+ band->bandParam = 0;
+ band->bandBuf = 0;
+ band->bandSize = 0;
+
+ subbandOffset += subbandSize;
+
+ *subbandMdatPtr += 0xC;
+ *mdatSize -= 0xC;
+ }
+ return 0;
+}
+
+int crxReadImageHeaders(crx_data_header_t *hdr, CrxImage *img, uint8_t *mdatPtr,
+ uint32_t mdatSize)
+{
+ int nTiles = img->tileRows * img->tileCols;
+
+ if (!nTiles)
+ return -1;
+
+ if (!img->tiles)
+ {
+ img->tiles = (CrxTile *)malloc(
+ sizeof(CrxTile) * nTiles +
+ sizeof(CrxPlaneComp) * nTiles * img->nPlanes +
+ sizeof(CrxSubband) * nTiles * img->nPlanes * img->subbandCount);
+ if (!img->tiles)
+ return -1;
+
+ // memory areas in allocated chunk
+ CrxTile *tile = img->tiles;
+ CrxPlaneComp *comps = (CrxPlaneComp *)(tile + nTiles);
+ CrxSubband *bands = (CrxSubband *)(comps + img->nPlanes * nTiles);
+
+ for (int curTile = 0; curTile < nTiles; curTile++, tile++)
+ {
+ tile->tileFlag = 0; // tile neighbouring flags
+ tile->tileNumber = curTile;
+ tile->tileSize = 0;
+ tile->comps = comps + curTile * img->nPlanes;
+
+ if ((curTile + 1) % img->tileCols)
+ {
+ // not the last tile in a tile row
+ tile->width = hdr->tileWidth;
+ if (img->tileCols > 1)
+ {
+ tile->tileFlag = E_HAS_TILES_ON_THE_RIGHT;
+ if (curTile % img->tileCols)
+ // not the first tile in tile row
+ tile->tileFlag |= E_HAS_TILES_ON_THE_LEFT;
+ }
+ }
+ else
+ {
+ // last tile in a tile row
+ tile->width = img->planeWidth - hdr->tileWidth * (img->tileCols - 1);
+ if (img->tileCols > 1)
+ tile->tileFlag = E_HAS_TILES_ON_THE_LEFT;
+ }
+ if (curTile < nTiles - img->tileCols)
+ {
+ // in first tile row
+ tile->height = hdr->tileHeight;
+ if (img->tileRows > 1)
+ {
+ tile->tileFlag |= E_HAS_TILES_ON_THE_BOTTOM;
+ if (curTile >= img->tileCols)
+ tile->tileFlag |= E_HAS_TILES_ON_THE_TOP;
+ }
+ }
+ else
+ {
+ // non first tile row
+ tile->height = img->planeHeight - hdr->tileHeight * (img->tileRows - 1);
+ if (img->tileRows > 1)
+ tile->tileFlag |= E_HAS_TILES_ON_THE_TOP;
+ }
+ if (img->nPlanes)
+ {
+ CrxPlaneComp *comp = tile->comps;
+ CrxSubband *band = bands + curTile * img->nPlanes * img->subbandCount;
+
+ for (int curComp = 0; curComp < img->nPlanes; curComp++, comp++)
+ {
+ comp->compNumber = curComp;
+ comp->supportsPartial = 1;
+ comp->tileFlag = tile->tileFlag;
+ comp->subBands = band;
+ comp->compBuf = 0;
+ comp->waveletTransform = 0;
+ if (img->subbandCount)
+ {
+ for (int curBand = 0; curBand < img->subbandCount;
+ curBand++, band++)
+ {
+ band->supportsPartial = 0;
+ band->quantValue = 4;
+ band->bandParam = 0;
+ band->dataSize = 0;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ uint32_t tileOffset = 0;
+ uint32_t dataSize = mdatSize;
+ uint8_t *dataPtr = mdatPtr;
+ CrxTile *tile = img->tiles;
+
+ for (int curTile = 0; curTile < nTiles; curTile++, tile++)
+ {
+ if (dataSize < 0xC)
+ return -1;
+
+ if (sgetn(2, dataPtr) != 0xFF01)
+ return -1;
+ if (sgetn(2, dataPtr + 8) != curTile)
+ return -1;
+
+ dataSize -= 0xC;
+
+ tile->tileSize = sgetn(4, dataPtr + 4);
+ tile->dataOffset = tileOffset;
+
+ int32_t hdrExtraBytes = sgetn(2, dataPtr + 2) - 8;
+ tileOffset += tile->tileSize;
+ dataPtr += hdrExtraBytes + 0xC;
+ dataSize -= hdrExtraBytes;
+
+ uint32_t compOffset = 0;
+ CrxPlaneComp *comp = tile->comps;
+
+ for (int compNum = 0; compNum < img->nPlanes; compNum++, comp++)
+ {
+ if (dataSize < 0xC)
+ return -1;
+
+ if (sgetn(2, dataPtr) != 0xFF02)
+ return -1;
+ if (compNum != dataPtr[8] >> 4)
+ return -1;
+
+ comp->compSize = sgetn(4, dataPtr + 4);
+
+ int32_t compHdrRoundedBits = (dataPtr[8] >> 1) & 3;
+ comp->supportsPartial = (dataPtr[8] & 8) != 0;
+
+ comp->dataOffset = compOffset;
+ comp->tileFlag = tile->tileFlag;
+
+ compOffset += comp->compSize;
+ dataSize -= 0xC;
+ dataPtr += 0xC;
+
+ comp->roundedBitsMask = 0;
+
+ if (compHdrRoundedBits)
+ {
+ if (img->levels || !comp->supportsPartial)
+ return -1;
+
+ comp->roundedBitsMask = 1 << (compHdrRoundedBits - 1);
+ }
+
+ if (crxReadSubbandHeaders(hdr, img, tile, comp, &dataPtr, &dataSize))
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int crxSetupImageData(crx_data_header_t *hdr, CrxImage *img, int16_t *outBuf,
+ uint64_t mdatOffset, uint32_t mdatSize,
+ uint8_t *mdatHdrPtr)
+{
+ int IncrBitTable[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0};
+
+ img->planeWidth = hdr->f_width;
+ img->planeHeight = hdr->f_height;
+
+ if (hdr->tileWidth < 0x16 || hdr->tileHeight < 0x16 ||
+ img->planeWidth > 0x7FFF || img->planeHeight > 0x7FFF)
+ return -1;
+
+ img->tileCols = (img->planeWidth + hdr->tileWidth - 1) / hdr->tileWidth;
+ img->tileRows = (img->planeHeight + hdr->tileHeight - 1) / hdr->tileHeight;
+
+ if (img->tileCols > 0xFF || img->tileRows > 0xFF ||
+ img->planeWidth - hdr->tileWidth * (img->tileCols - 1) < 0x16 ||
+ img->planeHeight - hdr->tileHeight * (img->tileRows - 1) < 0x16)
+ return -1;
+
+ img->tiles = 0;
+ img->levels = hdr->imageLevels;
+ img->subbandCount = 3 * img->levels + 1; // 3 bands per level + one last LL
+ img->nPlanes = hdr->nPlanes;
+ img->nBits = hdr->nBits;
+ img->encType = hdr->encType;
+ img->samplePrecision = hdr->nBits + IncrBitTable[4 * hdr->encType + 2] + 1;
+ img->mdatOffset = mdatOffset + hdr->mdatHdrSize;
+ img->mdatSize = mdatSize;
+ img->planeBuf = 0;
+ img->outBufs[0] = img->outBufs[1] = img->outBufs[2] = img->outBufs[3] = 0;
+
+ // The encoding type 3 needs all 4 planes to be decoded to generate row of
+ // RGGB values. It seems to be using some other colour space for raw encoding
+ // It is a massive buffer so ideallly it will need a different approach:
+ // decode planes line by line and convert single line then without
+ // intermediate plane buffer. At the moment though it's too many changes so
+ // left as is.
+ if (img->encType == 3 && img->nPlanes == 4 && img->nBits > 8)
+ {
+ img->planeBuf =
+ (int16_t *)malloc(img->planeHeight * img->planeWidth * img->nPlanes *
+ ((img->samplePrecision + 7) >> 3));
+ if (!img->planeBuf)
+ return -1;
+ }
+
+ int32_t rowSize = 2 * img->planeWidth;
+
+ if (img->nPlanes == 1)
+ img->outBufs[0] = outBuf;
+ else
+ switch (hdr->cfaLayout)
+ {
+ case 0:
+ // R G
+ // G B
+ img->outBufs[0] = outBuf;
+ img->outBufs[1] = outBuf + 1;
+ img->outBufs[2] = outBuf + rowSize;
+ img->outBufs[3] = img->outBufs[2] + 1;
+ break;
+ case 1:
+ // G R
+ // B G
+ img->outBufs[1] = outBuf;
+ img->outBufs[0] = outBuf + 1;
+ img->outBufs[3] = outBuf + rowSize;
+ img->outBufs[2] = img->outBufs[3] + 1;
+ break;
+ case 2:
+ // G B
+ // R G
+ img->outBufs[2] = outBuf;
+ img->outBufs[3] = outBuf + 1;
+ img->outBufs[0] = outBuf + rowSize;
+ img->outBufs[1] = img->outBufs[0] + 1;
+ break;
+ case 3:
+ // B G
+ // G R
+ img->outBufs[3] = outBuf;
+ img->outBufs[2] = outBuf + 1;
+ img->outBufs[1] = outBuf + rowSize;
+ img->outBufs[0] = img->outBufs[1] + 1;
+ break;
+ }
+
+ // read header
+ return crxReadImageHeaders(hdr, img, mdatHdrPtr, mdatSize);
+}
+
+int crxFreeImageData(CrxImage *img)
+{
+ CrxTile *tile = img->tiles;
+ int nTiles = img->tileRows * img->tileCols;
+
+ if (img->tiles)
+ {
+ for (int32_t curTile = 0; curTile < nTiles; curTile++, tile++)
+ if (tile[curTile].comps)
+ for (int32_t curPlane = 0; curPlane < img->nPlanes; curPlane++)
+ crxFreeSubbandData(img, tile[curTile].comps + curPlane);
+ free(img->tiles);
+ img->tiles = 0;
+ }
+
+ if (img->planeBuf)
+ {
+ free(img->planeBuf);
+ img->planeBuf = 0;
+ }
+
+ return 0;
+}
+
+} // namespace
+
+void DCraw::crxLoadDecodeLoop(void *img, int nPlanes)
+{
+#ifdef LIBRAW_USE_OPENMP
+ int results[4]; // nPlanes is always <= 4
+#pragma omp parallel for
+ for (int32_t plane = 0; plane < nPlanes; ++plane)
+ results[plane] = crxDecodePlane(img, plane);
+
+ for (int32_t plane = 0; plane < nPlanes; ++plane)
+ if (results[plane])
+ derror();
+#else
+ for (int32_t plane = 0; plane < nPlanes; ++plane)
+ if (crxDecodePlane(img, plane))
+ derror();
+#endif
+}
+
+void DCraw::crxConvertPlaneLineDf(void *p, int imageRow)
+{
+ crxConvertPlaneLine((CrxImage *)p, imageRow);
+}
+
+void DCraw::crxLoadFinalizeLoopE3(void *p, int planeHeight)
+{
+#ifdef LIBRAW_USE_OPENMP
+#pragma omp parallel for
+#endif
+ for (int i = 0; i < planeHeight; ++i)
+ crxConvertPlaneLineDf(p, i);
+}
+
+void DCraw::crxLoadRaw()
+{
+ CrxImage img;
+ if (RT_canon_CR3_data.crx_track_selected < 0 ||
+ RT_canon_CR3_data.crx_track_selected >=
+ LIBRAW_CRXTRACKS_MAXCOUNT)
+ derror();
+ crx_data_header_t hdr =
+ RT_canon_CR3_data
+ .crx_header[RT_canon_CR3_data.crx_track_selected];
+
+ LibRaw_abstract_datastream input = { ifp };
+ img.input = &input; //libraw_internal_data.internal_data.input;
+
+ // update sizes for the planes
+ if (hdr.nPlanes == 4)
+ {
+ hdr.f_width >>= 1;
+ hdr.f_height >>= 1;
+ hdr.tileWidth >>= 1;
+ hdr.tileHeight >>= 1;
+ }
+
+// /*imgdata.color.*/maximum = (1 << hdr.nBits) - 1;
+
+ uint8_t *hdrBuf = (uint8_t *)malloc(hdr.mdatHdrSize);
+
+ // read image header
+#ifdef LIBRAW_USE_OPENMP
+#pragma omp critical
+#endif
+ {
+#ifndef LIBRAW_USE_OPENMP
+ /*libraw_internal_data.internal_data.input->*/input.lock();
+#endif
+ /*libraw_internal_data.internal_data.input->*/input.seek(
+ data_offset, SEEK_SET);
+ /*libraw_internal_data.internal_data.input->*/input.read(hdrBuf, 1, hdr.mdatHdrSize);
+#ifndef LIBRAW_USE_OPENMP
+ /*libraw_internal_data.internal_data.input->*/input.unlock();
+#endif
+ }
+
+ // parse and setup the image data
+ if (crxSetupImageData(&hdr, &img, (int16_t *)raw_image,
+ hdr.MediaOffset/*data_offset*/,
+ hdr.MediaSize/*RT_canon_CR3_data.data_size*/, hdrBuf))
+ derror();
+ free(hdrBuf);
+
+ crxLoadDecodeLoop(&img, hdr.nPlanes);
+
+ if (img.encType == 3)
+ crxLoadFinalizeLoopE3(&img, img.planeHeight);
+
+ crxFreeImageData(&img);
+}
+
+int DCraw::crxParseImageHeader(uchar *cmp1TagData, int nTrack)
+{
+ if (nTrack < 0 || nTrack >= LIBRAW_CRXTRACKS_MAXCOUNT)
+ return -1;
+ if (!cmp1TagData)
+ return -1;
+
+ crx_data_header_t *hdr =
+ &RT_canon_CR3_data.crx_header[nTrack];
+
+ hdr->version = sgetn(2, cmp1TagData + 4);
+ hdr->f_width = sgetn(4, cmp1TagData + 8);
+ hdr->f_height = sgetn(4, cmp1TagData + 12);
+ hdr->tileWidth = sgetn(4, cmp1TagData + 16);
+ hdr->tileHeight = sgetn(4, cmp1TagData + 20);
+ hdr->nBits = cmp1TagData[24];
+ hdr->nPlanes = cmp1TagData[25] >> 4;
+ hdr->cfaLayout = cmp1TagData[25] & 0xF;
+ hdr->encType = cmp1TagData[26] >> 4;
+ hdr->imageLevels = cmp1TagData[26] & 0xF;
+ hdr->hasTileCols = cmp1TagData[27] >> 7;
+ hdr->hasTileRows = (cmp1TagData[27] >> 6) & 1;
+ hdr->mdatHdrSize = sgetn(4, cmp1TagData + 28);
+
+ // validation
+ if (hdr->version != 0x100 || !hdr->mdatHdrSize)
+ return -1;
+ if (hdr->encType == 1)
+ {
+ if (hdr->nBits > 15)
+ return -1;
+ }
+ else
+ {
+ if (hdr->encType && hdr->encType != 3)
+ return -1;
+ if (hdr->nBits > 14)
+ return -1;
+ }
+
+ if (hdr->nPlanes == 1)
+ {
+ if (hdr->cfaLayout || hdr->encType)
+ return -1;
+ if (hdr->nBits != 8)
+ return -1;
+ }
+ else if (hdr->nPlanes != 4 || hdr->f_width & 1 || hdr->f_height & 1 ||
+ hdr->tileWidth & 1 || hdr->tileHeight & 1 || hdr->cfaLayout > 3u ||
+ (hdr->encType && hdr->encType != 1 && hdr->encType != 3) ||
+ hdr->nBits == 8)
+ return -1;
+
+ if (hdr->tileWidth > hdr->f_width || hdr->tileHeight > hdr->f_height)
+ return -1;
+
+ if (hdr->imageLevels > 3 || hdr->hasTileCols > 1 || hdr->hasTileRows > 1)
+ return -1;
+ return 0;
+}
+
+#undef _abs
+#undef _min
+#undef _constrain
+#undef libraw_inline
+#undef LIBRAW_CRXTRACKS_MAXCOUNT
+
+#ifdef __GNUC__ // silence warning
+#pragma GCC diagnostic pop
+#endif
diff --git a/rtengine/dcraw.cc b/rtengine/dcraw.cc
index b81594dc4..0e95a3b1e 100644
--- a/rtengine/dcraw.cc
+++ b/rtengine/dcraw.cc
@@ -5595,13 +5595,26 @@ nf: order = 0x4949;
else if (!strcmp (buf,"AOC") ||
!strcmp (buf,"QVC"))
fseek (ifp, -4, SEEK_CUR);
+ // ALB -- taken from LibRaw ------------------------------------------------
+ else if (!strncmp(buf, "CMT3", 4))
+ {
+ order = sget2((uchar *)(buf + 4));
+ fseek(ifp, 2L, SEEK_CUR);
+ }
+ else if (RT_canon_CR3_data.CR3_CTMDtag)
+ {
+ order = sget2((uchar *)buf);
+ fseek(ifp, -2L, SEEK_CUR);
+ }
+ // -------------------------------------------------------------------------
+
else {
fseek (ifp, -10, SEEK_CUR);
if (!strncmp(make,"SAMSUNG",7))
base = ftell(ifp);
}
entries = get2();
- if (entries > 1000) return;
+ if (entries > 2000) return;
morder = order;
while (entries--) {
order = morder;
@@ -5806,16 +5819,335 @@ get2_256:
parse_thumb_note (base, 136, 137);
}
if (tag == 0x4001 && len > 500) {
- i = len == 582 ? 50 : len == 653 ? 68 : len == 5120 ? 142 : 126;
- fseek (ifp, i, SEEK_CUR);
- FORC4 cam_mul[c ^ (c >> 1)] = get2();
- for (i+=18; i <= len; i+=10) {
- get2();
- FORC4 sraw_mul[c ^ (c >> 1)] = get2();
- if (sraw_mul[1] == 1170) break;
+ // i = len == 582 ? 50 : len == 653 ? 68 : len == 5120 ? 142 : 126;
+ // fseek (ifp, i, SEEK_CUR);
+ // FORC4 cam_mul[c ^ (c >> 1)] = get2();
+ // for (i+=18; i <= len; i+=10) {
+ // get2();
+ // FORC4 sraw_mul[c ^ (c >> 1)] = get2();
+ // if (sraw_mul[1] == 1170) break;
+ // }
+ // -- ALB -- adapted from LibRaw --------------------------------------
+ int bls = 0;
+ long int offsetChannelBlackLevel = 0L;
+ long int offsetChannelBlackLevel2 = 0L;
+ long int offsetWhiteLevels = 0L;
+ struct {
+ int AverageBlackLevel;
+ int ColorDataSubVer;
+ int NormalWhiteLevel;
+ int SpecularWhiteLevel;
+ } imCanon = { 0, 0, 0, 0 };
+ long int save1 = ftell(ifp);
+
+ switch (len)
+ {
+
+ case 582:
+ // imCanon.ColorDataVer = 1; // 20D / 350D
+
+ fseek(ifp, save1 + (0x0019 << 1), SEEK_SET);
+ FORC4 cam_mul[c ^ (c >> 1)] = (float)get2();
+ // fseek(ifp, save1 + (0x001e << 1), SEEK_SET);
+ // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Auto][c ^ (c >> 1)] = get2();
+ // fseek(ifp, save1 + (0x0041 << 1), SEEK_SET);
+ // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Custom1][c ^ (c >> 1)] = get2();
+ // fseek(ifp, save1 + (0x0046 << 1), SEEK_SET);
+ // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Custom2][c ^ (c >> 1)] = get2();
+
+ // fseek(ifp, save1 + (0x0023 << 1), SEEK_SET);
+ // Canon_WBpresets(2, 2);
+ // fseek(ifp, save1 + (0x004b << 1), SEEK_SET);
+ // Canon_WBCTpresets(1); // ABCT
+ offsetChannelBlackLevel = save1 + (0x00a6 << 1);
+ break;
+
+ case 653:
+ // imCanon.ColorDataVer = 2; // 1Dmk2 / 1DsMK2
+
+ // fseek(ifp, save1 + (0x0018 << 1), SEEK_SET);
+ // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Auto][c ^ (c >> 1)] = get2();
+ fseek(ifp, save1 + (0x0022 << 1), SEEK_SET);
+ FORC4 cam_mul[c ^ (c >> 1)] = (float)get2();
+ // fseek(ifp, save1 + (0x0090 << 1), SEEK_SET);
+ // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Custom1][c ^ (c >> 1)] = get2();
+ // fseek(ifp, save1 + (0x0095 << 1), SEEK_SET);
+ // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Custom2][c ^ (c >> 1)] = get2();
+ // fseek(ifp, save1 + (0x009a << 1), SEEK_SET);
+ // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Custom3][c ^ (c >> 1)] = get2();
+
+ // fseek(ifp, save1 + (0x0027 << 1), SEEK_SET);
+ // Canon_WBpresets(2, 12);
+ // fseek(ifp, save1 + (0x00a4 << 1), SEEK_SET);
+ // Canon_WBCTpresets(1); // ABCT
+ offsetChannelBlackLevel = save1 + (0x011e << 1);
+ break;
+
+ case 796:
+ // imCanon.ColorDataVer = 3; // 1DmkIIN / 5D / 30D / 400D
+ // imCanon.ColorDataSubVer = get2();
+
+ fseek(ifp, save1 + (0x003f << 1), SEEK_SET);
+ FORC4 cam_mul[c ^ (c >> 1)] = (float)get2();
+ // fseek(ifp, save1 + (0x0044 << 1), SEEK_SET);
+ // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Auto][c ^ (c >> 1)] = get2();
+ // fseek(ifp, save1 + (0x0049 << 1), SEEK_SET);
+ // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Measured][c ^ (c >> 1)] = get2();
+ // fseek(ifp, save1 + (0x0071 << 1), SEEK_SET);
+ // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Custom1][c ^ (c >> 1)] = get2();
+ // fseek(ifp, save1 + (0x0076 << 1), SEEK_SET);
+ // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Custom2][c ^ (c >> 1)] = get2();
+ // fseek(ifp, save1 + (0x007b << 1), SEEK_SET);
+ // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Custom3][c ^ (c >> 1)] = get2();
+ // fseek(ifp, save1 + (0x0080 << 1), SEEK_SET);
+ // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Custom][c ^ (c >> 1)] = get2();
+
+ // fseek(ifp, save1 + (0x004e << 1), SEEK_SET);
+ // Canon_WBpresets(2, 12);
+ // fseek(ifp, save1 + (0x0085 << 1), SEEK_SET);
+ // Canon_WBCTpresets(0); // BCAT
+ offsetChannelBlackLevel = save1 + (0x00c4 << 1);
+ break;
+
+ // 1DmkIII / 1DSmkIII / 1DmkIV / 5DmkII
+ // 7D / 40D / 50D / 60D / 450D / 500D
+ // 550D / 1000D / 1100D
+ case 674:
+ case 692:
+ case 702:
+ case 1227:
+ case 1250:
+ case 1251:
+ case 1337:
+ case 1338:
+ case 1346:
+ // imCanon.ColorDataVer = 4;
+ imCanon.ColorDataSubVer = get2();
+
+ fseek(ifp, save1 + (0x003f << 1), SEEK_SET);
+ FORC4 cam_mul[c ^ (c >> 1)] = (float)get2();
+ // fseek(ifp, save1 + (0x0044 << 1), SEEK_SET);
+ // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Auto][c ^ (c >> 1)] = get2();
+ // fseek(ifp, save1 + (0x0049 << 1), SEEK_SET);
+ // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Measured][c ^ (c >> 1)] = get2();
+
+ fseek(ifp, save1 + (0x004e << 1), SEEK_SET);
+ FORC4 sraw_mul[c ^ (c >> 1)] = get2();
+ // fseek(ifp, save1 + (0x0053 << 1), SEEK_SET);
+ // Canon_WBpresets(2, 12);
+ // fseek(ifp, save1 + (0x00a8 << 1), SEEK_SET);
+ // Canon_WBCTpresets(0); // BCAT
+
+ if ((imCanon.ColorDataSubVer == 4) ||
+ (imCanon.ColorDataSubVer == 5))
+ {
+ offsetChannelBlackLevel = save1 + (0x02b4 << 1);
+ offsetWhiteLevels = save1 + (0x02b8 << 1);
}
+ else if ((imCanon.ColorDataSubVer == 6) ||
+ (imCanon.ColorDataSubVer == 7))
+ {
+ offsetChannelBlackLevel = save1 + (0x02cb << 1);
+ offsetWhiteLevels = save1 + (0x02cf << 1);
+ }
+ else if (imCanon.ColorDataSubVer == 9)
+ {
+ offsetChannelBlackLevel = save1 + (0x02cf << 1);
+ offsetWhiteLevels = save1 + (0x02d3 << 1);
+ }
+ else
+ offsetChannelBlackLevel = save1 + (0x00e7 << 1);
+ break;
+
+ case 5120: // PowerShot G10, G12, G5 X, G7 X, G9 X, EOS M3, EOS M5, EOS M6
+ // imCanon.ColorDataVer = 5;
+ imCanon.ColorDataSubVer = get2();
+
+ fseek(ifp, save1 + (0x0047 << 1), SEEK_SET);
+ FORC4 cam_mul[c ^ (c >> 1)] = (float)get2();
+
+ if (imCanon.ColorDataSubVer == 0xfffc)
+ { // -4: G7 X Mark II, G9 X Mark II, G1 X Mark III, M5, M100, M6
+ // fseek(ifp, save1 + (0x004f << 1), SEEK_SET);
+ // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Auto][c ^ (c >> 1)] = get2();
+ // fseek(ifp, 8, SEEK_CUR);
+ // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Measured][c ^ (c >> 1)] =
+ // get2();
+ // fseek(ifp, 8, SEEK_CUR);
+ // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Other][c ^ (c >> 1)] = get2();
+ // fseek(ifp, 8, SEEK_CUR);
+ // Canon_WBpresets(8, 24);
+ // fseek(ifp, 168, SEEK_CUR);
+ // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_WW][c ^ (c >> 1)] = get2();
+ // fseek(ifp, 24, SEEK_CUR);
+ // Canon_WBCTpresets(2); // BCADT
+ offsetChannelBlackLevel = save1 + (0x014d << 1);
+ offsetWhiteLevels = save1 + (0x0569 << 1);
+ }
+ else if (imCanon.ColorDataSubVer == 0xfffd)
+ { // -3: M10/M3/G1 X/G1 X II/G10/G11/G12/G15/G16/G3 X/G5 X/G7 X/G9
+ // X/S100/S110/S120/S90/S95/SX1 IX/SX50 HS/SX60 HS
+ // fseek(ifp, save1 + (0x004c << 1), SEEK_SET);
+ // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Auto][c ^ (c >> 1)] = get2();
+ // get2();
+ // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Measured][c ^ (c >> 1)] =
+ // get2();
+ // get2();
+ // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Other][c ^ (c >> 1)] = get2();
+ // get2();
+ // Canon_WBpresets(2, 12);
+ // fseek(ifp, save1 + (0x00ba << 1), SEEK_SET);
+ // Canon_WBCTpresets(2); // BCADT
+ offsetChannelBlackLevel = save1 + (0x0108 << 1);
+ }
+ break;
+
+ case 1273:
+ case 1275:
+ // imCanon.ColorDataVer = 6; // 600D / 1200D
+ imCanon.ColorDataSubVer = get2();
+
+ fseek(ifp, save1 + (0x003f << 1), SEEK_SET);
+ FORC4 cam_mul[c ^ (c >> 1)] = (float)get2();
+ // fseek(ifp, save1 + (0x0044 << 1), SEEK_SET);
+ // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Auto][c ^ (c >> 1)] = get2();
+ // fseek(ifp, save1 + (0x0049 << 1), SEEK_SET);
+ // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Measured][c ^ (c >> 1)] = get2();
+
+ fseek(ifp, save1 + (0x0062 << 1), SEEK_SET);
+ FORC4 sraw_mul[c ^ (c >> 1)] = get2();
+ // fseek(ifp, save1 + (0x0067 << 1), SEEK_SET);
+ // Canon_WBpresets(2, 12);
+ // fseek(ifp, save1 + (0x00bc << 1), SEEK_SET);
+ // Canon_WBCTpresets(0); // BCAT
+ offsetChannelBlackLevel = save1 + (0x01df << 1);
+ offsetWhiteLevels = save1 + (0x01e3 << 1);
+ break;
+
+ // 1DX / 5DmkIII / 6D / 100D / 650D / 700D / EOS M / 7DmkII / 750D / 760D
+ case 1312:
+ case 1313:
+ case 1316:
+ case 1506:
+ // imCanon.ColorDataVer = 7;
+ imCanon.ColorDataSubVer = get2();
+
+ fseek(ifp, save1 + (0x003f << 1), SEEK_SET);
+ FORC4 cam_mul[c ^ (c >> 1)] = (float)get2();
+ // fseek(ifp, save1 + (0x0044 << 1), SEEK_SET);
+ // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Auto][c ^ (c >> 1)] = get2();
+ // fseek(ifp, save1 + (0x0049 << 1), SEEK_SET);
+ // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Measured][c ^ (c >> 1)] = get2();
+
+ fseek(ifp, save1 + (0x007b << 1), SEEK_SET);
+ FORC4 sraw_mul[c ^ (c >> 1)] = get2();
+ // fseek(ifp, save1 + (0x0080 << 1), SEEK_SET);
+ // Canon_WBpresets(2, 12);
+ // fseek(ifp, save1 + (0x00d5 << 1), SEEK_SET);
+ // Canon_WBCTpresets(0); // BCAT
+
+ if (imCanon.ColorDataSubVer == 10)
+ {
+ offsetChannelBlackLevel = save1 + (0x01f8 << 1);
+ offsetWhiteLevels = save1 + (0x01fc << 1);
+ }
+ else if (imCanon.ColorDataSubVer == 11)
+ {
+ offsetChannelBlackLevel = save1 + (0x02d8 << 1);
+ offsetWhiteLevels = save1 + (0x02dc << 1);
+ }
+ break;
+
+ // 5DS / 5DS R / 80D / 1300D / 1500D / 3000D / 5D4 / 800D / 77D / 6D II /
+ // 200D
+ case 1560:
+ case 1592:
+ case 1353:
+ case 1602:
+ // imCanon.ColorDataVer = 8;
+ imCanon.ColorDataSubVer = get2();
+
+ fseek(ifp, save1 + (0x003f << 1), SEEK_SET);
+ FORC4 cam_mul[c ^ (c >> 1)] = (float)get2();
+ // fseek(ifp, save1 + (0x0044 << 1), SEEK_SET);
+ // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Auto][c ^ (c >> 1)] = get2();
+ // fseek(ifp, save1 + (0x0049 << 1), SEEK_SET);
+ // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Measured][c ^ (c >> 1)] = get2();
+
+ fseek(ifp, save1 + (0x0080 << 1), SEEK_SET);
+ FORC4 sraw_mul[c ^ (c >> 1)] = get2();
+ // fseek(ifp, save1 + (0x0085 << 1), SEEK_SET);
+ // Canon_WBpresets(2, 12);
+ // fseek(ifp, save1 + (0x0107 << 1), SEEK_SET);
+ // Canon_WBCTpresets(0); // BCAT
+
+ if (imCanon.ColorDataSubVer == 14)
+ { // 1300D / 1500D / 3000D
+ offsetChannelBlackLevel = save1 + (0x022c << 1);
+ offsetWhiteLevels = save1 + (0x0230 << 1);
+ }
+ else
+ {
+ offsetChannelBlackLevel = save1 + (0x030a << 1);
+ offsetWhiteLevels = save1 + (0x030e << 1);
+ }
+ break;
+
+ case 1820: // M50, ColorDataSubVer 16
+ case 1824: // EOS R, SX740HS, ColorDataSubVer 17
+ case 1816: // EOS RP, SX70HS, ColorDataSubVer 18;
+ // EOS M6 Mark II, EOS 90D, G7XmkIII, ColorDataSubVer 19
+ // imCanon.ColorDataVer = 9;
+ imCanon.ColorDataSubVer = get2();
+
+ fseek(ifp, save1 + (0x0047 << 1), SEEK_SET);
+ FORC4 cam_mul[c ^ (c >> 1)] = (float)get2();
+ // get2();
+ // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Auto][c ^ (c >> 1)] = get2();
+ // get2();
+ // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Measured][c ^ (c >> 1)] = get2();
+ // fseek(ifp, save1 + (0x0088 << 1), SEEK_SET);
+ // Canon_WBpresets(2, 12);
+ // fseek(ifp, save1 + (0x010a << 1), SEEK_SET);
+ // Canon_WBCTpresets(0);
+ offsetChannelBlackLevel = save1 + (0x0318 << 1);
+ offsetChannelBlackLevel2 = save1 + (0x0149 << 1);
+ offsetWhiteLevels = save1 + (0x031c << 1);
+ break;
}
- if (tag == 0x4021 && get4() && get4())
+
+ if (offsetChannelBlackLevel)
+ {
+ fseek(ifp, offsetChannelBlackLevel, SEEK_SET);
+ FORC4
+ bls += (cblack/*imCanon.ChannelBlackLevel*/[c ^ (c >> 1)] = get2());
+ imCanon.AverageBlackLevel = bls / 4;
+ // RT_blacklevel_from_constant = ThreeValBool::F;
+ }
+ if (offsetWhiteLevels)
+ {
+ if ((offsetWhiteLevels - offsetChannelBlackLevel) != 8L)
+ fseek(ifp, offsetWhiteLevels, SEEK_SET);
+ imCanon.NormalWhiteLevel = get2();
+ imCanon.SpecularWhiteLevel = get2();
+ // FORC4
+ // imgdata.color.linear_max[c] = imCanon.SpecularWhiteLevel;
+ maximum = imCanon.SpecularWhiteLevel;
+ // RT_whitelevel_from_constant = ThreeValBool::F;
+ }
+
+ if(!imCanon.AverageBlackLevel && offsetChannelBlackLevel2)
+ {
+ fseek(ifp, offsetChannelBlackLevel2, SEEK_SET);
+ FORC4
+ bls += (cblack/*imCanon.ChannelBlackLevel*/[c ^ (c >> 1)] = get2());
+ imCanon.AverageBlackLevel = bls / 4;
+ // RT_blacklevel_from_constant = ThreeValBool::F;
+ }
+ fseek(ifp, save1, SEEK_SET);
+
+ //---------------------------------------------------------------------
+ } if (tag == 0x4021 && get4() && get4())
FORC4 cam_mul[c] = 1024;
if (tag == 0xa021)
FORC4 cam_mul[c ^ (c >> 1)] = get4();
@@ -9313,6 +9645,13 @@ void CLASS identify()
parse_foveon();
else if (!memcmp (head,"CI",2))
parse_cine();
+ //--- RT ----------------------------------------------------------------
+ else if (!memcmp(head + 4, "ftypcrx ", 8)) {
+ std::cout << "11111 : " << 11111 << std::endl;
+
+ parse_canon_cr3();
+ }
+ //-------------------------------------------------------------------------
if (make[0] == 0)
for (zero_fsize=i=0; i < sizeof table / sizeof *table; i++)
if (fsize == table[i].fsize) {
diff --git a/rtengine/dcraw.h b/rtengine/dcraw.h
index 3d753d876..75570b065 100644
--- a/rtengine/dcraw.h
+++ b/rtengine/dcraw.h
@@ -164,6 +164,35 @@ protected:
PanasonicRW2Info(): bpp(0), encoding(0) {}
};
PanasonicRW2Info RT_pana_info;
+public:
+ struct CanonCR3Data {
+ // contents of tag CMP1 for relevant track in CR3 file
+ struct crx_data_header_t {
+ int32_t version;
+ int32_t f_width;
+ int32_t f_height;
+ int32_t tileWidth;
+ int32_t tileHeight;
+ int32_t nBits;
+ int32_t nPlanes;
+ int32_t cfaLayout;
+ int32_t encType;
+ int32_t imageLevels;
+ int32_t hasTileCols;
+ int32_t hasTileRows;
+ int32_t mdatHdrSize;
+ // Not from header, but from datastream
+ uint32_t MediaSize;
+ INT64 MediaOffset;
+ uint32_t MediaType; /* 1 -> /C/RAW, 2-> JPEG */
+ };
+ static constexpr size_t CRXTRACKS_MAXCOUNT = 16;
+ crx_data_header_t crx_header[CRXTRACKS_MAXCOUNT];
+ int crx_track_selected;
+ short CR3_CTMDtag;
+ };
+protected:
+ CanonCR3Data RT_canon_CR3_data;
float cam_mul[4], pre_mul[4], cmatrix[3][4], rgb_cam[3][4];
@@ -529,4 +558,20 @@ void shiftXtransMatrix( const int offsy, const int offsx) {
void nikon_14bit_load_raw(); // ported from LibRaw
+//-----------------------------------------------------------------------------
+// Canon CR3 support ported from LibRaw
+//-----------------------------------------------------------------------------
+void parse_canon_cr3();
+void selectCRXTrack(short maxTrack);
+int parseCR3(unsigned long long oAtomList,
+ unsigned long long szAtomList, short &nesting,
+ char *AtomNameStack, short &nTrack, short &TrackType);
+int crxDecodePlane(void *p, uint32_t planeNumber);
+void crxLoadDecodeLoop(void *img, int nPlanes);
+void crxConvertPlaneLineDf(void *p, int imageRow);
+void crxLoadFinalizeLoopE3(void *p, int planeHeight);
+void crxLoadRaw();
+int crxParseImageHeader(uchar *cmp1TagData, int nTrack);
+//-----------------------------------------------------------------------------
+
};