Author: post
Date: 2011-03-07 23:05:14 +0100 (Mon, 07 Mar 2011)
New Revision: 341

Modified:
   RawSpeed/DngDecoder.cpp
   RawSpeed/DngDecoder.h
Log:
Rewrite of black level decoding for DNG images. Now it load individual black 
levels and masked sensor areas.

Modified: RawSpeed/DngDecoder.cpp
===================================================================
--- RawSpeed/DngDecoder.cpp     2011-03-07 21:56:28 UTC (rev 340)
+++ RawSpeed/DngDecoder.cpp     2011-03-07 22:05:14 UTC (rev 341)
@@ -349,60 +349,17 @@
     }
   }
 
-  new_size = mRaw->dim;
-
-  // Default white level is (2 ** BitsPerSample) - 1
+ // Default white level is (2 ** BitsPerSample) - 1
   mRaw->whitePoint = (1 >> raw->getEntry(BITSPERSAMPLE)->getShort()) - 1;
-  // Black defaults to 0
-  int black = 0; 
 
   if (raw->hasEntry(WHITELEVEL)) {
     TiffEntry *whitelevel = raw->getEntry(WHITELEVEL);
     if (whitelevel->isInt())
       mRaw->whitePoint = whitelevel->getInt();
   }
+  // Set black
+  setBlack(raw);
 
-
-  if (raw->hasEntry(BLACKLEVELREPEATDIM)) {
-    black = 65536;
-    const ushort16 *blackdim = 
raw->getEntry(BLACKLEVELREPEATDIM)->getShortArray();
-    if (blackdim[0] != 0 && blackdim[1] != 0) {
-      if (raw->hasEntry(BLACKLEVELDELTAV)) {
-        const uint32 *blackarray = raw->getEntry(BLACKLEVEL)->getIntArray();
-        int blackbase = blackarray[0] / blackarray[1];
-        const int *blackarrayv = (const 
int*)raw->getEntry(BLACKLEVELDELTAV)->getIntArray();
-        for (int i = 0; i < new_size.y; i++)
-          if (blackarrayv[i*2+1])
-            black = MIN(black, blackbase + blackarrayv[i*2] / 
blackarrayv[i*2+1]);
-      } else {
-        TiffEntry* black_entry = raw->getEntry(BLACKLEVEL);
-        if (black_entry->type == TIFF_LONG) {
-          const uint32* blackarray = black_entry->getIntArray();
-          if (blackarray[1])
-            black = blackarray[0] / blackarray[1];
-          else
-            black = 0;
-        } else if (black_entry->isFloat()) {
-          black = (int)black_entry->getFloat();
-        }
-      }
-    } else {
-      black = 0;
-    }
-  } else if (raw->hasEntry(BLACKLEVEL)) {
-    // Attempt to read a single value as black
-    TiffEntry *blacklevel = raw->getEntry(BLACKLEVEL);
-    if (blacklevel->count >= 1 && (blacklevel->isInt()))
-      black = blacklevel->getInt();
-    if (blacklevel->count >= 1 && blacklevel->type == TIFF_RATIONAL) {
-      const uint32* blackarray = (const uint32*)blacklevel->getData();
-      if (blackarray[1])
-        black = blackarray[0] / blackarray[1];
-      else
-        black = 0;
-    }
-  }
-  mRaw->blackLevel = black;
   return mRaw;
 }
 
@@ -418,4 +375,140 @@
   this->checkCameraSupported(meta, make, model, "dng");
 }
 
