denef-0.3/0040700000076500007650000000000007214777641011732 5ustar danieldanieldenef-0.3/denef.cc0100600000076500007650000004070607214777641013330 0ustar danieldaniel/* ----------------------------------------------------------------------------- denef - Decode NEF image files Copyright (C) 2000 Daniel Stephens (daniel@cheeseplant.org) This program 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 2 of the License, or (at your option) any later version. This program 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ------------------------------------------------------------------------------ */ #include #include #include #include #include #include #include #include #include #include #include "options.h" #include "nefdata.h" #include "interp.h" static const char *rcsid="$Id: denef.cc,v 1.3 2000/12/10 21:46:50 daniel Exp $"; // Gamma correction - taken from C. Poynton's FAQ on Gamma // (http://www.inforamp.net/~poynton/) static double gammaCorrect(double d) { if (d <= 0.018) { return d * 4.5; } else { return 1.099 * pow(d, 0.45) - 0.099; } } // Command line options const int INT_NOT_SET = -997; int opt_width = INT_NOT_SET; int opt_height = INT_NOT_SET; int opt_x = INT_NOT_SET; int opt_y = INT_NOT_SET; const char *opt_interp = "gradlumin"; double opt_scale = 1.6; bool opt_cc = true; bool opt_gc = true; bool opt_hist = false; const char *opt_histfile = "histo.pgm"; const char *opt_outfile = "nef.ppm"; bool opt_show = false; bool opt_help = false; void Create_Options_List(vector &opts) { opts.push_back(new options::intOption("startx", 0, opt_x)); opts.push_back(new options::intOption("starty", 0, opt_y)); opts.push_back(new options::intOption("width", 0, opt_width)); opts.push_back(new options::intOption("height", 0, opt_height)); opts.push_back(new options::stringOption("interp", 0, opt_interp)); opts.push_back(new options::boolOption("cc", 0, opt_cc)); opts.push_back(new options::doubleOption("scale",0, opt_scale)); opts.push_back(new options::boolOption("gc", 0, opt_gc)); opts.push_back(new options::boolOption("hist", 0, opt_hist)); opts.push_back(new options::stringOption("histfile", 0, opt_histfile)); opts.push_back(new options::stringOption("outfile", 0, opt_outfile)); opts.push_back(new options::boolSetOption("show", 0, opt_show)); opts.push_back(new options::boolSetOption("help", 0, opt_help)); } void Show_Int_Option(ostream &os, int v, const char *notset="not set") { if (v == INT_NOT_SET) {os << "[" << notset << "]" ; return;} os << "[" << v << "]"; } void Show_Bool_Option(ostream &os, bool b) { if (b) {os << "[Yes]"; return;} os << "[No]"; } void Show_Options(ostream &os) { os << "Summary of options (Current settings in []'s)" << endl; os << endl << "Data source options:"; os << endl << " --startx= Start X position of processed output "; Show_Int_Option(os, opt_x, "minimum"); os << endl << " --starty= Start Y position of processed output "; Show_Int_Option(os, opt_y, "minimum"); os << endl << " --width= Width of processed output "; Show_Int_Option(os, opt_width, "maxmimum"); os << endl << " --height= Height of processed output "; Show_Int_Option(os, opt_height, "maxmimum"); os << endl << " --interp= Interpolation algorithm [" << opt_interp << "]"; os << endl << " Available: null, basic, rgb, lumin, gradlumin"; os << endl << endl << "Post-processing options:"; os << endl << " --cc= Perform sRGB color correction "; Show_Bool_Option(os, opt_cc); os << endl << " --scale= Set linear scale factor [" << opt_scale << "]"; os << endl << " --gc= Perform gamma correction "; Show_Bool_Option(os, opt_gc); os << endl << endl << "File options:"; os << endl << " --hist= Create histogram file "; Show_Bool_Option(os, opt_hist); os << endl << " --histfile= Histogram filename [" << opt_histfile << "]"; os << endl << " --outfile= Image output filename [" << opt_outfile << "]"; os << endl << endl << "Misc. Options:"; os << endl << " --show Show current settings before starting."; os << endl << " --help Show options and exit."; os << endl << endl; } void sRGB_Color_Correct(fullImageData *result) { rgbTriple *mt = result->Data(); double r,g,b; for (int i=0; i < (result->Width() * result->Height()); ++i, ++mt) { r = mt->r; g = mt->g; b = mt->b; // Pretty workable sRGB mt->r = 1.0428413 * r - 0.3416602 * g + 0.0509819 * b; mt->g = -0.1237831 * r + 1.2423621 * g - 0.3368242 * b; mt->b = -0.0078414 * r - 0.3630551 * g + 1.1382747 * b; // Oversaturated // mt->r = 1.1446599 * r - 0.4594811 * g + 0.0899564 * b; // mt->g = -0.0890504 * r + 1.1254676 * g - 0.3461829 * b; // mt->b = 0.0014389 * r - 0.2964618 * g + 1.1186995 * b; } } void Gamma_Correct(fullImageData *result, double scale=1.0) { rgbTriple *mt = result->Data(); for (int i=0; i < (result->Width() * result->Height()); ++i, ++mt) { mt->r = gammaCorrect(mt->r * scale); mt->g = gammaCorrect(mt->g * scale); mt->b = gammaCorrect(mt->b * scale); } } void Scale_Data(fullImageData *result, double scale=1.0) { rgbTriple *mt = result->Data(); for (int i=0; i < (result->Width() * result->Height()); ++i, ++mt) { mt->r *= scale; mt->g *= scale; mt->b *= scale; } } extern int main(int argc, char *argv[]) { vector opts; Create_Options_List(opts); bool optok = options::Process_Options(argc, argv, opts, true, true); if (!optok) { cerr << endl << "See '" << argv[0] << " --help' for usage information." << endl; exit(2); } if (opt_help) { cout << "Usage: " << argv[0] << " [options] filename" << endl << endl; Show_Options(cout); exit(0); } if (opt_show) Show_Options(cout); if (argc < 2) { cerr << "No filename given. Exiting" << endl; cerr << endl << "See '" << argv[0] << " --help' for usage information." << endl; exit(0); } ifstream is(argv[1]); if (!is) { int err = errno; cerr << "Failed to open NEF input file '" << argv[1] << "':n" << strerror(err) << endl; exit(2); } cerr << "Reading NEF Data" << endl; nefImageData *nef = Load_NEF_Data(is); // nefImageData *nef = Test_NEF_Data(); is.close(); if (!nef) {exit(2);} ifInterpolator *interpolator = 0; if (strcmp(opt_interp, "null") == 0) { interpolator = new nullInterpolator(); } else if (strcmp(opt_interp, "basic") == 0) { interpolator = new basicInterpolator(); } else if (strcmp(opt_interp, "rgb") == 0) { interpolator = new rgbInterpolator(); } else if (strcmp(opt_interp, "lumin") == 0) { interpolator = new luminanceInterpolator(); } else if (strcmp(opt_interp, "gradlumin") == 0) { interpolator = new gradientLuminanceInterpolator(); } if (!interpolator) { cerr << "Invalid interpolator '" << opt_interp << "'" << endl; exit(2); } int retwidth = nef->Width() - interpolator->Fringe() * 2; int retheight = nef->Height() - interpolator->Fringe() * 2; // Work out the border stuff - there's essentially a 6 pixel border // around the 'real image' section. int xclip = interpolator->Fringe() - 6; int yclip = interpolator->Fringe() - 6; if (opt_x == INT_NOT_SET) { opt_x = xclip; } else if (opt_x < xclip) { cerr << "WARNING: Clipping startx to " << xclip << endl; opt_x = xclip; } if (opt_y == INT_NOT_SET) { opt_y = yclip; } else if (opt_y < yclip) { cerr << "WARNING: Clipping starty to " << yclip << endl; opt_y = yclip; } int xofs = opt_x - xclip; int yofs = opt_y - yclip; if (xofs >= retwidth) { cerr << "Cannot have startx greater than available width" << endl; exit(2); } if (yofs >= retheight) { cerr << "Cannot have starty greater than available height" << endl; exit(2); } retwidth -= xofs; retheight -= yofs; if (opt_width == INT_NOT_SET) { opt_width = retwidth; } else if (opt_width < 1) { cerr << "Cannot have width < 1" << endl; exit(2); } else if (opt_width > retwidth) { cerr << "WARNING: Clipping width to " << retwidth << endl; } retwidth = opt_width; if (opt_height == INT_NOT_SET) { opt_height = retheight; } else if (opt_height < 1) { cerr << "Cannot have height < 1" << endl; exit(2); } else if (opt_height > retheight) { cerr << "WARNING: Clipping height to " << retheight << endl; } retheight = opt_height; fullImageData *result = new fullImageData(retwidth, retheight); cerr << "Interpolating [" << opt_x << "," << opt_y << "] - [" << opt_width << "x" << opt_height << "] (" << opt_interp << "): "; for (int xo=0; xo < retwidth; xo += interpolator->Max_Width()) { int w = retwidth - xo; if (w > interpolator->Max_Width()) {w = interpolator->Max_Width();} for (int yo=0; yo < retheight; yo += interpolator->Max_Height()) { int h = retheight - yo; if (h > interpolator->Max_Height()) { h = interpolator->Max_Height(); } cerr << "."; interpolator->Interpolate(*nef, xo + xofs, yo + yofs, w, h, *result, xo, yo); } } cerr << endl; delete interpolator; if (opt_cc) { cerr << "Color correcting to sRGB..." << endl; sRGB_Color_Correct(result); } if (opt_gc) { cerr << "Applying gamma/scaling..." << endl; Gamma_Correct(result, opt_scale); } else if (opt_scale != 1.0) { cerr << "Scaling..." << endl; Scale_Data(result, opt_scale); } const rgbTriple *t = result->Data(); double emin = t->Luminance(); double emax = emin; cerr << "Determining data range: "; int i; for (i=0; i < (retwidth * retheight); ++i, ++t) { double e = t->Luminance(); if (e>emax) {emax = e;} if (eData(); for (i=0; i < (retwidth * retheight); ++i, ++t) { double e = t->Luminance(); // e = (e - emin) / (emax - emin); int cell = int(e * (double)histogramSize); if (cell < 0) cell = 0; if (cell >= histogramSize) {cell = histogramSize-1;} histogram[cell] ++; } double cumul = 0; double rmin = 0.0; double rmax = 1.0; hlimit[0] = 0; for (i=0; i 0.99) { if (rmax > 0.9999999) { rmax = (double)i/(double)histogramSize; } } } cerr << rmin << " - " << rmax << endl; if (opt_hist) { cerr << "Writing histogram (" << opt_histfile << ")" << endl; { int histogramHeight = 200; double cmult = (double)(histogramHeight * 500) / (double)cmax; ofstream os(opt_histfile); if (!os) { int err = errno; cerr << "Unable to open histogram '" << opt_histfile << "': " << strerror(err) << endl; exit(2); } os << "P5" << endl << histogramSize << " " << histogramHeight << endl << 99 << endl; for (int r=(histogramHeight-1); r>=0; --r) { for (i=0; i 99) {v = 99;} u=v; os << u; } } os.close(); } } #if 0 cerr << "Applying histogram" << endl; rgbTriple *mt = result->Data(); for (i=0; i < (retwidth * retheight); ++i, ++mt) { double oe = mt->Luminance(); if (oe < 0) {oe = 0;} double e = (oe - emin) / (emax - emin); /* double incell = e * (double)histogramSize; int cell = int(e * (double)histogramSize); if (cell < 0) cell = 0; if (cell >= histogramSize) {cell = histogramSize-1;} incell -= cell; double s = hlimit[cell] + (hlimit[cell+1] - hlimit[cell]) * incell; */ double s = (e -rmin) / (rmax-rmin) * 0.90 + 0.05; // double s = (e -rmin) / (rmax-rmin) * 0.95 ; // double s = (e -rmin) / (rmax-rmin) * 0.30 ; // double s = (e - rmin) / (rmax-rmin); if (oe <= 0) { s=0; } else { s = s/oe; } mt->r *= s; mt->g *= s; mt->b *= s; } #endif cerr << "Writing PPM data (" << opt_outfile << ")" << endl; ofstream os(opt_outfile); if (!os) { int err = errno; cerr << "Unable to open output file '" << opt_outfile << "': " << strerror(err) << endl; exit(2); } os << "P6" << endl << retwidth << " " << retheight << endl << "255" << endl; unsigned char obuf[3000]; int oofs=0; int *err[6]; for (i=0; i<6; ++i) { err[i] = new int[retwidth+1]; for (int x=0; x<=retwidth; ++x) { (err[i])[x] = 0; } } int curofs = 0; int newofs = 3; t = result->Data(); double rv,gv,bv; int iv,ov,eov,errv,ebit; i=0; double mul = 1.0; double valofs = 0.0; // if ((emax < 1.0) && (emax > 0.0)) {mul = 1.0 / emax;} // if ((rmax < 1.0) && (rmax > 0.0)) {mul = 1.0 / rmax;} for (int y=0; yr + valofs) * mul; gv = (t->g + valofs) * mul; bv = (t->b + valofs) * mul; if (rv < 0.0) rv=0.0; if (rv > 1.0) rv=1.0; if (gv < 0.0) gv=0.0; if (gv > 1.0) gv=1.0; if (bv < 0.0) bv=0.0; if (bv > 1.0) bv=1.0; rv *= 256000.0; gv *= 256000.0; bv *= 256000.0; // ---------------------------------------- iv = (int)(round(rv)); if (iv > 255999) {iv = 255999;} iv += (err[curofs])[x]; ov = iv / 1000; if (ov < 0) {ov = 0;} if (ov > 255) {ov=255;} eov = ov * 1000 + (ov * 1000 / 255); if (eov > 255999) {eov = 255999;} errv = iv - eov ; ebit = errv * 7 / 16; (err[curofs])[x+1] += ebit; errv -= ebit; ebit = errv / 3; if (x>0) {err[newofs][x-1] += ebit;} errv -= ebit; ebit = errv * 5/ 6; err[newofs][x] += ebit; errv -= ebit; err[newofs][x+1] += errv; obuf[oofs++] = ov; // ---------------------------------------- iv = (int)(round(gv)); if (iv > 255999) {iv = 255999;} iv += (err[curofs+1])[x]; ov = iv / 1000; if (ov < 0) {ov = 0;} if (ov > 255) {ov=255;} eov = ov * 1000 + (ov * 1000 / 255); if (eov > 255999) {eov = 255999;} errv = iv - eov ; ebit = errv * 7 / 16; (err[curofs+1])[x+1] += ebit; errv -= ebit; ebit = errv / 3; if (x>0) {err[newofs+1][x-1] += ebit;} errv -= ebit; ebit = errv * 5/ 6; err[newofs+1][x] += ebit; errv -= ebit; err[newofs+1][x+1] += errv; obuf[oofs++] = ov; // ---------------------------------------- iv = (int)(round(bv)); if (iv > 255999) {iv = 255999;} iv += (err[curofs+2])[x]; ov = iv / 1000; if (ov < 0) {ov = 0;} if (ov > 255) {ov=255;} eov = ov * 1000 + (ov * 1000 / 255); if (eov > 255999) {eov = 255999;} errv = iv - eov ; ebit = errv * 7 / 16; (err[curofs+2])[x+1] += ebit; errv -= ebit; ebit = errv / 3; if (x>0) {err[newofs+2][x-1] += ebit;} errv -= ebit; ebit = errv * 5/ 6; err[newofs+2][x] += ebit; errv -= ebit; err[newofs+2][x+1] += errv; obuf[oofs++] = ov; if (oofs > 2997) { os.write(obuf, oofs); oofs =0; } } } if (oofs > 0) { os.write(obuf, oofs); oofs =0; } os.close(); exit(0); } denef-0.3/ifd.cc0100600000076500007650000000521507214777641013005 0ustar danieldaniel/* ------------------------------------------------------------------------------ denef - Decode NEF image files Copyright (C) 2000 Daniel Stephens (daniel@cheeseplant.org) This program 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 2 of the License, or (at your option) any later version. This program 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ------------------------------------------------------------------------------ */ #include #include "metacam.h" static const char *rcsid="$Id: ifd.cc,v 1.3 2000/09/18 07:51:43 daniel Exp $"; IFD::IFD(const IFD &i) : file(i.file), ofs(i.ofs), entries(i.entries), next_ifd(i.next_ifd) { if (entries) { table = new IFDEntry *[i.entries]; for (int x=0; x=entries)) { cerr << "IFD Array Bounds Violated" << endl; exit(2); } return *table[n]; } denef-0.3/ifdentry.cc0100600000076500007650000001251207214777641014065 0ustar danieldaniel/* ------------------------------------------------------------------------------ denef - Decode NEF image files Copyright (C) 2000 Daniel Stephens (daniel@cheeseplant.org) This program 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 2 of the License, or (at your option) any later version. This program 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ------------------------------------------------------------------------------ */ #include #include "metacam.h" static const char *rcsid="$Id: ifdentry.cc,v 1.3 2000/09/18 07:51:43 daniel Exp $"; vector IFDEntry::Get_UVALUES() const { vector v; if (type == tBYTE) { file.Seek(offset); for (unsigned int i=0; i IFDEntry::Get_SVALUES() const { vector v; if (type == tSBYTE) { file.Seek(offset); for (unsigned int i=0; i IFDEntry::Get_RATIONALS() const { vector v; if (type != tRATIONAL) {return v;} file.Seek(offset); for (unsigned int i=0; i IFDEntry::Get_SRATIONALS() const { vector v; if (type != tSRATIONAL) {return v;} file.Seek(offset); for (unsigned int i=0; i IFDEntry::Get_STRINGS() const { vector v; if (type != tASCII) {return v;} char tmpbuf[1024]; file.Seek(offset); file.Get_Data((unsigned char *)tmpbuf, values); tmpbuf[values] = 0; v.push_back(string(tmpbuf)); return v; } vector IFDEntry::Get_OPAQUE() const { vector v; if (type != tUNDEFINED) {return v;} int toget=values; file.Seek(offset); while (toget > 0) { unsigned char tmpbuf[1024]; int g = toget; if (g>1024) g=1024; file.Get_Data((unsigned char *)tmpbuf, g); for (int i=0; i v = Get_STRINGS(); vector::iterator iter; for (iter=v.begin(); iter != v.end(); ++iter) { os << "\"" << (*iter) << "\","; } return; } case 1: case 3: case 4: { vector v = Get_UVALUES(); vector::iterator iter; for (iter=v.begin(); iter != v.end(); ++iter) { os << (*iter) << ","; } return; } case 5: { vector v = Get_RATIONALS(); vector::iterator iter; for (iter=v.begin(); iter != v.end(); ++iter) { os << (*iter) << ","; } return; } case 7: { vector v = Get_OPAQUE(); vector::iterator iter; for (iter=v.begin(); iter != v.end(); ++iter) { unsigned char c=(*iter); os << hexdigit[(c >> 4) & 0x0f] << hexdigit[c&0x0F] << " "; } return; } case 6: case 8: case 9: { vector v = Get_SVALUES(); vector::iterator iter; for (iter=v.begin(); iter != v.end(); ++iter) { os << (*iter) << ","; } return; } case 10: { vector v = Get_SRATIONALS(); vector::iterator iter; for (iter=v.begin(); iter != v.end(); ++iter) { os << (*iter) << ","; } return; } } // 11 FLOAT // 12 DOUBLE } denef-0.3/interp.cc0100600000076500007650000000216207214777641013542 0ustar danieldaniel/* ----------------------------------------------------------------------------- denef - Decode NEF image files Copyright (C) 2000 Daniel Stephens (daniel@cheeseplant.org) This program 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 2 of the License, or (at your option) any later version. This program 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ------------------------------------------------------------------------------ */ #include #include #include #include "interp.h" static const char *rcsid="$Id: interp.cc,v 1.3 2000/09/18 07:51:43 daniel Exp $"; ifInterpolator::~ifInterpolator() {}; denef-0.3/interp_basic.cc0100600000076500007650000000525307214777641014707 0ustar danieldaniel/* ------------------------------------------------------------------------------ denef - Decode NEF image files Copyright (C) 2000 Daniel Stephens (daniel@cheeseplant.org) This program 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 2 of the License, or (at your option) any later version. This program 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ------------------------------------------------------------------------------ */ #include #include #include #include "interp.h" static const char *rcsid="$Id: interp_basic.cc,v 1.2 2000/09/18 07:51:43 daniel Exp $"; // Basic interpolator - uses nearest neighbors. basicInterpolator::basicInterpolator() { } basicInterpolator::~basicInterpolator() { } int basicInterpolator::Fringe() const { return 2; } int basicInterpolator::Max_Width() const { return 10000000; } int basicInterpolator::Max_Height() const { return 10000000; } void basicInterpolator::Interpolate(const nefImageData &nef, int xofs, int yofs, int width, int height, fullImageData &result, int rxofs, int ryofs) { /* This function takes a chunk of the NEF data and creates the decoded image from it. Very basic algorithm using neighbors */ for (int y=0; y #include #include #include "interp.h" static const char *rcsid="$Id: interp_gradlumin.cc,v 1.4 2000/09/18 07:51:43 daniel Exp $"; // Luminance based interpolator, which uses all colors to interpolate // luminance channel and then interpolates colors from that. // Algorithm has some 'gradient based' image quality enhancements. // Define the region we're willing to interpolate in a single pass (used to // determine how large of a 'workspace' area to allocate. static const int zoneWidth = 256; static const int zoneHeight = 256; static const int zoneSize = zoneWidth * zoneHeight; // Define coeficients for each color when determining luminance. // These may be a little off but I dont know the ACTUAL colors of the filters // over the CCD on a D1. This works on the basic assumption that the D1's // CCD returns a linear strength for each channel. // From C. Poynton's FAQ on Gamma (http://www.inforamp.net/~poynton/) // CIE Rec 709 static const double luminCoefRed = 0.2126; static const double luminCoefGreen = 0.7152; static const double luminCoefBlue = 0.0722; gradientLuminanceInterpolator::gradientLuminanceInterpolator() { tmpY = new double[zoneSize]; tmpCr = new double[zoneSize]; tmpCb = new double[zoneSize]; } gradientLuminanceInterpolator::~gradientLuminanceInterpolator() { delete [] tmpY; delete [] tmpCr; delete [] tmpCb; } int gradientLuminanceInterpolator::Fringe() const { return 2; } int gradientLuminanceInterpolator::Max_Width() const { return zoneWidth - 4; } int gradientLuminanceInterpolator::Max_Height() const { return zoneHeight - 4; } void gradientLuminanceInterpolator::Interpolate(const nefImageData &nef, int xofs, int yofs, int width, int height, fullImageData &result, int rxofs, int ryofs) { /* This function takes a chunk of the NEF data and creates the decoded image from it. Little bit more complex luminance based algorithm, attempts to be intelligent about 'edges' too. */ // Interpolate 'intermediate' red and blue values, normalize them all // to 0.0 - 1.0 for (int y=-2; y<(height+2); ++y) { const short *pn = nef.Data(xofs, yofs + y - 1); const short *p = nef.Data(xofs, yofs + y ); const short *ps = nef.Data(xofs, yofs + y + 1); int ofs = 0; if (y & 1) {ofs=1; ++pn; ++p; ++ps;} for (int x=ofs-2; x<(width+2); x+=2, pn+=2, p+=2, ps+=2) { double X; double gh = fabs(pn[-1]-ps[ 1]); double gv = fabs(pn[ 1]-ps[-1]); if (gh > 2.0 * gv) { X=(double)(pn[ 1]+ps[-1]) * 0.5; } else if (gv > 2.0 * gh) { X=(double)(pn[-1]+ps[ 1]) * 0.5; } else { X=(double)(pn[-1]+pn[1]+ps[-1]+ps[1]) * 0.25; } X /= (double)nef.Max_Value(); if (y & 1) { tmpCr[(y+2)*zoneWidth + (x+2)] = ((double)*p / (double)nef.Max_Value()); tmpCb[(y+2)*zoneWidth + (x+2)] = X; } else { tmpCr[(y+2)*zoneWidth + (x+2)] = X; tmpCb[(y+2)*zoneWidth + (x+2)] = ((double)*p / (double)nef.Max_Value()); } } } // Calculate Luminance for each pixel, normalized to 0.0 - 1.0 for (int y=-2; y<(height+2); ++y) { const short *pn = nef.Data(xofs, yofs + y - 1); const short *p = nef.Data(xofs, yofs + y ); const short *ps = nef.Data(xofs, yofs + y + 1); int ofs = (y+2)*zoneWidth; bool green_pixel = (y & 1); for (int x=-2; x<(width+2); ++x, ++pn, ++p, ++ps, ++ofs, green_pixel = !green_pixel) { double R,B,G; if (green_pixel) { G=(double)*p; double gh = fabs(tmpCr[ofs-1]-tmpCr[ofs+1]); double gv = fabs(tmpCr[ofs-zoneWidth]-tmpCr[ofs+zoneWidth]); // gh=gv; if (gh > 2.0 * gv) { R=(tmpCr[ofs-zoneWidth]+tmpCr[ofs+zoneWidth]) * 0.5; } else if (gv > 2.0 * gh) { R=(tmpCr[ofs-1]+tmpCr[ofs+1]) * 0.5; } else { R=(tmpCr[ofs-1] + tmpCr[ofs+1] + tmpCr[ofs-zoneWidth] + tmpCr[ofs+zoneWidth]) * 0.25; } gh = fabs(tmpCb[ofs-1]-tmpCb[ofs+1]); gv = fabs(tmpCb[ofs-zoneWidth]-tmpCb[ofs+zoneWidth]); // gh=gv; if (gh > 2.0 * gv) { B=(tmpCb[ofs-zoneWidth]+tmpCb[ofs+zoneWidth]) * 0.5; } else if (gv > 2.0 * gh) { B=(tmpCb[ofs-1]+tmpCb[ofs+1]) * 0.5; } else { B=(tmpCb[ofs-1] + tmpCb[ofs+1] + tmpCb[ofs-zoneWidth] + tmpCb[ofs+zoneWidth]) * 0.25; } } else { double gh = fabs(p[-1]-p[1]); double gv = fabs(pn[0]-ps[0]); if (gh > 2.0 * gv) { G=(double)(pn[0]+ps[0]) * 0.5; } else if (gv > 2.0 * gh) { G=(double)(p[1]+p[-1]) * 0.5; } else { G=(double)(pn[0]+p[1]+p[-1]+ps[0]) * 0.25; } R = tmpCr[ofs]; B = tmpCb[ofs]; } G /= (double)nef.Max_Value(); double Y = (luminCoefRed * R + luminCoefGreen * G + luminCoefBlue * B); tmpY[(y+2)*zoneWidth + (x+2)] = Y; } } // Now calculate chrominances.. Start by transferring known values for (int y=-2; y<(height+2); ++y) { const short *p = nef.Data(xofs, yofs + y ); int x = -2; int ofs = (y+2) * zoneWidth; if (y & 1) {++x; ++ofs; ++p;} for (; x<(width+2); x+=2, ofs+=2, p+=2) { double Y = tmpY[ofs]; if (y & 1) { tmpCr[ofs] = (double)*p / (double)nef.Max_Value() - Y; } else { tmpCb[ofs] = (double)*p / (double)nef.Max_Value() - Y; } } } // Next interpolate 'diagonals' again for (int y=-2; y<(height+2); ++y) { int x = -2; int ofs = (y+2) * zoneWidth; if (y & 1) {++x; ++ofs;} for (; x<(width+2); x+=2, ofs+=2) { double *Cx; if (y & 1) { Cx = tmpCb; } else { Cx = tmpCr; } double X; double gh = fabs(Cx[ofs - zoneWidth - 1]-Cx[ofs + zoneWidth + 1]); double gv = fabs(Cx[ofs - zoneWidth + 1]-Cx[ofs + zoneWidth - 1]); if (gh > 2.0 * gv) { X=(Cx[ofs - zoneWidth + 1] + Cx[ofs + zoneWidth - 1]) * 0.5; } else if (gv > 2.0 * gh) { X=(Cx[ofs - zoneWidth - 1] + Cx[ofs + zoneWidth + 1]) * 0.5; } else { X=(Cx[ofs - zoneWidth - 1] + Cx[ofs + zoneWidth + 1] + Cx[ofs - zoneWidth + 1] + Cx[ofs + zoneWidth - 1]) * 0.25; } Cx[ofs] = X; } } // Finally calculate color values for each pixel for (int y=0; y 2.0 * gv) { Cr=(tmpCr[ofs-zoneWidth]+tmpCr[ofs+zoneWidth]) * 0.5; } else if (gv > 2.0 * gh) { Cr=(tmpCr[ofs-1]+tmpCr[ofs+1]) * 0.5; } else { Cr=(tmpCr[ofs-1] + tmpCr[ofs+1] + tmpCr[ofs-zoneWidth] + tmpCr[ofs+zoneWidth]) * 0.25; } gh = fabs(tmpCb[ofs-1]-tmpCb[ofs+1]); gv = fabs(tmpCb[ofs-zoneWidth]-tmpCb[ofs+zoneWidth]); // gh=gv; if (gh > 2.0 * gv) { Cb=(tmpCb[ofs-zoneWidth]+tmpCb[ofs+zoneWidth]) * 0.5; } else if (gv > 2.0 * gh) { Cb=(tmpCb[ofs-1]+tmpCb[ofs+1]) * 0.5; } else { Cb=(tmpCb[ofs-1] + tmpCb[ofs+1] + tmpCb[ofs-zoneWidth] + tmpCb[ofs+zoneWidth]) * 0.25; } } else { Cr = tmpCr[ofs]; Cb = tmpCb[ofs]; } rgbTriple &res = result(rxofs+x, ryofs+y); res.r = Cr + Y; res.b = Cb + Y; res.g = (Y - luminCoefRed * (Cr + Y) - luminCoefBlue * (Cb + Y)) / luminCoefGreen; } } } denef-0.3/interp_lumin.cc0100600000076500007650000001406107214777641014747 0ustar danieldaniel/* ------------------------------------------------------------------------------ denef - Decode NEF image files Copyright (C) 2000 Daniel Stephens (daniel@cheeseplant.org) This program 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 2 of the License, or (at your option) any later version. This program 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ------------------------------------------------------------------------------ */ #include #include #include #include "interp.h" static const char *rcsid="$Id: interp_lumin.cc,v 1.3 2000/09/18 07:51:43 daniel Exp $"; // Luminance based interpolator, which uses all colors to interpolate // luminance channel and then interpolates colors from that. // Define the region we're willing to interpolate in a single pass (used to // determine how large of a 'workspace' area to allocate. static const int zoneWidth = 256; static const int zoneHeight = 256; static const int zoneSize = zoneWidth * zoneHeight; // Define coeficients for each color when determining luminance. // These may be a little off but I dont know the ACTUAL colors of the filters // over the CCD on a D1. This works on the basic assumption that the D1's // CCD returns a linear strength for each channel. // From C. Poynton's FAQ on Gamma (http://www.inforamp.net/~poynton/) // CIE Rec 709 static const double luminCoefRed = 0.2126; static const double luminCoefGreen = 0.7152; static const double luminCoefBlue = 0.0722; luminanceInterpolator::luminanceInterpolator() { tmpY = new double[zoneSize]; tmpCr = new double[zoneSize]; tmpCb = new double[zoneSize]; } luminanceInterpolator::~luminanceInterpolator() { delete [] tmpY; delete [] tmpCr; delete [] tmpCb; } int luminanceInterpolator::Fringe() const { return 2; } int luminanceInterpolator::Max_Width() const { return zoneWidth - 4; } int luminanceInterpolator::Max_Height() const { return zoneHeight - 4; } void luminanceInterpolator::Interpolate(const nefImageData &nef, int xofs, int yofs, int width, int height, fullImageData &result, int rxofs, int ryofs) { /* This function takes a chunk of the NEF data and creates the decoded image from it. Little bit more complex luminance based algorithm. */ // Interpolate 'intermediate' red and blue values, normalize them all // to 0.0 - 1.0 for (int y=-2; y<(height+2); ++y) { const short *pn = nef.Data(xofs, yofs + y - 1); const short *p = nef.Data(xofs, yofs + y ); const short *ps = nef.Data(xofs, yofs + y + 1); int ofs = 0; if (y & 1) {ofs=1; ++pn; ++p; ++ps;} for (int x=ofs-2; x<(width+2); x+=2, pn+=2, p+=2, ps+=2) { double X=(double)(pn[-1]+pn[1]+ps[-1]+ps[1]) * 0.25; X /= (double)nef.Max_Value(); if (y & 1) { tmpCr[(y+2)*zoneWidth + (x+2)] = ((double)*p / (double)nef.Max_Value()); tmpCb[(y+2)*zoneWidth + (x+2)] = X; } else { tmpCr[(y+2)*zoneWidth + (x+2)] = X; tmpCb[(y+2)*zoneWidth + (x+2)] = ((double)*p / (double)nef.Max_Value()); } } } // Calculate Luminance for each pixel, normalized to 0.0 - 1.0 for (int y=-2; y<(height+2); ++y) { const short *pn = nef.Data(xofs, yofs + y - 1); const short *p = nef.Data(xofs, yofs + y ); const short *ps = nef.Data(xofs, yofs + y + 1); int ofs = (y+2)*zoneWidth; bool green_pixel = (y & 1); for (int x=-2; x<(width+2); ++x, ++pn, ++p, ++ps, ++ofs, green_pixel = !green_pixel) { double R,B,G; if (green_pixel) { R=(tmpCr[ofs-1] + tmpCr[ofs+1] + tmpCr[ofs-zoneWidth] + tmpCr[ofs+zoneWidth]) * 0.25; G=(double)*p; B=(tmpCb[ofs-1] + tmpCb[ofs+1] + tmpCb[ofs-zoneWidth] + tmpCb[ofs+zoneWidth]) * 0.25; } else { R = tmpCr[ofs]; G=(double)(pn[0]+p[1]+p[-1]+ps[0]) * 0.25; B = tmpCb[ofs]; } G /= (double)nef.Max_Value(); double Y = (luminCoefRed * R + luminCoefGreen * G + luminCoefBlue * B); tmpY[(y+2)*zoneWidth + (x+2)] = Y; } } // Now calculate chrominances.. Start by transferring known values for (int y=-2; y<(height+2); ++y) { const short *p = nef.Data(xofs, yofs + y ); int x = -2; int ofs = (y+2) * zoneWidth; if (y & 1) {++x; ++ofs; ++p;} for (; x<(width+2); x+=2, ofs+=2, p+=2) { double Y = tmpY[ofs]; if (y & 1) { tmpCr[ofs] = (double)*p / (double)nef.Max_Value() - Y; } else { tmpCb[ofs] = (double)*p / (double)nef.Max_Value() - Y; } } } // Next interpolate 'diagonals' again for (int y=-2; y<(height+2); ++y) { int x = -2; int ofs = (y+2) * zoneWidth; if (y & 1) {++x; ++ofs;} for (; x<(width+2); x+=2, ofs+=2) { double *Cx; if (y & 1) { Cx = tmpCb; } else { Cx = tmpCr; } Cx[ofs] = (Cx[ofs - zoneWidth - 1] + Cx[ofs + zoneWidth + 1] + Cx[ofs - zoneWidth + 1] + Cx[ofs + zoneWidth - 1]) * 0.25; } } // Finally calculate color values for each pixel for (int y=0; y #include #include #include "interp.h" static const char *rcsid="$Id: interp_null.cc,v 1.3 2000/09/18 07:51:43 daniel Exp $"; // Simple 'Null' interpolator - Just copies NEF data directly to output // w/ appropriate colors nullInterpolator::nullInterpolator() { } nullInterpolator::~nullInterpolator() { } int nullInterpolator::Fringe() const { return 0; } int nullInterpolator::Max_Width() const { return 10000000; } int nullInterpolator::Max_Height() const { return 10000000; } void nullInterpolator::Interpolate(const nefImageData &nef, int xofs, int yofs, int width, int height, fullImageData &result, int rxofs, int ryofs) { /* This function takes a chunk of the NEF data and creates the decoded image from it. Essentially non-existant algorithm */ for (int y=0; y #include #include #include "interp.h" static const char *rcsid="$Id: interp_rgb.cc,v 1.3 2000/09/18 07:51:43 daniel Exp $"; // Very naive interpolator, simply interpolates red, green, and blue values // independently and sums them together (A great example of how NOT to do it) // Define the region we're willing to interpolate in a single pass (used to // determine how large of a 'workspace' area to allocate. static const int zoneWidth = 256; static const int zoneHeight = 256; static const int zoneSize = zoneWidth * zoneHeight; rgbInterpolator::rgbInterpolator() { tmpGreen = new double[zoneSize]; tmpRed = new double[zoneSize]; tmpBlue = new double[zoneSize]; } rgbInterpolator::~rgbInterpolator() { delete [] tmpGreen; delete [] tmpRed; delete [] tmpBlue; } int rgbInterpolator::Fringe() const { return 2; } int rgbInterpolator::Max_Width() const { return zoneWidth - 4; } int rgbInterpolator::Max_Height() const { return zoneHeight - 4; } void rgbInterpolator::Interpolate(const nefImageData &nef, int xofs, int yofs, int width, int height, fullImageData &result, int rxofs, int ryofs) { /* This function takes a chunk of the NEF data and creates the decoded image from it. Basic independent R,G,B interpolator */ // Interpolate 'intermediate' red and blue values for (int y=-2; y<(height+2); ++y) { const short *pn = nef.Data(xofs, yofs + y - 1); const short *p = nef.Data(xofs, yofs + y ); const short *ps = nef.Data(xofs, yofs + y + 1); int ofs = 0; if (y & 1) {ofs=1; ++pn; ++p; ++ps;} for (int x=ofs-2; x<(width+2); x+=2, pn+=2, p+=2, ps+=2) { double Y; double gh = fabs(pn[-1]-ps[ 1]); double gv = fabs(pn[ 1]-ps[-1]); if (gh > 2.0 * gv) { Y=(double)(pn[ 1]+ps[-1]) * 0.5; } else if (gv > 2.0 * gh) { Y=(double)(pn[-1]+ps[ 1]) * 0.5; } else { Y=(double)(pn[-1]+pn[1]+ps[-1]+ps[1]) * 0.25; } Y /= (double)nef.Max_Value(); if (y & 1) { tmpRed[(y+2)*zoneWidth + (x+2)] = (double)*p / (double)nef.Max_Value(); tmpBlue[(y+2)*zoneWidth + (x+2)] = Y; } else { tmpRed[(y+2)*zoneWidth + (x+2)] = Y; tmpBlue[(y+2)*zoneWidth + (x+2)] = (double)*p / (double)nef.Max_Value(); } } } // Calculate rgb for each pixel for (int y=0; y 2.0 * gv) { R=(tmpRed[ofs-zoneWidth]+tmpRed[ofs+zoneWidth]) * 0.5; } else if (gv > 2.0 * gh) { R=(tmpRed[ofs-1]+tmpRed[ofs+1]) * 0.5; } else { R=(tmpRed[ofs-1] + tmpRed[ofs+1] + tmpRed[ofs-zoneWidth] + tmpRed[ofs+zoneWidth]) * 0.25; } gh = fabs(tmpBlue[ofs-1]-tmpBlue[ofs+1]); gv = fabs(tmpBlue[ofs-zoneWidth]-tmpBlue[ofs+zoneWidth]); if (gh > 2.0 * gv) { B=(tmpBlue[ofs-zoneWidth]+tmpBlue[ofs+zoneWidth]) * 0.5; } else if (gv > 2.0 * gh) { B=(tmpBlue[ofs-1]+tmpBlue[ofs+1]) * 0.5; } else { B=(tmpBlue[ofs-1] + tmpBlue[ofs+1] + tmpBlue[ofs-zoneWidth] + tmpBlue[ofs+zoneWidth]) * 0.25; } } else { double gh = fabs(p[-1]-p[1]); double gv = fabs(pn[0]-ps[0]); if (gh > 2.0 * gv) { G=(double)(pn[0]+ps[0]) * 0.5; } else if (gv > 2.0 * gh) { G=(double)(p[1]+p[-1]) * 0.5; } else { G=(double)(pn[0]+p[1]+p[-1]+ps[0]) * 0.25; } R = tmpRed[ofs]; B = tmpBlue[ofs]; } G /= (double)nef.Max_Value(); if (R < 0) {R = 0;} if (G < 0) {G = 0;} if (B < 0) {B = 0;} rgbTriple &res = result(rxofs+x, ryofs+y); res.r = R; res.g = G; res.b = B; } } } denef-0.3/nefdata.cc0100600000076500007650000001177407214777641013654 0ustar danieldaniel/* ------------------------------------------------------------------------------ denef - Decode NEF image files Copyright (C) 2000 Daniel Stephens (daniel@cheeseplant.org) This program 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 2 of the License, or (at your option) any later version. This program 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ------------------------------------------------------------------------------ */ #include #include #include #include #include #include #include #include #include #include "metacam.h" #include "nefdata.h" static const char *rcsid="$Id: nefdata.cc,v 1.3 2000/09/18 07:51:43 daniel Exp $"; static void Process_IFD(const IFD &ifd, tagmap &tag_map) { for (int i=0; i uv = (*iter).second->Get_UVALUES(); nef_ifd_start = uv[0]; delete (*iter).second; (*iter).second = 0; } Clear_Tag_Map(tag_map); if (!nef_ifd_start) { cerr << "Couldn't locate NEF IFD" << endl; return 0; } IFD exif = tiff.Get_IFD(nef_ifd_start); Process_IFD(exif, tag_map); idpair stripoffsets_id(0x0111, 4); idpair stripcounts_id(0x0117, 4); bool got_data = true; vector stripoffsets; vector stripcounts; iter = tag_map.find(stripoffsets_id); if (iter != tag_map.end() && ((*iter).second)) { stripoffsets = (*iter).second->Get_UVALUES(); } else { got_data = false; } iter = tag_map.find(stripcounts_id); if (iter != tag_map.end() && ((*iter).second)) { stripcounts = (*iter).second->Get_UVALUES(); } else { got_data = false; } if (!got_data) { cerr << "Couldn't locate NEF Data" << endl; Clear_Tag_Map(tag_map); return 0; } unsigned long width=0; unsigned long height=0; iter = tag_map.find(idpair(256,4)); if (iter != tag_map.end() && ((*iter).second)) { width = (*iter).second->Get_UVALUES()[0]; } else { iter = tag_map.find(idpair(256,3)); if (iter != tag_map.end() && ((*iter).second)) { width = (*iter).second->Get_UVALUES()[0]; } } iter = tag_map.find(idpair(257,4)); if (iter != tag_map.end() && ((*iter).second)) { height = (*iter).second->Get_UVALUES()[0]; } else { tagmap::iterator iter = tag_map.find(idpair(257,3)); if (iter != tag_map.end() && ((*iter).second)) { height = (*iter).second->Get_UVALUES()[0]; } } nefImageData *nef = new nefImageData(width, height); short *s = nef->Data(); for (unsigned int i=0; i> 4; } // Now, val is a 12 bit number.. We'll multiply it by 2, so that // some divide by 2's later don't drop any data (*s++) = val*2; ++col; } delete [] buf; delete [] obuf; } Clear_Tag_Map(tag_map); return nef; } extern nefImageData * Test_NEF_Data() { int width=100; int height=100; nefImageData *nef = new nefImageData(width, height); short *s = nef->Data(); for (int y=0; y #include #include #include "options.h" static const char *rcsid="$Id: options.cc,v 1.2 2000/12/10 22:11:28 daniel Exp $"; bool options::Process_Options(int &argc, char **&argv, const vector &opts, bool dash_delimits_files, bool allow_intermixed_files) { bool oksofar=true; vector::const_iterator o; for (int a=1; aLong_Name(); if (!longname) continue; int l=strlen(longname); if (strncmp(&thisopt[2],longname,l)!=0) continue; if (thisopt[2+l]=='=') { found=true; if (!(*o)->Takes_Argument()) { cerr << argv[0] << ": Error - option --" << longname << " does not take an argument" << endl; oksofar=false; break; } oksofar &= (*o)->Process(&thisopt[2+l+1]); } else if (thisopt[2+l]==0) { found=true; if ((*o)->Requires_Argument()) { cerr << argv[0] << ": Error - option --" << longname << " requires an argument" << endl; oksofar=false; break; } oksofar &= (*o)->Process(0); } } if (!found) { cerr << argv[0] << ": Error - unknown option '" << thisopt << "' used." << endl; oksofar=false; } } else { bool done=false; for (int p=1; (!done) && thisopt[p]; ++p) { bool found=false; for (o=opts.begin(); (!found) && (o!= opts.end()); ++o) { if ((*o)->Short_Name()!=thisopt[p]) continue; found=true; if (!(*o)->Takes_Argument()) { oksofar &= (*o)->Process(0); break; } else { if ((*o)->Requires_Argument() && (!thisopt[p+1])) { cerr << argv[0] << ": Error - option -" << thisopt[p] << " requires an argument" << endl; oksofar=false; break; } oksofar &= (*o)->Process(&thisopt[p+1]); done=true; break; } } if (!found) { cerr << argv[0] << ": Error - unknown option '-" << thisopt[p] << "' used." << endl; oksofar=false; } } } } return oksofar; } bool options::boolSetOption::Process(const char *) const { b=true; return true; } bool options::boolClearOption::Process(const char *) const { b=false; return true; } bool options::intSetOption::Process(const char *) const { var=val; return true; } bool options::boolOption::Process(const char *c) const { if (!c) {b=defval; return true;} if ((strcasecmp(c,"y")==0) || (strcasecmp(c,"yes")==0) || (strcasecmp(c,"true")==0) || (strcasecmp(c,"1")==0) || (strcasecmp(c,"on")==0)) { b=true; return true; } if ((strcasecmp(c,"n")==0) || (strcasecmp(c,"no")==0) || (strcasecmp(c,"false")==0) || (strcasecmp(c,"0")==0) || (strcasecmp(c,"off")==0)) { b=false; return true; } cerr << "Unknown boolean value for " << Long_Name() << endl; return false; } bool options::intOption::Process(const char *c) const { var=atoi(c); return true; } bool options::doubleOption::Process(const char *c) const { var=(double)atof(c); return true; } bool options::stringOption::Process(const char *c) const { var=c; return true; } bool options::actionOption::Process(const char *) const { Action(); return true; } options::actionOption::~actionOption() {}; options::optionInterface::~optionInterface() {}; denef-0.3/tifffile.cc0100600000076500007650000000560107214777641014032 0ustar danieldaniel/* ------------------------------------------------------------------------------ denef - Decode NEF image files Copyright (C) 2000 Daniel Stephens (daniel@cheeseplant.org) This program 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 2 of the License, or (at your option) any later version. This program 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ------------------------------------------------------------------------------ */ #include #include #include #include #include "metacam.h" static const char *rcsid="$Id: tifffile.cc,v 1.3 2000/09/18 07:51:43 daniel Exp $"; tiffFile::tiffFile(istream &i, unsigned long ofs) : is(i), global_offset(ofs) { Seek(0); unsigned char header[2]; Get_Data(header,2); if ((header[0] == 'I') && (header[1] == 'I')) { bigendian = false; } else if ((header[0] == 'M') && (header[1] == 'M')) { bigendian = true; } else { cerr << "Unknown byte ordering - aborting" << endl; exit(2); } unsigned short checknum = Get_UShort(); if (checknum != 42) { cerr << "Bad checknum: " << checknum << endl; exit(2); } } void tiffFile::Seek(unsigned long ofs) { is.seekg(ofs+global_offset, ios::beg); } void tiffFile::Get_Data(unsigned char *buf, size_t bytes) { is.read(buf, bytes); if (is.gcount() != bytes) { int err = errno; cerr << "Read failed: " << strerror(err) << endl; exit(2); } } unsigned char tiffFile::Get_UByte() { unsigned char b; Get_Data((unsigned char *)&b, 1); return b; } unsigned short tiffFile::Get_UShort() { unsigned short s; Get_Data((unsigned char *)&s, 2); if (bigendian) {return ntohs(s);} return s; } unsigned long tiffFile::Get_ULong() { unsigned long l; Get_Data((unsigned char *)&l, 4); if (bigendian) {return ntohl(l);} return l; } signed char tiffFile::Get_SByte() { signed char b; Get_Data((unsigned char *)&b, 1); return b; } signed short tiffFile::Get_SShort() { signed short s; Get_Data((unsigned char *)&s, 2); if (bigendian) {return ntohs(s);} return s; } signed long tiffFile::Get_SLong() { signed long l; Get_Data((unsigned char *)&l, 4); if (bigendian) {return ntohl(l);} return l; } IFD tiffFile::Get_IFD(unsigned long ofs, unsigned long tagofs) { return IFD(*this, ofs, tagofs); } IFD tiffFile::Get_IFD() { return IFD(*this, First_IFD()); } denef-0.3/interp.h0100600000076500007650000000650607214777641013412 0ustar danieldaniel/* This file is -*-C++-*- ------------------------------------------------------------------------------ denef - Decode NEF image files Copyright (C) 2000 Daniel Stephens (daniel@cheeseplant.org) This program 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 2 of the License, or (at your option) any later version. This program 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ------------------------------------------------------------------------------ $Id: interp.h,v 1.6 2000/09/18 07:51:43 daniel Exp $ */ #ifndef INTERP_H_INCLUDED #define INTERP_H_INCLUDED #include "nefdata.h" class ifInterpolator { private: public: virtual ~ifInterpolator(); virtual int Fringe() const = 0; virtual int Max_Width() const = 0; virtual int Max_Height() const = 0; virtual void Interpolate(const nefImageData &nef, int xofs, int yofs, int wid, int hgt, fullImageData &result, int rxofs, int ryofs) = 0; }; class nullInterpolator : public ifInterpolator { public: nullInterpolator(); ~nullInterpolator(); int Fringe() const; int Max_Width() const; int Max_Height() const; void Interpolate(const nefImageData &nef, int xofs, int yofs, int wid, int hgt, fullImageData &result, int rxofs, int ryofs); }; class basicInterpolator : public ifInterpolator { public: basicInterpolator(); ~basicInterpolator(); int Fringe() const; int Max_Width() const; int Max_Height() const; void Interpolate(const nefImageData &nef, int xofs, int yofs, int wid, int hgt, fullImageData &result, int rxofs, int ryofs); }; class luminanceInterpolator : public ifInterpolator { private: double *tmpY,*tmpCr,*tmpCb; public: luminanceInterpolator(); ~luminanceInterpolator(); int Fringe() const; int Max_Width() const; int Max_Height() const; void Interpolate(const nefImageData &nef, int xofs, int yofs, int wid, int hgt, fullImageData &result, int rxofs, int ryofs); }; class gradientLuminanceInterpolator : public ifInterpolator { private: double *tmpY,*tmpCr,*tmpCb; public: gradientLuminanceInterpolator(); ~gradientLuminanceInterpolator(); int Fringe() const; int Max_Width() const; int Max_Height() const; void Interpolate(const nefImageData &nef, int xofs, int yofs, int wid, int hgt, fullImageData &result, int rxofs, int ryofs); }; class rgbInterpolator : public ifInterpolator { private: double *tmpRed,*tmpGreen,*tmpBlue; public: rgbInterpolator(); ~rgbInterpolator(); int Fringe() const; int Max_Width() const; int Max_Height() const; void Interpolate(const nefImageData &nef, int xofs, int yofs, int wid, int hgt, fullImageData &result, int rxofs, int ryofs); }; #endif /* INTERP_H_INCLUDED */ denef-0.3/metacam.h0100600000076500007650000001524607214777641013521 0ustar danieldaniel/* This file is -*-C++-*- ------------------------------------------------------------------------------ denef - Decode NEF image files Copyright (C) 2000 Daniel Stephens (daniel@cheeseplant.org) This program 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 2 of the License, or (at your option) any later version. This program 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ------------------------------------------------------------------------------ $Id: metacam.h,v 1.4 2000/09/18 15:37:53 daniel Exp $ */ #ifndef METACAM_H_INCLUDED #define METACAM_H_INCLUDED #include #include #include class IFD; class IFDEntry; class istream; class ostream; typedef unsigned long tiffUNSIGNED; typedef signed long tiffSIGNED; const unsigned short tBYTE = 1; const unsigned short tASCII = 2; const unsigned short tSHORT = 3; const unsigned short tLONG = 4; const unsigned short tRATIONAL = 5; const unsigned short tSBYTE = 6; const unsigned short tUNDEFINED = 7; const unsigned short tSSHORT = 8; const unsigned short tSLONG = 9; const unsigned short tSRATIONAL = 10; const unsigned short tFLOAT = 11; const unsigned short tDOUBLE = 12; class tiffRATIONAL { public: tiffUNSIGNED num; tiffUNSIGNED den; tiffRATIONAL() : num(0), den(0) {}; tiffRATIONAL(tiffUNSIGNED n, tiffUNSIGNED d) : num(n), den(d) {}; bool operator == (const tiffRATIONAL &r) const { return ((num == r.num) && (den == r.den)); } bool operator != (const tiffRATIONAL &r) const { return ((num != r.num) || (den != r.den)); } operator double() const { double n(num); double d(den); return n/d; } void Normalize(); }; class tiffSRATIONAL { public: tiffSIGNED num; tiffSIGNED den; tiffSRATIONAL() : num(0), den(0) {}; tiffSRATIONAL(tiffSIGNED n, tiffSIGNED d) : num(n), den(d) {}; bool operator == (const tiffSRATIONAL &r) const { return ((num == r.num) && (den == r.den)); } bool operator != (const tiffSRATIONAL &r) const { return ((num != r.num) || (den != r.den)); } operator double() const { double n(num); double d(den); return n/d; } void Normalize(); }; inline ostream &operator << (ostream &os, const tiffRATIONAL &r) { os << r.num << "/" << r.den; return os; } inline ostream &operator << (ostream &os, const tiffSRATIONAL &r) { os << r.num << "/" << r.den; return os; } class tiffFile { private: friend class IFD; friend class IFDEntry; istream &is; unsigned long global_offset; bool bigendian; protected: void Seek(unsigned long ofs); unsigned long Get_Offset() const { return is.tellg()-global_offset; } void Get_Data(unsigned char *buf, size_t bytes); unsigned char Get_UByte(); unsigned short Get_UShort(); unsigned long Get_ULong(); signed char Get_SByte(); signed short Get_SShort(); signed long Get_SLong(); unsigned long First_IFD() { Seek(4); return Get_ULong(); } public: tiffFile(istream &i, unsigned long ofs=0); IFD Get_IFD(); IFD Get_IFD(unsigned long ofs, unsigned long tagofs=0); }; class IFDEntry; class IFD { private: tiffFile &file; unsigned long ofs; unsigned short entries; unsigned long next_ifd; IFDEntry **table; public: IFD(const IFD &); IFD &operator=(const IFD &); IFD(tiffFile &t, unsigned long o, unsigned long tagofs = 0); ~IFD(); bool operator !() const {return ofs==0;} operator bool() const {return ofs!=0;} tiffFile &File() const {return file;} const IFDEntry &operator[](int n) const; unsigned short Entries() const {return entries;} IFD Next_IFD() const { return file.Get_IFD(next_ifd); } }; class IFDEntry { friend class IFD; private: tiffFile &file; unsigned long tag; unsigned short type; unsigned long values; unsigned long offset; public: IFDEntry(tiffFile &t) : file(t), tag(0), type(0), values(0), offset(0) {}; static int Type_Length(unsigned short); int Length() const {return Type_Length(type) * values;} unsigned long Tag() const {return tag;} unsigned short Type() const {return type;} unsigned long Values() const {return values;} unsigned long Offset() const {return offset;} void Output_Value(ostream &os) const; vector Get_UVALUES() const; vector Get_SVALUES() const; vector Get_RATIONALS() const; vector Get_SRATIONALS() const; vector Get_STRINGS() const; vector Get_OPAQUE() const; }; inline ostream & operator<<(ostream &os, const IFDEntry &e) { os << "[TAG " << hex << e.Tag() << dec << " TYPE " << e.Type() << " VALUES " << e.Values() << " OFFSET " << e.Offset() << "]"; return os; } class idpair { private: unsigned long tag; unsigned short type; public: idpair() : tag(0), type(0) {}; idpair(unsigned long a, unsigned short b) : tag(a), type(b) {}; bool operator==(const idpair &i) const { return (tag==i.tag) && (type == i.type); } bool operator!=(const idpair &i) const { return (tag!=i.tag) || (type != i.type); } bool operator<=(const idpair &i) const { if (tag < i.tag) return true; if (tag > i.tag) return false; return (type <= i.type); } bool operator<(const idpair &i) const { if (tag < i.tag) return true; if (tag > i.tag) return false; return (type < i.type); } bool operator>(const idpair &i) const { if (tag > i.tag) return true; if (tag < i.tag) return false; return (type > i.type); } bool operator>=(const idpair &i) const { if (tag > i.tag) return true; if (tag < i.tag) return false; return (type >= i.type); } unsigned long Tag() const {return tag;} unsigned long Type() const {return type;} }; typedef map tagmap; typedef void dpyFunction(ostream &os, const char *, const IFDEntry &e); struct knowntag { unsigned long tag; unsigned short type; int verbose; const char *name; dpyFunction *func; }; inline ostream & operator<<(ostream &os, const idpair &p) { os << hex << p.Tag() << ":" << p.Type() << dec; return os; } #endif /* METACAM_H_INCLUDED */ denef-0.3/nefdata.h0100600000076500007650000000513607214777641013511 0ustar danieldaniel/* This file is -*-C++-*- ------------------------------------------------------------------------------ denef - Decode NEF image files Copyright (C) 2000 Daniel Stephens (daniel@cheeseplant.org) This program 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 2 of the License, or (at your option) any later version. This program 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ------------------------------------------------------------------------------ $Id: nefdata.h,v 1.4 2000/09/18 07:51:43 daniel Exp $ */ #ifndef NEFDATA_H_INCLUDED #define NEFDATA_H_INCLUDED class nefImageData { private: nefImageData(const nefImageData &); nefImageData &operator=(const nefImageData &); int width; int height; public: short *data; nefImageData(int w, int h) : width(w), height(h) { data = new short[w*h]; }; ~nefImageData() { delete [] data; } int Width() const {return width;} int Height() const {return height;} short *Data() {return data;} const short *Data() const {return data;} const short *Data(int x, int y) const {return &data[x+y*width];} const double Max_Value() const { return (double)(2<<12);} }; extern nefImageData * Load_NEF_Data(istream &is); extern nefImageData * Test_NEF_Data(); struct rgbTriple { double r,g,b; double Luminance() const { // From C. Poynton's FAQ on Gamma (http://www.inforamp.net/~poynton/) // CIE Rec 709 return (r * 0.2126) + (g * 0.7152) + (b * 0.0722); }; }; class fullImageData { private: fullImageData(const fullImageData &); fullImageData &operator=(const fullImageData &); int width; int height; public: rgbTriple *data; fullImageData(int w, int h) : width(w), height(h) { data = new rgbTriple[w*h]; }; ~fullImageData() { delete [] data; } int Width() const {return width;} int Height() const {return height;} rgbTriple *Data() {return data;} rgbTriple &operator()(int x, int y) {return data[x+y*width];} const rgbTriple *Data() const {return data;} const rgbTriple *Data(int x, int y) const {return &data[x+y*width];} }; #endif /* NEFDATA_H_INCLUDED */ denef-0.3/options.h0100600000076500007650000001000707214777641013573 0ustar danieldaniel/* This file is -*-C++-*- ------------------------------------------------------------------------------ denef - Decode NEF image files Copyright (C) 2000 Daniel Stephens (daniel@cheeseplant.org) This program 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 2 of the License, or (at your option) any later version. This program 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ------------------------------------------------------------------------------ $Id: options.h,v 1.2 2000/12/10 22:11:00 daniel Exp $ */ #ifndef OPTIONS_H_INCLUDED #define OPTIONS_H_INCLUDED #include struct options { public: class optionInterface { private: const char *long_name; char short_name; bool takes_args; bool requires_argument; public: optionInterface(const char *n, char sn, bool ta=false, bool ar=true) : long_name(n), short_name(sn), takes_args(ta), requires_argument(ar) {}; virtual ~optionInterface(); const char *Long_Name() const {return long_name;} char Short_Name() const {return short_name;} bool Takes_Argument() const {return takes_args;} bool Requires_Argument() const {return requires_argument;} virtual bool Process(const char *) const {return true;} ; }; class boolSetOption : public optionInterface { private: bool &b; public: boolSetOption(const char *l, char s, bool &bv) : optionInterface(l,s,false,false), b(bv) {}; virtual bool Process(const char *) const; }; class boolClearOption : public optionInterface { private: bool &b; public: boolClearOption(const char *l, char s, bool &bv) : optionInterface(l,s,false,false), b(bv) {}; virtual bool Process(const char *) const; }; class boolOption : public optionInterface { private: bool &b; bool defval; public: boolOption(const char *l, char s, bool &bv, bool dv) : optionInterface(l,s,true,false), b(bv), defval(dv) {}; boolOption(const char *l, char s, bool &bv) : optionInterface(l,s,true,true), b(bv) {}; virtual bool Process(const char *) const; }; class intSetOption : public optionInterface { private: int &var; int val; public: intSetOption(const char *l, char s, int &vr, int vl) : optionInterface(l,s,false,false), var(vr), val(vl) {}; virtual bool Process(const char *) const; }; class stringOption : public optionInterface { private: const char *&var; public: stringOption(const char *l, char s, const char *&vr, bool req=true) : optionInterface(l,s,true,req), var(vr) {}; virtual bool Process(const char *) const; }; class intOption : public optionInterface { private: int &var; public: intOption(const char *l, char s, int &vr, bool req=true) : optionInterface(l,s,true,req), var(vr) {}; virtual bool Process(const char *) const; }; class doubleOption : public optionInterface { private: double &var; public: doubleOption(const char *l, char s, double &vr, bool req=true) : optionInterface(l,s,true,req), var(vr) {}; virtual bool Process(const char *) const; }; class actionOption : public optionInterface { public: actionOption(const char *l, char s) : optionInterface(l,s,false,false) {}; ~actionOption(); virtual bool Process(const char *) const; virtual bool Action() const = 0; }; static bool Process_Options(int &argc, char **&argv, const vector &opts, bool dash_delimits_files=true, bool allow_intermixed_files=true); }; #endif /* OPTIONS_H_INCLUDED */ denef-0.3/Makefile0100600000076500007650000000356407214777641013401 0ustar danieldaniel# ----------------------------------------------------------------------------- # Copyright (C) 2000 Daniel Stephens (daniel@cheeseplant.org) # # This program 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 2 # of the License, or (at your option) any later version. # # This program 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 this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # ----------------------------------------------------------------------------- # # $Id: Makefile,v 1.6 2000/12/10 21:46:50 daniel Exp $ CXX=g++ INCLUDES= CXXFLAGS=-Wall -ansi -pedantic -D_GNU_SOURCE $(INCLUDES) OBJS=denef.o nefdata.o tifffile.o ifd.o ifdentry.o interp.o \ interp_null.o \ interp_basic.o \ interp_rgb.o \ interp_gradlumin.o \ interp_lumin.o \ options.o HDRS= DEPS=$(OBJS:.o=.dep) ##### TARGETS ###### default: denef clean: -rm *.o *~ *.dep realclean: -rm denef -rm *.o *~ denef: $(OBJS) $(CXX) $(CXXFLAGS) $(OBJS) -o denef -lm # Dependency rules dependencies: Makefile $(DEPS) cat $(DEPS) > dependencies- mv -f dependencies- dependencies # Each .dep file will hold dependencies for both the .o file, and an identical # list to determine when the .dep file needs rebuilding. Clever eh? %.dep: %.cc $(HDRS) $(CXX) $(CFLAGS) $(INCS) -M -E -c $*.cc > $*.dep- sed -e 's/[.]o:/.dep:/' $*.dep- > $*.dep-- cat $*.dep-- >> $*.dep- rm -f $*.dep-- mv -f $*.dep- $*.dep include dependencies denef-0.3/README0100600000076500007650000000554707214777641012624 0ustar danieldaniel--------------------------------------------------------------------------- denef - Decode NEF image files $Id: README,v 1.2 2000/12/10 21:51:00 daniel Exp $ --------------------------------------------------------------------------- This is a utility which decodes 'NEF' files - the raw image files from the Nikon D1 camera, and produces an image which can be processed by standard image processing tools. This is a development release and simply represents a stake in the ground from which further development will continue. Once compiled, usage is very simple... denef filename.nef (Where, obviously, filename.nef is replaced by the NEF file you wish to decode). There are now a number of options, do 'denef --help' for a list, which allow you to exchange interpolators, skip a couple of post-processing steps if necessary, process only a part of the NEF file, change output filenames, etc. The utility will produce one two files, their default names are: nef.ppm The decoded NEF data histo.pgm A simple histogram showing distribution of intensities. (This is now optional, default OFF) What this utility currently DOES do... * Reads NEF file and extracts image data * Interpolates NEF data into linear RGB image * Color corrects to sRGB (or fairly close to) [Since the R/G/B filters on the D1 aren't 1:1 with any R/G/B I know of - Without color correction images always seem washed out] * Gamma converts linear data to standard 'camera data' gamma curve * Outputs 24 bit PPM image data, with unidirectional floyd-steinberg dithering. * Allow only a subset of the image to be converted * Allow selection of an interpolation algorithm (The code is modularized properly, it just doesn't use it) What this utility currently DOES NOT do (but in most cases will eventually do). * Sharpen the image (So you'll have to do that yourself) * Filter the image for 'local anomalies' from the interpolation process.. [Interpolation can introduce some artifacts, which in some cases can be filtered] * Attempt to adjust the levels of the resulting image based on the histogram. * Output JPEG/TIFF * Transfer the EXIF metadata from the NEF file to the output file * Allow multiple color-corrections * Allow the luminance data ONLY to be extracted * Allow the output of 48 bit (16 bit each of R,G,B) data (pre-gamma) * Provide support for batch-converting many files * Lots of other things. My apologies if the code is badly commented or if there are lots of blocks of code ifdef'ed or commented out since this IS development code and is a little organic right now.. Please find it useful, but try not to expect any level of 'support' just yet, it compiles fine on a RedHat 6.2 intel machine, on other platforms, your mileage may vary. Daniel Stephens - Dec 10 2000.