Files
rawTherapee/rtengine/rtthumbnail.cc
ffsup2 eef14f76dd Added dark frame subtraction
Moved debayer and preprocessing parameters to class ProcParams for every single image.
Added tab RAW for changing those parameters.
Progress bar shows only load step (work to do)
2010-08-19 00:37:53 +02:00

890 lines
32 KiB
C++

/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
*
* RawTherapee is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* RawTherapee 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
*/
#include <rtengine.h>
#include <rtthumbnail.h>
#include <image8.h>
#include <lcms.h>
#include <curves.h>
#include <glibmm.h>
#include <improcfun.h>
#include <colortemp.h>
#include <mytime.h>
#include <utils.h>
#include <iccstore.h>
#include <iccmatrices.h>
#include <rawimagesource.h>
#include <stdimagesource.h>
#include <glib/gstdio.h>
#include <setjmp.h>
#include <safekeyfile.h>
extern "C" {
#include <jpeglib.h>
extern jmp_buf jpeg_jmp_buf;
extern GLOBAL(struct jpeg_error_mgr *)
my_jpeg_std_error (struct jpeg_error_mgr * err);
extern GLOBAL(void)
my_jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile);
}
#define MAXVAL 0xffff
#define CLIP(a) ((a)>0?((a)<MAXVAL?(a):MAXVAL):0)
namespace rtengine {
Thumbnail* Thumbnail::loadFromImage (const Glib::ustring& fname, int &w, int &h, int fixwh) {
Image16* img = new Image16 ();
int err = img->load (fname);
if (err) {
delete img;
return NULL;
}
Thumbnail* tpp = new Thumbnail ();
tpp->camwbRed = 1.0;
tpp->camwbGreen = 1.0;
tpp->camwbBlue = 1.0;
tpp->embProfileLength = 0;
unsigned char* data;
img->getEmbeddedProfileData (tpp->embProfileLength, data);
if (data && tpp->embProfileLength) {
tpp->embProfileData = new unsigned char [tpp->embProfileLength];
memcpy (tpp->embProfileData, data, tpp->embProfileLength);
}
else {
tpp->embProfileLength = 0;
tpp->embProfileData = NULL;
}
tpp->redMultiplier = 1.0;
tpp->greenMultiplier = 1.0;
tpp->blueMultiplier = 1.0;
tpp->scaleForSave = 8192;
tpp->defGain = 1.0;
tpp->gammaCorrected = false;
tpp->isRaw = 0;
memset (tpp->colorMatrix, 0, sizeof(tpp->colorMatrix));
tpp->colorMatrix[0][0] = 1.0;
tpp->colorMatrix[1][1] = 1.0;
tpp->colorMatrix[2][2] = 1.0;
if (fixwh==1) {
w = h * img->width / img->height;
tpp->scale = (double)img->height / h;
}
else {
h = w * img->height / img->width;
tpp->scale = (double)img->width / w;
}
// bilinear interpolation
tpp->thumbImg = img->resize (w, h, TI_Bilinear);
// histogram computation
tpp->aeHistCompression = 3;
tpp->aeHistogram = new unsigned int[65536>>tpp->aeHistCompression];
memset (tpp->aeHistogram, 0, (65536>>tpp->aeHistCompression)*sizeof(int));
int ix = 0;
for (int i=0; i<img->height*img->width; i++) {
tpp->aeHistogram[CurveFactory::igamma_srgb (img->data[ix++])>>tpp->aeHistCompression]++;
tpp->aeHistogram[CurveFactory::igamma_srgb (img->data[ix++])>>tpp->aeHistCompression]++;
tpp->aeHistogram[CurveFactory::igamma_srgb (img->data[ix++])>>tpp->aeHistCompression]++;
}
// autowb computation
double avg_r = 0;
double avg_g = 0;
double avg_b = 0;
int n = 0;
int p = 6;
for (int i=1; i<img->height-1; i++)
for (int j=1; j<img->width-1; j++) {
int ofs = 3*(i*img->width + j);
if (img->data[ofs]>250 || img->data[ofs+1]>250 || img->data[ofs+2]>250)
continue;
avg_r += StdImageSource::intpow((double)img->data[ofs]*256, p);
avg_g += StdImageSource::intpow((double)img->data[ofs+1]*256, p);
avg_b += StdImageSource::intpow((double)img->data[ofs+2]*256, p);
n++;
}
ColorTemp::mul2temp (pow(avg_r/n, 1.0/p), pow(avg_g/n, 1.0/p), pow(avg_b/n, 1.0/p), tpp->autowbTemp, tpp->autowbGreen);
delete img;
tpp->init ();
return tpp;
}
void Thumbnail::init () {
RawImageSource::inverse33 (colorMatrix, iColorMatrix);
memset (camToD50, 0, sizeof(camToD50));
for (int i=0; i<3; i++)
for (int j=0; j<3; j++)
for (int k=0; k<3; k++)
camToD50[i][j] += colorMatrix[k][i] * sRGB_d50[k][j];
camProfile = iccStore.createFromMatrix (camToD50, false, "Camera");
}
bool Thumbnail::igammacomputed = false;
unsigned short Thumbnail::igammatab[256];
unsigned char Thumbnail::gammatab[65536];
Thumbnail::Thumbnail () :
embProfile(NULL), camProfile(NULL), aeHistogram(NULL), thumbImg(NULL), embProfileData(NULL) {
if (!igammacomputed) {
for (int i=0; i<256; i++)
igammatab[i] = (unsigned short)(255.0*pow(i/255.0,1.0/0.45));
for (int i=0; i<65536; i++)
gammatab[i] = (unsigned char)(255.0*pow(i/65535.0,0.45));
igammacomputed = true;
}
}
Thumbnail::~Thumbnail () {
delete thumbImg;
delete [] aeHistogram;
delete [] embProfileData;
if (embProfile)
cmsCloseProfile(embProfile);
if (camProfile)
cmsCloseProfile(camProfile);
}
IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rheight, TypeInterpolation interp, double& myscale) {
// compute WB multipliers
ColorTemp currWB = ColorTemp (params.wb.temperature, params.wb.green);
if (params.wb.method=="Camera") {
double cam_r = colorMatrix[0][0]*camwbRed + colorMatrix[0][1]*camwbGreen + colorMatrix[0][2]*camwbBlue;
double cam_g = colorMatrix[1][0]*camwbRed + colorMatrix[1][1]*camwbGreen + colorMatrix[1][2]*camwbBlue;
double cam_b = colorMatrix[2][0]*camwbRed + colorMatrix[2][1]*camwbGreen + colorMatrix[2][2]*camwbBlue;
currWB = ColorTemp (cam_r, cam_g, cam_b);
}
else if (params.wb.method=="Auto")
currWB = ColorTemp (autowbTemp, autowbGreen);
double r, g, b;
currWB.getMultipliers (r, g, b);
double rm = iColorMatrix[0][0]*r + iColorMatrix[0][1]*g + iColorMatrix[0][2]*b;
double gm = iColorMatrix[1][0]*r + iColorMatrix[1][1]*g + iColorMatrix[1][2]*b;
double bm = iColorMatrix[2][0]*r + iColorMatrix[2][1]*g + iColorMatrix[2][2]*b;
rm = camwbRed / rm;
gm = camwbGreen / gm;
bm = camwbBlue / bm;
double mul_lum = 0.299*rm + 0.587*gm + 0.114*bm;
double logDefGain = log(defGain) / log(2.0);
int rmi, gmi, bmi;
if (!isRaw || !params.hlrecovery.enabled) {
logDefGain = 0.0;
rmi = 1024.0 * rm * defGain / mul_lum;
gmi = 1024.0 * gm * defGain / mul_lum;
bmi = 1024.0 * bm * defGain / mul_lum;
}
else {
rmi = 1024.0 * rm / mul_lum;
gmi = 1024.0 * gm / mul_lum;
bmi = 1024.0 * bm / mul_lum;
}
// resize to requested width and perform coarse transformation
int rwidth;
if (params.coarse.rotate==90 || params.coarse.rotate==270) {
rwidth = rheight;
rheight = thumbImg->height * rwidth / thumbImg->width;
}
else
rwidth = thumbImg->width * rheight / thumbImg->height;
Image16* baseImg = thumbImg->resize (rwidth, rheight, interp);
if (params.coarse.rotate) {
Image16* tmp = baseImg->rotate (params.coarse.rotate);
rwidth = tmp->width;
rheight = tmp->height;
delete baseImg;
baseImg = tmp;
}
if (params.coarse.hflip) {
Image16* tmp = baseImg->hflip ();
delete baseImg;
baseImg = tmp;
}
if (params.coarse.vflip) {
Image16* tmp = baseImg->vflip ();
delete baseImg;
baseImg = tmp;
}
// apply white balance
int val;
for (int i=0; i<rheight; i++)
for (int j=0; j<rwidth; j++) {
val = baseImg->r[i][j]*rmi>>10;
baseImg->r[i][j] = CLIP(val);
val = baseImg->g[i][j]*gmi>>10;
baseImg->g[i][j] = CLIP(val);
val = baseImg->b[i][j]*bmi>>10;
baseImg->b[i][j] = CLIP(val);
}
// appy highlight recovery, if needed
if (isRaw && params.hlrecovery.enabled) {
int maxval = 65535 / defGain;
if (params.hlrecovery.method=="Luminance" || params.hlrecovery.method=="Color")
for (int i=0; i<rheight; i++)
RawImageSource::HLRecovery_Luminance (baseImg->r[i], baseImg->g[i], baseImg->b[i], baseImg->r[i], baseImg->g[i], baseImg->b[i], rwidth, maxval);
else if (params.hlrecovery.method=="CIELab blending") {
double icamToD50[3][3];
RawImageSource::inverse33 (camToD50, icamToD50);
for (int i=0; i<rheight; i++)
RawImageSource::HLRecovery_CIELab (baseImg->r[i], baseImg->g[i], baseImg->b[i], baseImg->r[i], baseImg->g[i], baseImg->b[i], rwidth, maxval, camToD50, icamToD50);
}
}
// perform color space transformation
if (isRaw)
RawImageSource::colorSpaceConversion (baseImg, params.icm, embProfile, camProfile, camToD50, logDefGain);
else
StdImageSource::colorSpaceConversion (baseImg, params.icm, embProfile);
int fw = baseImg->width;
int fh = baseImg->height;
ImProcFunctions ipf (&params, false);
ipf.setScale (sqrt(double(fw*fw+fh*fh))/sqrt(double(thumbImg->width*thumbImg->width+thumbImg->height*thumbImg->height))*scale);
unsigned int* hist16 = new unsigned int [65536];
ipf.firstAnalysis (baseImg, &params, hist16, isRaw ? 2.2 : 0.0);
// perform transform
if (ipf.needsTransform()) {
Image16* trImg = new Image16 (fw, fh);
ipf.transform (baseImg, trImg, 0, 0, 0, 0, fw, fh);
delete baseImg;
baseImg = trImg;
}
// update blurmap
SHMap* shmap = NULL;
if (params.sh.enabled) {
unsigned short** buffer = NULL;
if (params.sh.hq) {
buffer = new unsigned short*[fh];
for (int i=0; i<fh; i++)
buffer[i] = new unsigned short[fw];
}
shmap = new SHMap (fw, fh, false);
double radius = sqrt (double(fw*fw+fh*fh)) / 2.0;
double shradius = radius / 1800.0 * params.sh.radius;
shmap->update (baseImg, buffer, shradius, ipf.lumimul, params.sh.hq);
if (buffer) {
for (int i=0; i<fh; i++)
delete [] buffer[i];
delete [] buffer;
}
}
// RGB processing
double br = params.toneCurve.expcomp;
int bl = params.toneCurve.black;
if (params.toneCurve.autoexp && aeHistogram)
ipf.getAutoExp (aeHistogram, aeHistCompression, logDefGain, params.toneCurve.clip, br, bl);
int* curve = new int [65536];
CurveFactory::complexCurve (br, bl/65535.0, params.toneCurve.hlcompr, params.toneCurve.shcompr, params.toneCurve.brightness, params.toneCurve.contrast, logDefGain, isRaw ? 2.2 : 0, true, params.toneCurve.curve, hist16, curve, NULL, 16);
LabImage* labView = new LabImage (baseImg);
ipf.rgbProc (baseImg, labView, curve, shmap);
if (shmap)
delete shmap;
// luminance histogram update
memset (hist16, 0, 65536*sizeof(int));
for (int i=0; i<fh; i++)
for (int j=0; j<fw; j++)
hist16[labView->L[i][j]]++;
// luminance processing
CurveFactory::complexCurve (0.0, 0.0, 0.0, 0.0, params.lumaCurve.brightness, params.lumaCurve.contrast, 0.0, 0.0, false, params.lumaCurve.curve, hist16, curve, NULL, 16);
ipf.luminanceCurve (labView, labView, curve, 0, fh);
delete [] curve;
delete [] hist16;
// color processing
ipf.colorCurve (labView, labView);
// obtain final image
Image8* readyImg = new Image8 (fw, fh);
ipf.lab2rgb (labView, readyImg);
delete labView;
delete baseImg;
// calculate scale
if (params.coarse.rotate==90 || params.coarse.rotate==270)
myscale = scale * thumbImg->width / fh;
else
myscale = scale * thumbImg->height / fh;
if (params.resize.enabled) {
if (params.resize.dataspec==0)
myscale *= params.resize.scale;
else if (params.resize.dataspec==1)
myscale *= (double)params.resize.width / (params.coarse.rotate==90 || params.coarse.rotate==270 ? thumbImg->height : thumbImg->width) / scale;
else if (params.resize.dataspec==2)
myscale *= (double)params.resize.height / (params.coarse.rotate==90 || params.coarse.rotate==270 ? thumbImg->width : thumbImg->height) / scale;
}
myscale = 1.0 / myscale;
/* // apply crop
if (params.crop.enabled) {
int ix = 0;
for (int i=0; i<fh; i++)
for (int j=0; j<fw; j++)
if (i<params.crop.y/myscale || i>(params.crop.y+params.crop.h)/myscale || j<params.crop.x/myscale || j>(params.crop.x+params.crop.w)/myscale) {
readyImg->data[ix++] /= 3;
readyImg->data[ix++] /= 3;
readyImg->data[ix++] /= 3;
}
else
ix += 3;
}*/
return readyImg;
}
int Thumbnail::getImageWidth (const procparams::ProcParams& params, int rheight) {
int rwidth;
if (params.coarse.rotate==90 || params.coarse.rotate==270)
rwidth = thumbImg->height * rheight / thumbImg->width;
else
rwidth = thumbImg->width * rheight / thumbImg->height;
return rwidth;
}
void Thumbnail::getFinalSize (const rtengine::procparams::ProcParams& params, int& fullw, int& fullh) {
double fw = thumbImg->width*scale;
double fh = thumbImg->height*scale;
if (params.coarse.rotate==90 || params.coarse.rotate==270) {
fh = thumbImg->width*scale;
fw = thumbImg->height*scale;
}
if (!params.resize.enabled) {
fullw = fw;
fullh = fh;
}
else if (params.resize.dataspec==0) {
fullw = fw*params.resize.scale;
fullh = fh*params.resize.scale;
}
else if (params.resize.dataspec==1) {
fullw = params.resize.width;
fullh = (double)fh*params.resize.width/(params.coarse.rotate==90 || params.coarse.rotate==270 ? fh : fw);
}
else if (params.resize.dataspec==2) {
fullw = (double)fw*params.resize.height/(params.coarse.rotate==90 || params.coarse.rotate==270 ? fw : fh);
fullh = params.resize.height;
}
}
void Thumbnail::getCamWB (double& temp, double& green) {
double cam_r = colorMatrix[0][0]*camwbRed + colorMatrix[0][1]*camwbGreen + colorMatrix[0][2]*camwbBlue;
double cam_g = colorMatrix[1][0]*camwbRed + colorMatrix[1][1]*camwbGreen + colorMatrix[1][2]*camwbBlue;
double cam_b = colorMatrix[2][0]*camwbRed + colorMatrix[2][1]*camwbGreen + colorMatrix[2][2]*camwbBlue;
ColorTemp currWB = ColorTemp (cam_r, cam_g, cam_b);
temp = currWB.getTemp ();
green = currWB.getGreen ();
}
void Thumbnail::getAutoWB (double& temp, double& green) {
temp = autowbTemp;
green = autowbGreen;
}
void Thumbnail::applyAutoExp (procparams::ProcParams& params) {
if (params.toneCurve.autoexp && aeHistogram) {
ImProcFunctions ipf (&params, false);
ipf.getAutoExp (aeHistogram, aeHistCompression, log(defGain) / log(2.0), params.toneCurve.clip, params.toneCurve.expcomp, params.toneCurve.black);
}
}
void Thumbnail::getSpotWB (const procparams::ProcParams& params, int xp, int yp, int rect, double& rtemp, double& rgreen) {
std::vector<Coord2D> points, red, green, blue;
for (int i=yp-rect; i<=yp+rect; i++)
for (int j=xp-rect; j<=xp+rect; j++)
points.push_back (Coord2D (j, i));
int fw = thumbImg->width, fh = thumbImg->height;
if (params.coarse.rotate==90 || params.coarse.rotate==270) {
fw = thumbImg->height;
fh = thumbImg->width;
}
ImProcFunctions ipf (&params, false);
ipf.transCoord (fw, fh, points, red, green, blue);
int tr = TR_NONE;
if (params.coarse.rotate==90) tr |= TR_R90;
if (params.coarse.rotate==180) tr |= TR_R180;
if (params.coarse.rotate==270) tr |= TR_R270;
if (params.coarse.hflip) tr |= TR_HFLIP;
if (params.coarse.vflip) tr |= TR_VFLIP;
// calculate spot wb (copy & pasted from stdimagesource)
unsigned short igammatab[256];
for (int i=0; i<256; i++)
igammatab[i] = (unsigned short)(255.0*pow(i/255.0,1.0/0.45));
int x; int y;
double reds = 0, greens = 0, blues = 0;
int rn = 0, gn = 0, bn = 0;
for (int i=0; i<red.size(); i++) {
transformPixel (red[i].x, red[i].y, tr, x, y);
if (x>=0 && y>=0 && x<thumbImg->width && y<thumbImg->height) {
reds += thumbImg->r[y][x];
rn++;
}
transformPixel (green[i].x, green[i].y, tr, x, y);
if (x>=0 && y>=0 && x<thumbImg->width && y<thumbImg->height) {
greens += thumbImg->g[y][x];
gn++;
}
transformPixel (blue[i].x, blue[i].y, tr, x, y);
if (x>=0 && y>=0 && x<thumbImg->width && y<thumbImg->height) {
blues += thumbImg->b[y][x];
bn++;
}
}
reds = reds/rn * camwbRed;
greens = greens/gn * camwbGreen;
blues = blues/bn * camwbBlue;
double rm = colorMatrix[0][0]*reds + colorMatrix[0][1]*greens + colorMatrix[0][2]*blues;
double gm = colorMatrix[1][0]*reds + colorMatrix[1][1]*greens + colorMatrix[1][2]*blues;
double bm = colorMatrix[2][0]*reds + colorMatrix[2][1]*greens + colorMatrix[2][2]*blues;
ColorTemp ct (rm, gm, bm);
rtemp = ct.getTemp ();
rgreen = ct.getGreen ();
}
void Thumbnail::transformPixel (int x, int y, int tran, int& tx, int& ty) {
int W = thumbImg->width;
int H = thumbImg->height;
int sw = W, sh = H;
if ((tran & TR_ROT) == TR_R90 || (tran & TR_ROT) == TR_R270) {
sw = H;
sh = W;
}
int ppx = x, ppy = y;
if (tran & TR_HFLIP)
ppx = sw - 1 - x ;
if (tran & TR_VFLIP)
ppy = sh - 1 - y;
tx = ppx;
ty = ppy;
if ((tran & TR_ROT) == TR_R180) {
tx = W - 1 - ppx;
ty = H - 1 - ppy;
}
else if ((tran & TR_ROT) == TR_R90) {
tx = ppy;
ty = H - 1 - ppx;
}
else if ((tran & TR_ROT) == TR_R270) {
tx = W - 1 - ppy;
ty = ppx;
}
tx/=scale;
ty/=scale;
}
bool Thumbnail::writeImage (const Glib::ustring& fname, int format) {
if (!thumbImg)
return false;
if (format==1 || format==3) {
// to utilize the 8 bit color range of the thumbnail we brighten it and apply gamma correction
int max = 0;
for (int row=0; row<thumbImg->height; row++)
for (int col=0; col<thumbImg->width; col++) {
if (thumbImg->r[row][col]>max)
max = thumbImg->r[row][col];
if (thumbImg->g[row][col]>max)
max = thumbImg->g[row][col];
if (thumbImg->b[row][col]>max)
max = thumbImg->b[row][col];
}
if (max < 16384)
max = 16384;
scaleForSave = 65535*8192 / max;
unsigned char* tmpdata = new unsigned char[thumbImg->height*thumbImg->width*3];
int ix = 0;
if (gammaCorrected) {
for (int i=0; i<thumbImg->height; i++)
for (int j=0; j<thumbImg->width; j++) {
tmpdata[ix++] = gammatab[thumbImg->r[i][j]*scaleForSave >> 13];
tmpdata[ix++] = gammatab[thumbImg->g[i][j]*scaleForSave >> 13];
tmpdata[ix++] = gammatab[thumbImg->b[i][j]*scaleForSave >> 13];
}
}
else {
for (int i=0; i<thumbImg->height; i++)
for (int j=0; j<thumbImg->width; j++) {
tmpdata[ix++] = thumbImg->r[i][j]*scaleForSave >> 21;
tmpdata[ix++] = thumbImg->g[i][j]*scaleForSave >> 21;
tmpdata[ix++] = thumbImg->b[i][j]*scaleForSave >> 21;
}
}
if (format==1) {
FILE* f = g_fopen (fname.c_str(), "wb");
if (!f) {
delete [] tmpdata;
return false;
}
fwrite (&thumbImg->width, 1, sizeof (int), f);
fwrite (&thumbImg->height, 1, sizeof (int), f);
fwrite (tmpdata, thumbImg->width*thumbImg->height, 3, f);
fclose (f);
}
else if (format==3) {
FILE* f = g_fopen (fname.c_str(), "wb");
if (!f) {
delete [] tmpdata;
return false;
}
jpeg_compress_struct cinfo;
jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error (&jerr);
jpeg_create_compress (&cinfo);
jpeg_stdio_dest (&cinfo, f);
cinfo.image_width = thumbImg->width;
cinfo.image_height = thumbImg->height;
cinfo.in_color_space = JCS_RGB;
cinfo.input_components = 3;
jpeg_set_defaults (&cinfo);
cinfo.write_JFIF_header = FALSE;
jpeg_set_quality (&cinfo, 85, true);
jpeg_start_compress(&cinfo, TRUE);
int rowlen = thumbImg->width*3;
while (cinfo.next_scanline < cinfo.image_height) {
unsigned char* row = tmpdata + cinfo.next_scanline*thumbImg->width*3;
if (jpeg_write_scanlines (&cinfo, &row, 1) < 1) {
jpeg_finish_compress (&cinfo);
jpeg_destroy_compress (&cinfo);
fclose (f);
delete [] tmpdata;
return false;
}
}
jpeg_finish_compress (&cinfo);
jpeg_destroy_compress (&cinfo);
fclose (f);
}
delete [] tmpdata;
return true;
}
else if (format==2) {
FILE* f = g_fopen (fname.c_str(), "wb");
if (!f)
return false;
fwrite (&thumbImg->width, 1, sizeof (int), f);
fwrite (&thumbImg->height, 1, sizeof (int), f);
for (int i=0; i<thumbImg->height; i++)
fwrite (thumbImg->r[i], thumbImg->width, 2, f);
for (int i=0; i<thumbImg->height; i++)
fwrite (thumbImg->g[i], thumbImg->width, 2, f);
for (int i=0; i<thumbImg->height; i++)
fwrite (thumbImg->b[i], thumbImg->width, 2, f);
fclose (f);
return true;
}
else
return false;
}
bool Thumbnail::readImage (const Glib::ustring& fname) {
delete thumbImg;
thumbImg = NULL;
int imgType = 0;
if (Glib::file_test (fname+".cust16", Glib::FILE_TEST_EXISTS))
imgType = 2;
if (Glib::file_test (fname+".cust", Glib::FILE_TEST_EXISTS))
imgType = 1;
else if (Glib::file_test (fname+".jpg", Glib::FILE_TEST_EXISTS))
imgType = 3;
if (!imgType)
return false;
else if (imgType==1) {
FILE* f = g_fopen ((fname+".cust").c_str(), "rb");
if (!f)
return false;
int width, height;
fread (&width, 1, sizeof (int), f);
fread (&height, 1, sizeof (int), f);
unsigned char* tmpdata = new unsigned char [width*height*3];
fread (tmpdata, width*height, 3, f);
fclose (f);
thumbImg = new Image16 (width, height);
int ix = 0, val;
for (int i=0; i<height; i++)
for (int j=0; j<width; j++)
if (gammaCorrected) {
val = igammatab[tmpdata[ix++]]*256*8192/scaleForSave;
thumbImg->r[i][j] = CLIP(val);
val = igammatab[tmpdata[ix++]]*256*8192/scaleForSave;
thumbImg->g[i][j] = CLIP(val);
val = igammatab[tmpdata[ix++]]*256*8192/scaleForSave;
thumbImg->b[i][j] = CLIP(val);
}
else {
val = tmpdata[ix++]*256*8192/scaleForSave;
thumbImg->r[i][j] = CLIP(val);
val = tmpdata[ix++]*256*8192/scaleForSave;
thumbImg->g[i][j] = CLIP(val);
val = tmpdata[ix++]*256*8192/scaleForSave;
thumbImg->b[i][j] = CLIP(val);
}
delete [] tmpdata;
return true;
}
else if (imgType==2) {
FILE* f = g_fopen ((fname+".cust16").c_str(), "rb");
if (!f)
return false;
int width, height;
fread (&width, 1, sizeof (int), f);
fread (&height, 1, sizeof (int), f);
thumbImg = new Image16 (width, height);
for (int i=0; i<height; i++)
fread (thumbImg->r[i], width, 2, f);
for (int i=0; i<height; i++)
fread (thumbImg->g[i], width, 2, f);
for (int i=0; i<height; i++)
fread (thumbImg->b[i], width, 2, f);
fclose (f);
return true;
}
else if (imgType==3) {
FILE* f = g_fopen ((fname+".jpg").c_str(), "rb");
if (!f)
return false;
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
if (!setjmp(jpeg_jmp_buf)) {
cinfo.err = my_jpeg_std_error (&jerr);
jpeg_create_decompress (&cinfo);
my_jpeg_stdio_src (&cinfo,f);
jpeg_read_header (&cinfo, TRUE);
int width, height;
width = cinfo.image_width;
height = cinfo.image_height;
cinfo.dct_method = JDCT_FASTEST;
cinfo.do_fancy_upsampling = 1;
jpeg_start_decompress(&cinfo);
thumbImg = new Image16 (width, height);
unsigned char* row = new unsigned char [width*3];
while (cinfo.output_scanline < cinfo.output_height) {
jpeg_read_scanlines (&cinfo, &row, 1);
int ix = 0, val;
for (int j=0; j<width; j++) {
if (gammaCorrected) {
val = igammatab[row[ix++]]*256*8192/scaleForSave;
thumbImg->r[cinfo.output_scanline-1][j] = CLIP(val);
val = igammatab[row[ix++]]*256*8192/scaleForSave;
thumbImg->g[cinfo.output_scanline-1][j] = CLIP(val);
val = igammatab[row[ix++]]*256*8192/scaleForSave;
thumbImg->b[cinfo.output_scanline-1][j] = CLIP(val);
}
else {
val = row[ix++]*256*8192/scaleForSave;
thumbImg->r[cinfo.output_scanline-1][j] = CLIP(val);
val = row[ix++]*256*8192/scaleForSave;
thumbImg->g[cinfo.output_scanline-1][j] = CLIP(val);
val = row[ix++]*256*8192/scaleForSave;
thumbImg->b[cinfo.output_scanline-1][j] = CLIP(val);
}
}
}
jpeg_finish_decompress (&cinfo);
jpeg_destroy_decompress (&cinfo);
fclose (f);
delete [] row;
return true;
}
else {
fclose (f);
return false;
}
return true;
}
}
bool Thumbnail::readData (const Glib::ustring& fname) {
SafeKeyFile keyFile;
try {
if (!keyFile.load_from_file (fname))
return false;
if (keyFile.has_group ("LiveThumbData")) {
if (keyFile.has_key ("LiveThumbData", "CamWBRed")) camwbRed = keyFile.get_double ("LiveThumbData", "CamWBRed");
if (keyFile.has_key ("LiveThumbData", "CamWBGreen")) camwbGreen = keyFile.get_double ("LiveThumbData", "CamWBGreen");
if (keyFile.has_key ("LiveThumbData", "CamWBBlue")) camwbBlue = keyFile.get_double ("LiveThumbData", "CamWBBlue");
if (keyFile.has_key ("LiveThumbData", "AutoWBTemp")) autowbTemp = keyFile.get_double ("LiveThumbData", "AutoWBTemp");
if (keyFile.has_key ("LiveThumbData", "AutoWBGreen")) autowbGreen = keyFile.get_double ("LiveThumbData", "AutoWBGreen");
if (keyFile.has_key ("LiveThumbData", "AEHistCompression")) aeHistCompression = keyFile.get_integer ("LiveThumbData", "AEHistCompression");
if (keyFile.has_key ("LiveThumbData", "RedMultiplier")) redMultiplier = keyFile.get_double ("LiveThumbData", "RedMultiplier");
if (keyFile.has_key ("LiveThumbData", "GreenMultiplier")) greenMultiplier = keyFile.get_double ("LiveThumbData", "GreenMultiplier");
if (keyFile.has_key ("LiveThumbData", "BlueMultiplier")) blueMultiplier = keyFile.get_double ("LiveThumbData", "BlueMultiplier");
if (keyFile.has_key ("LiveThumbData", "Scale")) scale = keyFile.get_double ("LiveThumbData", "Scale");
if (keyFile.has_key ("LiveThumbData", "DefaultGain")) defGain = keyFile.get_double ("LiveThumbData", "DefaultGain");
if (keyFile.has_key ("LiveThumbData", "ScaleForSave")) scaleForSave = keyFile.get_integer ("LiveThumbData", "ScaleForSave");
if (keyFile.has_key ("LiveThumbData", "GammaCorrected")) gammaCorrected = keyFile.get_boolean ("LiveThumbData", "GammaCorrected");
if (keyFile.has_key ("LiveThumbData", "ColorMatrix")) {
std::vector<double> cm = keyFile.get_double_list ("LiveThumbData", "ColorMatrix");
int ix = 0;
for (int i=0; i<3; i++)
for (int j=0; j<3; j++)
colorMatrix[i][j] = cm[ix++];
}
}
return true;
}
catch (Glib::Error) {
return false;
}
}
bool Thumbnail::writeData (const Glib::ustring& fname) {
SafeKeyFile keyFile;
try {
if( Glib::file_test(fname,Glib::FILE_TEST_EXISTS) )
keyFile.load_from_file (fname);
} catch (...) {}
keyFile.set_double ("LiveThumbData", "CamWBRed", camwbRed);
keyFile.set_double ("LiveThumbData", "CamWBGreen", camwbGreen);
keyFile.set_double ("LiveThumbData", "CamWBBlue", camwbBlue);
keyFile.set_double ("LiveThumbData", "AutoWBTemp", autowbTemp);
keyFile.set_double ("LiveThumbData", "AutoWBGreen", autowbGreen);
keyFile.set_integer ("LiveThumbData", "AEHistCompression", aeHistCompression);
keyFile.set_double ("LiveThumbData", "RedMultiplier", redMultiplier);
keyFile.set_double ("LiveThumbData", "GreenMultiplier", greenMultiplier);
keyFile.set_double ("LiveThumbData", "BlueMultiplier", blueMultiplier);
keyFile.set_double ("LiveThumbData", "Scale", scale);
keyFile.set_double ("LiveThumbData", "DefaultGain", defGain);
keyFile.set_integer ("LiveThumbData", "ScaleForSave", scaleForSave);
keyFile.set_boolean ("LiveThumbData", "GammaCorrected", gammaCorrected);
Glib::ArrayHandle<double> cm ((double*)colorMatrix, 9, Glib::OWNERSHIP_NONE);
keyFile.set_double_list ("LiveThumbData", "ColorMatrix", cm);
FILE *f = g_fopen (fname.c_str(), "wt");
if (!f)
return false;
else {
fprintf (f, "%s", keyFile.to_data().c_str());
fclose (f);
return true;
}
}
bool Thumbnail::readEmbProfile (const Glib::ustring& fname) {
FILE* f = fopen (fname.c_str(), "rb");
if (!f) {
embProfileData = NULL;
embProfile = NULL;
embProfileLength = 0;
}
else {
fseek (f, 0, SEEK_END);
embProfileLength = ftell (f);
fseek (f, 0, SEEK_SET);
embProfileData = new unsigned char[embProfileLength];
fread (embProfileData, 1, embProfileLength, f);
fclose (f);
embProfile = cmsOpenProfileFromMem (embProfileData, embProfileLength);
return true;
}
return false;
}
bool Thumbnail::writeEmbProfile (const Glib::ustring& fname) {
if (embProfileLength) {
FILE* f = fopen (fname.c_str(), "wb");
if (f) {
fwrite (embProfileData, 1, embProfileLength, f);
fclose (f);
return true;
}
}
return false;
}
bool Thumbnail::readAEHistogram (const Glib::ustring& fname) {
FILE* f = fopen (fname.c_str(), "rb");
if (!f)
aeHistogram = NULL;
else {
aeHistogram = new unsigned int[65536>>aeHistCompression];
fread (aeHistogram, 1, (65536>>aeHistCompression)*sizeof(int), f);
fclose (f);
return true;
}
return false;
}
bool Thumbnail::writeAEHistogram (const Glib::ustring& fname) {
if (aeHistogram) {
FILE* f = fopen (fname.c_str(), "wb");
if (f) {
fwrite (aeHistogram, 1, (65536>>aeHistCompression)*sizeof(int), f);
fclose (f);
return true;
}
}
return false;
}
}