+/* Decodes DNG masked areas into blackareas in the image */
+bool DngDecoder::decodeMaskedAreas(TiffIFD* raw) {
+  TiffEntry *masked = raw->getEntry(MASKEDAREAS);
+  int nrects = masked->count/4;
+
+  if (0 == nrects)
+    return FALSE;
+
+  /* Since we may both have short or int, copy it to int array. */
+  int *rects = new int[nrects*4];
+  if (masked->type == TIFF_SHORT) {
+    const ushort16* r = masked->getShortArray();
+    for (int i = 0; i< nrects*4; i++)
+      rects[i] = r[i];
+  } else if (masked->type == TIFF_LONG) {
+    const uint32* r = masked->getIntArray();
+    for (int i = 0; i< nrects*4; i++)
+      rects[i] = r[i];
+  } else {
+    delete[] rects;
+    return FALSE;
+  }
+
+  iPoint2D top = mRaw->getCropOffset();
+
+  for (int i=0; i<nrects; i++) {
+    iPoint2D topleft = iPoint2D(rects[i*4+1], rects[i*4]);
+    iPoint2D bottomright = iPoint2D(rects[i*4+3], rects[i*4+2]);
+    // Is this a horizontal box, only add it if it covers the active width of 
the image
+    if (topleft.x <= top.x && bottomright.x >= (mRaw->dim.x+top.x))
+      mRaw->blackAreas.push_back(BlackArea(topleft.y, bottomright.y-topleft.y, 
FALSE));
+    // Is it a vertical box, only add it if it covers the active height of the 
image
+    else if (topleft.y <= top.y && bottomright.y >= (mRaw->dim.y+top.y)) {
+        mRaw->blackAreas.push_back(BlackArea(topleft.x, 
bottomright.x-topleft.x, TRUE));
+    }
+  }
+  delete[] rects;
+  return !!mRaw->blackAreas.size();
+}
+
+bool DngDecoder::decodeBlackLevels(TiffIFD* raw) {
+  iPoint2D blackdim(1,1);
+  if (raw->hasEntry(BLACKLEVELREPEATDIM)) {
+    const ushort16 *dim = raw->getEntry(BLACKLEVELREPEATDIM)->getShortArray();
+    blackdim = iPoint2D(dim[0], dim[1]);
+  }
+
+  if (blackdim.x == 0 || blackdim.y == 0)
+    return FALSE;
+
+  if (!raw->hasEntry(BLACKLEVEL))
+    return TRUE;
+
+  if (mRaw->getCpp() != 1)
+    return FALSE;
+
+  TiffEntry* black_entry = raw->getEntry(BLACKLEVEL);
+  const uint32* iblackarray = NULL;
+  const ushort16* sblackarray = NULL;
+  if (black_entry->type == TIFF_SHORT)
+    sblackarray = black_entry->getShortArray();
+  else
+    iblackarray = black_entry->getIntArray();
+
+  if (blackdim.x < 2 || blackdim.y < 2) {
+    // We so not have enough to fill all individually, read a single and copy 
it
+    for (int y = 0; y < 2; y++) {
+      for (int x = 0; x < 2; x++) {
+        int offset = 0;
+        if (black_entry->type == TIFF_RATIONAL) {
+          if (iblackarray[offset*2+1])
+            mRaw->blackLevelSeparate[y*2+x] = iblackarray[offset*2] / 
iblackarray[offset*2+1];
+          else
+            mRaw->blackLevelSeparate[y*2+x] = 0;
+        } else if (black_entry->type == TIFF_LONG) {
+          mRaw->blackLevelSeparate[y*2+x] = iblackarray[offset];
+        } else if (black_entry->type == TIFF_SHORT) {
+          mRaw->blackLevelSeparate[y*2+x] = sblackarray[offset];
+        }
+      }
+    }
+  } else {
+    for (int y = 0; y < 2; y++) {
+      for (int x = 0; x < 2; x++) {
+        int offset = y*blackdim.x+x;
+        if (black_entry->type == TIFF_RATIONAL) {
+          if (iblackarray[offset*2+1])
+            mRaw->blackLevelSeparate[y*2+x] = iblackarray[offset*2] / 
iblackarray[offset*2+1];
+          else
+            mRaw->blackLevelSeparate[y*2+x] = 0;
+        } else if (black_entry->type == TIFF_LONG) {
+          mRaw->blackLevelSeparate[y*2+x] = iblackarray[offset];
+        } else if (black_entry->type == TIFF_SHORT) {
+          mRaw->blackLevelSeparate[y*2+x] = sblackarray[offset];
+        }
+      }
+    }
+  }
+
+  // DNG Spec says we must add black in deltav and deltah
+  if (raw->hasEntry(BLACKLEVELDELTAV)) {
+    const int *blackarrayv = (const 
int*)raw->getEntry(BLACKLEVELDELTAV)->getIntArray();
+    float black_sum[2] = {0.0f, 0.0f};
+    for (int i = 0; i < mRaw->dim.y; i++)
+      if (blackarrayv[i*2+1])
+        black_sum[i&1] += blackarrayv[i*2] / blackarrayv[i*2+1];
+
+    for (int i = 0; i < 4; i++)
+      mRaw->blackLevelSeparate[i] += (int)(black_sum[i>>1] / 
(float)mRaw->dim.y * 2.0f);
+  } 
+
+  if (raw->hasEntry(BLACKLEVELDELTAH)){
+    const int *blackarrayh = (const 
int*)raw->getEntry(BLACKLEVELDELTAH)->getIntArray();
+    float black_sum[2] = {0.0f, 0.0f};
+    for (int i = 0; i < mRaw->dim.x; i++)
+      if (blackarrayh[i*2+1])
+        black_sum[i&1] += blackarrayh[i*2] / blackarrayh[i*2+1];
+
+    for (int i = 0; i < 4; i++)
+      mRaw->blackLevelSeparate[i] += (int)(black_sum[i&1] / (float)mRaw->dim.x 
* 2.0f);
+  }
+  return TRUE;
+}
+
+void DngDecoder::setBlack(TiffIFD* raw) {
+
+  if (raw->hasEntry(MASKEDAREAS))
+    if (decodeMaskedAreas(raw))
+      return;
+
+  // Black defaults to 0
+  memset(mRaw->blackLevelSeparate,0,sizeof(mRaw->blackLevelSeparate)); 
+
+  if (raw->hasEntry(BLACKLEVEL))
+    decodeBlackLevels(raw);
+}
 } // namespace RawSpeed

Modified: RawSpeed/DngDecoder.h
===================================================================
--- RawSpeed/DngDecoder.h       2011-03-07 21:56:28 UTC (rev 340)
+++ RawSpeed/DngDecoder.h       2011-03-07 22:05:14 UTC (rev 341)
@@ -39,6 +39,9 @@
   TiffIFD *mRootIFD;
   bool mFixLjpeg;
   void printMetaData();
+  bool decodeMaskedAreas(TiffIFD* raw);
+  bool decodeBlackLevels(TiffIFD* raw);
+  void setBlack(TiffIFD* raw);
 };
 
 class DngStrip {


_______________________________________________
Rawstudio-commit mailing list
[email protected]
http://rawstudio.org/cgi-bin/mailman/listinfo/rawstudio-commit

Reply via email to