Author: post
Date: 2012-07-28 18:05:49 +0200 (Sat, 28 Jul 2012)
New Revision: 441

Added:
   RawSpeed/DngOpcodes.cpp
   RawSpeed/DngOpcodes.h
Modified:
   RawSpeed/ArwDecoder.cpp
   RawSpeed/Common.h
   RawSpeed/Cr2Decoder.cpp
   RawSpeed/DngDecoder.cpp
   RawSpeed/DngDecoder.h
   RawSpeed/DngDecoderSlices.cpp
   RawSpeed/DngDecoderSlices.h
   RawSpeed/LJpegPlain.cpp
   RawSpeed/NefDecoder.cpp
   RawSpeed/OrfDecoder.cpp
   RawSpeed/PefDecoder.cpp
   RawSpeed/Point.h
   RawSpeed/RawDecoder.cpp
   RawSpeed/RawDecoder.h
   RawSpeed/RawImage.cpp
   RawSpeed/RawImage.h
   RawSpeed/RawImageDataU16.cpp
   RawSpeed/StdAfx.h
Log:
Add "Lossy DNG" support, and a few refactored items. This has the following 
interface consequnces:
* Add "DngOpcodes.cpp"/"DngOpcodes.h" to project.
* 'libjpeg' must be linked.
* 'errors' moved from the RawDecoder to the RawImage, so it follows the image.


Modified: RawSpeed/ArwDecoder.cpp
===================================================================
--- RawSpeed/ArwDecoder.cpp     2012-07-18 12:28:33 UTC (rev 440)
+++ RawSpeed/ArwDecoder.cpp     2012-07-28 16:05:49 UTC (rev 441)
@@ -106,7 +106,7 @@
     else
       DecodeARW2(input, width, height, bitPerPixel);
   } catch (IOException &e) {
-    errors.push_back(_strdup(e.what()));
+    mRaw->setError(e.what());
     // Let's ignore it, it may have delivered somewhat useful data.
   }
 

Modified: RawSpeed/Common.h
===================================================================
--- RawSpeed/Common.h   2012-07-18 12:28:33 UTC (rev 440)
+++ RawSpeed/Common.h   2012-07-28 16:05:49 UTC (rev 441)
@@ -107,6 +107,11 @@
 }
 
 inline Endianness getHostEndianness() {
+#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+  return little;
+#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+  return big;
+#else
   ushort16 testvar = 0xfeff; 
   uint32 firstbyte = ((uchar8 *)&testvar)[0];
   if (firstbyte == 0xff)
@@ -118,9 +123,29 @@
 
   // Return something to make compilers happy
   return unknown;
+#endif
 }
-inline uint32 clampbits(int x, uint32 n) { uint32 _y_temp; if( (_y_temp=x>>n) 
) x = ~_y_temp >> (32-n); return x;}
 
+#if defined(__GNUC__) && (PIPE_CC_GCC_VERSION >= 403) && 
defined(__BYTE_ORDER__) 
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ && __alignof__ (int) == 1
+#define LE_PLATFORM_HAS_BSWAP
+#define PLATFORM_BSWAP32(A) __builtin_bswap32(A)
+#endif
+#endif
+
+#ifdef _MSC_VER
+#include <intrin.h>
+#define LE_PLATFORM_HAS_BSWAP
+#define PLATFORM_BSWAP32(A) _byteswap_ulong(A)
+#endif
+
+inline uint32 clampbits(int x, uint32 n) { 
+  uint32 _y_temp; 
+  if( (_y_temp=x>>n) ) 
+    x = ~_y_temp >> (32-n); 
+  return x;
+}
+
 /* This is faster - at least when compiled on visual studio 32 bits */
 inline int other_abs(int x) { int const mask = x >> 31; return (x + mask) ^ 
mask;}
 

Modified: RawSpeed/Cr2Decoder.cpp
===================================================================
--- RawSpeed/Cr2Decoder.cpp     2012-07-18 12:28:33 UTC (rev 440)
+++ RawSpeed/Cr2Decoder.cpp     2012-07-28 16:05:49 UTC (rev 441)
@@ -120,10 +120,10 @@
       if (i == 0)
         throw;
       // These may just be single slice error - store the error and move on
-      errors.push_back(_strdup(e.what()));
+      mRaw->setError(e.what());
     } catch (IOException &e) {
       // Let's try to ignore this - it might be truncated data, so something 
might be useful.
-      errors.push_back(_strdup(e.what()));
+      mRaw->setError(e.what());
     }
     offY += slice.w;
   }
@@ -208,12 +208,13 @@
       interpolate_422_new(mRaw->dim.x / 2, mRaw->dim.y , 0, mRaw->dim.y);
     else
       interpolate_422(mRaw->dim.x / 2, mRaw->dim.y , 0, mRaw->dim.y);
-  } else {
+  } else if (mRaw->subsampling.y == 2 && mRaw->subsampling.x == 2) {
     if (isNewSraw)
       interpolate_420_new(mRaw->dim.x / 2, mRaw->dim.y / 2 , 0 , mRaw->dim.y / 
2);
     else
       interpolate_420(mRaw->dim.x / 2, mRaw->dim.y / 2 , 0 , mRaw->dim.y / 2);
-  }
+  } else
+    ThrowRDE("CR2 Decoder: Unknown subsampling");
 }
 
 #define YUV_TO_RGB(Y, Cb, Cr) r = sraw_coeffs[0] * ((int)Y + (( 50*(int)Cb + 
22929*(int)Cr) >> 12));\

Modified: RawSpeed/DngDecoder.cpp
===================================================================
--- RawSpeed/DngDecoder.cpp     2012-07-18 12:28:33 UTC (rev 440)
+++ RawSpeed/DngDecoder.cpp     2012-07-28 16:05:49 UTC (rev 441)
@@ -60,7 +60,7 @@
     try {
       isSubsampled = (*i)->getEntry(NEWSUBFILETYPE)->getInt() & 1; // bit 0 is 
on if image is subsampled
     } catch (TiffParserException) {}
