Author: post
Date: 2009-08-04 20:13:21 +0200 (Tue, 04 Aug 2009)
New Revision: 92

Added:
   RawSpeed/TiffParserHeaderless.cpp
   RawSpeed/TiffParserHeaderless.h
Modified:
   RawSpeed/Common.h
   RawSpeed/Cr2Decoder.cpp
   RawSpeed/Cr2Decoder.h
   RawSpeed/LJpegPlain.cpp
   RawSpeed/LJpegPlain.h
   RawSpeed/RawImage.cpp
   RawSpeed/RawImage.h
   RawSpeed/RawSpeed.vcproj
Log:
Added Canon sRaw support.

Modified: RawSpeed/Common.h
===================================================================
--- RawSpeed/Common.h   2009-08-03 14:53:21 UTC (rev 91)
+++ RawSpeed/Common.h   2009-08-04 18:13:21 UTC (rev 92)
@@ -64,6 +64,9 @@
     srcp += src_pitch;
   }
 }
+inline bool isPowerOfTwo (int val) {
+  return (val & (~val+1)) == val;
+}
 
 inline int lmin(int p0, int p1) {
   return p1 + ((p0 - p1) & ((p0 - p1) >> 31));

Modified: RawSpeed/Cr2Decoder.cpp
===================================================================
--- RawSpeed/Cr2Decoder.cpp     2009-08-03 14:53:21 UTC (rev 91)
+++ RawSpeed/Cr2Decoder.cpp     2009-08-04 18:13:21 UTC (rev 92)
@@ -1,5 +1,6 @@
 #include "StdAfx.h"
 #include "Cr2Decoder.h"
+
 /* 
     RawSpeed - RAW file decoder.
 
@@ -34,11 +35,13 @@
 
 RawImage Cr2Decoder::decodeRaw()
 {
+  
   vector<TiffIFD*> data = mRootIFD->getIFDsWithTag((TiffTag)0xc5d8);
 
   if (data.empty())
     ThrowRDE("CR2 Decoder: No image data found");
 
+
   TiffIFD* raw = data[0];
   mRaw = RawImage::create();
   mRaw->isCFA = true;
@@ -91,7 +94,7 @@
   }
   guint offY = 0;
 
-  for (guint i = 0; i < slices.size(); i++ ) {  // This loop is obvious for 
threading, as slices are independent
+  for (guint i = 0; i < slices.size(); i++ ) {
     Cr2Slice slice = slices[i];
     try {
       LJpegPlain l(mFile,mRaw);
@@ -107,6 +110,9 @@
     offY += slice.w;
   }
 
+  if (mRaw->subsampling.x >1 || mRaw->subsampling.y >1)
+    sRawInterpolate();
+
   return mRaw;
 }
 
@@ -124,10 +130,208 @@
   vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(MODEL);
 
   if (data.empty())
-    ThrowRDE("ARW Meta Decoder: Model name found");
+    ThrowRDE("CR2 Meta Decoder: Model name found");
 
   string make = data[0]->getEntry(MAKE)->getString();
   string model = data[0]->getEntry(MODEL)->getString();
 
   setMetaData(meta, make, model,"");
-}
\ No newline at end of file
+
+}
+
+// Interpolate and convert sRaw data.
+void Cr2Decoder::sRawInterpolate()
+{
+  if (mRaw->subsampling.y == 1 && mRaw->subsampling.x == 2) {
+    interpolate_422(mRaw->dim.x / 2, mRaw->dim.y ,0, mRaw->dim.y);
+  } else {
+    interpolate_420(mRaw->dim.x / 2, mRaw->dim.y / 2 ,0 , mRaw->dim.y / 2);
+  }
+}
+
+#define YUV_TO_RGB(Y, Cb, Cr) r = (int)Y + (( 200*(int)Cb + 22929*(int)Cr) >> 
12);\
+  g = (int)Y + ((-5640*(int)Cb - 11751*(int)Cb) >> 12);\
+  b = (int)Y + ((29040*(int)Cb - 101*(int)Cb) >> 12);
+
+/* sRaw interpolators - ugly as sin, but does the job in reasonably speed */
+
+// Note: Thread safe.
+
+void Cr2Decoder::interpolate_422(int w, int h, int start_h , int end_h)
+{
+  // Last pixel should not be interpolated
+  w--; 
+
+  // Current line
+  gushort* c_line;
+
+  for (int y = start_h; y < end_h; y++) {
+    c_line = (gushort*)mRaw->getData(0,y);
+    gint r,g,b;
+    int off = 0;
+    for (int x = 0; x < w; x++) {
+      int Y = c_line[off];
+      int Cb = c_line[off+1]- 16384;
+      int Cr = c_line[off+2]- 16384;
+      YUV_TO_RGB(Y, Cb, Cr);
+      c_line[off++] = clampbits(r,16); 
+      c_line[off++] = clampbits(g,16); 
+      c_line[off++] = clampbits(b,16);
+
+      Y = c_line[off];
+      int Cb2 = (Cb + c_line[off+1+3] - 16384)>>1;
+      int Cr2 = (Cr + c_line[off+2+3] - 16384)>>1;
+      YUV_TO_RGB(Y, Cb2, Cr2);
+      c_line[off++] = clampbits(r,16); 
+      c_line[off++] = clampbits(g,16); 
+      c_line[off++] = clampbits(b,16);
+    }
+    // Last two pixels
+    int Y = c_line[off];
+    int Cb = c_line[off+1]- 16384;
+    int Cr = c_line[off+2]- 16384;
+    YUV_TO_RGB(Y, Cb, Cr);
+    c_line[off++] = clampbits(r,16); 
+    c_line[off++] = clampbits(g,16); 
+    c_line[off++] = clampbits(b,16);
+
+    Y = c_line[off];
+    YUV_TO_RGB(Y, Cb, Cr);
+    c_line[off++] = clampbits(r,16); 
+    c_line[off++] = clampbits(g,16); 
+    c_line[off++] = clampbits(b,16);
+  }
+}
+
+
+// Note: Not thread safe, since it writes inplace.
+void Cr2Decoder::interpolate_420(int w, int h, int start_h , int end_h)
+{
+  // Last pixel should not be interpolated
+  w--; 
+
+  gboolean atLastLine = FALSE;
+
+  if (end_h == h) {
+    end_h--;
+    atLastLine = TRUE;
+  }
+
+  // Current line
+  gushort* c_line;
+  // Next line
+  gushort* n_line;
+  // Next line again
+  gushort* nn_line;
+
+  int off;
+  gint r,g,b;
+
+  for (int y = start_h; y < end_h; y++) {
+    c_line = (gushort*)mRaw->getData(0,y*2);
+    n_line = (gushort*)mRaw->getData(0,y*2+1);
+    nn_line = (gushort*)mRaw->getData(0,y*2+2);
+    off = 0;
+    for (int x = 0; x < w; x++) {
+      int Y = c_line[off];
+      int Cb = c_line[off+1]- 16384;
+      int Cr = c_line[off+2]- 16384;
+      YUV_TO_RGB(Y, Cb, Cr);
+      c_line[off] = clampbits(r,16); 
+      c_line[off+1] = clampbits(g,16); 
+      c_line[off+2] = clampbits(b,16);
+
+      Y = c_line[off+3];
+      int Cb2 = (Cb + c_line[off+1+6] - 16383)>>1;
+      int Cr2 = (Cr + c_line[off+2+6] - 16383)>>1;
+      YUV_TO_RGB(Y, Cb2, Cr2);
+      c_line[off+3] = clampbits(r,16); 
+      c_line[off+4] = clampbits(g,16); 
+      c_line[off+5] = clampbits(b,16);
+
+      // Next line
+      Y = n_line[off];
+      int Cb3 = (Cb + nn_line[off+1]- 16383)>>1;
+      int Cr3 = (Cr + nn_line[off+2]- 16383)>>1;
+      YUV_TO_RGB(Y, Cb3, Cr3);
+      n_line[off] = clampbits(r,16); 
+      n_line[off+1] = clampbits(g,16); 
+      n_line[off+2] = clampbits(b,16);
+
+      Y = n_line[off+3];
+      Cb = (Cb + Cb2 + Cb3 + nn_line[off+1+6] - 16382)>>2;  //Left + Above + 
Right +Below
+      Cr = (Cr + Cr2 + Cr3 + nn_line[off+2+6] - 16382)>>2;
+      YUV_TO_RGB(Y, Cb, Cr);
+      n_line[off+3] = clampbits(r,16); 
+      n_line[off+4] = clampbits(g,16); 
+      n_line[off+5] = clampbits(b,16);
+      off+=6;
+    }
+    int Y = c_line[off];
+    int Cb = c_line[off+1]- 16384;
+    int Cr = c_line[off+2]- 16384;
+    YUV_TO_RGB(Y, Cb, Cr);
+    c_line[off] = clampbits(r,16); 
+    c_line[off+1] = clampbits(g,16); 
+    c_line[off+2] = clampbits(b,16);
+
+    Y = c_line[off+3];
+    YUV_TO_RGB(Y, Cb, Cr);
+    c_line[off+3] = clampbits(r,16); 
+    c_line[off+4] = clampbits(g,16); 
+    c_line[off+5] = clampbits(b,16);
+
+    // Next line
+    Y = n_line[off];
+    Cb = (Cb + nn_line[off+1]- 16383)>>1;
+    Cr = (Cr + nn_line[off+2]- 16383)>>1;
+    YUV_TO_RGB(Y, Cb, Cr);
+    n_line[off] = clampbits(r,16); 
+    n_line[off+1] = clampbits(g,16); 
+    n_line[off+2] = clampbits(b,16);
+
+    Y = n_line[off+3];
+    YUV_TO_RGB(Y, Cb, Cr);
+    n_line[off+3] = clampbits(r,16); 
+    n_line[off+4] = clampbits(g,16); 
+    n_line[off+5] = clampbits(b,16);
+  }
+
+  if (atLastLine) {
+    c_line = (gushort*)mRaw->getData(0,end_h*2);
+    n_line = (gushort*)mRaw->getData(0,end_h*2);
+    off = 0;
+
+    // Last line
+    for (int x = 0; x < w; x++) {
+      int Y = c_line[off];
+      int Cb = c_line[off+1]- 16384;
+      int Cr = c_line[off+2]- 16384;
+      YUV_TO_RGB(Y, Cb, Cr);
+      c_line[off] = clampbits(r,16); 
+      c_line[off+1] = clampbits(g,16); 
+      c_line[off+2] = clampbits(b,16);
+
+      Y = c_line[off+3];
+      YUV_TO_RGB(Y, Cb, Cr);
+      c_line[off+3] = clampbits(r,16); 
+      c_line[off+4] = clampbits(g,16); 
+      c_line[off+5] = clampbits(b,16);
+
+      // Next line
+      Y = n_line[off];
+      YUV_TO_RGB(Y, Cb, Cr);
+      n_line[off] = clampbits(r,16); 
+      n_line[off+1] = clampbits(g,16); 
+      n_line[off+2] = clampbits(b,16);
+
+      Y = n_line[off+3];
+      YUV_TO_RGB(Y, Cb, Cr);
+      n_line[off+3] = clampbits(r,16); 
+      n_line[off+4] = clampbits(g,16); 
+      n_line[off+5] = clampbits(b,16);
+      off+=6;
+    }
+  }
+}
+

Modified: RawSpeed/Cr2Decoder.h
===================================================================
--- RawSpeed/Cr2Decoder.h       2009-08-03 14:53:21 UTC (rev 91)
+++ RawSpeed/Cr2Decoder.h       2009-08-04 18:13:21 UTC (rev 92)
@@ -34,6 +34,9 @@
   virtual void decodeMetaData(CameraMetaData *meta);
   virtual ~Cr2Decoder(void);
 protected:
+  void sRawInterpolate();
+  void interpolate_420(int w, int h, int start_h , int end_h);
+  void interpolate_422(int w, int h, int start_h , int end_h);
   TiffIFD *mRootIFD;
 };
 

