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(¶meters[0]);
+ mLeft = getLong(¶meters[4]);
+ mBottom = getLong(¶meters[8]);
+ mRight = getLong(¶meters[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(¶meters[4]), getLong(¶meters[0]),
getLong(¶meters[12]), getLong(¶meters[8]));
+ mFirstPlane = getLong(¶meters[16]);
+ mPlanes = getLong(¶meters[20]);
+ mRowPitch = getLong(¶meters[24]);
+ mColPitch = getLong(¶meters[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(¶meters[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(¶meters[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(¶meters[4]), getLong(¶meters[0]),
getLong(¶meters[12]), getLong(¶meters[8]));
+ mFirstPlane = getLong(¶meters[16]);
+ mPlanes = getLong(¶meters[20]);
+ mRowPitch = getLong(¶meters[24]);
+ mColPitch = getLong(¶meters[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(¶meters[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(¶meters[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