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