"Fossies" - the Fresh Open Source Software Archive

Member "darktable-2.6.3/src/external/rawspeed/src/librawspeed/decoders/OrfDecoder.cpp" (19 Oct 2019, 9462 Bytes) of package /linux/misc/darktable-2.6.3.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "OrfDecoder.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.6.2_vs_2.6.3.

    1 /*
    2     RawSpeed - RAW file decoder.
    3 
    4     Copyright (C) 2009-2014 Klaus Post
    5     Copyright (C) 2014-2015 Pedro CĂ´rte-Real
    6     Copyright (C) 2017 Roman Lebedev
    7 
    8     This library is free software; you can redistribute it and/or
    9     modify it under the terms of the GNU Lesser General Public
   10     License as published by the Free Software Foundation; either
   11     version 2 of the License, or (at your option) any later version.
   12 
   13     This library is distributed in the hope that it will be useful,
   14     but WITHOUT ANY WARRANTY; without even the implied warranty of
   15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   16     Lesser General Public License for more details.
   17 
   18     You should have received a copy of the GNU Lesser General Public
   19     License along with this library; if not, write to the Free Software
   20     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
   21 */
   22 
   23 #include "decoders/OrfDecoder.h"
   24 #include "common/Common.h"                          // for uint32_t, uint8_t
   25 #include "common/NORangesSet.h"                     // for set
   26 #include "common/Point.h"                           // for iPoint2D
   27 #include "decoders/RawDecoderException.h"           // for ThrowRDE
   28 #include "decompressors/OlympusDecompressor.h"      // for OlympusDecompressor
   29 #include "decompressors/UncompressedDecompressor.h" // for UncompressedDeco...
   30 #include "io/Buffer.h"                              // for Buffer
   31 #include "io/ByteStream.h"                          // for ByteStream
   32 #include "io/Endianness.h"                          // for Endianness, getH...
   33 #include "metadata/ColorFilterArray.h"              // for ColorFilterArray
   34 #include "tiff/TiffEntry.h"                         // for TiffEntry, TIFF_...
   35 #include "tiff/TiffIFD.h"                           // for TiffRootIFD, Tif...
   36 #include "tiff/TiffTag.h"                           // for STRIPOFFSETS
   37 #include <array>                                    // for array
   38 #include <memory>                                   // for unique_ptr
   39 #include <string>                                   // for operator==, string
   40 
   41 namespace rawspeed {
   42 
   43 class CameraMetaData;
   44 
   45 bool OrfDecoder::isAppropriateDecoder(const TiffRootIFD* rootIFD,
   46                                       const Buffer* file) {
   47   const auto id = rootIFD->getID();
   48   const std::string& make = id.make;
   49 
   50   // FIXME: magic
   51 
   52   return make == "OLYMPUS IMAGING CORP." || make == "OLYMPUS CORPORATION" ||
   53          make == "OLYMPUS OPTICAL CO.,LTD";
   54 }
   55 
   56 ByteStream OrfDecoder::handleSlices() const {
   57   auto raw = mRootIFD->getIFDWithTag(STRIPOFFSETS);
   58 
   59   TiffEntry *offsets = raw->getEntry(STRIPOFFSETS);
   60   TiffEntry *counts = raw->getEntry(STRIPBYTECOUNTS);
   61 
   62   if (counts->count != offsets->count) {
   63     ThrowRDE(
   64         "Byte count number does not match strip size: count:%u, strips:%u ",
   65         counts->count, offsets->count);
   66   }
   67 
   68   const uint32_t off = offsets->getU32(0);
   69   uint32_t size = counts->getU32(0);
   70   auto end = [&off, &size]() -> uint32_t { return off + size; };
   71 
   72   for (uint32_t i = 0; i < counts->count; i++) {
   73     const auto offset = offsets->getU32(i);
   74     const auto count = counts->getU32(i);
   75     if (!mFile->isValid(offset, count))
   76       ThrowRDE("Truncated file");
   77 
   78     if (count < 1)
   79       ThrowRDE("Empty slice");
   80 
   81     if (i == 0)
   82       continue;
   83 
   84     if (offset < end())
   85       ThrowRDE("Slices overlap");
   86 
   87     // Now, everything would be great, but some uncompressed raws
   88     // (packed_with_control i believe) have "padding" between at least
   89     // the first two slices, and we need to account for it.
   90     const uint32_t padding = offset - end();
   91 
   92     size += padding;
   93     size += count;
   94   }
   95 
   96   ByteStream input(offsets->getRootIfdData());
   97   input.setPosition(off);
   98 
   99   return input.getStream(size);
  100 }
  101 
  102 RawImage OrfDecoder::decodeRawInternal() {
  103   auto raw = mRootIFD->getIFDWithTag(STRIPOFFSETS);
  104 
  105   int compression = raw->getEntry(COMPRESSION)->getU32();
  106   if (1 != compression)
  107     ThrowRDE("Unsupported compression");
  108 
  109   uint32_t width = raw->getEntry(IMAGEWIDTH)->getU32();
  110   uint32_t height = raw->getEntry(IMAGELENGTH)->getU32();
  111 
  112   if (!width || !height || width % 2 != 0 || width > 10400 || height > 7796)
  113     ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height);
  114 
  115   mRaw->dim = iPoint2D(width, height);
  116 
  117   ByteStream input(handleSlices());
  118 
  119   if (decodeUncompressed(input, width, height, input.getSize()))
  120     return mRaw;
  121 
  122   if (raw->getEntry(STRIPOFFSETS)->count != 1)
  123     ThrowRDE("%u stripes, and not uncompressed. Unsupported.",
  124              raw->getEntry(STRIPOFFSETS)->count);
  125 
  126   OlympusDecompressor o(mRaw);
  127   mRaw->createData();
  128   o.decompress(std::move(input));
  129 
  130   return mRaw;
  131 }
  132 
  133 bool OrfDecoder::decodeUncompressed(const ByteStream& s, uint32_t w, uint32_t h,
  134                                     uint32_t size) {
  135   UncompressedDecompressor u(s, mRaw);
  136   // FIXME: most of this logic should be in UncompressedDecompressor,
  137   // one way or another.
  138 
  139   if (size == h * ((w * 12 / 8) + ((w + 2) / 10))) {
  140     // 12-bit  packed 'with control' raw
  141     mRaw->createData();
  142     u.decode12BitRaw<Endianness::little, false, true>(w, h);
  143     return true;
  144   }
  145 
  146   if (size == w * h * 12 / 8) { // We're in a 12-bit packed raw
  147     iPoint2D dimensions(w, h);
  148     iPoint2D pos(0, 0);
  149     mRaw->createData();
  150     u.readUncompressedRaw(dimensions, pos, w * 12 / 8, 12, BitOrder_MSB32);
  151     return true;
  152   }
  153 
  154   if (size == w * h * 2) { // We're in an unpacked raw
  155     mRaw->createData();
  156     // FIXME: seems fishy
  157     if (s.getByteOrder() == getHostEndianness())
  158       u.decodeRawUnpacked<12, Endianness::little>(w, h);
  159     else
  160       u.decode12BitRawUnpackedLeftAligned<Endianness::big>(w, h);
  161     return true;
  162   }
  163 
  164   if (size >
  165       w * h * 3 / 2) { // We're in one of those weird interlaced packed raws
  166     mRaw->createData();
  167     u.decode12BitRaw<Endianness::big, true>(w, h);
  168     return true;
  169   }
  170 
  171   // Does not appear to be uncomporessed. Maybe it's compressed?
  172   return false;
  173 }
  174 
  175 void OrfDecoder::parseCFA() {
  176   if (!mRootIFD->hasEntryRecursive(EXIFCFAPATTERN))
  177     ThrowRDE("No EXIFCFAPATTERN entry found!");
  178 
  179   TiffEntry* CFA = mRootIFD->getEntryRecursive(EXIFCFAPATTERN);
  180   if (CFA->type != TiffDataType::TIFF_UNDEFINED || CFA->count != 8) {
  181     ThrowRDE("Bad EXIFCFAPATTERN entry (type %u, count %u).", CFA->type,
  182              CFA->count);
  183   }
  184 
  185   iPoint2D cfaSize(CFA->getU16(0), CFA->getU16(1));
  186   if (cfaSize != iPoint2D{2, 2})
  187     ThrowRDE("Bad CFA size: (%i, %i)", cfaSize.x, cfaSize.y);
  188 
  189   mRaw->cfa.setSize(cfaSize);
  190 
  191   auto int2enum = [](uint8_t i) -> CFAColor {
  192     switch (i) {
  193     case 0:
  194       return CFA_RED;
  195     case 1:
  196       return CFA_GREEN;
  197     case 2:
  198       return CFA_BLUE;
  199     default:
  200       ThrowRDE("Unexpected CFA color: %u", i);
  201     }
  202   };
  203 
  204   for (int y = 0; y < cfaSize.y; y++) {
  205     for (int x = 0; x < cfaSize.x; x++) {
  206       uint8_t c1 = CFA->getByte(4 + x + y * cfaSize.x);
  207       CFAColor c2 = int2enum(c1);
  208       mRaw->cfa.setColorAt(iPoint2D(x, y), c2);
  209     }
  210   }
  211 }
  212 
  213 void OrfDecoder::decodeMetaDataInternal(const CameraMetaData* meta) {
  214   int iso = 0;
  215 
  216   if (mRootIFD->hasEntryRecursive(ISOSPEEDRATINGS))
  217     iso = mRootIFD->getEntryRecursive(ISOSPEEDRATINGS)->getU32();
  218 
  219   parseCFA();
  220 
  221   setMetaData(meta, "", iso);
  222 
  223   if (mRootIFD->hasEntryRecursive(OLYMPUSREDMULTIPLIER) &&
  224       mRootIFD->hasEntryRecursive(OLYMPUSBLUEMULTIPLIER)) {
  225     mRaw->metadata.wbCoeffs[0] = static_cast<float>(
  226         mRootIFD->getEntryRecursive(OLYMPUSREDMULTIPLIER)->getU16());
  227     mRaw->metadata.wbCoeffs[1] = 256.0F;
  228     mRaw->metadata.wbCoeffs[2] = static_cast<float>(
  229         mRootIFD->getEntryRecursive(OLYMPUSBLUEMULTIPLIER)->getU16());
  230   } else if (mRootIFD->hasEntryRecursive(OLYMPUSIMAGEPROCESSING)) {
  231     // Newer cameras process the Image Processing SubIFD in the makernote
  232     TiffEntry* img_entry = mRootIFD->getEntryRecursive(OLYMPUSIMAGEPROCESSING);
  233     // get makernote ifd with containing Buffer
  234     NORangesSet<Buffer> ifds;
  235 
  236     TiffRootIFD image_processing(nullptr, &ifds, img_entry->getRootIfdData(),
  237                                  img_entry->getU32());
  238 
  239     // Get the WB
  240     if (image_processing.hasEntry(static_cast<TiffTag>(0x0100))) {
  241       TiffEntry* wb = image_processing.getEntry(static_cast<TiffTag>(0x0100));
  242       if (wb->count == 2 || wb->count == 4) {
  243         mRaw->metadata.wbCoeffs[0] = wb->getFloat(0);
  244         mRaw->metadata.wbCoeffs[1] = 256.0F;
  245         mRaw->metadata.wbCoeffs[2] = wb->getFloat(1);
  246       }
  247     }
  248 
  249     // Get the black levels
  250     if (image_processing.hasEntry(static_cast<TiffTag>(0x0600))) {
  251       TiffEntry* blackEntry =
  252           image_processing.getEntry(static_cast<TiffTag>(0x0600));
  253       // Order is assumed to be RGGB
  254       if (blackEntry->count == 4) {
  255         for (int i = 0; i < 4; i++) {
  256           auto c = mRaw->cfa.getColorAt(i & 1, i >> 1);
  257           int j;
  258           switch (c) {
  259           case CFA_RED:
  260             j = 0;
  261             break;
  262           case CFA_GREEN:
  263             j = i < 2 ? 1 : 2;
  264             break;
  265           case CFA_BLUE:
  266             j = 3;
  267             break;
  268           default:
  269             ThrowRDE("Unexpected CFA color: %u", c);
  270           }
  271 
  272           mRaw->blackLevelSeparate[i] = blackEntry->getU16(j);
  273         }
  274         // Adjust whitelevel based on the read black (we assume the dynamic
  275         // range is the same)
  276         mRaw->whitePoint -= (mRaw->blackLevel - mRaw->blackLevelSeparate[0]);
  277       }
  278     }
  279   }
  280 }
  281 
  282 } // namespace rawspeed