-    if ((compression != 7 && compression != 1) || isSubsampled) {  // Erase if 
subsampled, or not JPEG or uncompressed
+    if ((compression != 7 && compression != 1 && compression != 0x884c) || 
isSubsampled) {  // Erase if subsampled, or not JPEG or uncompressed
       i = data.erase(i);
     } else {
       ++i;
@@ -108,9 +108,10 @@
     ThrowRDE("DNG Decoder: Could not read basic image information.");
   }
 
+  int compression = -1;
+
   try {
-
-    int compression = raw->getEntry(COMPRESSION)->getShort();
+    compression = raw->getEntry(COMPRESSION)->getShort();
     if (mRaw->isCFA) {
 
       // Check if layout is OK, if present
@@ -218,7 +219,7 @@
             readUncompressedRaw(in, size, pos, width*bps / 8, bps, big_endian);
           } catch(IOException &ex) {
             if (i > 0)
-              errors.push_back(_strdup(ex.what()));
+              mRaw->setError(ex.what());
             else
               ThrowRDE("DNG decoder: IO error occurred in first slice, unable 
to decode more. Error is: %s", ex.what());
           }
@@ -227,7 +228,7 @@
       } catch (TiffParserException) {
         ThrowRDE("DNG Decoder: Unsupported format, uncompressed with no 
strips.");
       }
-    } else if (compression == 7) {
+    } else if (compression == 7 || compression == 0x884c) {
       try {
         // Let's try loading it as tiles instead
 
@@ -239,7 +240,7 @@
         if (sample_format != 1)
            ThrowRDE("DNG Decoder: Only 16 bit unsigned data supported for 
compressed data.");
 
-        DngDecoderSlices slices(mFile, mRaw);
+        DngDecoderSlices slices(mFile, mRaw, compression);
         if (raw->hasEntry(TILEOFFSETS)) {
           uint32 tilew = raw->getEntry(TILEWIDTH)->getInt();
           uint32 tileh = raw->getEntry(TILELENGTH)->getInt();
@@ -299,11 +300,8 @@
 
         slices.startDecoding();
 
-        if (!slices.errors.empty())
-          errors = slices.errors;
-
-        if (errors.size() >= nSlices)
-          ThrowRDE("DNG Decoding: Too many errors encountered. Giving 
up.\nFirst Error:%s", errors[0]);
+        if (mRaw->errors.size() >= nSlices)
+          ThrowRDE("DNG Decoding: Too many errors encountered. Giving 
up.\nFirst Error:%s", mRaw->errors[0]);
       } catch (TiffParserException e) {
         ThrowRDE("DNG Decoder: Unsupported format, tried strips and 
tiles:\n%s", e.what());
       }
@@ -320,45 +318,44 @@
     const uint32 *corners = raw->getEntry(ACTIVEAREA)->getIntArray();
     if (iPoint2D(corners[1], corners[0]).isThisInside(mRaw->dim)) {
       if (iPoint2D(corners[3], corners[2]).isThisInside(mRaw->dim)) {
-        iPoint2D top_left(corners[1], corners[0]);
-        new_size = iPoint2D(corners[3] - corners[1], corners[2] - corners[0]);
-        mRaw->subFrame(top_left, new_size);
+        iRectangle2D crop(corners[1], corners[0], corners[3] - corners[1], 
corners[2] - corners[0]);
+        mRaw->subFrame(crop);
       }
     }
   }
 
   if (raw->hasEntry(DEFAULTCROPORIGIN)) {
-    iPoint2D top_left(0, 0);
-    iPoint2D new_size(mRaw->dim.x, mRaw->dim.y);
+    iRectangle2D cropped(0, 0, mRaw->dim.x, mRaw->dim.y);
     if (raw->getEntry(DEFAULTCROPORIGIN)->type == TIFF_LONG) {
       const uint32* tl = raw->getEntry(DEFAULTCROPORIGIN)->getIntArray();
       const uint32* sz = raw->getEntry(DEFAULTCROPSIZE)->getIntArray();
       if (iPoint2D(tl[0], tl[1]).isThisInside(mRaw->dim) && iPoint2D(sz[0], 
sz[1]).isThisInside(mRaw->dim)) {
-        top_left = iPoint2D(tl[0], tl[1]);
-        new_size = iPoint2D(sz[0], sz[1]);
+        cropped = iRectangle2D(tl[0], tl[1], sz[0], sz[1]);
       }
     } else if (raw->getEntry(DEFAULTCROPORIGIN)->type == TIFF_SHORT) {
       const ushort16* tl = raw->getEntry(DEFAULTCROPORIGIN)->getShortArray();
       const ushort16* sz = raw->getEntry(DEFAULTCROPSIZE)->getShortArray();
       if (iPoint2D(tl[0], tl[1]).isThisInside(mRaw->dim) && iPoint2D(sz[0], 
sz[1]).isThisInside(mRaw->dim)) {
-        top_left = iPoint2D(tl[0], tl[1]);
-        new_size = iPoint2D(sz[0], sz[1]);
+        cropped = iRectangle2D(tl[0], tl[1], sz[0], sz[1]);
       }
     } else if (raw->getEntry(DEFAULTCROPORIGIN)->type == TIFF_RATIONAL) {
       // Crop as rational numbers, really?
       const uint32* tl = raw->getEntry(DEFAULTCROPORIGIN)->getIntArray();
       const uint32* sz = raw->getEntry(DEFAULTCROPSIZE)->getIntArray();
-      if (iPoint2D(tl[0]/tl[1],tl[2]/tl[3]).isThisInside(mRaw->dim) && 
iPoint2D(sz[0]/sz[1],sz[2]/sz[3]).isThisInside(mRaw->dim)) {
-        top_left = iPoint2D(tl[0]/tl[1],tl[2]/tl[3]);
-        new_size = iPoint2D(iPoint2D(sz[0]/sz[1],sz[2]/sz[3]));
+      if (tl[1] && tl[3] && sz[1] && sz[3]) {
+        if (iPoint2D(tl[0]/tl[1],tl[2]/tl[3]).isThisInside(mRaw->dim) && 
iPoint2D(sz[0]/sz[1],sz[2]/sz[3]).isThisInside(mRaw->dim)) {
+          cropped = iRectangle2D(tl[0]/tl[1], tl[2]/tl[3], sz[0]/sz[1], 
sz[2]/sz[3]);
+        }
       }
     }
-    mRaw->subFrame(top_left, new_size);
-    if (top_left.x %2 == 1)
+    mRaw->subFrame(cropped);
+    if (cropped.pos.x %2 == 1)
       mRaw->cfa.shiftLeft();
-    if (top_left.y %2 == 1)
+    if (cropped.pos.y %2 == 1)
       mRaw->cfa.shiftDown();
   }
+  if (mRaw->dim.area() <= 0)
+    ThrowRDE("DNG Decoder: No image left after crop");
 
   // Linearization
   if (raw->hasEntry(LINEARIZATIONTABLE)) {
@@ -391,10 +388,33 @@
   // Set black
   setBlack(raw);
 
+  // Apply opcodes to lossy DNG 
+  if (compression == 0x884c) {
+    if (raw->hasEntry(OPCODELIST2))
+    {
+      // We must apply black/white scaling
+      mRaw->scaleBlackWhite();
+      // Apply stage 2 codes
+      try{
+        DngOpcodes codes(raw->getEntry(OPCODELIST2));
+        mRaw = codes.applyOpCodes(mRaw);
+      } catch (RawDecoderException &e) {
+        // We push back errors from the opcode parser, since the image may 
still be usable
+        mRaw->setError(e.what());
+      }
+      mRaw->blackAreas.clear();
+      mRaw->blackLevel = 0;
+      mRaw->blackLevelSeparate[0] = mRaw->blackLevelSeparate[1] = 
mRaw->blackLevelSeparate[2] = mRaw->blackLevelSeparate[3] = 0;
+      mRaw->whitePoint = 65535;
+    }
+  }
   return mRaw;
 }
 
 void DngDecoder::decodeMetaDataInternal(CameraMetaData *meta) {
+  if (mRootIFD->hasEntryRecursive(ISOSPEEDRATINGS))
+    mRaw->isoSpeed = mRootIFD->getEntryRecursive(ISOSPEEDRATINGS)->getInt();
+
 }
 
 void DngDecoder::checkSupportInternal(CameraMetaData *meta) {

Modified: RawSpeed/DngDecoder.h
===================================================================
--- RawSpeed/DngDecoder.h       2012-07-18 12:28:33 UTC (rev 440)
+++ RawSpeed/DngDecoder.h       2012-07-28 16:05:49 UTC (rev 441)
@@ -4,6 +4,7 @@
 #include "LJpegPlain.h"
 #include "TiffIFD.h"
 #include "DngDecoderSlices.h"
+#include "DngOpcodes.h"
 /* 
     RawSpeed - RAW file decoder.
 

Modified: RawSpeed/DngDecoderSlices.cpp
===================================================================
--- RawSpeed/DngDecoderSlices.cpp       2012-07-18 12:28:33 UTC (rev 440)
+++ RawSpeed/DngDecoderSlices.cpp       2012-07-28 16:05:49 UTC (rev 441)
@@ -24,22 +24,28 @@
 
 namespace RawSpeed {
 
+#if defined(CHECKSIZE)
+#undef CHECKSIZE
+#endif
+#define CHECKSIZE(A) if (A > size) ThrowIOE("Error decoding DNG Slice (invalid 
size). File Corrupt")
+
 void *DecodeThread(void *_this) {
   DngDecoderThread* me = (DngDecoderThread*)_this;
   DngDecoderSlices* parent = me->parent;
   try {
     parent->decodeSlice(me);
   } catch (...) {
-    parent->setError("DNGDEcodeThread: Caught exception.");
+    parent->mRaw->setError("DNGDEcodeThread: Caught exception.");
   }
   pthread_exit(NULL);
   return NULL;
 }
 
 
-DngDecoderSlices::DngDecoderSlices(FileMap* file, RawImage img) :
+DngDecoderSlices::DngDecoderSlices(FileMap* file, RawImage img, int 
_compression) :
     mFile(file), mRaw(img) {
   mFixLjpeg = false;
+  compression = _compression;
 }
 
 DngDecoderSlices::~DngDecoderSlices(void) {
@@ -59,7 +65,6 @@
   /* Initialize and set thread detached attribute */
   pthread_attr_init(&attr);
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
-  pthread_mutex_init(&errMutex, NULL);
 
   for (uint32 i = 0; i < nThreads; i++) {
     DngDecoderThread* t = new DngDecoderThread();
@@ -80,36 +85,139 @@
     pthread_join(threads[i]->threadid, &status);
     delete(threads[i]);
   }
-  pthread_mutex_destroy(&errMutex);
 
 }
 
+#if JPEG_LIB_VERSION < 80
+/* Read JPEG image from a memory segment */
+
+static void init_source (j_decompress_ptr cinfo) {}
+static boolean fill_input_buffer (j_decompress_ptr cinfo)
+{
+  struct jpeg_source_mgr* src = (struct jpeg_source_mgr*) cinfo->src;
+  return !!src->bytes_in_buffer;
+}
+static void skip_input_data (j_decompress_ptr cinfo, long num_bytes)
+{
+  struct jpeg_source_mgr* src = (struct jpeg_source_mgr*) cinfo->src;
+
+  if (num_bytes > (int)src->bytes_in_buffer)
+    ThrowIOE("JPEG Decoder - read out of buffer");
+  if (num_bytes > 0) {
+    src->next_input_byte += (size_t) num_bytes;
+    src->bytes_in_buffer -= (size_t) num_bytes;
+  }
+}
+static void term_source (j_decompress_ptr cinfo) {}
+static void jpeg_mem_src (j_decompress_ptr cinfo, unsigned char* buffer, long 
nbytes)
+{
+  struct jpeg_source_mgr* src;
+
+  if (cinfo->src == NULL) {   /* first time for this JPEG object? */
+    cinfo->src = (struct jpeg_source_mgr *)
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+      sizeof(struct jpeg_source_mgr));
+  }
+
+  src = (struct jpeg_source_mgr*) cinfo->src;
+  src->init_source = init_source;
+  src->fill_input_buffer = fill_input_buffer;
+  src->skip_input_data = skip_input_data;
+  src->resync_to_restart = jpeg_resync_to_restart; /* use default method */
+  src->term_source = term_source;
+  src->bytes_in_buffer = nbytes;
+  src->next_input_byte = (JOCTET*)buffer;
+}
+#endif
+
+METHODDEF(void)
+my_error_throw (j_common_ptr cinfo)
+{
+  ThrowRDE("JPEG decoder error!");
+} 
+
+
 void DngDecoderSlices::decodeSlice(DngDecoderThread* t) {
-  while (!t->slices.empty()) {
-    LJpegPlain l(mFile, mRaw);
-    l.mDNGCompatible = mFixLjpeg;
-    DngSliceElement e = t->slices.front();
-    l.mUseBigtable = e.mUseBigtable;
-    t->slices.pop();
-    try {
-      l.startDecoder(e.byteOffset, e.byteCount, e.offX, e.offY);
-    } catch (RawDecoderException &err) {
-      setError(err.what());
-    } catch (IOException) {
-      setError("DngDecoderSlices::decodeSlice: IO error occurred.");
+  if (compression == 7) {
+    while (!t->slices.empty()) {
+      LJpegPlain l(mFile, mRaw);
+      l.mDNGCompatible = mFixLjpeg;
+      DngSliceElement e = t->slices.front();
+      l.mUseBigtable = e.mUseBigtable;
+      t->slices.pop();
+      try {
+        l.startDecoder(e.byteOffset, e.byteCount, e.offX, e.offY);
+      } catch (RawDecoderException &err) {
+        mRaw->setError(err.what());
+      } catch (IOException &err) {
+        mRaw->setError(err.what());
+      }
     }
+    /* Lossy DNG */
+  } else if (compression == 0x884c) {
+    /* Each slice is a JPEG image */
+    struct jpeg_decompress_struct dinfo;
+    struct jpeg_error_mgr jerr;
+    while (!t->slices.empty()) {
+      DngSliceElement e = t->slices.front();
+      t->slices.pop();
+      uchar8 *complete_buffer = NULL;
+      JSAMPARRAY buffer = (JSAMPARRAY)malloc(sizeof(JSAMPROW));
+
+      try {
+        uint32 size = mFile->getSize();
+        jpeg_create_decompress(&dinfo);
+        dinfo.err = jpeg_std_error(&jerr);
+        jerr.error_exit = my_error_throw;
+        CHECKSIZE(e.byteOffset);
+        CHECKSIZE(e.byteOffset+e.byteCount);
+        jpeg_mem_src(&dinfo, (unsigned char*)mFile->getData(e.byteOffset), 
e.byteCount);
+
+        if (JPEG_HEADER_OK != jpeg_read_header(&dinfo, TRUE))
+          ThrowRDE("DngDecoderSlices: Unable to read JPEG header");
+
+        jpeg_start_decompress(&dinfo);
+        if (dinfo.output_components != (int)mRaw->getCpp())
+          ThrowRDE("DngDecoderSlices: Component count doesn't match");
+        int row_stride = dinfo.output_width * dinfo.output_components;
+        int pic_size = dinfo.output_height * row_stride;
+        complete_buffer = (uchar8*)_aligned_malloc(pic_size, 16);
+        while (dinfo.output_scanline < dinfo.output_height) {
+          buffer[0] = 
(JSAMPROW)(&complete_buffer[dinfo.output_scanline*row_stride]);
+          if (0 == jpeg_read_scanlines(&dinfo, buffer, 1))
+            ThrowRDE("DngDecoderSlices: JPEG Error while decompressing 
image.");
+        }
+        jpeg_finish_decompress(&dinfo);
+
+        // Now the image is decoded, and we copy the image data
+        int copy_w = min(mRaw->dim.x-e.offX, dinfo.output_width);
+        int copy_h = min(mRaw->dim.y-e.offY, dinfo.output_height);
+        for (int y = 0; y < copy_h; y++) {
+          uchar8* src = &complete_buffer[row_stride*y];
+          ushort16* dst = (ushort16*)mRaw->getData(e.offX, y+e.offY);
+          for (int x = 0; x < copy_w; x++) {
+            for (int c=0; c < dinfo.output_components; c++)
+              *dst++ = (*src++);
+          }
+        }
+      } catch (RawDecoderException &err) {
+        mRaw->setError(err.what());
+      } catch (IOException &err) {
+        mRaw->setError(err.what());
+      }
+      free(buffer);
+      if (complete_buffer)
+        _aligned_free(complete_buffer);
+      jpeg_destroy_decompress(&dinfo);
+    }
   }
+  else
+    mRaw->setError("DngDecoderSlices: Unknown compression");
 }
 
 int DngDecoderSlices::size() {
   return (int)slices.size();
 }
 
-void DngDecoderSlices::setError( const char* err )
-{
-  pthread_mutex_lock(&errMutex);
-  errors.push_back(_strdup(err));
-  pthread_mutex_unlock(&errMutex);
-}
 
 } // namespace RawSpeed

Modified: RawSpeed/DngDecoderSlices.h
===================================================================
--- RawSpeed/DngDecoderSlices.h 2012-07-18 12:28:33 UTC (rev 440)
+++ RawSpeed/DngDecoderSlices.h 2012-07-28 16:05:49 UTC (rev 441)
@@ -56,21 +56,19 @@
 class DngDecoderSlices
 {
 public:
-  DngDecoderSlices(FileMap* file, RawImage img );
+  DngDecoderSlices(FileMap* file, RawImage img, int compression );
   ~DngDecoderSlices(void);
   void addSlice(DngSliceElement slice);
   void startDecoding();
   void decodeSlice(DngDecoderThread* t);
-  void setError(const char* err);
   int size();
   queue<DngSliceElement> slices;
   vector<DngDecoderThread*> threads;
   FileMap *mFile; 
   RawImage mRaw;
-  vector<const char*> errors;
-  pthread_mutex_t errMutex;   // Mutex for above
   bool mFixLjpeg;
   uint32 nThreads;
+  int compression;
 };
 
 } // namespace RawSpeed

Added: RawSpeed/DngOpcodes.cpp
===================================================================
--- RawSpeed/DngOpcodes.cpp                             (rev 0)
+++ RawSpeed/DngOpcodes.cpp     2012-07-28 16:05:49 UTC (rev 441)
@@ -0,0 +1,249 @@
+#include "StdAfx.h"
+#include "DngOpcodes.h"
+/* 
+RawSpeed - RAW file decoder.
+
+Copyright (C) 2012 Klaus Post
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+http://www.klauspost.com
+*/
+
+namespace RawSpeed {
+
+DngOpcodes::DngOpcodes(TiffEntry *entry)
+{
+  host = getHostEndianness();
+  const uchar8* data = entry->getData();
+  uint32 entry_size = entry->count;
+  uint32 opcode_count = getULong(&data[0]);
+
+  int bytes_used = 4;
+  for (uint32 i = 0; i < opcode_count; i++) {
+    uint32 code = getULong(&data[bytes_used]);
+    //uint32 version = getULong(&data[bytes_used+4]);
+    //uint32 flags = getULong(&data[bytes_used+8]);
+    uint32 expected_size = getULong(&data[bytes_used+12]);
+    bytes_used += 16;
+    uint32 opcode_used = 0;
+    switch (code)
+    {
+      case 6:
+        mOpcodes.push_back(new OpcodeTrimBounds(&data[bytes_used], entry_size 
- bytes_used, &opcode_used));
+      case 7:
+        mOpcodes.push_back(new OpcodeMapTable(&data[bytes_used], entry_size - 
bytes_used, &opcode_used));
+      case 8:
+        mOpcodes.push_back(new OpcodeMapPolynomial(&data[bytes_used], 
entry_size - bytes_used, &opcode_used));
+        break;
+      default:
+        ThrowRDE("DngOpcodes: Unsupported Opcode: %d", code);
+    }
+    if (opcode_used != expected_size)
+      ThrowRDE("DngOpcodes: Inconsistent length of opcode");
+    bytes_used += opcode_used;
+    if (bytes_used > (int)entry_size)
+      ThrowRDE("DngOpcodes: More codes than entry size (should be caught 
earlier)");
+  }
+}
+
+DngOpcodes::~DngOpcodes(void)
+{
+  size_t codes = mOpcodes.size();
+  for (uint32 i = 0; i < codes; i++)
+    delete mOpcodes[i];
+  mOpcodes.clear();
+}
+
+/* TODO: Apply in separate threads */
+RawImage& DngOpcodes::applyOpCodes( RawImage &img )
+{
+  size_t codes = mOpcodes.size();
+  for (uint32 i = 0; i < codes; i++)
+  {
+    DngOpcode* code = mOpcodes[i];
+    RawImage img_out = code->createOutput(img);
+    iRectangle2D fullImage(0,0,img->dim.x, img->dim.y);
+
+    if (!code->mAoi.isThisInside(fullImage))
+      ThrowRDE("DngOpcodes: Area of interest not inside image!");
+    if (code->mAoi.hasPositiveArea()) {
+      code->apply(img, img_out, code->mAoi.getTop(), code->mAoi.getBottom());
+      img = img_out;
+    }
+  }
+  return img;
+}
+
+ /***************** OpcodeTrimBounds   ****************/
+
+OpcodeTrimBounds::OpcodeTrimBounds(const uchar8* parameters, int 
param_max_bytes, uint32 *bytes_used )
+{
+  if (param_max_bytes < 16)
+    ThrowRDE("OpcodeTrimBounds: Not enough data to read parameters, only %d 
bytes left.", param_max_bytes);
+  mTop = getLong(&parameters[0]);
+  mLeft = getLong(&parameters[4]);
+  mBottom = getLong(&parameters[8]);
+  mRight = getLong(&parameters[12]);
+  *bytes_used = 16;
+}
+
+void OpcodeTrimBounds::apply( RawImage &in, RawImage &out, int startY, int 
endY )
+{
+  iRectangle2D crop(mLeft, mTop, mRight-mLeft, mBottom-mTop);
+  out->subFrame(crop);
+}
+
+/***************** OpcodeMapTable   ****************/
+
+OpcodeMapTable::OpcodeMapTable(const uchar8* parameters, int param_max_bytes, 
uint32 *bytes_used )
+{
+  if (param_max_bytes < 36)
+    ThrowRDE("OpcodeMapTable: Not enough data to read parameters, only %d 
bytes left.", param_max_bytes);
+  mAoi.setAbsolute(getLong(&parameters[4]), getLong(&parameters[0]), 
getLong(&parameters[12]), getLong(&parameters[8]));
+  mFirstPlane = getLong(&parameters[16]);
+  mPlanes = getLong(&parameters[20]);
+  mRowPitch = getLong(&parameters[24]);
+  mColPitch = getLong(&parameters[28]);
+  if (mFirstPlane < 0)
+    ThrowRDE("OpcodeMapPolynomial: Negative first plane");
+  if (mPlanes <= 0)
+    ThrowRDE("OpcodeMapPolynomial: Negative number of planes");
+  if (mRowPitch <= 0 || mColPitch <= 0)
+    ThrowRDE("OpcodeMapPolynomial: Invalid Pitch");
+
+  int tablesize = getLong(&parameters[32]);
+  *bytes_used = 36;
+
+  if (tablesize > 65536)
+    ThrowRDE("OpcodeMapTable: A map with more than 65536 entries not allowed");
+
+  if (param_max_bytes < 36 + (tablesize*2))
+    ThrowRDE("OpcodeMapPolynomial: Not enough data to read parameters, only %d 
bytes left.", param_max_bytes);
+
+  for (int i = 0; i <= 65535; i++)
+  {
+    int location = min(tablesize-1, i);
+    mLookup[i] = getUshort(&parameters[36+2*location]);
+  }
+
+  *bytes_used += tablesize*2;
+  mFlags = MultiThreaded | PureLookup;
+}
+
+
+RawImage& OpcodeMapTable::createOutput( RawImage &in )
+{
+  if (in->getDataType() != TYPE_USHORT16)
+    ThrowRDE("OpcodeMapTable: Only 16 bit images supported");
+
+  if (mFirstPlane > (int)in->getCpp())
+    ThrowRDE("OpcodeMapTable: Not that many planes in actual image");
+
+  if (mFirstPlane+mPlanes > (int)in->getCpp())
+    ThrowRDE("OpcodeMapTable: Not that many planes in actual image");
+
+  return in;
+}
+
+void OpcodeMapTable::apply( RawImage &in, RawImage &out, int startY, int endY )
+{
+  int cpp = out->getCpp();
+  for (int y = startY; y < endY; y += mRowPitch) {
+    ushort16 *src = (ushort16*)out->getData(mAoi.getLeft(), y);
+    // Add offset, so this is always first plane
+    src+=mFirstPlane;
+    for (int x = 0; x < mAoi.getWidth(); x += mColPitch) {
+      for (int p = 0; p < mPlanes; p++)
+      {
+        src[x*cpp+p] = mLookup[src[x*cpp+p]];
+      }
+    }
+  }
+}
+
+
+
+ /***************** OpcodeMapPolynomial   ****************/
+
+OpcodeMapPolynomial::OpcodeMapPolynomial(const uchar8* parameters, int 
param_max_bytes, uint32 *bytes_used )
+{
+  if (param_max_bytes < 36)
+    ThrowRDE("OpcodeMapPolynomial: Not enough data to read parameters, only %d 
bytes left.", param_max_bytes);
+  mAoi.setAbsolute(getLong(&parameters[4]), getLong(&parameters[0]), 
getLong(&parameters[12]), getLong(&parameters[8]));
+  mFirstPlane = getLong(&parameters[16]);
+  mPlanes = getLong(&parameters[20]);
+  mRowPitch = getLong(&parameters[24]);
+  mColPitch = getLong(&parameters[28]);
+  if (mFirstPlane < 0)
+    ThrowRDE("OpcodeMapPolynomial: Negative first plane");
+  if (mPlanes <= 0)
+    ThrowRDE("OpcodeMapPolynomial: Negative number of planes");
+  if (mRowPitch <= 0 || mColPitch <= 0)
+    ThrowRDE("OpcodeMapPolynomial: Invalid Pitch");
+
+  mDegree = getLong(&parameters[32]);
+  *bytes_used = 36;
+  if (mDegree > 8)
+    ThrowRDE("OpcodeMapPolynomial: A polynomial with more than 8 degrees not 
allowed");
+  if (param_max_bytes < 36 + (mDegree*8))
+    ThrowRDE("OpcodeMapPolynomial: Not enough data to read parameters, only %d 
bytes left.", param_max_bytes);
+  for (int i = 0; i <= mDegree; i++)
+    mCoefficient[i] = getDouble(&parameters[36+8*i]);
+  *bytes_used += 8*mDegree+8;
+  mFlags = MultiThreaded | PureLookup;
+}
+
+
+RawImage& OpcodeMapPolynomial::createOutput( RawImage &in )
+{
+  if (in->getDataType() != TYPE_USHORT16)
+    ThrowRDE("OpcodeMapPolynomial: Only 16 bit images supported");
+
+  if (mFirstPlane > (int)in->getCpp())
+    ThrowRDE("OpcodeMapPolynomial: Not that many planes in actual image");
+
+  if (mFirstPlane+mPlanes > (int)in->getCpp())
+    ThrowRDE("OpcodeMapPolynomial: Not that many planes in actual image");
+
+  // Create lookup
+  for (int i = 0; i < 65536; i++)
+  {
+    double in_val = (double)i/65536.0;
+    double val = mCoefficient[0];
+    for (int j = 1; j <= mDegree; j++)
+      val += mCoefficient[j] * pow(in_val, (double)(j));
+    mLookup[i] = clampbits((int)(val*65535.5), 16);
+  }
+  return in;
+}
+
+void OpcodeMapPolynomial::apply( RawImage &in, RawImage &out, int startY, int 
endY )
+{
+  int cpp = out->getCpp();
+  for (int y = startY; y < endY; y += mRowPitch) {
+    ushort16 *src = (ushort16*)out->getData(mAoi.getLeft(), y);
+    // Add offset, so this is always first plane
+    src+=mFirstPlane;
+    for (int x = 0; x < mAoi.getWidth(); x += mColPitch) {
+      for (int p = 0; p < mPlanes; p++)
+      {
+        src[x*cpp+p] = mLookup[src[x*cpp+p]];
+      }
+    }
+  }
+}
+
+} // namespace RawSpeed 

Added: RawSpeed/DngOpcodes.h
===================================================================
--- RawSpeed/DngOpcodes.h                               (rev 0)
+++ RawSpeed/DngOpcodes.h       2012-07-28 16:05:49 UTC (rev 441)
@@ -0,0 +1,134 @@
+#ifndef DNG_OPCODES_H
+#define DNG_OPCODES_H
+#include <vector>
+#include "TiffIFD.h"
+#include "RawImage.h"
+/* 
+RawSpeed - RAW file decoder.
+
+Copyright (C) 2012 Klaus Post
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+http://www.klauspost.com
+*/
+
+namespace RawSpeed {
+
+class DngOpcode
+{
+public:
+  DngOpcode(void) {host = getHostEndianness();};
+  virtual ~DngOpcode(void) {};
+
+  /* Will be called exactly once, when input changes */
+  /* Can be used for preparing pre-calculated values, etc */
+  virtual RawImage& createOutput(RawImage &in) {return in;}
+  /* Will be called for actual processing */
+  /* If multiThreaded is TRUE, it will be called several times, */
+  /* otherwise only once */
+  /* Properties of out will not have changed from createOutput */
+  virtual void apply(RawImage &in, RawImage &out, int startY, int endY) = 0;
+  iRectangle2D mAoi;
+  int mFlags;
+  enum Flags
+  {
+    MultiThreaded = 1,
+    PureLookup = 2
+  };
+
+  
+protected:
+  Endianness host;
+  int getLong(const uchar8 *ptr) {
+    if (host == big)
+      return *(int*)ptr;
+    return (int)ptr[0] << 24 | (int)ptr[1] << 16 | (int)ptr[2] << 8 | 
(int)ptr[3];
+  }
+  double getDouble(const uchar8 *ptr) {
+    if (host == big)
+      return *(double*)ptr;
+    double ret;
+    uchar8 *tmp = (uchar8*)&ret;
+    for (int i = 0; i < 8; i++)
+     tmp[i] = ptr[7-i];
+    return ret;
+  }
+  ushort16 getUshort(const uchar8 *ptr) {
+    if (host == big)
+      return *(ushort16*)ptr;
+    return (ushort16)ptr[0] << 8 | (ushort16)ptr[1];
+  }
+
+};
+
+
+class DngOpcodes
+{
+public:
+  DngOpcodes(TiffEntry *entry);
+  virtual ~DngOpcodes(void);
+  RawImage& applyOpCodes(RawImage &img);
+private:
+  vector<DngOpcode*> mOpcodes;
+  Endianness host;
+  int getULong(const uchar8 *ptr) {
+    if (host == big)
+      return *(unsigned int*)ptr;
+    return (unsigned int)ptr[0] << 24 | (unsigned int)ptr[1] << 16 | (unsigned 
int)ptr[2] << 8 | (unsigned int)ptr[3];
+  }
+};
+
+class OpcodeTrimBounds: public DngOpcode
+{
+public:
+  OpcodeTrimBounds(const uchar8* parameters, int param_max_bytes, uint32 
*bytes_used);
+  virtual ~OpcodeTrimBounds(void) {};
+  virtual void apply(RawImage &in, RawImage &out, int startY, int endY);
+private:
+  int mTop, mLeft, mBottom, mRight;
+};
+
+
+
+class OpcodeMapTable: public DngOpcode
+{
+public:
+  OpcodeMapTable(const uchar8* parameters, int param_max_bytes, uint32 
*bytes_used);
+  virtual ~OpcodeMapTable(void) {};
+  virtual RawImage& createOutput(RawImage &in);
+  virtual void apply(RawImage &in, RawImage &out, int startY, int endY);
+private:
+  int mFirstPlane, mPlanes, mRowPitch, mColPitch;
+  ushort16 mLookup[65535];
+};
+
+class OpcodeMapPolynomial: public DngOpcode
+{
+public:
+  OpcodeMapPolynomial(const uchar8* parameters, int param_max_bytes, uint32 
*bytes_used);
+  virtual ~OpcodeMapPolynomial(void) {};
+  virtual RawImage& createOutput(RawImage &in);
+  virtual void apply(RawImage &in, RawImage &out, int startY, int endY);
+private:
+  int mFirstPlane, mPlanes, mRowPitch, mColPitch, mDegree;
+  double mCoefficient[9];
+  ushort16 mLookup[65535];
+};
+
+
+} // namespace RawSpeed 
+
+#endif // DNG_OPCODES_H
\ No newline at end of file

Modified: RawSpeed/LJpegPlain.cpp
===================================================================
--- RawSpeed/LJpegPlain.cpp     2012-07-18 12:28:33 UTC (rev 440)
+++ RawSpeed/LJpegPlain.cpp     2012-07-28 16:05:49 UTC (rev 441)
@@ -77,6 +77,7 @@
           decodeScanLeft4_2_2();
           return;
         } else {
+          ThrowRDE("LJpegDecompressor::decodeScan: Unsupported subsampling");
           decodeScanLeftGeneric();
           return;
         }

Modified: RawSpeed/NefDecoder.cpp
===================================================================
--- RawSpeed/NefDecoder.cpp     2012-07-18 12:28:33 UTC (rev 440)
+++ RawSpeed/NefDecoder.cpp     2012-07-28 16:05:49 UTC (rev 441)
@@ -125,7 +125,7 @@
 
     delete metastream;
   } catch (IOException &e) {
-    errors.push_back(_strdup(e.what()));
+    mRaw->setError(e.what());
     // Let's ignore it, it may have delivered somewhat useful data.
   }
 
@@ -212,12 +212,12 @@
         readUncompressedRaw(in, size, pos, width*bitPerPixel / 8, bitPerPixel, 
true);
     } catch (RawDecoderException e) {
       if (i>0)
-        errors.push_back(_strdup(e.what()));
+        mRaw->setError(e.what());
       else
         throw;
     } catch (IOException e) {
       if (i>0)
-        errors.push_back(_strdup(e.what()));
+        mRaw->setError(e.what());
       else
         ThrowRDE("NEF decoder: IO error occurred in first slice, unable to 
decode more. Error is: %s", e.what());
     }

Modified: RawSpeed/OrfDecoder.cpp
===================================================================
--- RawSpeed/OrfDecoder.cpp     2012-07-18 12:28:33 UTC (rev 440)
+++ RawSpeed/OrfDecoder.cpp     2012-07-28 16:05:49 UTC (rev 441)
@@ -95,7 +95,7 @@
   try {
     decodeCompressed(s, width, height);
   } catch (IOException &e) {
-    errors.push_back(_strdup(e.what()));
+    mRaw->setError(e.what());
     // Let's ignore it, it may have delivered somewhat useful data.
   }
 

Modified: RawSpeed/PefDecoder.cpp
===================================================================
--- RawSpeed/PefDecoder.cpp     2012-07-18 12:28:33 UTC (rev 440)
+++ RawSpeed/PefDecoder.cpp     2012-07-28 16:05:49 UTC (rev 441)
@@ -74,7 +74,7 @@
     PentaxDecompressor l(mFile, mRaw);
     l.decodePentax(mRootIFD, offsets->getInt(), counts->getInt());
   } catch (IOException &e) {
-    errors.push_back(_strdup(e.what()));
+    mRaw->setError(e.what());
     // Let's ignore it, it may have delivered somewhat useful data.
   }
 

Modified: RawSpeed/Point.h
===================================================================
--- RawSpeed/Point.h    2012-07-18 12:28:33 UTC (rev 440)
+++ RawSpeed/Point.h    2012-07-28 16:05:49 UTC (rev 441)
@@ -35,15 +35,88 @@
   iPoint2D( const iPoint2D& pt) {x=pt.x; y=pt.y;}
   iPoint2D operator += (const iPoint2D& other) { x += other.x; y += other.y; 
return *this;}
   iPoint2D operator -= (const iPoint2D& other) { x -= other.x; y -= other.y; 
return *this;}
-  iPoint2D operator - (const iPoint2D& b) { return iPoint2D(x-b.x,y-b.y); }
-  iPoint2D operator + (const iPoint2D& b) { return iPoint2D(x+b.x,y+b.y); }
+  iPoint2D operator - (const iPoint2D& b) const { return 
iPoint2D(x-b.x,y-b.y); }
+  iPoint2D operator + (const iPoint2D& b) const { return 
iPoint2D(x+b.x,y+b.y); }
   iPoint2D operator = (const iPoint2D& b) { x = b.x; y = b.y; return *this;}
        ~iPoint2D() {};
-  uint32 area() {return abs(x*y);}
-  bool isThisInside(const iPoint2D &otherPoint) {return (x<=otherPoint.x && 
y<=otherPoint.y); };
+  uint32 area() const {return abs(x*y);}
+  bool isThisInside(const iPoint2D &otherPoint) const {return (x<=otherPoint.x 
&& y<=otherPoint.y); };
   int x,y;
 };
 
+/* Helper class for managing a rectangle in 2D space. */
+class iRectangle2D {
+public:
+  iRectangle2D() {}
+  iRectangle2D( int w, int h) {dim = iPoint2D(w,h);}
+  iRectangle2D( int x_pos, int y_pos, int w, int h) {dim = iPoint2D(w,h); 
pos=iPoint2D(x_pos, y_pos);}
+  iRectangle2D( const iRectangle2D& r) {dim = iPoint2D(r.dim); pos = 
iPoint2D(r.pos);}
+  iRectangle2D( const iPoint2D& _pos, const iPoint2D& size) {dim = size; 
pos=_pos;}
+  iRectangle2D operator = (const iRectangle2D& b) {dim = iPoint2D(b.dim); pos 
= iPoint2D(b.pos); return *this;}
+  ~iRectangle2D() {};
+  uint32 area() const {return dim.area();}
+  void offset(const iPoint2D& offset) {pos+=offset;}
+  bool isThisInside(const iRectangle2D &otherPoint) const {
+    iPoint2D br1 = getBottomRight();
+    iPoint2D br2 = otherPoint.getBottomRight();
+    return pos.x >= otherPoint.pos.x && pos.y >= otherPoint.pos.y && br1.x <= 
br2.x && br1.y <= br2.y;
+  }
+  bool isPointInside(const iPoint2D &checkPoint) const {
+    iPoint2D br1 = getBottomRight();
+    return pos.x <= checkPoint.x && pos.y <= checkPoint.y && br1.x >= 
checkPoint.x && br1.y >= checkPoint.y;
+  }
+  int getTop() const {return pos.y; }
+  int getBottom() const {return pos.y+dim.y; }
+  int getLeft() const {return pos.x; }
+  int getRight() const {return pos.x+dim.x; }
+  int getWidth() const {return dim.x; }
+  int getHeight() const {return dim.y; }
+  iPoint2D getTopLeft() const {return pos; }
+  iPoint2D getBottomRight() const {return dim-pos;}
+  /* Retains size */
+  void setTopLeft(const iPoint2D& top_left) {pos = top_left;}
+  /* Set BR  */
+  void setBottomRightAbsolute(const iPoint2D& bottom_right) {dim = 
iPoint2D(bottom_right) - pos;};
+  void setAbsolute(int x1, int y1, int x2, int y2) {pos = iPoint2D(x1,y1); 
setBottomRightAbsolute(iPoint2D(x2,y2));};
+  void setAbsolute(const iPoint2D& top_left, const iPoint2D& bottom_right) 
{pos = top_left; setBottomRightAbsolute(bottom_right);};
+  void setSize(const iPoint2D& size) {dim = size;};
+  bool hasPositiveArea() const {return (dim.x > 0) && (dim.y > 0);};
+  /* Crop, so area is postitive, and return true, if there is any area left */
+  /* This will ensure that bottomright is never on the left/top of the offset 
*/
+  bool cropArea(){ dim.x = max(0,dim.x); dim.y = max(0, dim.y); return 
hasPositiveArea();};
+  /* This will make sure that offset is positive, and make the area smaller if 
needed */
+  /* This will return true if there is any area left */
+  bool cropOffsetToZero(){ 
+    iPoint2D crop_pixels; 
+    if (pos.x < 0) {
+      crop_pixels.x = -(pos.x);
+      pos.x = 0;
+    }
+    if (pos.y < 0) {
+      crop_pixels.y = -pos.y;
+      pos.y = 0;
+    }
+    dim -= crop_pixels;
+    return cropArea();
+  };
+  iRectangle2D getOverlap(const iRectangle2D& other) const {
+    iRectangle2D overlap;
+    iPoint2D br1 = getBottomRight();
+    iPoint2D br2 = other.getBottomRight();
+    overlap.setAbsolute(max(pos.x, other.pos.x), max(pos.y, other.pos.y), 
min(br1.x, br2.x), min(br2.y, br2.y));
+    return overlap;
+  };
+  iRectangle2D combine(const iRectangle2D& other) const {
+    iRectangle2D combined;
+               iPoint2D br1 = getBottomRight();
+               iPoint2D br2 = other.getBottomRight();
+               combined.setAbsolute(min(pos.x, other.pos.x), min(pos.y, 
other.pos.y), max(br1.x, br2.x), max(br2.y, br2.y));
+               return combined;
+  };
+  iPoint2D pos;
+  iPoint2D dim;
+};
+
 } // namespace RawSpeed
 
 #endif // SS_Point_H

Modified: RawSpeed/RawDecoder.cpp
===================================================================
--- RawSpeed/RawDecoder.cpp     2012-07-18 12:28:33 UTC (rev 440)
+++ RawSpeed/RawDecoder.cpp     2012-07-28 16:05:49 UTC (rev 441)
@@ -30,10 +30,6 @@
 }
 
 RawDecoder::~RawDecoder(void) {
-  for (uint32 i = 0 ; i < errors.size(); i++) {
-    free((void*)errors[i]);
-  }
-  errors.clear();
 }
 
 void RawDecoder::decodeUncompressed(TiffIFD *rawIFD, bool MSBOrder) {
@@ -81,12 +77,12 @@
       readUncompressedRaw(in, size, pos, width*bitPerPixel / 8, bitPerPixel, 
MSBOrder);
     } catch (RawDecoderException &e) {
       if (i>0)
-        errors.push_back(_strdup(e.what()));
+        mRaw->setError(e.what());
       else
         throw;
     } catch (IOException &e) {
       if (i>0)
-        errors.push_back(_strdup(e.what()));
+        mRaw->setError(e.what());
       else
         ThrowRDE("RAW decoder: IO error occurred in first slice, unable to 
decode more. Error is: %s", e.what());
     }
@@ -233,7 +229,8 @@
   if (new_size.y <= 0)
     new_size.y = mRaw->dim.y - cam->cropPos.y + new_size.y;
 
-  mRaw->subFrame(cam->cropPos, new_size);
+  iRectangle2D(cam->cropPos, new_size);
+  mRaw->subFrame(iRectangle2D(cam->cropPos, new_size));
   mRaw->cfa = cam->cfa;
 
   // Shift CFA to match crop
@@ -254,9 +251,9 @@
   try {
     me->parent->decodeThreaded(me);
   } catch (RawDecoderException &ex) {
-    me->error = _strdup(ex.what());
+    me->parent->mRaw->setError(ex.what());
   } catch (IOException &ex) {
-    me->error = _strdup(ex.what());
+    me->parent->mRaw->setError(ex.what());
   }
 
   pthread_exit(NULL);
@@ -287,11 +284,8 @@
   void *status;
   for (uint32 i = 0; i < threads; i++) {
     pthread_join(t[i].threadid, &status);
-    if (t[i].error) {
-      errors.push_back(t[i].error);
-    }
   }
-  if (errors.size() >= threads)
+  if (mRaw->errors.size() >= threads)
     ThrowRDE("RawDecoder::startThreads: All threads reported errors. Cannot 
load image.");
 
   delete[] t;

Modified: RawSpeed/RawDecoder.h
===================================================================
--- RawSpeed/RawDecoder.h       2012-07-18 12:28:33 UTC (rev 440)
+++ RawSpeed/RawDecoder.h       2012-07-28 16:05:49 UTC (rev 441)
@@ -92,11 +92,7 @@
   /* DNGs are always attempted to be decoded, so this variable has no effect 
on DNGs */
   bool failOnUnknown;
 
-  /* Vector containing silent errors that occurred doing decoding, that may 
have lead to */
-  /* an incomplete image. */
-  vector<const char*> errors;
 
-
 protected:
   /* Attempt to decode the image */
   /* A RawDecoderException will be thrown if the image cannot be decoded, */

Modified: RawSpeed/RawImage.cpp
===================================================================
--- RawSpeed/RawImage.cpp       2012-07-18 12:28:33 UTC (rev 440)
+++ RawSpeed/RawImage.cpp       2012-07-28 16:05:49 UTC (rev 441)
@@ -37,6 +37,7 @@
   pthread_mutex_init(&mymutex, NULL);
   subsampling.x = subsampling.y = 1;
   isoSpeed = 0;
+  pthread_mutex_init(&errMutex, NULL);
 }
 
 RawImageData::RawImageData(iPoint2D _dim, uint32 _bpc, uint32 _cpp) :
@@ -49,6 +50,7 @@
   isoSpeed = 0;
   createData();
   pthread_mutex_init(&mymutex, NULL);
+  pthread_mutex_init(&errMutex, NULL);
 }
 
 RawImageData::~RawImageData(void) {
@@ -58,6 +60,11 @@
   data = 0;
   mOffset = iPoint2D(0, 0);
   pthread_mutex_destroy(&mymutex);
+  pthread_mutex_destroy(&errMutex);
+  for (uint32 i = 0 ; i < errors.size(); i++) {
+    free((void*)errors[i]);
+  }
+  errors.clear();
 }
 
 
@@ -136,20 +143,26 @@
   return mOffset;
 }
 
-void RawImageData::subFrame(iPoint2D offset, iPoint2D new_size) {
-  if (!new_size.isThisInside(dim - offset)) {
+void RawImageData::subFrame(iRectangle2D crop) {
+  if (!crop.dim.isThisInside(dim - crop.pos)) {
     printf("WARNING: RawImageData::subFrame - Attempted to create new subframe 
larger than original size. Crop skipped.\n");
     return;
   }
-  if (offset.x < 0 || offset.y < 0) {
+  if (crop.pos.x < 0 || crop.pos.y < 0 || !crop.hasPositiveArea()) {
     printf("WARNING: RawImageData::subFrame - Negative crop offset. Crop 
skipped.\n");
     return;
   }
 
-  mOffset += offset;
-  dim = new_size;
+  mOffset += crop.pos;
+  dim = crop.dim;
 }
 
+void RawImageData::setError( const char* err )
+{
+  pthread_mutex_lock(&errMutex);
+  errors.push_back(_strdup(err));
+  pthread_mutex_unlock(&errMutex);
+}
 
 RawImage::RawImage(RawImageData* p) : p_(p) {
   pthread_mutex_lock(&p_->mymutex);
@@ -222,13 +235,21 @@
 
 void RawImageWorker::_performTask()
 {
-  switch(task)
-  {
+  try {
+    switch(task)
+    {
     case TASK_SCALE_VALUES:
       data->scaleValues(start_y, end_y);
       break;
     default:
       _ASSERTE(false);
+    }
+  } catch (RawDecoderException &e) {
+    data->setError(e.what());
+  } catch (TiffParserException &e) {
+    data->setError(e.what());
+  } catch (IOException &e) {
+    data->setError(e.what());
   }
 }
 

Modified: RawSpeed/RawImage.h
===================================================================
--- RawSpeed/RawImage.h 2012-07-18 12:28:33 UTC (rev 440)
+++ RawSpeed/RawImage.h 2012-07-28 16:05:49 UTC (rev 441)
@@ -46,7 +46,7 @@
   uchar8* getData();
   uchar8* getData(uint32 x, uint32 y);    // Not super fast, but safe. Don't 
use per pixel.
   uchar8* getDataUncropped(uint32 x, uint32 y);
-  virtual void subFrame( iPoint2D offset, iPoint2D new_size );
+  virtual void subFrame( iRectangle2D cropped );
   iPoint2D getUncroppedDim();
   iPoint2D getCropOffset();
   virtual void scaleBlackWhite() = 0;
@@ -62,6 +62,12 @@
   iPoint2D subsampling;
   string mode;
   int isoSpeed;
+  /* Vector containing silent errors that occurred doing decoding, that may 
have lead to */
+  /* an incomplete image. */
+  vector<const char*> errors;
+  pthread_mutex_t errMutex;   // Mutex for above
+  void setError(const char* err);
+
 protected:
   RawImageType dataType;
   RawImageData(void);

Modified: RawSpeed/RawImageDataU16.cpp
===================================================================
--- RawSpeed/RawImageDataU16.cpp        2012-07-18 12:28:33 UTC (rev 440)
+++ RawSpeed/RawImageDataU16.cpp        2012-07-28 16:05:49 UTC (rev 441)
@@ -137,13 +137,15 @@
   }
 
   /* Skip, if not needed */
-  if (blackAreas.size() == 0 && blackLevel == 0 && whitePoint == 65535 && 
blackLevelSeparate[0] < 0)
+  if ((blackAreas.size() == 0 && blackLevel == 0 && whitePoint == 65535 && 
blackLevelSeparate[0] < 0) || dim.area() <= 0)
     return;
 
   /* If filter has not set separate blacklevel, compute or fetch it */
   if (blackLevelSeparate[0] < 0)
     calculateBlackAreas();
 
+  //printf("ISO:%d, black:%d, white: %d\n", isoSpeed, blackLevelSeparate[0], 
whitePoint);
+
   int threads = getThreadCount(); 
   if (threads <= 1)
     scaleValues(0, dim.y);

Modified: RawSpeed/StdAfx.h
===================================================================
--- RawSpeed/StdAfx.h   2012-07-18 12:28:33 UTC (rev 440)
+++ RawSpeed/StdAfx.h   2012-07-28 16:05:49 UTC (rev 441)
@@ -58,6 +58,8 @@
 #endif // __unix__
 #include <math.h>
 #include "pthread.h"
+#include "jpeglib.h"
+
 // STL
 #include <iostream>
 #include <string>


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

Reply via email to