Modified: RawSpeed/LJpegPlain.cpp
===================================================================
--- RawSpeed/LJpegPlain.cpp     2009-08-03 14:53:21 UTC (rev 91)
+++ RawSpeed/LJpegPlain.cpp     2009-08-04 18:13:21 UTC (rev 92)
@@ -46,8 +46,36 @@
     slicesW.push_back(frame.w*frame.cps);
   
   for (guint i = 0; i < frame.cps;  i++) {
-    if (frame.compInfo[i].superH != 1 || frame.compInfo[i].superV != 1)
-      ThrowRDE("LJpegDecompressor: Supersampled components not supported.");
+    if (frame.compInfo[i].superH != 1 || frame.compInfo[i].superV != 1) {      
+      mRaw->destroyData();
+      mRaw->dim.x /= frame.cps;
+      mRaw->setCpp(frame.cps);
+      mRaw->isCFA = false;
+      mRaw->createData();
+
+      if (pred == 1) {
+        if (frame.compInfo[0].superH == 2 && frame.compInfo[0].superV == 2 &&
+          frame.compInfo[1].superH == 1 && frame.compInfo[1].superV == 1 &&
+          frame.compInfo[2].superH == 1 && frame.compInfo[2].superV == 1) 
+        {
+          // Something like Cr2 sRaw1, use fast decoder
+          decodeScanLeft4_2_0();
+          return;
+        } else if (frame.compInfo[0].superH == 2 && frame.compInfo[0].superV 
== 1 &&
+            frame.compInfo[1].superH == 1 && frame.compInfo[1].superV == 1 &&
+            frame.compInfo[2].superH == 1 && frame.compInfo[2].superV == 1) 
+          {
+            // Something like Cr2 sRaw2, use fast decoder
+            decodeScanLeft4_2_2();
+            return;
+        } else {
+          decodeScanLeftGeneric();
+          return;
+        }
+      } else {
+        ThrowRDE("LJpegDecompressor::decodeScan: Unsupported prediction 
direction.");
+      }
+    }
   }
 
   if (pred == 1) {
@@ -64,46 +92,75 @@
   ThrowRDE("LJpegDecompressor::decodeScan: Unsupported prediction direction.");
 }
 
+/** 
+ *  CR2 Slice handling:
+ *  In the following code, canon slices are handled in-place, to avoid having 
to
+ *  copy the entire frame afterwards.
+ *  The "offset" array is created to easily map slice positions on to the 
output image.
+ *  The offset array size is the number of slices multiplied by height.
+ *  Each of these offsets are an offset into the destination image, and it 
also contains the
+ *  slice number (shifted up 28 bits), so it is possible to retrieve the width 
of each slice.
+ *  Every time "components" pixels has been processed the slice size is 
tested, and output offset
+ *  is adjusted if needed. This makes slice handling very "light", since it 
involves a single 
+ *  counter, and a predictable branch.
+ *  For unsliced images, add one slice with the width of the image.
+ **/
+
 void LJpegPlain::decodeScanLeftGeneric() {
   _ASSERTE(slicesW.size()<16);  // We only have 4 bits for slice number.
   _ASSERTE(!(slicesW.size()>1 && skipX));   // Check if this is a valid state
 
   guint comps = frame.cps;  // Components
   HuffmanTable *dctbl[4];   // Tables for up to 4 components
-  gushort *predict[4];      // Prediction pointers for each of the four 
components
+  gushort *predict;         // Prediction pointer
+  /* Fast access to supersampling component settings
+   * this is the number of components in a given block.
+   */
   guint samplesH[4];
   guint samplesV[4];
-  guint skipEveryH[4];
-  guint skipEveryV[4];
 
   guchar *draw = mRaw->getData();
   guint maxSuperH = 1;
   guint maxSuperV = 1;
+  guint samplesComp[4]; // How many samples per group does this component have
+  guint pixGroup = 0;   // How many pixels per group.
+
   for (guint i = 0; i < comps; i++) {
     dctbl[i] = &huff[frame.compInfo[i].dcTblNo];
     samplesH[i] = frame.compInfo[i].superH;
+    if (!isPowerOfTwo(samplesH[i]))
+      ThrowRDE("LJpegPlain::decodeScanLeftGeneric: Horizontal sampling is not 
power of two.");
     maxSuperH = max(samplesH[i], maxSuperH);
     samplesV[i] = frame.compInfo[i].superV;
+    if (!isPowerOfTwo(samplesV[i]))
+      ThrowRDE("LJpegPlain::decodeScanLeftGeneric: Vertical sampling is not 
power of two.");
     maxSuperV = max(samplesV[i], maxSuperV);
+    samplesComp[i] = samplesV[i] * samplesH[i];
+    pixGroup += samplesComp[i];
   }
-  for (guint i = 0; i < comps; i++) {
-    skipEveryH[i] = maxSuperH / samplesH[i] - 1;  // Mask for determining if 
we should skip
-    skipEveryV[i] = maxSuperV / samplesV[i] - 1;  // 0 = skip no lines, 1 = 
skip odd, 3 = skip 1-2-3
-  }
 
+  mRaw->subsampling.x = maxSuperH;
+  mRaw->subsampling.y = maxSuperV;
+
   //Prepare slices (for CR2)
-  guint slices =  (guint)slicesW.size()*(frame.h-skipY);
+  guint slices =  (guint)slicesW.size()*(frame.h-skipY)/maxSuperV;
   offset = new guint[slices+1];
 
   guint t_y = 0;
   guint t_x = 0;
   guint t_s = 0;
   guint slice = 0;
+  guint pitch_s = mRaw->pitch/2;  // Pitch in shorts
+
+  // This is divided by comps, since comps pixels are processed at the time
+  for (guint i = 0 ; i <  slicesW.size(); i++)
+    slicesW[i] /= pixGroup/maxSuperH;   // This is a guess, but works for 
sRaw1+2.
+
   for (slice = 0; slice< slices; slice++) {
     offset[slice] = ((t_x+offX)*mRaw->bpp+((offY+t_y)*mRaw->pitch)) | 
(t_s<<28);
     _ASSERTE((offset[slice]&0x0fffffff)<mRaw->pitch*mRaw->dim.y);
-    t_y++;
-    if (t_y == (frame.h-skipY)) {
+    t_y += maxSuperV;
+    if (t_y >= (frame.h-skipY)) {
       t_y = 0;
       t_x += slicesW[t_s++];
     }
@@ -111,64 +168,344 @@
   offset[slices] = offset[slices-1];        // Extra offset to avoid branch in 
loop.
 
   if (skipX)
-    slicesW[slicesW.size()-1] -= skipX*frame.cps;
+    slicesW[slicesW.size()-1] -= skipX;
 
-  // First pixels are obviously not predicted
+  // Predictors for components
   gint p[4];
   gushort *dest = (gushort*)&draw[offset[0]&0x0fffffff];
 
-  // First pixels
+  // Always points to next slice
+  slice = 1;
+  guint pixInSlice = slicesW[0];    
+
+  // Initialize predictors and decode one group.
+  guint x = 0;
+  predict = dest;
   for (guint i = 0; i < comps; i++) {
-    predict[i] = dest;
-    *dest++ = p[i] = (1<<(frame.prec-Pt-1)) + HuffDecode(dctbl[i]);
-    for (guint j = 0; j < samplesH[i]; j++) {
-      p[i] += HuffDecode(dctbl[i]);
-      *dest++ = p[i];
+    for (guint y2 = 0; y2 < samplesV[i]; y2++) {
+      for (guint x2 = 0; x2 < samplesH[i]; x2++) {
+        // First pixel is not predicted, all other are.
+        if (y2 == 0 && x2 == 0) {
+          *dest = p[i] = (1<<(frame.prec-Pt-1)) + HuffDecode(dctbl[i]);
+        } else {
+          p[i] += HuffDecode(dctbl[i]);
+          _ASSERTE(p[i]>=0 && p[i]<65536);
+          dest[x2*comps+y2*pitch_s] = p[i];
+        }
+      }
     }
+    // Set predictor for this component
+    // Next component
+    dest++;
   }
 
-  slices =  (guint)slicesW.size();
-  slice = 1;
-  guint pixInSlice = slicesW[0]/comps-1;    // This is divided by comps, since 
comps pixels are processed at the time
+  // Increment destination to next group
+  dest += (maxSuperH-1)*comps;
+  x = maxSuperH;
+  pixInSlice -= maxSuperH;
 
   guint cw = (frame.w-skipX);
-  guint x = 1;                            // Skip first pixels on first line.
+  for (guint y=0;y<(frame.h-skipY);y+=maxSuperV) {
+    for (; x < cw ; x+=maxSuperH) {
 
-  for (guint y=0;y<(frame.h-skipY);y++) {
-    for (; x < cw ; x++) {
-      for (guint i = 0; i < comps; i++) {
-        if (((y&skipEveryV[i])==0) && ((x&skipEveryH[i])==0)) {  // Should 
this component be decoded?
-          p[i] += HuffDecode(dctbl[i]);
-          _ASSERTE(p[i]>=0 && p[i]<65536);
-          *dest++ = p[i];          
-        }
-      }
-
-      if (0 == --pixInSlice) { // Next slice
+      if (0 == pixInSlice) { // Next slice
+        _ASSERTE(slice<slices);
         guint o = offset[slice++];
         dest = (gushort*)&draw[o&0x0fffffff];  // Adjust destination for next 
pixel
-        _ASSERTE((o&0x0fffffff)<mRaw->pitch*mRaw->dim.y);    
-        pixInSlice = slicesW[o>>28]/comps;
+        _ASSERTE((o&0x0fffffff)<mRaw->pitch*mRaw->dim.y);
+        pixInSlice = slicesW[o>>28];
+
+        // If new are at the start of a new line, also update predictors.
+        if (x == 0) 
+          predict = dest;
       }
+
+      for (guint i = 0; i < comps; i++) {
+         for (guint y2 = 0; y2 < samplesV[i]; y2++) {
+           for (guint x2 = 0; x2 < samplesH[i]; x2++) {            
+             p[i] += HuffDecode(dctbl[i]);
+             _ASSERTE(p[i]>=0 && p[i]<65536);
+             dest[x2*comps+y2*pitch_s] = p[i];
+           }
+         }
+         dest++;
+      }
+      dest += (maxSuperH*comps) - comps;
+      pixInSlice -= maxSuperH;
+      // Check if we are still within the file.
       bits->checkPos();
     }
     if (skipX) {
-      for (guint i = 0; i < skipX; i++) {
-        for (guint i = 0; i < comps; i++)
-          if ((y&skipEveryV[i])==0 && (x&skipEveryV[i])==0)
-            HuffDecode(dctbl[i]);
+      for (guint i = 0; i < skipX; i+=maxSuperH) {
+        for (guint j = 0; j < pixGroup; i++)
+          HuffDecode(dctbl[i]);
       }
     }
+    // Update predictors
     for (guint i = 0; i < comps; i++) {
-      if ((y&skipEveryV[i])==0) {
-        p[i] = *predict[i];
-        predict[i] = dest;
+      p[i] = predict[i];
+      // Ensure, that there is a slice shift at new line
+      _ASSERTE(pixInSlice == 0 || maxSuperV == 1);
+    }
+    predict = dest;
+    x = 0;
+  }
+}
+
+#define COMPS 3
+/*************************************************************************/
+/* These are often used compression schemes, heavily optimized to decode */
+/* that specfic kind of images.                                          */
+/*************************************************************************/
+
+void LJpegPlain::decodeScanLeft4_2_0() {
+  _ASSERTE(slicesW.size()<16);  // We only have 4 bits for slice number.
+  _ASSERTE(!(slicesW.size()>1 && skipX));   // Check if this is a valid state
+  _ASSERTE(frame.compInfo[0].superH == 2);   // Check if this is a valid state
+  _ASSERTE(frame.compInfo[0].superV == 2);   // Check if this is a valid state
+  _ASSERTE(frame.compInfo[1].superH == 1);   // Check if this is a valid state
+  _ASSERTE(frame.compInfo[1].superV == 1);   // Check if this is a valid state
+  _ASSERTE(frame.compInfo[2].superH == 1);   // Check if this is a valid state
+  _ASSERTE(frame.compInfo[2].superV == 1);   // Check if this is a valid state
+  _ASSERTE(frame.cps == COMPS);
+  _ASSERTE(skipX == 0);
+
+  HuffmanTable *dctbl1 = &huff[frame.compInfo[0].dcTblNo];
+  HuffmanTable *dctbl2 = &huff[frame.compInfo[1].dcTblNo];
+  HuffmanTable *dctbl3 = &huff[frame.compInfo[2].dcTblNo];
+
+  gushort *predict;      // Prediction pointer
+  /* Fast access to supersampling component settings
+  * this is the number of components in a given block.
+  */
+
+  mRaw->subsampling.x = 2;
+  mRaw->subsampling.y = 2;
+
+  guchar *draw = mRaw->getData();
+  guint pixGroup = 6;   // How many pixels per group.
+
+  //Prepare slices (for CR2)
+  guint slices =  (guint)slicesW.size()*(frame.h-skipY)/2;
+  offset = new guint[slices+1];
+
+  guint t_y = 0;
+  guint t_x = 0;
+  guint t_s = 0;
+  guint slice = 0;
+  guint pitch_s = mRaw->pitch/2;  // Pitch in shorts
+
+  // This is divided by comps, since comps pixels are processed at the time
+  for (guint i = 0 ; i <  slicesW.size(); i++)
+    slicesW[i] /= COMPS;
+
+  for (slice = 0; slice< slices; slice++) {
+    offset[slice] = ((t_x+offX)*mRaw->bpp+((offY+t_y)*mRaw->pitch)) | 
(t_s<<28);
+    _ASSERTE((offset[slice]&0x0fffffff)<mRaw->pitch*mRaw->dim.y);
+    t_y += 2;
+    if (t_y >= (frame.h-skipY)) {
+      t_y = 0;
+      t_x += slicesW[t_s++];
+    }
+  }
+  offset[slices] = offset[slices-1];        // Extra offset to avoid branch in 
loop.
+
+  if (skipX)
+    slicesW[slicesW.size()-1] -= skipX;
+
+  // Predictors for components
+  gushort *dest = (gushort*)&draw[offset[0]&0x0fffffff];
+
+  // Always points to next slice
+  slice = 1;
+  guint pixInSlice = slicesW[0];
+
+  // Initialize predictors and decode one group.
+  guint x = 0;
+  gint p1;
+  gint p2;
+  gint p3;
+  // First pixel is not predicted, all other are.
+  *dest = p1 = (1<<(frame.prec-Pt-1)) + HuffDecode(dctbl1);
+  p1 = dest[COMPS] = p1 + HuffDecode(dctbl1);
+  p1 = dest[pitch_s] = p1 + HuffDecode(dctbl1);
+  p1 = dest[COMPS+pitch_s] = p1 + HuffDecode(dctbl1);
+  predict = dest;
+
+  dest[1] = p2 = (1<<(frame.prec-Pt-1)) + HuffDecode(dctbl2);  
+  dest[2] = p3 = (1<<(frame.prec-Pt-1)) + HuffDecode(dctbl3);
+
+  // Skip next
+  dest+=COMPS*2;
+
+  x = 2;
+  pixInSlice -= 2;
+
+  guint cw = (frame.w-skipX);
+  for (guint y=0;y<(frame.h-skipY);y+=2) {
+    for (; x < cw ; x+=2) {
+
+      if (0 == pixInSlice) { // Next slice
+        guint o = offset[slice++];
+        dest = (gushort*)&draw[o&0x0fffffff];  // Adjust destination for next 
pixel
+        _ASSERTE((o&0x0fffffff)<mRaw->pitch*mRaw->dim.y);
+        pixInSlice = slicesW[o>>28];
+
+        // If new are at the start of a new line, also update predictors.
+        if (x == 0) {
+          predict = dest;
+        }
       }
+      p1 += HuffDecode(dctbl1);
+      *dest = p1;
+      p1 += HuffDecode(dctbl1);
+      dest[COMPS] = p1;
+      p1 += HuffDecode(dctbl1);
+      dest[pitch_s] = p1;
+      p1 += HuffDecode(dctbl1);
+      dest[pitch_s+COMPS] = p1;
+
+      dest[1] = p2 = p2 + HuffDecode(dctbl2);  
+      dest[2] = p3 = p3 + HuffDecode(dctbl3);
+
+      dest += COMPS * 2;
+      pixInSlice -= 2;
+      // Check if we are still within the file.
+      bits->checkPos();
     }
+
+    // Update predictors
+    p1 = predict[0];
+    p2 = predict[1];
+    p3 = predict[2];
+    _ASSERTE(pixInSlice == 0);  // Ensure, that there is a slice shift at new 
line
+
     x = 0;
   }
 }
 
+void LJpegPlain::decodeScanLeft4_2_2()
+{
+  _ASSERTE(slicesW.size()<16);  // We only have 4 bits for slice number.
+  _ASSERTE(!(slicesW.size()>1 && skipX));   // Check if this is a valid state
+  _ASSERTE(frame.compInfo[0].superH == 2);   // Check if this is a valid state
+  _ASSERTE(frame.compInfo[0].superV == 1);   // Check if this is a valid state
+  _ASSERTE(frame.compInfo[1].superH == 1);   // Check if this is a valid state
+  _ASSERTE(frame.compInfo[1].superV == 1);   // Check if this is a valid state
+  _ASSERTE(frame.compInfo[2].superH == 1);   // Check if this is a valid state
+  _ASSERTE(frame.compInfo[2].superV == 1);   // Check if this is a valid state
+  _ASSERTE(frame.cps == COMPS);
+  _ASSERTE(skipX == 0);
+
+  HuffmanTable *dctbl1 = &huff[frame.compInfo[0].dcTblNo];
+  HuffmanTable *dctbl2 = &huff[frame.compInfo[1].dcTblNo];
+  HuffmanTable *dctbl3 = &huff[frame.compInfo[2].dcTblNo];
+
+  mRaw->subsampling.x = 2;
+  mRaw->subsampling.y = 1;
+
+  gushort *predict;      // Prediction pointer
+  /* Fast access to supersampling component settings
+  * this is the number of components in a given block.
+  */
+
+  guchar *draw = mRaw->getData();
+  guint pixGroup = 4;   // How many pixels per group.
+
+  //Prepare slices (for CR2)
+  guint slices =  (guint)slicesW.size()*(frame.h-skipY);
+  offset = new guint[slices+1];
+
+  guint t_y = 0;
+  guint t_x = 0;
+  guint t_s = 0;
+  guint slice = 0;
+  guint pitch_s = mRaw->pitch/2;  // Pitch in shorts
+
+  // This is divided by comps, since comps pixels are processed at the time
+  for (guint i = 0 ; i <  slicesW.size(); i++)
+    slicesW[i] /= 2;
+
+  for (slice = 0; slice< slices; slice++) {
+    offset[slice] = ((t_x+offX)*mRaw->bpp+((offY+t_y)*mRaw->pitch)) | 
(t_s<<28);
+    _ASSERTE((offset[slice]&0x0fffffff)<mRaw->pitch*mRaw->dim.y);
+    t_y ++;
+    if (t_y >= (frame.h-skipY)) {
+      t_y = 0;
+      t_x += slicesW[t_s++];
+    }
+  }
+  offset[slices] = offset[slices-1];        // Extra offset to avoid branch in 
loop.
+
+  if (skipX)
+    slicesW[slicesW.size()-1] -= skipX;
+
+  // Predictors for components
+  gushort *dest = (gushort*)&draw[offset[0]&0x0fffffff];
+
+  // Always points to next slice
+  slice = 1;
+  guint pixInSlice = slicesW[0];
+
+  // Initialize predictors and decode one group.
+  guint x = 0;
+  gint p1;
+  gint p2;
+  gint p3;
+  // First pixel is not predicted, all other are.
+  *dest = p1 = (1<<(frame.prec-Pt-1)) + HuffDecode(dctbl1);
+  p1 = dest[COMPS] = p1 + HuffDecode(dctbl1);
+  predict = dest;
+
+  dest[1] = p2 = (1<<(frame.prec-Pt-1)) + HuffDecode(dctbl2);  
+  dest[2] = p3 = (1<<(frame.prec-Pt-1)) + HuffDecode(dctbl3);
+
+  // Skip next
+  dest+=COMPS*2;
+
+  x = 2;
+  pixInSlice -= 2;
+
+  guint cw = (frame.w-skipX);
+  for (guint y=0;y<(frame.h-skipY);y++) {
+    for (; x < cw ; x+=2) {
+
+      if (0 == pixInSlice) { // Next slice
+        guint o = offset[slice++];
+        dest = (gushort*)&draw[o&0x0fffffff];  // Adjust destination for next 
pixel
+        _ASSERTE((o&0x0fffffff)<mRaw->pitch*mRaw->dim.y);
+        pixInSlice = slicesW[o>>28];
+
+        // If new are at the start of a new line, also update predictors.
+        if (x == 0) {
+          predict = dest;
+        }
+      }
+      p1 += HuffDecode(dctbl1);
+      *dest = p1;
+      p1 += HuffDecode(dctbl1);
+      dest[COMPS] = p1;
+
+      dest[1] = p2 = p2 + HuffDecode(dctbl2);
+      dest[2] = p3 = p3 + HuffDecode(dctbl3);
+
+      dest += COMPS * 2;
+      pixInSlice -= 2;
+      // Check if we are still within the file.
+      bits->checkPos();
+    }
+
+    // Update predictors
+    p1 = predict[0];
+    p2 = predict[1];
+    p3 = predict[2];
+    predict = dest;
+
+    x = 0;
+  }
+}
+
+#undef COMPS
 #define COMPS 2
 void LJpegPlain::decodeScanLeft2Comps() {
   _ASSERTE(slicesW.size()<16);  // We only have 4 bits for slice number.
@@ -201,6 +538,10 @@
   if (skipX)
     slicesW[slicesW.size()-1] -= skipX*frame.cps;
 
+  // This is divided by comps, since comps pixels are processed at the time
+  for (guint i = 0 ; i <  slicesW.size(); i++)
+    slicesW[i] /= COMPS;
+
   // First pixels are obviously not predicted
   gint p1;
   gint p2;
@@ -210,8 +551,8 @@
   *dest++ = p2 = (1<<(frame.prec-Pt-1)) + HuffDecode(dctbl2);
 
   slices =  (guint)slicesW.size();
-  slice = 1;
-  guint pixInSlice = slicesW[0]/COMPS-1;    // This is divided by comps, since 
comps pixels are processed at the time
+  slice = 1;    // Always points to next slice
+  guint pixInSlice = slicesW[0]-1;    // Skip first pixel
 
   guint cw = (frame.w-skipX);
   guint x = 1;                            // Skip first pixels on first line.
@@ -232,7 +573,7 @@
         guint o = offset[slice++];
         dest = (gushort*)&draw[o&0x0fffffff];  // Adjust destination for next 
pixel
         _ASSERTE((o&0x0fffffff)<mRaw->pitch*mRaw->dim.y);    
-        pixInSlice = slicesW[o>>28]/COMPS;
+        pixInSlice = slicesW[o>>28];
       }
       bits->checkPos();
     }
@@ -281,6 +622,10 @@
   if (skipX)
     slicesW[slicesW.size()-1] -= skipX*frame.cps;
 
+  // This is divided by comps, since comps pixels are processed at the time
+  for (guint i = 0 ; i <  slicesW.size(); i++)
+    slicesW[i] /= COMPS;
+
   // First pixels are obviously not predicted
   gint p1;
   gint p2;
@@ -293,7 +638,7 @@
 
   slices =  (guint)slicesW.size();
   slice = 1;
-  guint pixInSlice = slicesW[0]/COMPS-1;    // This is divided by comps, since 
comps pixels are processed at the time
+  guint pixInSlice = slicesW[0]-1;
 
   guint cw = (frame.w-skipX);
   guint x = 1;                            // Skip first pixels on first line.
@@ -313,7 +658,7 @@
         guint o = offset[slice++];
         dest = (gushort*)&draw[o&0x0fffffff];  // Adjust destination for next 
pixel
         _ASSERTE((o&0x0fffffff)<mRaw->pitch*mRaw->dim.y);    
-        pixInSlice = slicesW[o>>28]/COMPS;
+        pixInSlice = slicesW[o>>28];
       }
       bits->checkPos();
     }
@@ -377,9 +722,13 @@
   *dest++ = p3 = (1<<(frame.prec-Pt-1)) + HuffDecode(dctbl3);
   *dest++ = p4 = (1<<(frame.prec-Pt-1)) + HuffDecode(dctbl4);
 
+  // This is divided by comps, since comps pixels are processed at the time
+  for (guint i = 0 ; i <  slicesW.size(); i++)
+    slicesW[i] /= COMPS;
+
   slices =  (guint)slicesW.size();
   slice = 1;
-  guint pixInSlice = slicesW[0]/COMPS-1;    // This is divided by comps, since 
comps pixels are processed at the time
+  guint pixInSlice = slicesW[0]-1;
 
   guint cw = (frame.w-skipX);
   guint x = 1;                            // Skip first pixels on first line.
@@ -402,7 +751,7 @@
         guint o = offset[slice++];
         dest = (gushort*)&draw[o&0x0fffffff];  // Adjust destination for next 
pixel
         _ASSERTE((o&0x0fffffff)<mRaw->pitch*mRaw->dim.y);    
-        pixInSlice = slicesW[o>>28]/COMPS;
+        pixInSlice = slicesW[o>>28];
       }
       bits->checkPos();
     }
@@ -422,3 +771,4 @@
     x = 0;
   }
 }
+

Modified: RawSpeed/LJpegPlain.h
===================================================================
--- RawSpeed/LJpegPlain.h       2009-08-03 14:53:21 UTC (rev 91)
+++ RawSpeed/LJpegPlain.h       2009-08-04 18:13:21 UTC (rev 92)
@@ -40,5 +40,7 @@
   void decodeScanLeft2Comps();
   void decodeScanLeft3Comps();
   void decodeScanLeftGeneric();
+  void decodeScanLeft4_2_0();
+  void decodeScanLeft4_2_2();
   guint *offset;
 };

Modified: RawSpeed/RawImage.cpp
===================================================================
--- RawSpeed/RawImage.cpp       2009-08-03 14:53:21 UTC (rev 91)
+++ RawSpeed/RawImage.cpp       2009-08-04 18:13:21 UTC (rev 92)
@@ -29,6 +29,7 @@
 dataRefCount(0), data(0), cpp(1)
 {
   pthread_mutex_init(&mymutex, NULL);
+  subsampling.x = subsampling.y = 1;
 }
 
 RawImageData::RawImageData(iPoint2D _dim, guint _bpc, guint _cpp) : 
@@ -36,6 +37,7 @@
 blackLevel(-1), whitePoint(65536), 
 dataRefCount(0),data(0), cpp(cpp)
 {
+  subsampling.x = subsampling.y = 1;
   createData();
   pthread_mutex_init(&mymutex, NULL);
 }
@@ -52,12 +54,21 @@
 
 
 void RawImageData::createData() {  
+  if (data)
+    ThrowRDE("RawImageData: Duplicate data allocation in createData.");
   pitch = (((dim.x*bpp) + 15)/16)*16;
   data = (guchar*)_aligned_malloc(pitch*dim.y,16);
   if (!data)
     ThrowRDE("RawImageData::createData: Memory Allocation failed.");
 }
 
+void RawImageData::destroyData()
+{
+  if (data)
+    _aligned_free(data);
+  data = 0;
+}
+
 void RawImageData::setCpp( guint val )
 {
   if (data)
@@ -93,8 +104,10 @@
 
 void RawImageData::subFrame( iPoint2D offset, iPoint2D new_size )
 {
-  if (!new_size.isThisInside(dim-offset))
-    ThrowRDE("RawImageData::subFrame - Attempted to create new subframe larger 
than original size.");
+  if (!new_size.isThisInside(dim-offset)) {
+    printf("WARNING: RawImageData::subFrame - Attempted to create new subframe 
larger than original size. Crop skipped.\n");
+    return;
+  }
 
   mOffset += offset;
   dim = new_size;
@@ -131,6 +144,7 @@
   }
 }
 
+
 RawImage::RawImage( RawImageData* p ) : p_(p)
 {
   pthread_mutex_lock(&p_->mymutex);

Modified: RawSpeed/RawImage.h
===================================================================
--- RawSpeed/RawImage.h 2009-08-03 14:53:21 UTC (rev 91)
+++ RawSpeed/RawImage.h 2009-08-04 18:13:21 UTC (rev 92)
@@ -22,6 +22,7 @@
 #pragma once
 #include "pthread.h"
 #include "ColorFilterArray.h"
+#include "BlackArea.h"
 
 class RawImage;
 class RawImageData
@@ -35,6 +36,7 @@
   void setCpp(guint val);
   guint pitch;
   virtual void createData();
+  virtual void destroyData();
   guchar* getData();
   guchar* getData(guint x, guint y);    // Not super fast, but safe. Don't use 
per pixel.
   virtual void subFrame( iPoint2D offset, iPoint2D new_size );
@@ -43,6 +45,8 @@
   ColorFilterArray cfa;
   int blackLevel;
   int whitePoint;
+  vector<BlackArea> blackAreas;
+  iPoint2D subsampling;
 protected:
   RawImageData(void);
   RawImageData(iPoint2D dim, guint bpp, guint cpp=1);

Modified: RawSpeed/RawSpeed.vcproj
===================================================================
--- RawSpeed/RawSpeed.vcproj    2009-08-03 14:53:21 UTC (rev 91)
+++ RawSpeed/RawSpeed.vcproj    2009-08-04 18:13:21 UTC (rev 92)
@@ -291,6 +291,10 @@
                                        >
                                </File>
                                <File
+                                       
RelativePath=".\TiffParserHeaderless.cpp"
+                                       >
+                               </File>
+                               <File
                                        RelativePath=".\TiffParserOlympus.cpp"
                                        >
                                </File>
@@ -468,42 +472,6 @@
                                        RelativePath=".\Point.h"
                                        >
                                </File>
-                               <Filter
-                                       Name="Tiff"
-                                       >
-                                       <File
-                                               RelativePath=".\TiffEntry.h"
-                                               >
-                                       </File>
-                                       <File
-                                               RelativePath=".\TiffEntryBE.h"
-                                               >
-                                       </File>
-                                       <File
-                                               RelativePath=".\TiffIFD.h"
-                                               >
-                                       </File>
-                                       <File
-                                               RelativePath=".\TiffIFDBE.h"
-                                               >
-                                       </File>
-                                       <File
-                                               RelativePath=".\TiffParser.h"
-                                               >
-                                       </File>
-                                       <File
-                                               
RelativePath=".\TiffParserException.h"
-                                               >
-                                       </File>
-                                       <File
-                                               
RelativePath=".\TiffParserOlympus.h"
-                                               >
-                                       </File>
-                                       <File
-                                               RelativePath=".\TiffTag.h"
-                                               >
-                                       </File>
-                               </Filter>
                        </Filter>
                        <Filter
                                Name="Decompressors"
@@ -597,6 +565,46 @@
                                        >
                                </File>
                        </Filter>
+                       <Filter
+                               Name="Tiff"
+                               >
+                               <File
+                                       RelativePath=".\TiffEntry.h"
+                                       >
+                               </File>
+                               <File
+                                       RelativePath=".\TiffEntryBE.h"
+                                       >
+                               </File>
+                               <File
+                                       RelativePath=".\TiffIFD.h"
+                                       >
+                               </File>
+                               <File
+                                       RelativePath=".\TiffIFDBE.h"
+                                       >
+                               </File>
+                               <File
+                                       RelativePath=".\TiffParser.h"
+                                       >
+                               </File>
+                               <File
+                                       RelativePath=".\TiffParserException.h"
+                                       >
+                               </File>
+                               <File
+                                       RelativePath=".\TiffParserHeaderless.h"
+                                       >
+                               </File>
+                               <File
+                                       RelativePath=".\TiffParserOlympus.h"
+                                       >
+                               </File>
+                               <File
+                                       RelativePath=".\TiffTag.h"
+                                       >
+                               </File>
+                       </Filter>
                </Filter>
                <Filter
                        Name="Resource Files"

Added: RawSpeed/TiffParserHeaderless.cpp
===================================================================
--- RawSpeed/TiffParserHeaderless.cpp                           (rev 0)
+++ RawSpeed/TiffParserHeaderless.cpp   2009-08-04 18:13:21 UTC (rev 92)
@@ -0,0 +1,46 @@
+#include "StdAfx.h"
+#include "TiffParserHeaderless.h"
+
+TiffParserHeaderless::TiffParserHeaderless(FileMap* input, Endianness _end) :
+TiffParser(input)
+{
+  endian = _end;
+}
+
+TiffParserHeaderless::~TiffParserHeaderless(void)
+{
+}
+
+#ifdef CHECKSIZE
+#undef CHECKSIZE
+#endif
+#ifdef CHECKPTR
+#undef CHECKPTR
+#endif
+
+#define CHECKSIZE(A) if (A >= mInput->getSize()) throw 
TiffParserException("Error reading TIFF structure. File Corrupt")
+#define CHECKPTR(A) if ((int)A >= ((int)(mInput->data) + size))) throw 
TiffParserException("Error reading TIFF structure. File Corrupt")
+
+
+void TiffParserHeaderless::parseData() {
+  const unsigned char* data = mInput->getData(0);
+  if (mInput->getSize() < 12)
+    throw TiffParserException("Not a TIFF file (size too small)");
+
+  if (endian == little)
+    mRootIFD = new TiffIFD();
+  else
+    mRootIFD = new TiffIFDBE();
+
+  guint nextIFD = 0;
+  do {
+    CHECKSIZE(nextIFD);
+
+    if (endian == little)
+      mRootIFD->mSubIFD.push_back(new TiffIFD(mInput, nextIFD));
+    else
+      mRootIFD->mSubIFD.push_back(new TiffIFDBE(mInput, nextIFD));
+
+    nextIFD = mRootIFD->mSubIFD.back()->getNextIFD();
+  } while (nextIFD);
+}

Added: RawSpeed/TiffParserHeaderless.h
===================================================================
--- RawSpeed/TiffParserHeaderless.h                             (rev 0)
+++ RawSpeed/TiffParserHeaderless.h     2009-08-04 18:13:21 UTC (rev 92)
@@ -0,0 +1,11 @@
+#pragma once
+#include "TiffParser.h"
+
+class TiffParserHeaderless :
+  public TiffParser
+{
+public:
+  TiffParserHeaderless(FileMap* input, Endianness _end);
+  virtual ~TiffParserHeaderless(void);
+  virtual void parseData();
+};


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

Reply via email to