diff --git a/ac_openmp.m4 b/ac_openmp.m4 new file mode 100644 index 00000000..32c4ced7 --- /dev/null +++ b/ac_openmp.m4 @@ -0,0 +1,92 @@ +# openmp.m4 serial 4 +dnl Copyright (C) 2006-2007 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl This file can be removed once we assume autoconf >= 2.62. + +# _AC_LANG_OPENMP +# --------------- +# Expands to some language dependent source code for testing the presence of +# OpenMP. +AC_DEFUN([_AC_LANG_OPENMP], +[_AC_LANG_DISPATCH([$0], _AC_LANG, $@)]) + +# _AC_LANG_OPENMP(C) +# ------------------ +m4_define([_AC_LANG_OPENMP(C)], +[ +#ifndef _OPENMP + choke me +#endif +#include +int main () { return omp_get_num_threads (); } +]) + +# _AC_LANG_OPENMP(C++) +# -------------------- +m4_copy([_AC_LANG_OPENMP(C)], [_AC_LANG_OPENMP(C++)]) + +# _AC_LANG_OPENMP(Fortran 77) +# --------------------------- +m4_define([_AC_LANG_OPENMP(Fortran 77)], +[AC_LANG_FUNC_LINK_TRY([omp_get_num_threads])]) + +# _AC_LANG_OPENMP(Fortran) +# --------------------------- +m4_copy([_AC_LANG_OPENMP(Fortran 77)], [_AC_LANG_OPENMP(Fortran)]) + +# AC_OPENMP +# --------- +# Check which options need to be passed to the C compiler to support OpenMP. +# Set the OPENMP_CFLAGS / OPENMP_CXXFLAGS / OPENMP_FFLAGS variable to these +# options. +# The options are necessary at compile time (so the #pragmas are understood) +# and at link time (so the appropriate library is linked with). +# This macro takes care to not produce redundant options if $CC $CFLAGS already +# supports OpenMP. It also is careful to not pass options to compilers that +# misinterpret them; for example, most compilers accept "-openmp" and create +# an output file called 'penmp' rather than activating OpenMP support. +AC_DEFUN([AC_OPENMP], +[ + OPENMP_[]_AC_LANG_PREFIX[]FLAGS= + AC_ARG_ENABLE([openmp], + [AS_HELP_STRING([--disable-openmp], [do not use OpenMP])]) + if test "$enable_openmp" != no; then + AC_CACHE_CHECK([for $CC option to support OpenMP], + [ac_cv_prog_[]_AC_LANG_ABBREV[]_openmp], + [AC_LINK_IFELSE([_AC_LANG_OPENMP], + [ac_cv_prog_[]_AC_LANG_ABBREV[]_openmp='none needed'], + [ac_cv_prog_[]_AC_LANG_ABBREV[]_openmp='unsupported' + dnl Try these flags: + dnl GCC >= 4.2 -fopenmp + dnl SunPRO C -xopenmp + dnl Intel C -openmp + dnl SGI C, PGI C -mp + dnl Tru64 Compaq C -omp + dnl IBM C (AIX, Linux) -qsmp=omp + dnl If in this loop a compiler is passed an option that it doesn't + dnl understand or that it misinterprets, the AC_LINK_IFELSE test + dnl will fail (since we know that it failed without the option), + dnl therefore the loop will continue searching for an option, and + dnl no output file called 'penmp' or 'mp' is created. + for ac_option in -fopenmp -xopenmp -openmp -mp -omp -qsmp=omp; do + ac_save_[]_AC_LANG_PREFIX[]FLAGS=$[]_AC_LANG_PREFIX[]FLAGS + _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $ac_option" + AC_LINK_IFELSE([_AC_LANG_OPENMP], + [ac_cv_prog_[]_AC_LANG_ABBREV[]_openmp=$ac_option]) + _AC_LANG_PREFIX[]FLAGS=$ac_save_[]_AC_LANG_PREFIX[]FLAGS + if test "$ac_cv_prog_[]_AC_LANG_ABBREV[]_openmp" != unsupported; then + break + fi + done])]) + case $ac_cv_prog_[]_AC_LANG_ABBREV[]_openmp in #( + "none needed" | unsupported) + ;; #( + *) + OPENMP_[]_AC_LANG_PREFIX[]FLAGS=$ac_cv_prog_[]_AC_LANG_ABBREV[]_openmp ;; + esac + fi + AC_SUBST([OPENMP_]_AC_LANG_PREFIX[FLAGS]) +]) diff --git a/configure.ac b/configure.ac index 6bec4ed9..e94fb146 100644 --- a/configure.ac +++ b/configure.ac @@ -10,9 +10,22 @@ AC_CONFIG_MACRO_DIR([m4]) AC_SEARCH_LIBS([strerror],[cposix]) AC_PROG_CC AC_PROG_CXX +AC_PROG_CPP +AC_PROG_INSTALL +LT_INIT #AC_CHECK_INCLUDES_DEFAULT AC_PROG_EGREP +# Make sure that pow is available, trying libm if necessary. +AC_SEARCH_LIBS(pow, m) +AC_CHECK_FUNCS(canonicalize_file_name) +AC_CHECK_FUNCS(strcasestr) + +m4_ifndef([AC_OPENMP], [m4_include([ac_openmp.m4])]) +AC_OPENMP +CFLAGS="$CFLAGS $OPENMP_CFLAGS" +CXXFLAGS="$CXXFLAGS $OPENMP_CFLAGS" + AC_ARG_ENABLE(experimental, AS_HELP_STRING( [--enable-experimental], @@ -129,6 +142,7 @@ ALL_LINGUAS="cs da de en fr it nb pl ru fi es sv nl pt_BR ca hu ja" AM_GNU_GETTEXT_VERSION([0.19]) AM_GNU_GETTEXT([external]) AC_CHECK_FUNCS(memmem) +AC_CHECK_FUNCS(strcasecmp) AX_CHECK_COMPILER_FLAGS("-msse2", [_CAN_COMPILE_SSE2=yes], [_CAN_COMPILE_SSE2=no]) AX_CHECK_COMPILER_FLAGS("-msse4.1", [_CAN_COMPILE_SSE4_1=yes],[_CAN_COMPILE_SSE4_1=no]) @@ -170,6 +184,7 @@ plugins/fuji-rotate/Makefile plugins/input-file/Makefile plugins/input-image16/Makefile plugins/lensfun/Makefile +plugins/load-dcraw/Makefile plugins/load-gdk/Makefile plugins/load-png/Makefile plugins/load-rawspeed/Makefile diff --git a/plugins/Makefile.am b/plugins/Makefile.am index f5bdb0f8..31c9bfc2 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -13,6 +13,7 @@ SUBDIRS = \ input-file \ input-image16 \ lensfun \ + load-dcraw \ load-gdk \ load-png \ load-rawspeed \ diff --git a/plugins/load-dcraw/Makefile.am b/plugins/load-dcraw/Makefile.am new file mode 100644 index 00000000..e39fd84a --- /dev/null +++ b/plugins/load-dcraw/Makefile.am @@ -0,0 +1,58 @@ +# +# Note for Rawstudio developers: +# +# load-dcraw is copied from ufraw-0.22.tar.gz +# https://sourceforge.net/projects/ufraw/files/ufraw/ufraw-0.22/ufraw-0.22.tar.gz +# +# From ufraw we copied: +# dcraw.cc +# dcraw.h +# dcraw_api.cc +# dcraw_api.h +# dcraw_indi.c +# nikon_curve.c +# nikon_curve.h +# uf_glib.h +# uf_progress.h +# ufobject.cc +# ufobject.h +# ufraw-batch.c +# ufraw.h +# ufraw_colorspaces.c +# ufraw_colorspaces.h +# ufraw_conf.c +# ufraw_developer.c +# ufraw_embedded.c +# ufraw_exiv2.cc +# ufraw_message.c +# ufraw_routines.c +# ufraw_settings.cc +# ufraw_ufraw.c +# ufraw_writer.c +# wb_presets.c +# +# - Thanks Dave and Udi, you rock! +# + +AM_CFLAGS =\ + -DDCRAW_NOMAIN\ + -DDCRAW_NOLCMS\ + -DWITH_MMAP_HACK\ + -DPACKAGE_DATA_DIR=\""$(datadir)"\" \ + -DPACKAGE_LOCALE_DIR=\""@localedir@"\" \ + @PACKAGE_CFLAGS@ @LCMS_CFLAGS@\ + -I$(top_srcdir)/librawstudio/ \ + -I$(top_srcdir)/ + +AM_CXXFLAGS = $(AM_CFLAGS) +AM_CPPFLAGS = -DDCRAW_NOMAIN \ + -DUFRAW_LOCALEDIR=\"$(datadir)/locale\" + + +lib_LTLIBRARIES = load_dcraw.la + +libdir = @RAWSTUDIO_PLUGINS_LIBS_DIR@ + +load_dcraw_la_LIBADD = @PACKAGE_LIBS@ @LCMS_LIBS@ +load_dcraw_la_LDFLAGS = -module -avoid-version +load_dcraw_la_SOURCES = dcrawloader.c mmap-hack.c mmap-hack.h dcraw_indi.c ufraw_ufraw.c ufraw_conf.c wb_presets.c ufraw_routines.c ufraw_developer.c ufraw_message.c ufraw_embedded.c ufraw_colorspaces.c ufraw-batch.c ufraw_writer.c nikon_curve.c ufraw_settings.cc ufobject.cc dcraw.cc dcraw.h dcraw_api.cc ufraw_exiv2.cc dcraw_api.h uf_glib.h uf_progress.h ufraw.h ufobject.h nikon_curve.h ufraw_colorspaces.h diff --git a/plugins/load-dcraw/dcraw.cc b/plugins/load-dcraw/dcraw.cc new file mode 100644 index 00000000..db994f18 --- /dev/null +++ b/plugins/load-dcraw/dcraw.cc @@ -0,0 +1,11021 @@ +/* + dcraw.cc - Dave Coffin's raw photo decoder - C++ adaptation + Copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net + Copyright 2004-2016 by Udi Fuchs, udifuchs a gmail o com + + 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 is a adaptation of Dave Coffin's original dcraw.c to C++. + It can work as either a command-line tool or called by other programs. + + $Revision: 1.478 $ + $Date: 2018/06/01 20:36:25 $ + */ + +#ifdef HAVE_CONFIG_H /*For UFRaw config system - NKBJ*/ +#include "config.h" +#endif +extern "C" { +#include "uf_progress.h" +} + +#define DCRAW_VERSION "9.28" + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#define _USE_MATH_DEFINES +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef HAVE_CONFIG_H /*fseeko() is handled by the UFRaw config system - NKBJ*/ +#if defined(DJGPP) || defined(__MINGW32__) +#define fseeko fseek +#define ftello ftell +#else +#define fgetc getc_unlocked +#endif +#endif +#ifdef __CYGWIN__ +#include +#endif +#ifdef _WIN32 +#include +#include +#ifndef __MINGW32__ +#pragma comment(lib, "ws2_32.lib") +#endif +#define snprintf _snprintf +#define strcasecmp stricmp +#define strncasecmp strnicmp +typedef __int64 INT64; +typedef unsigned __int64 UINT64; +#else +#include +#include +#include +typedef long long INT64; +typedef unsigned long long UINT64; +#endif + +#ifdef NODEPS +#define NO_JASPER +#define NO_JPEG +#define NO_LCMS +#endif +#ifdef HAVE_LIBJASPER +#include /* Decode Red camera movies */ +#endif +#ifdef HAVE_LIBJPEG +extern "C" { +#include /* Decode compressed Kodak DC120 photos */ +} +#endif /* and Adobe Lossy DNGs */ +#ifndef NO_LCMS +#include /* Support color profiles */ +#endif +#ifndef DCRAW_NOMAIN +#ifdef LOCALEDIR +#include +#define _(String) gettext(String) +#else +#define _(String) (String) +#endif +#else +#include /*For _(String) definition - NKBJ*/ +#endif + +/* All definitions of global variables are defined inside a class in dcraw.h */ +#include "dcraw.h" + +#ifdef DCRAW_NOMAIN +extern +#endif +const double xyz_rgb[3][3] = { /* XYZ from RGB */ + { 0.412453, 0.357580, 0.180423 }, + { 0.212671, 0.715160, 0.072169 }, + { 0.019334, 0.119193, 0.950227 } }; +#ifdef DCRAW_NOMAIN +extern +#endif +const float d65_white[3] = { 0.950456, 1, 1.088754 }; + +#define DCRAW_SUCCESS 0 /* Centralize the error handling - UF*/ +#define DCRAW_ERROR 1 +#define DCRAW_UNSUPPORTED 2 +#define DCRAW_NO_CAMERA_WB 3 +#define DCRAW_VERBOSE 4 +#define DCRAW_WARNING 5 + +#define CLASS DCRaw:: + +CLASS DCRaw() +{ +order=0, fuji_dr=0; /* Suppress valgrind error. */ +shot_select=0, multi_out=0, aber[0] = aber[1] = aber[2] = aber[3] = 1; +gamm[0] = 0.45, gamm[1] = 4.5, gamm[2] = gamm[3] = gamm[4] = gamm[5] = 0; +bright=1, user_mul[0] = user_mul[1] = user_mul[2] = user_mul[3] = 0; +threshold=0, half_size=0, four_color_rgb=0, document_mode=0, highlight=0; +verbose=0, use_auto_wb=0, use_camera_wb=0, use_camera_matrix=1; +output_color=1, output_bps=8, output_tiff=0, med_passes=0, no_auto_bright=0; +greybox[0] = greybox[1] = 0, greybox[2] = greybox[3] = UINT_MAX; +tone_curve_size = 0, tone_curve_offset = 0; /* Nikon Tone Curves UF*/ +tone_mode_offset = 0, tone_mode_size = 0; /* Nikon ToneComp UF*/ +messageBuffer = NULL; +lastStatus = DCRAW_SUCCESS; +ifname = NULL; +ifname_display = NULL; +ifpReadCount = 0; +ifpSize = 0; +ifpStepProgress = 0; +eofCount = 0; +} + +CLASS ~DCRaw() +{ +free(ifname); +free(ifname_display); +} + +void CLASS ifpProgress(unsigned readCount) { + ifpReadCount += readCount; + if (ifpSize==0) return; + unsigned newStepProgress = STEPS * ifpReadCount / ifpSize; + if (newStepProgress > ifpStepProgress) { +#ifdef DCRAW_NOMAIN + if (ifpStepProgress) + progress(PROGRESS_LOAD, newStepProgress - ifpStepProgress); + else + progress(PROGRESS_LOAD, -STEPS); +#endif + } + ifpStepProgress = newStepProgress; +} + +size_t CLASS fread(void *ptr, size_t size, size_t nmemb, FILE *stream) { + size_t num = ::fread(ptr, size, nmemb, stream); + if ( num != nmemb ) { + if (eofCount < 10) + // Maybe this should be a DCRAW_WARNING + dcraw_message(DCRAW_VERBOSE, "%s: fread %d != %d\n", + ifname_display, num, nmemb); + if (eofCount == 10) + dcraw_message(DCRAW_VERBOSE, "%s: fread eof reached 10 times\n", + ifname_display); + eofCount++; + } + if (stream==ifp) ifpProgress(size*nmemb); + return num; +} + +size_t CLASS fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) { + size_t num = ::fwrite(ptr, size, nmemb, stream); + if ( num != nmemb ) + dcraw_message(DCRAW_WARNING, "%s: fwrite %d != %d\n", + ifname_display, num, nmemb); + return num; +} + +char *CLASS fgets(char *s, int size, FILE *stream) { + char *str = ::fgets(s, size, stream); + if (str == NULL) { + if (eofCount < 10) + // Maybe this should be a DCRAW_WARNING + dcraw_message(DCRAW_VERBOSE, "%s: fgets returned NULL\n", + ifname_display); + if (eofCount == 10) + dcraw_message(DCRAW_VERBOSE, "%s: fgets eof reached 10 times\n", + ifname_display); + eofCount++; + } + if (stream==ifp) ifpProgress(strlen(s)); + return str; +} + +int CLASS fgetc(FILE *stream) { + int chr = ::fgetc(stream); + if (stream==ifp) ifpProgress(1); + return chr; +} + +int CLASS fscanf(FILE *stream, const char *format, void *ptr) { + int count = ::fscanf(stream, format, ptr); + if ( count != 1 ) + dcraw_message(DCRAW_WARNING, "%s: fscanf %d != 1\n", + ifname_display, count); + return 1; +} + +#define FORC(cnt) for (c=0; c < cnt; c++) +#define FORC3 FORC(3) +#define FORC4 FORC(4) +#define FORCC FORC(colors) + +#define SQR(x) ((x)*(x)) +#ifndef DCRAW_NOMAIN +#ifndef ABS +#define ABS(x) (((int)(x) ^ ((int)(x) >> 31)) - ((int)(x) >> 31)) +#endif +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif +#ifndef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif +#endif +#define LIM(x,min,max) MAX(min,MIN(x,max)) +#define ULIM(x,y,z) ((y) < (z) ? LIM(x,y,z) : LIM(x,z,y)) +#define CLIP(x) LIM((int)(x),0,65535) +#define SWAP(a,b) { a=a+b; b=a-b; a=a-b; } + +/* + In order to inline this calculation, I make the risky + assumption that all filter patterns can be described + by a repeating pattern of eight rows and two columns + + Do not use the FC or BAYER macros with the Leaf CatchLight, + because its pattern is 16x16, not 2x8. + + Return values are either 0/1/2/3 = G/M/C/Y or 0/1/2/3 = R/G1/B/G2 + + PowerShot 600 PowerShot A50 PowerShot Pro70 Pro90 & G1 + 0xe1e4e1e4: 0x1b4e4b1e: 0x1e4b4e1b: 0xb4b4b4b4: + + 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 + 0 G M G M G M 0 C Y C Y C Y 0 Y C Y C Y C 0 G M G M G M + 1 C Y C Y C Y 1 M G M G M G 1 M G M G M G 1 Y C Y C Y C + 2 M G M G M G 2 Y C Y C Y C 2 C Y C Y C Y + 3 C Y C Y C Y 3 G M G M G M 3 G M G M G M + 4 C Y C Y C Y 4 Y C Y C Y C + PowerShot A5 5 G M G M G M 5 G M G M G M + 0x1e4e1e4e: 6 Y C Y C Y C 6 C Y C Y C Y + 7 M G M G M G 7 M G M G M G + 0 1 2 3 4 5 + 0 C Y C Y C Y + 1 G M G M G M + 2 C Y C Y C Y + 3 M G M G M G + + All RGB cameras use one of these Bayer grids: + + 0x16161616: 0x61616161: 0x49494949: 0x94949494: + + 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 + 0 B G B G B G 0 G R G R G R 0 G B G B G B 0 R G R G R G + 1 G R G R G R 1 B G B G B G 1 R G R G R G 1 G B G B G B + 2 B G B G B G 2 G R G R G R 2 G B G B G B 2 R G R G R G + 3 G R G R G R 3 B G B G B G 3 R G R G R G 3 G B G B G B + */ + +#define RAW(row,col) \ + raw_image[(row)*raw_width+(col)] + +#define FC(row,col) \ + (filters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3) + +#define BAYER(row,col) \ + image[((row) >> shrink)*iwidth + ((col) >> shrink)][FC(row,col)] + +#define BAYER2(row,col) \ + image[((row) >> shrink)*iwidth + ((col) >> shrink)][fcol(row,col)] + +int CLASS fcol (int row, int col) +{ + static const char filter[16][16] = + { { 2,1,1,3,2,3,2,0,3,2,3,0,1,2,1,0 }, + { 0,3,0,2,0,1,3,1,0,1,1,2,0,3,3,2 }, + { 2,3,3,2,3,1,1,3,3,1,2,1,2,0,0,3 }, + { 0,1,0,1,0,2,0,2,2,0,3,0,1,3,2,1 }, + { 3,1,1,2,0,1,0,2,1,3,1,3,0,1,3,0 }, + { 2,0,0,3,3,2,3,1,2,0,2,0,3,2,2,1 }, + { 2,3,3,1,2,1,2,1,2,1,1,2,3,0,0,1 }, + { 1,0,0,2,3,0,0,3,0,3,0,3,2,1,2,3 }, + { 2,3,3,1,1,2,1,0,3,2,3,0,2,3,1,3 }, + { 1,0,2,0,3,0,3,2,0,1,1,2,0,1,0,2 }, + { 0,1,1,3,3,2,2,1,1,3,3,0,2,1,3,2 }, + { 2,3,2,0,0,1,3,0,2,0,1,2,3,0,1,0 }, + { 1,3,1,2,3,2,3,2,0,2,0,1,1,0,3,0 }, + { 0,2,0,3,1,0,0,1,1,3,3,2,3,2,2,1 }, + { 2,1,3,2,3,1,2,1,0,3,0,2,0,2,0,2 }, + { 0,3,1,0,0,2,0,3,2,1,3,1,1,3,1,3 } }; + + if (filters == 1) return filter[(row+top_margin)&15][(col+left_margin)&15]; + if (filters == 9) return xtrans[(row+6) % 6][(col+6) % 6]; + return FC(row,col); +} + +#ifndef HAVE_MEMMEM +const char *memmem (const char *haystack, size_t haystacklen, + const char *needle, size_t needlelen) +{ + const char *c; + for (c = haystack; c <= haystack + haystacklen - needlelen; c++) + if (!memcmp (c, needle, needlelen)) + return c; + return 0; +} +#endif +#ifndef HAVE_STRCASESTR +char *strcasestr (char *haystack, const char *needle) +{ + char *c; + for (c = haystack; *c; c++) + if (!strncasecmp(c, needle, strlen(needle))) + return c; + return 0; +} +#endif + +#ifndef DCRAW_NOMAIN +#include +void CLASS dcraw_message(int code, const char *format, ...) { + if (verbose || code!=DCRAW_VERBOSE) { + va_list ap; + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + } +} +#endif /*DCRAW_NOMAIN*/ + +void CLASS merror (void *ptr, const char *where) +{ + if (ptr) return; + dcraw_message (DCRAW_ERROR,_("%s: Out of memory in %s\n"), ifname_display, where); + longjmp (failure, 1); +} + +void CLASS derror() +{ + if (!data_error) { + dcraw_message (DCRAW_WARNING, "%s: ", ifname_display); + if (feof(ifp)) + dcraw_message (DCRAW_WARNING,_("Unexpected end of file\n")); + else +#ifdef HAVE_FSEEKO + dcraw_message (DCRAW_WARNING,_("Corrupt data near 0x%llx\n"), + (INT64) ftello(ifp)); +#else + dcraw_message (DCRAW_WARNING,_("Corrupt data near 0x%lx\n"), ftell(ifp)); +#endif + } + data_error++; +} + +ushort CLASS sget2 (uchar *s) +{ + if (order == 0x4949) /* "II" means little-endian */ + return s[0] | s[1] << 8; + else /* "MM" means big-endian */ + return s[0] << 8 | s[1]; +} + +ushort CLASS get2() +{ + uchar str[2] = { 0xff,0xff }; + fread (str, 1, 2, ifp); + return sget2(str); +} + +unsigned CLASS sget4 (uchar *s) +{ + if (order == 0x4949) + return s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24; + else + return s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]; +} +#define sget4(s) sget4((uchar *)s) + +unsigned CLASS get4() +{ + uchar str[4] = { 0xff,0xff,0xff,0xff }; + fread (str, 1, 4, ifp); + return sget4(str); +} + +unsigned CLASS getint (int type) +{ + return type == 3 ? get2() : get4(); +} + +float CLASS int_to_float (int i) +{ + union { int i; float f; } u; + u.i = i; + return u.f; +} + +double CLASS getreal (int type) +{ + union { char c[8]; double d; } u; + int i, rev; + + switch (type) { + case 3: return (unsigned short) get2(); + case 4: return (unsigned int) get4(); + case 5: u.d = (unsigned int) get4(); + return u.d / (unsigned int) get4(); + case 8: return (signed short) get2(); + case 9: return (signed int) get4(); + case 10: u.d = (signed int) get4(); + return u.d / (signed int) get4(); + case 11: return int_to_float (get4()); + case 12: + rev = 7 * ((order == 0x4949) == (ntohs(0x1234) == 0x1234)); + for (i=0; i < 8; i++) + u.c[i ^ rev] = fgetc(ifp); + return u.d; + default: return fgetc(ifp); + } +} + +void CLASS read_shorts (ushort *pixel, unsigned count) +{ + if (fread (pixel, 2, count, ifp) < count) derror(); + if ((order == 0x4949) == (ntohs(0x1234) == 0x1234)) +#if defined(__MINGW64_VERSION_MAJOR) && __MINGW64_VERSION_MAJOR < 4 + swab ((char *) pixel, (char *) pixel, count*2); +#else + swab ((const char *) pixel, (char *) pixel, count*2); +#endif +} + +void CLASS cubic_spline (const int *x_, const int *y_, const int len) +{ + float **A, *b, *c, *d, *x, *y; + int i, j; + + A = (float **) calloc (((2*len + 4)*sizeof **A + sizeof *A), 2*len); + if (!A) return; + A[0] = (float *) (A + 2*len); + for (i = 1; i < 2*len; i++) + A[i] = A[0] + 2*len*i; + y = len + (x = i + (d = i + (c = i + (b = A[0] + i*i)))); + for (i = 0; i < len; i++) { + x[i] = x_[i] / 65535.0; + y[i] = y_[i] / 65535.0; + } + for (i = len-1; i > 0; i--) { + b[i] = (y[i] - y[i-1]) / (x[i] - x[i-1]); + d[i-1] = x[i] - x[i-1]; + } + for (i = 1; i < len-1; i++) { + A[i][i] = 2 * (d[i-1] + d[i]); + if (i > 1) { + A[i][i-1] = d[i-1]; + A[i-1][i] = d[i-1]; + } + A[i][len-1] = 6 * (b[i+1] - b[i]); + } + for(i = 1; i < len-2; i++) { + float v = A[i+1][i] / A[i][i]; + for(j = 1; j <= len-1; j++) + A[i+1][j] -= v * A[i][j]; + } + for(i = len-2; i > 0; i--) { + float acc = 0; + for(j = i; j <= len-2; j++) + acc += A[i][j]*c[j]; + c[i] = (A[i][len-1] - acc) / A[i][i]; + } + for (i = 0; i < 0x10000; i++) { + float x_out = (float)(i / 65535.0); + float y_out = 0; + for (j = 0; j < len-1; j++) { + if (x[j] <= x_out && x_out <= x[j+1]) { + float v = x_out - x[j]; + y_out = y[j] + + ((y[j+1] - y[j]) / d[j] - (2 * d[j] * c[j] + c[j+1] * d[j])/6) * v + + (c[j] * 0.5) * v*v + ((c[j+1] - c[j]) / (6 * d[j])) * v*v*v; + } + } + curve[i] = y_out < 0.0 ? 0 : (y_out >= 1.0 ? 65535 : + (ushort)(y_out * 65535.0 + 0.5)); + } + free (A); +} + +void CLASS canon_600_fixed_wb (int temp) +{ + static const short mul[4][5] = { + { 667, 358,397,565,452 }, + { 731, 390,367,499,517 }, + { 1119, 396,348,448,537 }, + { 1399, 485,431,508,688 } }; + int lo, hi, i; + float frac=0; + + for (lo=4; --lo; ) + if (*mul[lo] <= temp) break; + for (hi=0; hi < 3; hi++) + if (*mul[hi] >= temp) break; + if (lo != hi) + frac = (float) (temp - *mul[lo]) / (*mul[hi] - *mul[lo]); + for (i=1; i < 5; i++) + pre_mul[i-1] = 1 / (frac * mul[hi][i] + (1-frac) * mul[lo][i]); +} + +/* Return values: 0 = white 1 = near white 2 = not white */ +int CLASS canon_600_color (int ratio[2], int mar) +{ + int clipped=0, target, miss; + + if (flash_used) { + if (ratio[1] < -104) + { ratio[1] = -104; clipped = 1; } + if (ratio[1] > 12) + { ratio[1] = 12; clipped = 1; } + } else { + if (ratio[1] < -264 || ratio[1] > 461) return 2; + if (ratio[1] < -50) + { ratio[1] = -50; clipped = 1; } + if (ratio[1] > 307) + { ratio[1] = 307; clipped = 1; } + } + target = flash_used || ratio[1] < 197 + ? -38 - (398 * ratio[1] >> 10) + : -123 + (48 * ratio[1] >> 10); + if (target - mar <= ratio[0] && + target + 20 >= ratio[0] && !clipped) return 0; + miss = target - ratio[0]; + if (abs(miss) >= mar*4) return 2; + if (miss < -20) miss = -20; + if (miss > mar) miss = mar; + ratio[0] = target - miss; + return 1; +} + +void CLASS canon_600_auto_wb() +{ + int mar, row, col, i, j, st, count[] = { 0,0 }; + int test[8], total[2][8], ratio[2][2], stat[2]; + + memset (&total, 0, sizeof total); + i = canon_ev + 0.5; + if (i < 10) mar = 150; + else if (i > 12) mar = 20; + else mar = 280 - 20 * i; + if (flash_used) mar = 80; + for (row=14; row < height-14; row+=4) + for (col=10; col < width; col+=2) { + for (i=0; i < 8; i++) + test[(i & 4) + FC(row+(i >> 1),col+(i & 1))] = + BAYER(row+(i >> 1),col+(i & 1)); + for (i=0; i < 8; i++) + if (test[i] < 150 || test[i] > 1500) goto next; + for (i=0; i < 4; i++) + if (abs(test[i] - test[i+4]) > 50) goto next; + for (i=0; i < 2; i++) { + for (j=0; j < 4; j+=2) + ratio[i][j >> 1] = ((test[i*4+j+1]-test[i*4+j]) << 10) / test[i*4+j]; + stat[i] = canon_600_color (ratio[i], mar); + } + if ((st = stat[0] | stat[1]) > 1) goto next; + for (i=0; i < 2; i++) + if (stat[i]) + for (j=0; j < 2; j++) + test[i*4+j*2+1] = test[i*4+j*2] * (0x400 + ratio[i][j]) >> 10; + for (i=0; i < 8; i++) + total[st][i] += test[i]; + count[st]++; +next: ; + } + if (count[0] | count[1]) { + st = count[0]*200 < count[1]; + for (i=0; i < 4; i++) + pre_mul[i] = 1.0 / (total[st][i] + total[st][i+4]); + } +} + +void CLASS canon_600_coeff() +{ + static const short table[6][12] = { + { -190,702,-1878,2390, 1861,-1349,905,-393, -432,944,2617,-2105 }, + { -1203,1715,-1136,1648, 1388,-876,267,245, -1641,2153,3921,-3409 }, + { -615,1127,-1563,2075, 1437,-925,509,3, -756,1268,2519,-2007 }, + { -190,702,-1886,2398, 2153,-1641,763,-251, -452,964,3040,-2528 }, + { -190,702,-1878,2390, 1861,-1349,905,-393, -432,944,2617,-2105 }, + { -807,1319,-1785,2297, 1388,-876,769,-257, -230,742,2067,-1555 } }; + unsigned t=0, i, c; + float mc, yc; + + mc = pre_mul[1] / pre_mul[2]; + yc = pre_mul[3] / pre_mul[2]; + if (mc > 1 && mc <= 1.28 && yc < 0.8789) t=1; + if (mc > 1.28 && mc <= 2) { + if (yc < 0.8789) t=3; + else if (yc <= 2) t=4; + } + if (flash_used) t=5; + for (raw_color = i=0; i < 3; i++) + FORCC rgb_cam[i][c] = table[t][i*4 + c] / 1024.0; +} + +void CLASS canon_600_load_raw() +{ + uchar data[1120], *dp; + ushort *pix; + int irow, row; + + for (irow=row=0; irow < height; irow++) { + if (fread (data, 1, 1120, ifp) < 1120) derror(); + pix = raw_image + row*raw_width; + for (dp=data; dp < data+1120; dp+=10, pix+=8) { + pix[0] = (dp[0] << 2) + (dp[1] >> 6 ); + pix[1] = (dp[2] << 2) + (dp[1] >> 4 & 3); + pix[2] = (dp[3] << 2) + (dp[1] >> 2 & 3); + pix[3] = (dp[4] << 2) + (dp[1] & 3); + pix[4] = (dp[5] << 2) + (dp[9] & 3); + pix[5] = (dp[6] << 2) + (dp[9] >> 2 & 3); + pix[6] = (dp[7] << 2) + (dp[9] >> 4 & 3); + pix[7] = (dp[8] << 2) + (dp[9] >> 6 ); + } + if ((row+=2) > height) row = 1; + } +} + +void CLASS canon_600_correct() +{ + int row, col, val; + static const short mul[4][2] = + { { 1141,1145 }, { 1128,1109 }, { 1178,1149 }, { 1128,1109 } }; + + for (row=0; row < height; row++) + for (col=0; col < width; col++) { + if ((val = BAYER(row,col) - black) < 0) val = 0; + val = val * mul[row & 3][col & 1] >> 9; + BAYER(row,col) = val; + } + canon_600_fixed_wb(1311); + canon_600_auto_wb(); + canon_600_coeff(); + maximum = (0x3ff - black) * 1109 >> 9; + black = 0; +} + +int CLASS canon_s2is() +{ + unsigned row; + + for (row=0; row < 100; row++) { + fseek (ifp, row*3340 + 3284, SEEK_SET); + if (getc(ifp) > 15) return 1; + } + return 0; +} + +unsigned CLASS getbithuff (int nbits, ushort *huff) +{ + // TODO: The following static variables are not thread-safe + static unsigned bitbuf=0; + static int vbits=0, reset=0; + unsigned c; + + if (nbits > 25) return 0; + if (nbits < 0) + return bitbuf = vbits = reset = 0; + if (nbits == 0 || vbits < 0) return 0; + while (!reset && vbits < nbits && (c = fgetc(ifp)) != (unsigned) EOF && + !(reset = zero_after_ff && c == 0xff && fgetc(ifp))) { + bitbuf = (bitbuf << 8) + (uchar) c; + vbits += 8; + } + c = bitbuf << (32-vbits) >> (32-nbits); + if (huff) { + vbits -= huff[c] >> 8; + c = (uchar) huff[c]; + } else + vbits -= nbits; + if (vbits < 0) derror(); + return c; +} + +#define getbits(n) getbithuff(n,0) +#define gethuff(h) getbithuff(*h,h+1) + +/* + Construct a decode tree according the specification in *source. + The first 16 bytes specify how many codes should be 1-bit, 2-bit + 3-bit, etc. Bytes after that are the leaf values. + + For example, if the source is + + { 0,1,4,2,3,1,2,0,0,0,0,0,0,0,0,0, + 0x04,0x03,0x05,0x06,0x02,0x07,0x01,0x08,0x09,0x00,0x0a,0x0b,0xff }, + + then the code is + + 00 0x04 + 010 0x03 + 011 0x05 + 100 0x06 + 101 0x02 + 1100 0x07 + 1101 0x01 + 11100 0x08 + 11101 0x09 + 11110 0x00 + 111110 0x0a + 1111110 0x0b + 1111111 0xff + */ +ushort * CLASS make_decoder_ref (const uchar **source) +{ + int max, len, h, i, j; + const uchar *count; + ushort *huff; + + count = (*source += 16) - 17; + for (max=16; max && !count[max]; max--); + huff = (ushort *) calloc (1 + (1 << max), sizeof *huff); + merror (huff, "make_decoder()"); + huff[0] = max; + for (h=len=1; len <= max; len++) + for (i=0; i < count[len]; i++, ++*source) + for (j=0; j < 1 << (max-len); j++) + if (h <= 1 << max) + huff[h++] = len << 8 | **source; + return huff; +} + +ushort * CLASS make_decoder (const uchar *source) +{ + return make_decoder_ref (&source); +} + +void CLASS crw_init_tables (unsigned table, ushort *huff[2]) +{ + static const uchar first_tree[3][29] = { + { 0,1,4,2,3,1,2,0,0,0,0,0,0,0,0,0, + 0x04,0x03,0x05,0x06,0x02,0x07,0x01,0x08,0x09,0x00,0x0a,0x0b,0xff }, + { 0,2,2,3,1,1,1,1,2,0,0,0,0,0,0,0, + 0x03,0x02,0x04,0x01,0x05,0x00,0x06,0x07,0x09,0x08,0x0a,0x0b,0xff }, + { 0,0,6,3,1,1,2,0,0,0,0,0,0,0,0,0, + 0x06,0x05,0x07,0x04,0x08,0x03,0x09,0x02,0x00,0x0a,0x01,0x0b,0xff }, + }; + static const uchar second_tree[3][180] = { + { 0,2,2,2,1,4,2,1,2,5,1,1,0,0,0,139, + 0x03,0x04,0x02,0x05,0x01,0x06,0x07,0x08, + 0x12,0x13,0x11,0x14,0x09,0x15,0x22,0x00,0x21,0x16,0x0a,0xf0, + 0x23,0x17,0x24,0x31,0x32,0x18,0x19,0x33,0x25,0x41,0x34,0x42, + 0x35,0x51,0x36,0x37,0x38,0x29,0x79,0x26,0x1a,0x39,0x56,0x57, + 0x28,0x27,0x52,0x55,0x58,0x43,0x76,0x59,0x77,0x54,0x61,0xf9, + 0x71,0x78,0x75,0x96,0x97,0x49,0xb7,0x53,0xd7,0x74,0xb6,0x98, + 0x47,0x48,0x95,0x69,0x99,0x91,0xfa,0xb8,0x68,0xb5,0xb9,0xd6, + 0xf7,0xd8,0x67,0x46,0x45,0x94,0x89,0xf8,0x81,0xd5,0xf6,0xb4, + 0x88,0xb1,0x2a,0x44,0x72,0xd9,0x87,0x66,0xd4,0xf5,0x3a,0xa7, + 0x73,0xa9,0xa8,0x86,0x62,0xc7,0x65,0xc8,0xc9,0xa1,0xf4,0xd1, + 0xe9,0x5a,0x92,0x85,0xa6,0xe7,0x93,0xe8,0xc1,0xc6,0x7a,0x64, + 0xe1,0x4a,0x6a,0xe6,0xb3,0xf1,0xd3,0xa5,0x8a,0xb2,0x9a,0xba, + 0x84,0xa4,0x63,0xe5,0xc5,0xf3,0xd2,0xc4,0x82,0xaa,0xda,0xe4, + 0xf2,0xca,0x83,0xa3,0xa2,0xc3,0xea,0xc2,0xe2,0xe3,0xff,0xff }, + { 0,2,2,1,4,1,4,1,3,3,1,0,0,0,0,140, + 0x02,0x03,0x01,0x04,0x05,0x12,0x11,0x06, + 0x13,0x07,0x08,0x14,0x22,0x09,0x21,0x00,0x23,0x15,0x31,0x32, + 0x0a,0x16,0xf0,0x24,0x33,0x41,0x42,0x19,0x17,0x25,0x18,0x51, + 0x34,0x43,0x52,0x29,0x35,0x61,0x39,0x71,0x62,0x36,0x53,0x26, + 0x38,0x1a,0x37,0x81,0x27,0x91,0x79,0x55,0x45,0x28,0x72,0x59, + 0xa1,0xb1,0x44,0x69,0x54,0x58,0xd1,0xfa,0x57,0xe1,0xf1,0xb9, + 0x49,0x47,0x63,0x6a,0xf9,0x56,0x46,0xa8,0x2a,0x4a,0x78,0x99, + 0x3a,0x75,0x74,0x86,0x65,0xc1,0x76,0xb6,0x96,0xd6,0x89,0x85, + 0xc9,0xf5,0x95,0xb4,0xc7,0xf7,0x8a,0x97,0xb8,0x73,0xb7,0xd8, + 0xd9,0x87,0xa7,0x7a,0x48,0x82,0x84,0xea,0xf4,0xa6,0xc5,0x5a, + 0x94,0xa4,0xc6,0x92,0xc3,0x68,0xb5,0xc8,0xe4,0xe5,0xe6,0xe9, + 0xa2,0xa3,0xe3,0xc2,0x66,0x67,0x93,0xaa,0xd4,0xd5,0xe7,0xf8, + 0x88,0x9a,0xd7,0x77,0xc4,0x64,0xe2,0x98,0xa5,0xca,0xda,0xe8, + 0xf3,0xf6,0xa9,0xb2,0xb3,0xf2,0xd2,0x83,0xba,0xd3,0xff,0xff }, + { 0,0,6,2,1,3,3,2,5,1,2,2,8,10,0,117, + 0x04,0x05,0x03,0x06,0x02,0x07,0x01,0x08, + 0x09,0x12,0x13,0x14,0x11,0x15,0x0a,0x16,0x17,0xf0,0x00,0x22, + 0x21,0x18,0x23,0x19,0x24,0x32,0x31,0x25,0x33,0x38,0x37,0x34, + 0x35,0x36,0x39,0x79,0x57,0x58,0x59,0x28,0x56,0x78,0x27,0x41, + 0x29,0x77,0x26,0x42,0x76,0x99,0x1a,0x55,0x98,0x97,0xf9,0x48, + 0x54,0x96,0x89,0x47,0xb7,0x49,0xfa,0x75,0x68,0xb6,0x67,0x69, + 0xb9,0xb8,0xd8,0x52,0xd7,0x88,0xb5,0x74,0x51,0x46,0xd9,0xf8, + 0x3a,0xd6,0x87,0x45,0x7a,0x95,0xd5,0xf6,0x86,0xb4,0xa9,0x94, + 0x53,0x2a,0xa8,0x43,0xf5,0xf7,0xd4,0x66,0xa7,0x5a,0x44,0x8a, + 0xc9,0xe8,0xc8,0xe7,0x9a,0x6a,0x73,0x4a,0x61,0xc7,0xf4,0xc6, + 0x65,0xe9,0x72,0xe6,0x71,0x91,0x93,0xa6,0xda,0x92,0x85,0x62, + 0xf3,0xc5,0xb2,0xa4,0x84,0xba,0x64,0xa5,0xb3,0xd2,0x81,0xe5, + 0xd3,0xaa,0xc4,0xca,0xf2,0xb1,0xe4,0xd1,0x83,0x63,0xea,0xc3, + 0xe2,0x82,0xf1,0xa3,0xc2,0xa1,0xc1,0xe3,0xa2,0xe1,0xff,0xff } + }; + if (table > 2) table = 2; + huff[0] = make_decoder ( first_tree[table]); + huff[1] = make_decoder (second_tree[table]); +} + +/* + Return 0 if the image starts with compressed data, + 1 if it starts with uncompressed low-order bits. + + In Canon compressed data, 0xff is always followed by 0x00. + */ +int CLASS canon_has_lowbits() +{ + uchar test[0x4000]; + unsigned ret=1, i; + + fseek (ifp, 0, SEEK_SET); + fread (test, 1, sizeof test, ifp); + for (i=540; i < int(sizeof test - 1); i++) + if (test[i] == 0xff) { + if (test[i+1]) return 1; + ret=0; + } + return ret; +} + +void CLASS canon_load_raw() +{ + ushort *pixel, *prow, *huff[2]; + int nblocks, lowbits, i, c, row, r, save, val; + int block, diffbuf[64], leaf, len, diff, carry=0, pnum=0, base[2]; + + crw_init_tables (tiff_compress, huff); + lowbits = canon_has_lowbits(); + if (!lowbits) maximum = 0x3ff; + fseek (ifp, 540 + lowbits*raw_height*raw_width/4, SEEK_SET); + zero_after_ff = 1; + getbits(-1); + for (row=0; row < raw_height; row+=8) { + pixel = raw_image + row*raw_width; + nblocks = MIN (8, raw_height-row) * raw_width >> 6; + for (block=0; block < nblocks; block++) { + memset (diffbuf, 0, sizeof diffbuf); + for (i=0; i < 64; i++ ) { + leaf = gethuff(huff[i > 0]); + if (leaf == 0 && i) break; + if (leaf == 0xff) continue; + i += leaf >> 4; + len = leaf & 15; + if (len == 0) continue; + diff = getbits(len); + if ((diff & (1 << (len-1))) == 0) + diff -= (1 << len) - 1; + if (i < 64) diffbuf[i] = diff; + } + diffbuf[0] += carry; + carry = diffbuf[0]; + for (i=0; i < 64; i++ ) { + if (pnum++ % raw_width == 0) + base[0] = base[1] = 512; + if ((pixel[(block << 6) + i] = base[i & 1] += diffbuf[i]) >> 10) + derror(); + } + } + if (lowbits) { + save = ftell(ifp); + fseek (ifp, 26 + row*raw_width/4, SEEK_SET); + for (prow=pixel, i=0; i < raw_width*2; i++) { + c = fgetc(ifp); + for (r=0; r < 8; r+=2, prow++) { + val = (*prow << 2) + ((c >> r) & 3); + if (raw_width == 2672 && val < 512) val += 2; + *prow = val; + } + } + fseek (ifp, save, SEEK_SET); + } + } + FORC(2) free (huff[c]); +} + +struct jhead { + int algo, bits, high, wide, clrs, sraw, psv, restart, vpred[6]; + ushort quant[64], idct[64], *huff[20], *free[20], *row; +}; + +int CLASS ljpeg_start (struct jhead *jh, int info_only) +{ + ushort c, tag, len; + uchar data[0x10000]; + const uchar *dp; + + memset (jh, 0, sizeof *jh); + jh->restart = INT_MAX; + if ((fgetc(ifp),fgetc(ifp)) != 0xd8) return 0; + do { + if (!fread (data, 2, 2, ifp)) return 0; + tag = data[0] << 8 | data[1]; + len = (data[2] << 8 | data[3]); + if (tag <= 0xff00 || len <= 2) return 0; + len -= 2; + fread (data, 1, len, ifp); + switch (tag) { + case 0xffc3: + jh->sraw = ((data[7] >> 4) * (data[7] & 15) - 1) & 3; + case 0xffc1: + case 0xffc0: + jh->algo = tag & 0xff; + jh->bits = data[0]; + jh->high = data[1] << 8 | data[2]; + jh->wide = data[3] << 8 | data[4]; + jh->clrs = data[5] + jh->sraw; + if (len == 9 && !dng_version) getc(ifp); + break; + case 0xffc4: + if (info_only) break; + for (dp = data; dp < data+len && !((c = *dp++) & -20); ) + jh->free[c] = jh->huff[c] = make_decoder_ref (&dp); + break; + case 0xffda: + jh->psv = data[1+data[0]*2]; + jh->bits -= data[3+data[0]*2] & 15; + break; + case 0xffdb: + FORC(64) jh->quant[c] = data[c*2+1] << 8 | data[c*2+2]; + break; + case 0xffdd: + jh->restart = data[0] << 8 | data[1]; + } + } while (tag != 0xffda); + if (jh->bits > 16 || jh->clrs > 6 || + !jh->bits || !jh->high || !jh->wide || !jh->clrs) return 0; + if (info_only) return 1; + if (!jh->huff[0]) return 0; + FORC(19) if (!jh->huff[c+1]) jh->huff[c+1] = jh->huff[c]; + if (jh->sraw) { + FORC(4) jh->huff[2+c] = jh->huff[1]; + FORC(jh->sraw) jh->huff[1+c] = jh->huff[0]; + } + jh->row = (ushort *) calloc (jh->wide*jh->clrs, 16); + merror (jh->row, "ljpeg_start()"); + return zero_after_ff = 1; +} + +void CLASS ljpeg_end (struct jhead *jh) +{ + int c; + FORC4 if (jh->free[c]) free (jh->free[c]); + free (jh->row); +} + +int CLASS ljpeg_diff (ushort *huff) +{ + int len, diff; + + if (!huff) + longjmp(failure, 2); + + len = gethuff(huff); + if (len == 16 && (!dng_version || dng_version >= 0x1010000)) + return -32768; + diff = getbits(len); + if ((diff & (1 << (len-1))) == 0) + diff -= (1 << len) - 1; + return diff; +} + +ushort * CLASS ljpeg_row (int jrow, struct jhead *jh) +{ + int col, c, diff, pred, spred=0; + ushort mark=0, *row[3]; + + if (jrow * jh->wide % jh->restart == 0) { + FORC(6) jh->vpred[c] = 1 << (jh->bits-1); + if (jrow) { + fseek (ifp, -2, SEEK_CUR); + do mark = (mark << 8) + (c = fgetc(ifp)); + while (c != EOF && mark >> 4 != 0xffd); + } + getbits(-1); + } + FORC3 row[c] = jh->row + jh->wide*jh->clrs*((jrow+c) & 1); + for (col=0; col < jh->wide; col++) + FORC(jh->clrs) { + diff = ljpeg_diff (jh->huff[c]); + if (jh->sraw && c <= jh->sraw && (col | c)) + pred = spred; + else if (col) pred = row[0][-jh->clrs]; + else pred = (jh->vpred[c] += diff) - diff; + if (jrow && col) switch (jh->psv) { + case 1: break; + case 2: pred = row[1][0]; break; + case 3: pred = row[1][-jh->clrs]; break; + case 4: pred = pred + row[1][0] - row[1][-jh->clrs]; break; + case 5: pred = pred + ((row[1][0] - row[1][-jh->clrs]) >> 1); break; + case 6: pred = row[1][0] + ((pred - row[1][-jh->clrs]) >> 1); break; + case 7: pred = (pred + row[1][0]) >> 1; break; + default: pred = 0; + } + if ((**row = pred + diff) >> jh->bits) derror(); + if (c <= jh->sraw) spred = **row; + row[0]++; row[1]++; + } + return row[2]; +} + +void CLASS lossless_jpeg_load_raw() +{ + int jwide, jrow, jcol, val, jidx, i, j, row=0, col=0; + struct jhead jh; + ushort *rp; + + if (!ljpeg_start (&jh, 0)) return; + if (jh.wide < 1 || jh.high < 1 || jh.clrs < 1 || jh.bits < 1) + longjmp (failure, 2); + jwide = jh.wide * jh.clrs; + + for (jrow=0; jrow < jh.high; jrow++) { + rp = ljpeg_row (jrow, &jh); + if (load_flags & 1) + row = jrow & 1 ? height-1-jrow/2 : jrow/2; + for (jcol=0; jcol < jwide; jcol++) { + val = curve[*rp++]; + if (cr2_slice[0]) { + jidx = jrow*jwide + jcol; + i = jidx / (cr2_slice[1]*raw_height); + if ((j = i >= cr2_slice[0])) + i = cr2_slice[0]; + jidx -= i * (cr2_slice[1]*raw_height); + row = jidx / cr2_slice[1+j]; + col = jidx % cr2_slice[1+j] + i*cr2_slice[1]; + } + if (raw_width == 3984 && (col -= 2) < 0) + col += (row--,raw_width); + if (row > raw_height) + longjmp (failure, 3); + if ((unsigned) row < raw_height) RAW(row,col) = val; + if (++col >= raw_width) + col = (row++,0); + } + } + ljpeg_end (&jh); +} + +void CLASS canon_sraw_load_raw() +{ + struct jhead jh; + short *rp=0, (*ip)[4]; + int jwide, slice, scol, ecol, row, col, jrow=0, jcol=0, pix[3], c; + int v[3]={0,0,0}, ver, hue; + char *cp; + + if (!ljpeg_start (&jh, 0) || jh.clrs < 4) return; + jwide = (jh.wide >>= 1) * jh.clrs; + + for (ecol=slice=0; slice <= cr2_slice[0]; slice++) { + scol = ecol; + ecol += cr2_slice[1] * 2 / jh.clrs; + if (!cr2_slice[0] || ecol > raw_width-1) ecol = raw_width & -2; + for (row=0; row < height; row += (jh.clrs >> 1) - 1) { + ip = (short (*)[4]) image + row*width; + for (col=scol; col < ecol; col+=2, jcol+=jh.clrs) { + if ((jcol %= jwide) == 0) + rp = (short *) ljpeg_row (jrow++, &jh); + if (col >= width) continue; + FORC (jh.clrs-2) + ip[col + (c >> 1)*width + (c & 1)][0] = rp[jcol+c]; + ip[col][1] = rp[jcol+jh.clrs-2] - 16384; + ip[col][2] = rp[jcol+jh.clrs-1] - 16384; + } + } + } + for (cp=model2; *cp && !isdigit(*cp); cp++); + sscanf (cp, "%d.%d.%d", v, v+1, v+2); + ver = (v[0]*1000 + v[1])*1000 + v[2]; + hue = (jh.sraw+1) << 2; + if (unique_id >= 0x80000281 || (unique_id == 0x80000218 && ver > 1000006)) + hue = jh.sraw << 1; + ip = (short (*)[4]) image; + rp = ip[0]; + for (row=0; row < height; row++, ip+=width) { + if (row & (jh.sraw >> 1)) + for (col=0; col < width; col+=2) + for (c=1; c < 3; c++) + if (row == height-1) + ip[col][c] = ip[col-width][c]; + else ip[col][c] = (ip[col-width][c] + ip[col+width][c] + 1) >> 1; + for (col=1; col < width; col+=2) + for (c=1; c < 3; c++) + if (col == width-1) + ip[col][c] = ip[col-1][c]; + else ip[col][c] = (ip[col-1][c] + ip[col+1][c] + 1) >> 1; + } + for ( ; rp < ip[0]; rp+=4) { + if (unique_id == 0x80000218 || + unique_id == 0x80000250 || + unique_id == 0x80000261 || + unique_id == 0x80000281 || + unique_id == 0x80000287) { + rp[1] = (rp[1] << 2) + hue; + rp[2] = (rp[2] << 2) + hue; + pix[0] = rp[0] + (( 50*rp[1] + 22929*rp[2]) >> 14); + pix[1] = rp[0] + ((-5640*rp[1] - 11751*rp[2]) >> 14); + pix[2] = rp[0] + ((29040*rp[1] - 101*rp[2]) >> 14); + } else { + if (unique_id < 0x80000218) rp[0] -= 512; + pix[0] = rp[0] + rp[2]; + pix[2] = rp[0] + rp[1]; + pix[1] = rp[0] + ((-778*rp[1] - (rp[2] << 11)) >> 12); + } + FORC3 rp[c] = CLIP(pix[c] * sraw_mul[c] >> 10); + } + ljpeg_end (&jh); + maximum = 0x3fff; +} + +void CLASS adobe_copy_pixel (unsigned row, unsigned col, ushort **rp) +{ + unsigned c; + + if (tiff_samples == 2 && shot_select) (*rp)++; + if (raw_image) { + if (row < raw_height && col < raw_width) + RAW(row,col) = curve[**rp]; + *rp += tiff_samples; + } else { + if (row < height && col < width) + FORC(tiff_samples) + image[row*width+col][c] = curve[(*rp)[c]]; + *rp += tiff_samples; + } + if (tiff_samples == 2 && shot_select) (*rp)--; +} + +void CLASS ljpeg_idct (struct jhead *jh) +{ + int c, i, j, len, skip, coef; + float work[3][8][8]; + static float cs[106] = { 0 }; + static const uchar zigzag[80] = + { 0, 1, 8,16, 9, 2, 3,10,17,24,32,25,18,11, 4, 5,12,19,26,33, + 40,48,41,34,27,20,13, 6, 7,14,21,28,35,42,49,56,57,50,43,36, + 29,22,15,23,30,37,44,51,58,59,52,45,38,31,39,46,53,60,61,54, + 47,55,62,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63 }; + + if (!cs[0]) + FORC(106) cs[c] = cos((c & 31)*M_PI/16)/2; + memset (work, 0, sizeof work); + work[0][0][0] = jh->vpred[0] += ljpeg_diff (jh->huff[0]) * jh->quant[0]; + for (i=1; i < 64; i++ ) { + len = gethuff (jh->huff[16]); + i += skip = len >> 4; + if (!(len &= 15) && skip < 15) break; + coef = getbits(len); + if ((coef & (1 << (len-1))) == 0) + coef -= (1 << len) - 1; + ((float *)work)[zigzag[i]] = coef * jh->quant[i]; + } + FORC(8) work[0][0][c] *= M_SQRT1_2; + FORC(8) work[0][c][0] *= M_SQRT1_2; + for (i=0; i < 8; i++) + for (j=0; j < 8; j++) + FORC(8) work[1][i][j] += work[0][i][c] * cs[(j*2+1)*c]; + for (i=0; i < 8; i++) + for (j=0; j < 8; j++) + FORC(8) work[2][i][j] += work[1][c][j] * cs[(i*2+1)*c]; + + FORC(64) jh->idct[c] = CLIP(((float *)work[2])[c]+0.5); +} + +void CLASS lossless_dng_load_raw() +{ + unsigned save, trow=0, tcol=0, jwide, jrow, jcol, row, col, i, j; + struct jhead jh; + ushort *rp; + + while (trow < raw_height) { + save = ftell(ifp); + if (tile_length < INT_MAX) + fseek (ifp, get4(), SEEK_SET); + if (!ljpeg_start (&jh, 0)) break; + jwide = jh.wide; + if (filters) jwide *= jh.clrs; + jwide /= MIN (is_raw, tiff_samples); + switch (jh.algo) { + case 0xc1: + jh.vpred[0] = 16384; + getbits(-1); + for (jrow=0; jrow+7 < (unsigned) jh.high; jrow += 8) { + for (jcol=0; jcol+7 < (unsigned) jh.wide; jcol += 8) { + ljpeg_idct (&jh); + rp = jh.idct; + row = trow + jcol/tile_width + jrow*2; + col = tcol + jcol%tile_width; + for (i=0; i < 16; i+=2) + for (j=0; j < 8; j++) + adobe_copy_pixel (row+i, col+j, &rp); + } + } + break; + case 0xc3: + for (row=col=jrow=0; jrow < (unsigned) jh.high; jrow++) { + rp = ljpeg_row (jrow, &jh); + for (jcol=0; jcol < jwide; jcol++) { + adobe_copy_pixel (trow+row, tcol+col, &rp); + if (++col >= tile_width || col >= raw_width) + row += 1 + (col = 0); + } + } + } + fseek (ifp, save+4, SEEK_SET); + if ((tcol += tile_width) >= raw_width) + trow += tile_length + (tcol = 0); + ljpeg_end (&jh); + } +} + +void CLASS packed_dng_load_raw() +{ + ushort *pixel, *rp; + unsigned row, col; + + pixel = (ushort *) calloc (raw_width, tiff_samples*sizeof *pixel); + merror (pixel, "packed_dng_load_raw()"); + for (row=0; row < raw_height; row++) { + if (tiff_bps == 16) + read_shorts (pixel, raw_width * tiff_samples); + else { + getbits(-1); + for (col=0; col < raw_width * tiff_samples; col++) + pixel[col] = getbits(tiff_bps); + } + for (rp=pixel, col=0; col < raw_width; col++) + adobe_copy_pixel (row, col, &rp); + } + free (pixel); +} + +void CLASS pentax_load_raw() +{ + ushort bit[2][15], huff[4097]; + int dep, row, col, diff, c, i; + ushort vpred[2][2] = {{0,0},{0,0}}, hpred[2]; + + fseek (ifp, meta_offset, SEEK_SET); + dep = (get2() + 12) & 15; + fseek (ifp, 12, SEEK_CUR); + FORC(dep) bit[0][c] = get2(); + FORC(dep) bit[1][c] = fgetc(ifp); + FORC(dep) + for (i=bit[0][c]; i <= ((bit[0][c]+(4096 >> bit[1][c])-1) & 4095); ) + huff[++i] = bit[1][c] << 8 | c; + huff[0] = 12; + fseek (ifp, data_offset, SEEK_SET); + getbits(-1); + for (row=0; row < raw_height; row++) + for (col=0; col < raw_width; col++) { + diff = ljpeg_diff (huff); + if (col < 2) hpred[col] = vpred[row & 1][col] += diff; + else hpred[col & 1] += diff; + RAW(row,col) = hpred[col & 1]; + if (hpred[col & 1] >> tiff_bps) derror(); + } +} + +void CLASS nikon_load_raw() +{ + static const uchar nikon_tree[][32] = { + { 0,1,5,1,1,1,1,1,1,2,0,0,0,0,0,0, /* 12-bit lossy */ + 5,4,3,6,2,7,1,0,8,9,11,10,12 }, + { 0,1,5,1,1,1,1,1,1,2,0,0,0,0,0,0, /* 12-bit lossy after split */ + 0x39,0x5a,0x38,0x27,0x16,5,4,3,2,1,0,11,12,12 }, + { 0,1,4,2,3,1,2,0,0,0,0,0,0,0,0,0, /* 12-bit lossless */ + 5,4,6,3,7,2,8,1,9,0,10,11,12 }, + { 0,1,4,3,1,1,1,1,1,2,0,0,0,0,0,0, /* 14-bit lossy */ + 5,6,4,7,8,3,9,2,1,0,10,11,12,13,14 }, + { 0,1,5,1,1,1,1,1,1,1,2,0,0,0,0,0, /* 14-bit lossy after split */ + 8,0x5c,0x4b,0x3a,0x29,7,6,5,4,3,2,1,0,13,14 }, + { 0,1,4,2,2,3,1,2,0,0,0,0,0,0,0,0, /* 14-bit lossless */ + 7,6,8,5,9,4,10,3,11,12,2,0,1,13,14 } }; + ushort *huff, ver0, ver1, vpred[2][2], hpred[2], csize; + int i, min, max, step=0, tree=0, split=0, row, col, len, shl, diff; + + fseek (ifp, meta_offset, SEEK_SET); + ver0 = fgetc(ifp); + ver1 = fgetc(ifp); + if (ver0 == 0x49 || ver1 == 0x58) + fseek (ifp, 2110, SEEK_CUR); + if (ver0 == 0x46) tree = 2; + if (tiff_bps == 14) tree += 3; + read_shorts (vpred[0], 4); + max = 1 << tiff_bps & 0x7fff; + if ((csize = get2()) > 1) + step = max / (csize-1); + if (ver0 == 0x44 && ver1 == 0x20 && step > 0) { + for (i=0; i < csize; i++) + curve[i*step] = get2(); + for (i=0; i < max; i++) + curve[i] = ( curve[i-i%step]*(step-i%step) + + curve[i-i%step+step]*(i%step) ) / step; + fseek (ifp, meta_offset+562, SEEK_SET); + split = get2(); + } else if (ver0 != 0x46 && csize <= 0x4001) + read_shorts (curve, max=csize); + while (max > 2 && (curve[max-2] == curve[max-1])) max--; + huff = make_decoder (nikon_tree[tree]); + fseek (ifp, data_offset, SEEK_SET); + getbits(-1); + for (min=row=0; row < height; row++) { + if (split && row == split) { + free (huff); + huff = make_decoder (nikon_tree[tree+1]); + max += (min = 16) << 1; + } + for (col=0; col < raw_width; col++) { + i = gethuff(huff); + len = i & 15; + shl = i >> 4; + diff = ((getbits(len-shl) << 1) + 1) << shl >> 1; + if ((diff & (1 << (len-1))) == 0) + diff -= (1 << len) - !shl; + if (col < 2) hpred[col] = vpred[row & 1][col] += diff; + else hpred[col & 1] += diff; + if ((ushort)(hpred[col & 1] + min) >= max) derror(); + RAW(row,col) = curve[LIM((short)hpred[col & 1],0,0x3fff)]; + } + } + free (huff); +} + +void CLASS nikon_yuv_load_raw() +{ + int row, col, yuv[4], rgb[3], b, c; + UINT64 bitbuf=0; + + for (row=0; row < raw_height; row++) + for (col=0; col < raw_width; col++) { + if (!(b = col & 1)) { + bitbuf = 0; + FORC(6) bitbuf |= (UINT64) fgetc(ifp) << c*8; + FORC(4) yuv[c] = (bitbuf >> c*12 & 0xfff) - (c >> 1 << 11); + } + rgb[0] = yuv[b] + 1.370705*yuv[3]; + rgb[1] = yuv[b] - 0.337633*yuv[2] - 0.698001*yuv[3]; + rgb[2] = yuv[b] + 1.732446*yuv[2]; + FORC3 image[row*width+col][c] = curve[LIM(rgb[c],0,0xfff)] / cam_mul[c]; + } +} + +/* + Returns 1 for a Coolpix 995, 0 for anything else. + */ +int CLASS nikon_e995() +{ + int i, histo[256]; + const uchar often[] = { 0x00, 0x55, 0xaa, 0xff }; + + memset (histo, 0, sizeof histo); + fseek (ifp, -2000, SEEK_END); + for (i=0; i < 2000; i++) + histo[fgetc(ifp)]++; + for (i=0; i < 4; i++) + if (histo[often[i]] < 200) + return 0; + return 1; +} + +/* + Returns 1 for a Coolpix 2100, 0 for anything else. + */ +int CLASS nikon_e2100() +{ + uchar t[12]; + int i; + + fseek (ifp, 0, SEEK_SET); + for (i=0; i < 1024; i++) { + fread (t, 1, 12, ifp); + if (((t[2] & t[4] & t[7] & t[9]) >> 4 + & t[1] & t[6] & t[8] & t[11] & 3) != 3) + return 0; + } + return 1; +} + +void CLASS nikon_3700() +{ + unsigned i; + int bits; + uchar dp[24]; + static const struct { + int bits; + char make[12], model[15]; + } table[] = { + { 0x00, "Pentax", "Optio 33WR" }, + { 0x03, "Nikon", "E3200" }, + { 0x32, "Nikon", "E3700" }, + { 0x33, "Olympus", "C740UZ" } }; + + fseek (ifp, 3072, SEEK_SET); + fread (dp, 1, 24, ifp); + bits = (dp[8] & 3) << 4 | (dp[20] & 3); + for (i=0; i < sizeof table / sizeof *table; i++) + if (bits == table[i].bits) { + strcpy (make, table[i].make ); + strcpy (model, table[i].model); + } +} + +/* + Separates a Minolta DiMAGE Z2 from a Nikon E4300. + */ +int CLASS minolta_z2() +{ + unsigned i, nz; + char tail[424]; + + fseek (ifp, -sizeof tail, SEEK_END); + fread (tail, 1, sizeof tail, ifp); + for (nz=i=0; i < sizeof tail; i++) + if (tail[i]) nz++; + return nz > 20; +} + +//void CLASS jpeg_thumb(); + +void CLASS ppm_thumb() +{ + char *thumb; + thumb_length = thumb_width*thumb_height*3; + thumb = (char *) malloc (thumb_length); + merror (thumb, "ppm_thumb()"); + fprintf (ofp, "P6\n%d %d\n255\n", thumb_width, thumb_height); + fread (thumb, 1, thumb_length, ifp); + fwrite (thumb, 1, thumb_length, ofp); + free (thumb); +} + +void CLASS ppm16_thumb() +{ + unsigned i; + char *thumb; + thumb_length = thumb_width*thumb_height*3; + thumb = (char *) calloc (thumb_length, 2); + merror (thumb, "ppm16_thumb()"); + read_shorts ((ushort *) thumb, thumb_length); + for (i=0; i < thumb_length; i++) + thumb[i] = ((ushort *) thumb)[i] >> 8; + fprintf (ofp, "P6\n%d %d\n255\n", thumb_width, thumb_height); + fwrite (thumb, 1, thumb_length, ofp); + free (thumb); +} + +void CLASS layer_thumb() +{ + unsigned i, c; + char *thumb, map[][4] = { "012","102" }; + + colors = thumb_misc >> 5 & 7; + thumb_length = thumb_width*thumb_height; + thumb = (char *) calloc (colors, thumb_length); + merror (thumb, "layer_thumb()"); + fprintf (ofp, "P%d\n%d %d\n255\n", + 5 + (colors >> 1), thumb_width, thumb_height); + fread (thumb, thumb_length, colors, ifp); + for (i=0; i < thumb_length; i++) + FORCC putc (thumb[i+thumb_length*(map[thumb_misc >> 8][c]-'0')], ofp); + free (thumb); +} + +void CLASS rollei_thumb() +{ + unsigned i; + ushort *thumb; + + thumb_length = thumb_width * thumb_height; + thumb = (ushort *) calloc (thumb_length, 2); + merror (thumb, "rollei_thumb()"); + fprintf (ofp, "P6\n%d %d\n255\n", thumb_width, thumb_height); + read_shorts (thumb, thumb_length); + for (i=0; i < thumb_length; i++) { + putc (thumb[i] << 3, ofp); + putc (thumb[i] >> 5 << 2, ofp); + putc (thumb[i] >> 11 << 3, ofp); + } + free (thumb); +} + +void CLASS rollei_load_raw() +{ + uchar pixel[10]; + unsigned iten=0, isix, i, buffer=0, todo[16]; + + isix = raw_width * raw_height * 5 / 8; + while (fread (pixel, 1, 10, ifp) == 10) { + for (i=0; i < 10; i+=2) { + todo[i] = iten++; + todo[i+1] = pixel[i] << 8 | pixel[i+1]; + buffer = pixel[i] >> 2 | buffer << 6; + } + for ( ; i < 16; i+=2) { + todo[i] = isix++; + todo[i+1] = buffer >> (14-i)*5; + } + for (i=0; i < 16; i+=2) + raw_image[todo[i]] = (todo[i+1] & 0x3ff); + } + maximum = 0x3ff; +} + +int CLASS raw (unsigned row, unsigned col) +{ + return (row < raw_height && col < raw_width) ? RAW(row,col) : 0; +} + +void CLASS phase_one_flat_field (int is_float, int nc) +{ + ushort head[8]; + int wide, high, y, x, c, rend, cend, row, col; + float *mrow, num, mult[4]; + + read_shorts (head, 8); + if (head[2] * head[3] * head[4] * head[5] == 0) return; + wide = head[2] / head[4] + (head[2] % head[4] != 0); + high = head[3] / head[5] + (head[3] % head[5] != 0); + mrow = (float *) calloc (nc*wide, sizeof *mrow); + merror (mrow, "phase_one_flat_field()"); + for (y=0; y < high; y++) { + for (x=0; x < wide; x++) + for (c=0; c < nc; c+=2) { + num = is_float ? getreal(11) : get2()/32768.0; + if (y==0) mrow[c*wide+x] = num; + else mrow[(c+1)*wide+x] = (num - mrow[c*wide+x]) / head[5]; + } + if (y==0) continue; + rend = head[1] + y*head[5]; + for (row = rend-head[5]; + row < raw_height && row < rend && + row < head[1]+head[3]-head[5]; row++) { + for (x=1; x < wide; x++) { + for (c=0; c < nc; c+=2) { + mult[c] = mrow[c*wide+x-1]; + mult[c+1] = (mrow[c*wide+x] - mult[c]) / head[4]; + } + cend = head[0] + x*head[4]; + for (col = cend-head[4]; + col < raw_width && + col < cend && col < head[0]+head[2]-head[4]; col++) { + c = nc > 2 ? FC(row-top_margin,col-left_margin) : 0; + if (!(c & 1)) { + c = RAW(row,col) * mult[c]; + RAW(row,col) = LIM(c,0,65535); + } + for (c=0; c < nc; c+=2) + mult[c] += mult[c+1]; + } + } + for (x=0; x < wide; x++) + for (c=0; c < nc; c+=2) + mrow[c*wide+x] += mrow[(c+1)*wide+x]; + } + } + free (mrow); +} + +void CLASS phase_one_correct() +{ + unsigned entries, tag, data, save, col, row, type; + int len, i, j, k, cip, val[4], dev[4], sum, max; + int head[9], diff, mindiff=INT_MAX, off_412=0; + static const signed char dir[12][2] = + { {-1,-1}, {-1,1}, {1,-1}, {1,1}, {-2,0}, {0,-2}, {0,2}, {2,0}, + {-2,-2}, {-2,2}, {2,-2}, {2,2} }; + float poly[8], num, cfrac, frac, mult[2], *yval[2]; + ushort *xval[2]; + int qmult_applied = 0, qlin_applied = 0; + + if (half_size || !meta_length) return; + dcraw_message (DCRAW_VERBOSE,_("Phase One correction...\n")); + fseek (ifp, meta_offset, SEEK_SET); + order = get2(); + fseek (ifp, 6, SEEK_CUR); + fseek (ifp, meta_offset+get4(), SEEK_SET); + entries = get4(); get4(); + while (entries--) { + tag = get4(); + len = get4(); + data = get4(); + save = ftell(ifp); + fseek (ifp, meta_offset+data, SEEK_SET); + if (tag == 0x419) { /* Polynomial curve */ + for (get4(), i=0; i < 8; i++) + poly[i] = getreal(11); + poly[3] += (ph1.tag_210 - poly[7]) * poly[6] + 1; + for (i=0; i < 0x10000; i++) { + num = (poly[5]*i + poly[3])*i + poly[1]; + curve[i] = LIM(num,0,65535); + } goto apply; /* apply to right half */ + } else if (tag == 0x41a) { /* Polynomial curve */ + for (i=0; i < 4; i++) + poly[i] = getreal(11); + for (i=0; i < 0x10000; i++) { + for (num=0, j=4; j--; ) + num = num * i + poly[j]; + curve[i] = LIM(num+i,0,65535); + } apply: /* apply to whole image */ + for (row=0; row < raw_height; row++) + for (col = (tag & 1)*ph1.split_col; col < raw_width; col++) + RAW(row,col) = curve[RAW(row,col)]; + } else if (tag == 0x400) { /* Sensor defects */ + while ((len -= 8) >= 0) { + col = get2(); + row = get2(); + type = get2(); get2(); + if (col >= raw_width) continue; + if (type == 131 || type == 137) /* Bad column */ + for (row=0; row < raw_height; row++) + if (FC(row-top_margin,col-left_margin) == 1) { + for (sum=i=0; i < 4; i++) + sum += val[i] = raw (row+dir[i][0], col+dir[i][1]); + for (max=i=0; i < 4; i++) { + dev[i] = abs((val[i] << 2) - sum); + if (dev[max] < dev[i]) max = i; + } + RAW(row,col) = (sum - val[max])/3.0 + 0.5; + } else { + for (sum=0, i=8; i < 12; i++) + sum += raw (row+dir[i][0], col+dir[i][1]); + RAW(row,col) = 0.5 + sum * 0.0732233 + + (raw(row,col-2) + raw(row,col+2)) * 0.3535534; + } + else if (type == 129) { /* Bad pixel */ + if (row >= raw_height) continue; + j = (FC(row-top_margin,col-left_margin) != 1) * 4; + for (sum=0, i=j; i < j+8; i++) + sum += raw (row+dir[i][0], col+dir[i][1]); + RAW(row,col) = (sum + 4) >> 3; + } + } + } else if (tag == 0x401) { /* All-color flat fields */ + phase_one_flat_field (1, 2); + } else if (tag == 0x416 || tag == 0x410) { + phase_one_flat_field (0, 2); + } else if (tag == 0x40b) { /* Red+blue flat field */ + phase_one_flat_field (0, 4); + } else if (tag == 0x412) { + fseek (ifp, 36, SEEK_CUR); + diff = abs (get2() - ph1.tag_21a); + if (mindiff > diff) { + mindiff = diff; + off_412 = ftell(ifp) - 38; + } + } else if (tag == 0x41f && !qlin_applied) { /* Quadrant linearization */ + ushort lc[2][2][16], ref[16]; + int qr, qc; + for (qr = 0; qr < 2; qr++) + for (qc = 0; qc < 2; qc++) + for (i = 0; i < 16; i++) + lc[qr][qc][i] = get4(); + for (i = 0; i < 16; i++) { + int v = 0; + for (qr = 0; qr < 2; qr++) + for (qc = 0; qc < 2; qc++) + v += lc[qr][qc][i]; + ref[i] = (v + 2) >> 2; + } + for (qr = 0; qr < 2; qr++) { + for (qc = 0; qc < 2; qc++) { + int cx[19], cf[19]; + for (i = 0; i < 16; i++) { + cx[1+i] = lc[qr][qc][i]; + cf[1+i] = ref[i]; + } + cx[0] = cf[0] = 0; + cx[17] = cf[17] = ((unsigned) ref[15] * 65535) / lc[qr][qc][15]; + cx[18] = cf[18] = 65535; + cubic_spline(cx, cf, 19); + for (row = (qr ? ph1.split_row : 0); + (int) row < (qr ? raw_height : ph1.split_row); row++) + for (col = (qc ? ph1.split_col : 0); + (int) col < (qc ? raw_width : ph1.split_col); col++) + RAW(row,col) = curve[RAW(row,col)]; + } + } + qlin_applied = 1; + } else if (tag == 0x41e && !qmult_applied) { /* Quadrant multipliers */ + float qmult[2][2] = { { 1, 1 }, { 1, 1 } }; + get4(); get4(); get4(); get4(); + qmult[0][0] = 1.0 + getreal(11); + get4(); get4(); get4(); get4(); get4(); + qmult[0][1] = 1.0 + getreal(11); + get4(); get4(); get4(); + qmult[1][0] = 1.0 + getreal(11); + get4(); get4(); get4(); + qmult[1][1] = 1.0 + getreal(11); + for (row=0; row < raw_height; row++) + for (col=0; col < raw_width; col++) { + i = qmult[(int) row >= ph1.split_row][(int) col >= ph1.split_col] * RAW(row,col); + RAW(row,col) = LIM(i,0,65535); + } + qmult_applied = 1; + } else if (tag == 0x431 && !qmult_applied) { /* Quadrant combined */ + ushort lc[2][2][7], ref[7]; + int qr, qc; + for (i = 0; i < 7; i++) + ref[i] = get4(); + for (qr = 0; qr < 2; qr++) + for (qc = 0; qc < 2; qc++) + for (i = 0; i < 7; i++) + lc[qr][qc][i] = get4(); + for (qr = 0; qr < 2; qr++) { + for (qc = 0; qc < 2; qc++) { + int cx[9], cf[9]; + for (i = 0; i < 7; i++) { + cx[1+i] = ref[i]; + cf[1+i] = ((unsigned) ref[i] * lc[qr][qc][i]) / 10000; + } + cx[0] = cf[0] = 0; + cx[8] = cf[8] = 65535; + cubic_spline(cx, cf, 9); + for (row = (qr ? ph1.split_row : 0); + (int) row < (qr ? raw_height : ph1.split_row); row++) + for (col = (qc ? ph1.split_col : 0); + (int) col < (qc ? raw_width : ph1.split_col); col++) + RAW(row,col) = curve[RAW(row,col)]; + } + } + qmult_applied = 1; + qlin_applied = 1; + } + fseek (ifp, save, SEEK_SET); + } + if (off_412) { + fseek (ifp, off_412, SEEK_SET); + for (i=0; i < 9; i++) head[i] = get4() & 0x7fff; + yval[0] = (float *) calloc (head[1]*head[3] + head[2]*head[4], 6); + merror (yval[0], "phase_one_correct()"); + yval[1] = (float *) (yval[0] + head[1]*head[3]); + xval[0] = (ushort *) (yval[1] + head[2]*head[4]); + xval[1] = (ushort *) (xval[0] + head[1]*head[3]); + get2(); + for (i=0; i < 2; i++) + for (j=0; j < head[i+1]*head[i+3]; j++) + yval[i][j] = getreal(11); + for (i=0; i < 2; i++) + for (j=0; j < head[i+1]*head[i+3]; j++) + xval[i][j] = get2(); + for (row=0; row < raw_height; row++) + for (col=0; col < raw_width; col++) { + cfrac = (float) col * head[3] / raw_width; + cfrac -= cip = cfrac; + num = RAW(row,col) * 0.5; + for (i=cip; i < cip+2; i++) { + for (k=j=0; j < head[1]; j++) + if (num < xval[0][k = head[1]*i+j]) break; + frac = (j == 0 || j == head[1]) ? 0 : + (xval[0][k] - num) / (xval[0][k] - xval[0][k-1]); + mult[i-cip] = yval[0][k-1] * frac + yval[0][k] * (1-frac); + } + i = ((mult[0] * (1-cfrac) + mult[1] * cfrac) * row + num) * 2; + RAW(row,col) = LIM(i,0,65535); + } + free (yval[0]); + } +} + +void CLASS phase_one_load_raw() +{ + int a, b, i; + ushort akey, bkey, mask; + + fseek (ifp, ph1.key_off, SEEK_SET); + akey = get2(); + bkey = get2(); + mask = ph1.format == 1 ? 0x5555:0x1354; + fseek (ifp, data_offset, SEEK_SET); + read_shorts (raw_image, raw_width*raw_height); + if (ph1.format) + for (i=0; i < raw_width*raw_height; i+=2) { + a = raw_image[i+0] ^ akey; + b = raw_image[i+1] ^ bkey; + raw_image[i+0] = (a & mask) | (b & ~mask); + raw_image[i+1] = (b & mask) | (a & ~mask); + } +} + +unsigned CLASS ph1_bithuff (int nbits, ushort *huff) +{ + // TODO: The following static variables are not thread-safe + static UINT64 bitbuf=0; + static int vbits=0; + unsigned c; + + if (nbits == -1) + return bitbuf = vbits = 0; + if (nbits == 0) return 0; + if (vbits < nbits) { + bitbuf = bitbuf << 32 | get4(); + vbits += 32; + } + c = bitbuf << (64-vbits) >> (64-nbits); + if (huff) { + vbits -= huff[c] >> 8; + return (uchar) huff[c]; + } + vbits -= nbits; + return c; +} +#define ph1_bits(n) ph1_bithuff(n,0) +#define ph1_huff(h) ph1_bithuff(*h,h+1) + +void CLASS phase_one_load_raw_c() +{ + static const int length[] = { 8,7,6,9,11,10,5,12,14,13 }; + int *offset, len[2], pred[2], row, col, i, j; + ushort *pixel; + short (*cblack)[2], (*rblack)[2]; + + pixel = (ushort *) calloc (raw_width*3 + raw_height*4, 2); + merror (pixel, "phase_one_load_raw_c()"); + offset = (int *) (pixel + raw_width); + fseek (ifp, strip_offset, SEEK_SET); + for (row=0; row < raw_height; row++) + offset[row] = get4(); + cblack = (short (*)[2]) (offset + raw_height); + fseek (ifp, ph1.black_col, SEEK_SET); + if (ph1.black_col) + read_shorts ((ushort *) cblack[0], raw_height*2); + rblack = cblack + raw_height; + fseek (ifp, ph1.black_row, SEEK_SET); + if (ph1.black_row) + read_shorts ((ushort *) rblack[0], raw_width*2); + for (i=0; i < 256; i++) + curve[i] = i*i / 3.969 + 0.5; + for (row=0; row < raw_height; row++) { + fseek (ifp, data_offset + offset[row], SEEK_SET); + ph1_bits(-1); + pred[0] = pred[1] = 0; + for (col=0; col < raw_width; col++) { + if (col >= (raw_width & -8)) + len[0] = len[1] = 14; + else if ((col & 7) == 0) + for (i=0; i < 2; i++) { + for (j=0; j < 5 && !ph1_bits(1); j++); + if (j--) len[i] = length[j*2 + ph1_bits(1)]; + } + if ((i = len[col & 1]) == 14) + pixel[col] = pred[col & 1] = ph1_bits(16); + else + pixel[col] = pred[col & 1] += ph1_bits(i) + 1 - (1 << (i - 1)); + if (pred[col & 1] >> 16) derror(); + if (ph1.format == 5 && pixel[col] < 256) + pixel[col] = curve[pixel[col]]; + } + for (col=0; col < raw_width; col++) { + i = (pixel[col] << 2*(ph1.format != 8)) - ph1.black + + cblack[row][col >= ph1.split_col] + + rblack[col][row >= ph1.split_row]; + if (i > 0) RAW(row,col) = i; + } + } + free (pixel); + maximum = 0xfffc - ph1.black; +} + +void CLASS hasselblad_load_raw() +{ + struct jhead jh; + int shot, row, col, *back[5], len[2], diff[12], pred, sh, f, s, c; + unsigned upix, urow, ucol; + ushort *ip; + + if (!ljpeg_start (&jh, 0)) return; + order = 0x4949; + ph1_bits(-1); + back[4] = (int *) calloc (raw_width, 3*sizeof **back); + merror (back[4], "hasselblad_load_raw()"); + FORC3 back[c] = back[4] + c*raw_width; + cblack[6] >>= sh = tiff_samples > 1; + shot = LIM(shot_select, 1, tiff_samples) - 1; + for (row=0; row < raw_height; row++) { + FORC4 back[(c+3) & 3] = back[c]; + for (col=0; col < raw_width; col+=2) { + for (s=0; s < (int) tiff_samples*2; s+=2) { + FORC(2) len[c] = ph1_huff(jh.huff[0]); + FORC(2) { + diff[s+c] = ph1_bits(len[c]); + if ((diff[s+c] & (1 << (len[c]-1))) == 0) + diff[s+c] -= (1 << len[c]) - 1; + if (diff[s+c] == 65535) diff[s+c] = -32768; + } + } + for (s=col; s < col+2; s++) { + pred = 0x8000 + load_flags; + if (col) pred = back[2][s-2]; + if (col && row > 1) switch (jh.psv) { + case 11: pred += back[0][s]/2 - back[0][s-2]/2; break; + } + f = (row & 1)*3 ^ ((col+s) & 1); + FORC ((int) tiff_samples) { + pred += diff[(s & 1)*tiff_samples+c]; + upix = pred >> sh & 0xffff; + if (raw_image && c == shot) + RAW(row,s) = upix; + if (image) { + urow = row-top_margin + (c & 1); + ucol = col-left_margin - ((c >> 1) & 1); + ip = &image[urow*width+ucol][f]; + if (urow < height && ucol < width) + *ip = c < 4 ? upix : (*ip + upix) >> 1; + } + } + back[2][s] = pred; + } + } + } + free (back[4]); + ljpeg_end (&jh); + if (image) mix_green = 1; +} + +void CLASS leaf_hdr_load_raw() +{ + ushort *pixel=0; + unsigned tile=0, r, c, row, col; + + if (!filters) { + pixel = (ushort *) calloc (raw_width, sizeof *pixel); + merror (pixel, "leaf_hdr_load_raw()"); + } + FORC(tiff_samples) + for (r=0; r < raw_height; r++) { + if (r % tile_length == 0) { + fseek (ifp, data_offset + 4*tile++, SEEK_SET); + fseek (ifp, get4(), SEEK_SET); + } + if (filters && c != shot_select) continue; + if (filters) pixel = raw_image + r*raw_width; + read_shorts (pixel, raw_width); + if (!filters && (row = r - top_margin) < height) + for (col=0; col < width; col++) + image[row*width+col][c] = pixel[col+left_margin]; + } + if (!filters) { + maximum = 0xffff; + raw_color = 1; + free (pixel); + } +} + +void CLASS unpacked_load_raw() +{ + int row, col, bits=0; + + while ((unsigned) 1 << ++bits < maximum); + read_shorts (raw_image, raw_width*raw_height - (fuji_layout && shot_select ? raw_width >> 1 : 0)); + for (row=0; row < raw_height; row++) + for (col=0; col < raw_width; col++) + if ((RAW(row,col) >>= load_flags) >> bits + && (unsigned) (row-top_margin) < height + && (unsigned) (col-left_margin) < width) derror(); +} + +void CLASS sinar_4shot_load_raw() +{ + ushort *pixel; + unsigned shot, row, col, r, c; + + if (raw_image) { + shot = LIM (shot_select, 1, 4) - 1; + fseek (ifp, data_offset + shot*4, SEEK_SET); + fseek (ifp, get4(), SEEK_SET); + unpacked_load_raw(); + return; + } + pixel = (ushort *) calloc (raw_width, sizeof *pixel); + merror (pixel, "sinar_4shot_load_raw()"); + for (shot=0; shot < 4; shot++) { + fseek (ifp, data_offset + shot*4, SEEK_SET); + fseek (ifp, get4(), SEEK_SET); + for (row=0; row < raw_height; row++) { + read_shorts (pixel, raw_width); + if ((r = row-top_margin - (shot >> 1 & 1)) >= height) continue; + for (col=0; col < raw_width; col++) { + if ((c = col-left_margin - (shot & 1)) >= width) continue; + image[r*width+c][(row & 1)*3 ^ (~col & 1)] = pixel[col]; + } + } + } + free (pixel); + mix_green = 1; +} + +void CLASS imacon_full_load_raw() +{ + int row, col; + + if (!image) return; + for (row=0; row < height; row++) + for (col=0; col < width; col++) + read_shorts (image[row*width+col], 3); +} + +void CLASS packed_load_raw() +{ + int vbits=0, bwide, rbits, bite, half, irow, row, col, val, i; + UINT64 bitbuf=0; + + bwide = raw_width * tiff_bps / 8; + bwide += bwide & load_flags >> 9; + rbits = bwide * 8 - raw_width * tiff_bps; + if (load_flags & 1) bwide = bwide * 16 / 15; + bite = 8 + (load_flags & 56); + half = (raw_height+1) >> 1; + for (irow=0; irow < raw_height; irow++) { + row = irow; + if (load_flags & 2 && + (row = irow % half * 2 + irow / half) == 1 && + load_flags & 4) { + if (vbits=0, tiff_compress) + fseek (ifp, data_offset - (-half*bwide & -2048), SEEK_SET); + else { + fseek (ifp, 0, SEEK_END); + fseek (ifp, ftell(ifp) >> 3 << 2, SEEK_SET); + } + } + for (col=0; col < raw_width; col++) { + for (vbits -= tiff_bps; vbits < 0; vbits += bite) { + bitbuf <<= bite; + for (i=0; i < bite; i+=8) + bitbuf |= ((UINT64) fgetc(ifp) << i); + } + val = bitbuf << (64-tiff_bps-vbits) >> (64-tiff_bps); + RAW(row,col ^ (load_flags >> 6 & 3)) = val; + if (load_flags & 1 && (col % 10) == 9 && fgetc(ifp) && + row < height+top_margin && col < width+left_margin) derror(); + } + vbits -= rbits; + } +} + +void CLASS nokia_load_raw() +{ + uchar *data, *dp; + int rev, dwide, row, col, c; + double sum[]={0,0}; + + rev = 3 * (order == 0x4949); + dwide = (raw_width * 5 + 1) / 4; + data = (uchar *) malloc (dwide*2); + merror (data, "nokia_load_raw()"); + for (row=0; row < raw_height; row++) { + if ((int) fread (data+dwide, 1, dwide, ifp) < dwide) derror(); + FORC(dwide) data[c] = data[dwide+(c ^ rev)]; + for (dp=data, col=0; col < raw_width; dp+=5, col+=4) + FORC4 RAW(row,col+c) = (dp[c] << 2) | (dp[4] >> (c << 1) & 3); + } + free (data); + maximum = 0x3ff; + if (strcmp(make,"OmniVision")) return; + row = raw_height/2; + FORC(width-1) { + sum[ c & 1] += SQR(RAW(row,c)-RAW(row+1,c+1)); + sum[~c & 1] += SQR(RAW(row+1,c)-RAW(row,c+1)); + } + if (sum[1] > sum[0]) filters = 0x4b4b4b4b; +} + +void CLASS canon_rmf_load_raw() +{ + int row, col, bits, orow, ocol, c; + + for (row=0; row < raw_height; row++) + for (col=0; col < raw_width-2; col+=3) { + bits = get4(); + FORC3 { + orow = row; + if ((ocol = col+c-4) < 0) { + ocol += raw_width; + if ((orow -= 2) < 0) + orow += raw_height; + } + RAW(orow,ocol) = curve[bits >> (10*c+2) & 0x3ff]; + } + } + maximum = curve[0x3ff]; +} + +unsigned CLASS pana_bits (int nbits) +{ + static uchar buf[0x4000]; + static int vbits; + int byte; + + if (!nbits) return vbits=0; + if (!vbits) { + fread (buf+load_flags, 1, 0x4000-load_flags, ifp); + fread (buf, 1, load_flags, ifp); + } + vbits = (vbits - nbits) & 0x1ffff; + byte = vbits >> 3 ^ 0x3ff0; + return (buf[byte] | buf[byte+1] << 8) >> (vbits & 7) & ~(-1 << nbits); +} + +void CLASS panasonic_load_raw() +{ + int row, col, i, j, sh=0, pred[2], nonz[2]; + + pana_bits(0); + for (row=0; row < height; row++) + for (col=0; col < raw_width; col++) { + if ((i = col % 14) == 0) + pred[0] = pred[1] = nonz[0] = nonz[1] = 0; + if (i % 3 == 2) sh = 4 >> (3 - pana_bits(2)); + if (nonz[i & 1]) { + if ((j = pana_bits(8))) { + if ((pred[i & 1] -= 0x80 << sh) < 0 || sh == 4) + pred[i & 1] &= ~(-1 << sh); + pred[i & 1] += j << sh; + } + } else if ((nonz[i & 1] = pana_bits(8)) || i > 11) + pred[i & 1] = nonz[i & 1] << 4 | pana_bits(4); + if ((RAW(row,col) = pred[col & 1]) > 4098 && col < width) derror(); + } +} + +void CLASS olympus_load_raw() +{ + ushort huff[4096]; + int row, col, nbits, sign, low, high, i, c, w, n, nw; + int acarry[2][3], *carry, pred, diff; + + huff[n=0] = 0xc0c; + for (i=12; i--; ) + FORC(2048 >> i) huff[++n] = (i+1) << 8 | i; + fseek (ifp, 7, SEEK_CUR); + getbits(-1); + for (row=0; row < height; row++) { + memset (acarry, 0, sizeof acarry); + for (col=0; col < raw_width; col++) { + carry = acarry[col & 1]; + i = 2 * (carry[2] < 3); + for (nbits=2+i; (ushort) carry[0] >> (nbits+i); nbits++); + low = (sign = getbits(3)) & 3; + sign = sign << 29 >> 31; + if ((high = getbithuff(12,huff)) == 12) + high = getbits(16-nbits) >> 1; + carry[0] = (high << nbits) | getbits(nbits); + diff = (carry[0] ^ sign) + carry[1]; + carry[1] = (diff*3 + carry[1]) >> 5; + carry[2] = carry[0] > 16 ? 0 : carry[2]+1; + if (col >= width) continue; + if (row < 2 && col < 2) pred = 0; + else if (row < 2) pred = RAW(row,col-2); + else if (col < 2) pred = RAW(row-2,col); + else { + w = RAW(row,col-2); + n = RAW(row-2,col); + nw = RAW(row-2,col-2); + if ((w < nw && nw < n) || (n < nw && nw < w)) { + if (ABS(w-nw) > 32 || ABS(n-nw) > 32) + pred = w + n - nw; + else pred = (w + n) >> 1; + } else pred = ABS(w-nw) > ABS(n-nw) ? w : n; + } + if ((RAW(row,col) = pred + ((diff << 2) | low)) >> 12) derror(); + } + } +} + +void CLASS canon_crx_load_raw() +{ +} + +void CLASS fuji_xtrans_load_raw() +{ +} + +void CLASS minolta_rd175_load_raw() +{ + uchar pixel[768]; + unsigned irow, box, row, col; + + for (irow=0; irow < 1481; irow++) { + if (fread (pixel, 1, 768, ifp) < 768) derror(); + box = irow / 82; + row = irow % 82 * 12 + ((box < 12) ? box | 1 : (box-12)*2); + switch (irow) { + case 1477: case 1479: continue; + case 1476: row = 984; break; + case 1480: row = 985; break; + case 1478: row = 985; box = 1; + } + if ((box < 12) && (box & 1)) { + for (col=0; col < 1533; col++, row ^= 1) + if (col != 1) RAW(row,col) = (col+1) & 2 ? + pixel[col/2-1] + pixel[col/2+1] : pixel[col/2] << 1; + RAW(row,1) = pixel[1] << 1; + RAW(row,1533) = pixel[765] << 1; + } else + for (col=row & 1; col < 1534; col+=2) + RAW(row,col) = pixel[col/2] << 1; + } + maximum = 0xff << 1; +} + +void CLASS quicktake_100_load_raw() +{ + uchar pixel[484][644]; + static const short gstep[16] = + { -89,-60,-44,-32,-22,-15,-8,-2,2,8,15,22,32,44,60,89 }; + static const short rstep[6][4] = + { { -3,-1,1,3 }, { -5,-1,1,5 }, { -8,-2,2,8 }, + { -13,-3,3,13 }, { -19,-4,4,19 }, { -28,-6,6,28 } }; + static const short curve[256] = + { 0,1,2,3,4,5,6,7,8,9,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27, + 28,29,30,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,53, + 54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,74,75,76,77,78, + 79,80,81,82,83,84,86,88,90,92,94,97,99,101,103,105,107,110,112,114,116, + 118,120,123,125,127,129,131,134,136,138,140,142,144,147,149,151,153,155, + 158,160,162,164,166,168,171,173,175,177,179,181,184,186,188,190,192,195, + 197,199,201,203,205,208,210,212,214,216,218,221,223,226,230,235,239,244, + 248,252,257,261,265,270,274,278,283,287,291,296,300,305,309,313,318,322, + 326,331,335,339,344,348,352,357,361,365,370,374,379,383,387,392,396,400, + 405,409,413,418,422,426,431,435,440,444,448,453,457,461,466,470,474,479, + 483,487,492,496,500,508,519,531,542,553,564,575,587,598,609,620,631,643, + 654,665,676,687,698,710,721,732,743,754,766,777,788,799,810,822,833,844, + 855,866,878,889,900,911,922,933,945,956,967,978,989,1001,1012,1023 }; + int rb, row, col, sharp, val=0; + + getbits(-1); + memset (pixel, 0x80, sizeof pixel); + for (row=2; row < height+2; row++) { + for (col=2+(row & 1); col < width+2; col+=2) { + val = ((pixel[row-1][col-1] + 2*pixel[row-1][col+1] + + pixel[row][col-2]) >> 2) + gstep[getbits(4)]; + pixel[row][col] = val = LIM(val,0,255); + if (col < 4) + pixel[row][col-2] = pixel[row+1][~row & 1] = val; + if (row == 2) + pixel[row-1][col+1] = pixel[row-1][col+3] = val; + } + pixel[row][col] = val; + } + for (rb=0; rb < 2; rb++) + for (row=2+rb; row < height+2; row+=2) + for (col=3-(row & 1); col < width+2; col+=2) { + if (row < 4 || col < 4) sharp = 2; + else { + val = ABS(pixel[row-2][col] - pixel[row][col-2]) + + ABS(pixel[row-2][col] - pixel[row-2][col-2]) + + ABS(pixel[row][col-2] - pixel[row-2][col-2]); + sharp = val < 4 ? 0 : val < 8 ? 1 : val < 16 ? 2 : + val < 32 ? 3 : val < 48 ? 4 : 5; + } + val = ((pixel[row-2][col] + pixel[row][col-2]) >> 1) + + rstep[sharp][getbits(2)]; + pixel[row][col] = val = LIM(val,0,255); + if (row < 4) pixel[row-2][col+2] = val; + if (col < 4) pixel[row+2][col-2] = val; + } + for (row=2; row < height+2; row++) + for (col=3-(row & 1); col < width+2; col+=2) { + val = ((pixel[row][col-1] + (pixel[row][col] << 2) + + pixel[row][col+1]) >> 1) - 0x100; + pixel[row][col] = LIM(val,0,255); + } + for (row=0; row < height; row++) + for (col=0; col < width; col++) + RAW(row,col) = curve[pixel[row+2][col+2]]; + maximum = 0x3ff; +} + +#define radc_token(tree) ((signed char) getbithuff(8,huff[tree])) + +#define FORYX for (y=1; y < 3; y++) for (x=col+1; x >= col; x--) + +#define PREDICTOR (c ? (buf[c][y-1][x] + buf[c][y][x+1]) / 2 \ +: (buf[c][y-1][x+1] + 2*buf[c][y-1][x] + buf[c][y][x+1]) / 4) + +void CLASS kodak_radc_load_raw() +{ + static const signed char src[] = { + 1,1, 2,3, 3,4, 4,2, 5,7, 6,5, 7,6, 7,8, + 1,0, 2,1, 3,3, 4,4, 5,2, 6,7, 7,6, 8,5, 8,8, + 2,1, 2,3, 3,0, 3,2, 3,4, 4,6, 5,5, 6,7, 6,8, + 2,0, 2,1, 2,3, 3,2, 4,4, 5,6, 6,7, 7,5, 7,8, + 2,1, 2,4, 3,0, 3,2, 3,3, 4,7, 5,5, 6,6, 6,8, + 2,3, 3,1, 3,2, 3,4, 3,5, 3,6, 4,7, 5,0, 5,8, + 2,3, 2,6, 3,0, 3,1, 4,4, 4,5, 4,7, 5,2, 5,8, + 2,4, 2,7, 3,3, 3,6, 4,1, 4,2, 4,5, 5,0, 5,8, + 2,6, 3,1, 3,3, 3,5, 3,7, 3,8, 4,0, 5,2, 5,4, + 2,0, 2,1, 3,2, 3,3, 4,4, 4,5, 5,6, 5,7, 4,8, + 1,0, 2,2, 2,-2, + 1,-3, 1,3, + 2,-17, 2,-5, 2,5, 2,17, + 2,-7, 2,2, 2,9, 2,18, + 2,-18, 2,-9, 2,-2, 2,7, + 2,-28, 2,28, 3,-49, 3,-9, 3,9, 4,49, 5,-79, 5,79, + 2,-1, 2,13, 2,26, 3,39, 4,-16, 5,55, 6,-37, 6,76, + 2,-26, 2,-13, 2,1, 3,-39, 4,16, 5,-55, 6,-76, 6,37 + }; + ushort huff[19][256]; + int row, col, tree, nreps, rep, step, i, c, s, r, x, y, val; + short last[3] = { 16,16,16 }, mul[3], buf[3][3][386]; + static const ushort pt[] = + { 0,0, 1280,1344, 2320,3616, 3328,8000, 4095,16383, 65535,16383 }; + + for (i=2; i < 12; i+=2) + for (c=pt[i-2]; c <= pt[i]; c++) + curve[c] = (float) + (c-pt[i-2]) / (pt[i]-pt[i-2]) * (pt[i+1]-pt[i-1]) + pt[i-1] + 0.5; + for (s=i=0; i < (int) sizeof src; i+=2) + FORC(256 >> src[i]) + ((ushort *)huff)[s++] = src[i] << 8 | (uchar) src[i+1]; + s = kodak_cbpp == 243 ? 2 : 3; + FORC(256) huff[18][c] = (8-s) << 8 | c >> s << s | 1 << (s-1); + getbits(-1); + for (i=0; i < (int) sizeof(buf)/(int) sizeof(short); i++) + ((short *)buf)[i] = 2048; + for (row=0; row < height; row+=4) { + FORC3 mul[c] = getbits(6); + FORC3 { + val = ((0x1000000/last[c] + 0x7ff) >> 12) * mul[c]; + s = val > 65564 ? 10:12; + x = ~(-1 << (s-1)); + val <<= 12-s; + for (i=0; i < (int) sizeof(buf[0])/(int) sizeof(short); i++) + ((short *)buf[c])[i] = (((short *)buf[c])[i] * val + x) >> s; + last[c] = mul[c]; + for (r=0; r <= !c; r++) { + buf[c][1][width/2] = buf[c][2][width/2] = mul[c] << 7; + for (tree=1, col=width/2; col > 0; ) { + if ((tree = radc_token(tree))) { + col -= 2; + if (tree == 8) + FORYX buf[c][y][x] = (uchar) radc_token(18) * mul[c]; + else + FORYX buf[c][y][x] = radc_token(tree+10) * 16 + PREDICTOR; + } else + do { + nreps = (col > 2) ? radc_token(9) + 1 : 1; + for (rep=0; rep < 8 && rep < nreps && col > 0; rep++) { + col -= 2; + FORYX buf[c][y][x] = PREDICTOR; + if (rep & 1) { + step = radc_token(10) << 4; + FORYX buf[c][y][x] += step; + } + } + } while (nreps == 9); + } + for (y=0; y < 2; y++) + for (x=0; x < width/2; x++) { + val = (buf[c][y+1][x] << 4) / mul[c]; + if (val < 0) val = 0; + if (c) RAW(row+y*2+c-1,x*2+2-c) = val; + else RAW(row+r*2+y,x*2+y) = val; + } + memcpy (buf[c][0]+!c, buf[c][2], sizeof buf[c][0]-2*!c); + } + } + for (y=row; y < row+4; y++) + for (x=0; x < width; x++) + if ((x+y) & 1) { + r = x ? x-1 : x+1; + s = x+1 < width ? x+1 : x-1; + val = (RAW(y,x)-2048)*2 + (RAW(y,r)+RAW(y,s))/2; + if (val < 0) val = 0; + RAW(y,x) = val; + } + } + for (i=0; i < height*width; i++) + raw_image[i] = curve[raw_image[i]]; + maximum = 0x3fff; +} + +#undef FORYX +#undef PREDICTOR + +#ifndef HAVE_LIBJPEG +void CLASS kodak_jpeg_load_raw() {} +void CLASS lossy_dng_load_raw() {} +#else + +METHODDEF(boolean) +fill_input_buffer (j_decompress_ptr cinfo) +{ + // TODO: The following static variable is not thread-safe + static uchar jpeg_buffer[4096]; + size_t nbytes; + DCRaw *d = (DCRaw*)cinfo->client_data; + + nbytes = fread (jpeg_buffer, 1, 4096, d->ifp); +#if defined(__MINGW64_VERSION_MAJOR) && __MINGW64_VERSION_MAJOR < 4 + swab ((char *) jpeg_buffer, (char *) jpeg_buffer, nbytes); +#else + swab ((const char *) jpeg_buffer, (char *) jpeg_buffer, nbytes); +#endif + cinfo->src->next_input_byte = jpeg_buffer; + cinfo->src->bytes_in_buffer = nbytes; + return boolean(TRUE); +} + +void CLASS kodak_jpeg_load_raw() +{ + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + JSAMPARRAY buf; + JSAMPLE (*pixel)[3]; + int row, col; + + cinfo.err = jpeg_std_error (&jerr); + cinfo.client_data = this; + jpeg_create_decompress (&cinfo); + jpeg_stdio_src (&cinfo, ifp); + cinfo.src->fill_input_buffer = fill_input_buffer; + jpeg_read_header (&cinfo, boolean(TRUE)); + jpeg_start_decompress (&cinfo); + if ((cinfo.output_width != width ) || + (cinfo.output_height*2 != height ) || + (cinfo.output_components != 3 )) { + dcraw_message (DCRAW_ERROR,_("%s: incorrect JPEG dimensions\n"), ifname_display); + jpeg_destroy_decompress (&cinfo); + longjmp (failure, 3); + } + buf = (*cinfo.mem->alloc_sarray) + ((j_common_ptr) &cinfo, JPOOL_IMAGE, width*3, 1); + + while (cinfo.output_scanline < cinfo.output_height) { + row = cinfo.output_scanline * 2; + jpeg_read_scanlines (&cinfo, buf, 1); + pixel = (JSAMPLE (*)[3]) buf[0]; + for (col=0; col < width; col+=2) { + RAW(row+0,col+0) = pixel[col+0][1] << 1; + RAW(row+1,col+1) = pixel[col+1][1] << 1; + RAW(row+0,col+1) = pixel[col][0] + pixel[col+1][0]; + RAW(row+1,col+0) = pixel[col][2] + pixel[col+1][2]; + } + } + jpeg_finish_decompress (&cinfo); + jpeg_destroy_decompress (&cinfo); + maximum = 0xff << 1; +} + +//void CLASS gamma_curve (double pwr, double ts, int mode, int imax); + +void CLASS lossy_dng_load_raw() +{ + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + JSAMPARRAY buf; + JSAMPLE (*pixel)[3]; + unsigned sorder=order, ntags, opcode, deg, i, j, c; + unsigned save=data_offset-4, trow=0, tcol=0, row, col; + ushort cur[3][256]; + double coeff[9], tot; + + if (meta_offset) { + fseek (ifp, meta_offset, SEEK_SET); + order = 0x4d4d; + ntags = get4(); + while (ntags--) { + opcode = get4(); get4(); get4(); + if (opcode != 8) + { fseek (ifp, get4(), SEEK_CUR); continue; } + fseek (ifp, 20, SEEK_CUR); + if ((c = get4()) > 2) break; + fseek (ifp, 12, SEEK_CUR); + if ((deg = get4()) > 8) break; + for (i=0; i <= deg && i < 9; i++) + coeff[i] = getreal(12); + for (i=0; i < 256; i++) { + for (tot=j=0; j <= deg; j++) + tot += coeff[j] * pow(i/255.0, (double) j); + cur[c][i] = tot*0xffff; + } + } + order = sorder; + } else { + gamma_curve (1/2.4, 12.92, 1, 255); + FORC3 memcpy (cur[c], curve, sizeof cur[0]); + } + cinfo.err = jpeg_std_error (&jerr); + jpeg_create_decompress (&cinfo); + while (trow < raw_height) { + fseek (ifp, save+=4, SEEK_SET); + if (tile_length < INT_MAX) + fseek (ifp, get4(), SEEK_SET); + jpeg_stdio_src (&cinfo, ifp); + jpeg_read_header (&cinfo, boolean(TRUE)); + jpeg_start_decompress (&cinfo); + buf = (*cinfo.mem->alloc_sarray) + ((j_common_ptr) &cinfo, JPOOL_IMAGE, cinfo.output_width*3, 1); + while (cinfo.output_scanline < cinfo.output_height && + (row = trow + cinfo.output_scanline) < height) { + jpeg_read_scanlines (&cinfo, buf, 1); + pixel = (JSAMPLE (*)[3]) buf[0]; + for (col=0; col < cinfo.output_width && tcol+col < width; col++) { + FORC3 image[row*width+tcol+col][c] = cur[c][pixel[col][c]]; + } + } + jpeg_abort_decompress (&cinfo); + if ((tcol += tile_width) >= raw_width) + trow += tile_length + (tcol = 0); + } + jpeg_destroy_decompress (&cinfo); + maximum = 0xffff; +} +#endif + +void CLASS kodak_dc120_load_raw() +{ + static const int mul[4] = { 162, 192, 187, 92 }; + static const int add[4] = { 0, 636, 424, 212 }; + uchar pixel[848]; + int row, shift, col; + + for (row=0; row < height; row++) { + if (fread (pixel, 1, 848, ifp) < 848) derror(); + shift = row * mul[row & 3] + add[row & 3]; + for (col=0; col < width; col++) + RAW(row,col) = (ushort) pixel[(col + shift) % 848]; + } + maximum = 0xff; +} + +void CLASS eight_bit_load_raw() +{ + uchar *pixel; + unsigned row, col; + + pixel = (uchar *) calloc (raw_width, sizeof *pixel); + merror (pixel, "eight_bit_load_raw()"); + for (row=0; row < raw_height; row++) { + if (fread (pixel, 1, raw_width, ifp) < raw_width) derror(); + for (col=0; col < raw_width; col++) + RAW(row,col) = curve[pixel[col]]; + } + free (pixel); + maximum = curve[0xff]; +} + +void CLASS kodak_c330_load_raw() +{ + uchar *pixel; + int row, col, y, cb, cr, rgb[3], c; + + pixel = (uchar *) calloc (raw_width, 2*sizeof *pixel); + merror (pixel, "kodak_c330_load_raw()"); + for (row=0; row < height; row++) { + if (fread (pixel, raw_width, 2, ifp) < 2) derror(); + if (load_flags && (row & 31) == 31) + fseek (ifp, raw_width*32, SEEK_CUR); + for (col=0; col < width; col++) { + y = pixel[col*2]; + cb = pixel[(col*2 & -4) | 1] - 128; + cr = pixel[(col*2 & -4) | 3] - 128; + rgb[1] = y - ((cb + cr + 2) >> 2); + rgb[2] = rgb[1] + cb; + rgb[0] = rgb[1] + cr; + FORC3 image[row*width+col][c] = curve[LIM(rgb[c],0,255)]; + } + } + free (pixel); + maximum = curve[0xff]; +} + +void CLASS kodak_c603_load_raw() +{ + uchar *pixel; + int row, col, y, cb, cr, rgb[3], c; + + pixel = (uchar *) calloc (raw_width, 3*sizeof *pixel); + merror (pixel, "kodak_c603_load_raw()"); + for (row=0; row < height; row++) { + if (~row & 1) + if (fread (pixel, raw_width, 3, ifp) < 3) derror(); + for (col=0; col < width; col++) { + y = pixel[width*2*(row & 1) + col]; + cb = pixel[width + (col & -2)] - 128; + cr = pixel[width + (col & -2)+1] - 128; + rgb[1] = y - ((cb + cr + 2) >> 2); + rgb[2] = rgb[1] + cb; + rgb[0] = rgb[1] + cr; + FORC3 image[row*width+col][c] = curve[LIM(rgb[c],0,255)]; + } + } + free (pixel); + maximum = curve[0xff]; +} + +void CLASS kodak_262_load_raw() +{ + static const uchar kodak_tree[2][26] = + { { 0,1,5,1,1,2,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9 }, + { 0,3,1,1,1,1,1,2,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9 } }; + ushort *huff[2]; + uchar *pixel; + int *strip, ns, c, row, col, chess, pi=0, pi1, pi2, pred, val; + + FORC(2) huff[c] = make_decoder (kodak_tree[c]); + ns = (raw_height+63) >> 5; + pixel = (uchar *) malloc (raw_width*32 + ns*4); + merror (pixel, "kodak_262_load_raw()"); + strip = (int *) (pixel + raw_width*32); + order = 0x4d4d; + FORC(ns) strip[c] = get4(); + for (row=0; row < raw_height; row++) { + if ((row & 31) == 0) { + fseek (ifp, strip[row >> 5], SEEK_SET); + getbits(-1); + pi = 0; + } + for (col=0; col < raw_width; col++) { + chess = (row + col) & 1; + pi1 = chess ? pi-2 : pi-raw_width-1; + pi2 = chess ? pi-2*raw_width : pi-raw_width+1; + if (col <= chess) pi1 = -1; + if (pi1 < 0) pi1 = pi2; + if (pi2 < 0) pi2 = pi1; + if (pi1 < 0 && col > 1) pi1 = pi2 = pi-2; + pred = (pi1 < 0) ? 0 : (pixel[pi1] + pixel[pi2]) >> 1; + pixel[pi] = val = pred + ljpeg_diff (huff[chess]); + if (val >> 8) derror(); + val = curve[pixel[pi++]]; + RAW(row,col) = val; + } + } + free (pixel); + FORC(2) free (huff[c]); +} + +int CLASS kodak_65000_decode (short *out, int bsize) +{ + uchar c, blen[768]; + ushort raw[6]; + INT64 bitbuf=0; + int save, bits=0, i, j, len, diff; + + save = ftell(ifp); + bsize = (bsize + 3) & -4; + for (i=0; i < bsize; i+=2) { + c = fgetc(ifp); + if ((blen[i ] = c & 15) > 12 || + (blen[i+1] = c >> 4) > 12 ) { + fseek (ifp, save, SEEK_SET); + for (i=0; i < bsize; i+=8) { + read_shorts (raw, 6); + out[i ] = raw[0] >> 12 << 8 | raw[2] >> 12 << 4 | raw[4] >> 12; + out[i+1] = raw[1] >> 12 << 8 | raw[3] >> 12 << 4 | raw[5] >> 12; + for (j=0; j < 6; j++) + out[i+2+j] = raw[j] & 0xfff; + } + return 1; + } + } + if ((bsize & 7) == 4) { + bitbuf = fgetc(ifp) << 8; + bitbuf += fgetc(ifp); + bits = 16; + } + for (i=0; i < bsize; i++) { + len = blen[i]; + if (bits < len) { + for (j=0; j < 32; j+=8) + bitbuf += (INT64) fgetc(ifp) << (bits+(j^8)); + bits += 32; + } + diff = bitbuf & (0xffff >> (16-len)); + bitbuf >>= len; + bits -= len; + if ((diff & (1 << (len-1))) == 0) + diff -= (1 << len) - 1; + out[i] = diff; + } + return 0; +} + +void CLASS kodak_65000_load_raw() +{ + short buf[256]; + int row, col, len, pred[2], ret, i; + + for (row=0; row < height; row++) + for (col=0; col < width; col+=256) { + pred[0] = pred[1] = 0; + len = MIN (256, width-col); + ret = kodak_65000_decode (buf, len); + for (i=0; i < len; i++) + if ((RAW(row,col+i) = curve[ret ? buf[i] : + (pred[i & 1] += buf[i])]) >> 12) derror(); + } +} + +void CLASS kodak_ycbcr_load_raw() +{ + short buf[384], *bp; + int row, col, len, c, i, j, k, y[2][2], cb, cr, rgb[3]; + ushort *ip; + + if (!image) return; + for (row=0; row < height; row+=2) + for (col=0; col < width; col+=128) { + len = MIN (128, width-col); + kodak_65000_decode (buf, len*3); + y[0][1] = y[1][1] = cb = cr = 0; + for (bp=buf, i=0; i < len; i+=2, bp+=2) { + cb += bp[4]; + cr += bp[5]; + rgb[1] = -((cb + cr + 2) >> 2); + rgb[2] = rgb[1] + cb; + rgb[0] = rgb[1] + cr; + for (j=0; j < 2; j++) + for (k=0; k < 2; k++) { + if ((y[j][k] = y[j][k^1] + *bp++) >> 10) derror(); + ip = image[(row+j)*width + col+i+k]; + FORC3 ip[c] = curve[LIM(y[j][k]+rgb[c], 0, 0xfff)]; + } + } + } +} + +void CLASS kodak_rgb_load_raw() +{ + short buf[768], *bp; + int row, col, len, c, i, rgb[3]; + ushort *ip=image[0]; + + for (row=0; row < height; row++) + for (col=0; col < width; col+=256) { + len = MIN (256, width-col); + kodak_65000_decode (buf, len*3); + memset (rgb, 0, sizeof rgb); + for (bp=buf, i=0; i < len; i++, ip+=4) + FORC3 if ((ip[c] = rgb[c] += *bp++) >> 12) derror(); + } +} + +void CLASS kodak_thumb_load_raw() +{ + int row, col; + colors = thumb_misc >> 5; + for (row=0; row < height; row++) + for (col=0; col < width; col++) + read_shorts (image[row*width+col], colors); + maximum = (1 << (thumb_misc & 31)) - 1; +} + +void CLASS sony_decrypt (unsigned *data, int len, int start, int key) +{ + // TODO: The following static variables are not thread-safe + static unsigned pad[128], p; + + if (start) { + for (p=0; p < 4; p++) + pad[p] = key = key * 48828125 + 1; + pad[3] = pad[3] << 1 | (pad[0]^pad[2]) >> 31; + for (p=4; p < 127; p++) + pad[p] = (pad[p-4]^pad[p-2]) << 1 | (pad[p-3]^pad[p-1]) >> 31; + for (p=0; p < 127; p++) + pad[p] = htonl(pad[p]); + } + while (len-- && p++) + *data++ ^= pad[(p-1) & 127] = pad[p & 127] ^ pad[(p+64) & 127]; +} + +void CLASS sony_load_raw() +{ + uchar head[40]; + ushort *pixel; + unsigned i, key, row, col; + + fseek (ifp, 200896, SEEK_SET); + fseek (ifp, (unsigned) fgetc(ifp)*4 - 1, SEEK_CUR); + order = 0x4d4d; + key = get4(); + fseek (ifp, 164600, SEEK_SET); + fread (head, 1, 40, ifp); + sony_decrypt ((unsigned *) head, 10, 1, key); + for (i=26; i-- > 22; ) + key = key << 8 | head[i]; + fseek (ifp, data_offset, SEEK_SET); + for (row=0; row < raw_height; row++) { + pixel = raw_image + row*raw_width; + if (fread (pixel, 2, raw_width, ifp) < raw_width) derror(); + sony_decrypt ((unsigned *) pixel, raw_width/2, !row, key); + for (col=0; col < raw_width; col++) + if ((pixel[col] = ntohs(pixel[col])) >> 14) derror(); + } + maximum = 0x3ff0; +} + +void CLASS sony_arw_load_raw() +{ + ushort huff[32770]; + static const ushort tab[18] = + { 0xf11,0xf10,0xe0f,0xd0e,0xc0d,0xb0c,0xa0b,0x90a,0x809, + 0x708,0x607,0x506,0x405,0x304,0x303,0x300,0x202,0x201 }; + int i, c, n, col, row, sum=0; + + huff[0] = 15; + for (n=i=0; i < 18; i++) + FORC(32768 >> (tab[i] >> 8)) huff[++n] = tab[i]; + getbits(-1); + for (col = raw_width; col--; ) + for (row=0; row < raw_height+1; row+=2) { + if (row == raw_height) row = 1; + if ((sum += ljpeg_diff(huff)) >> 12) derror(); + if (row < height) RAW(row,col) = sum; + } +} + +void CLASS sony_arw2_load_raw() +{ + uchar *data, *dp; + ushort pix[16]; + int row, col, val, max, min, imax, imin, sh, bit, i; + + data = (uchar *) malloc (raw_width+1); + merror (data, "sony_arw2_load_raw()"); + for (row=0; row < height; row++) { + fread (data, 1, raw_width, ifp); + for (dp=data, col=0; col < raw_width-30; dp+=16) { + max = 0x7ff & (val = sget4(dp)); + min = 0x7ff & val >> 11; + imax = 0x0f & val >> 22; + imin = 0x0f & val >> 26; + for (sh=0; sh < 4 && 0x80 << sh <= max-min; sh++); + for (bit=30, i=0; i < 16; i++) + if (i == imax) pix[i] = max; + else if (i == imin) pix[i] = min; + else { + pix[i] = ((sget2(dp+(bit >> 3)) >> (bit & 7) & 0x7f) << sh) + min; + if (pix[i] > 0x7ff) pix[i] = 0x7ff; + bit += 7; + } + for (i=0; i < 16; i++, col+=2) + RAW(row,col) = curve[pix[i] << 1] >> 2; + col -= col & 1 ? 1:31; + } + } + free (data); +} + +void CLASS samsung_load_raw() +{ + int row, col, c, i, dir, op[4], len[4]; + + order = 0x4949; + for (row=0; row < raw_height; row++) { + fseek (ifp, strip_offset+row*4, SEEK_SET); + fseek (ifp, data_offset+get4(), SEEK_SET); + ph1_bits(-1); + FORC4 len[c] = row < 2 ? 7:4; + for (col=0; col < raw_width; col+=16) { + dir = ph1_bits(1); + FORC4 op[c] = ph1_bits(2); + FORC4 switch (op[c]) { + case 3: len[c] = ph1_bits(4); break; + case 2: len[c]--; break; + case 1: len[c]++; + } + for (c=0; c < 16; c+=2) { + i = len[((c & 1) << 1) | (c >> 3)]; + RAW(row,col+c) = ((signed) ph1_bits(i) << (32-i) >> (32-i)) + + (dir ? RAW(row+(~c | -2),col+c) : col ? RAW(row,col+(c | -2)) : 128); + if (c == 14) c = -1; + } + } + } + for (row=0; row < raw_height-1; row+=2) + for (col=0; col < raw_width-1; col+=2) + SWAP (RAW(row,col+1), RAW(row+1,col)); +} + +void CLASS samsung2_load_raw() +{ + static const ushort tab[14] = + { 0x304,0x307,0x206,0x205,0x403,0x600,0x709, + 0x80a,0x90b,0xa0c,0xa0d,0x501,0x408,0x402 }; + ushort huff[1026], vpred[2][2] = {{0,0},{0,0}}, hpred[2]; + int i, c, n, row, col, diff; + + huff[0] = 10; + for (n=i=0; i < 14; i++) + FORC(1024 >> (tab[i] >> 8)) huff[++n] = tab[i]; + getbits(-1); + for (row=0; row < raw_height; row++) + for (col=0; col < raw_width; col++) { + diff = ljpeg_diff (huff); + if (col < 2) hpred[col] = vpred[row & 1][col] += diff; + else hpred[col & 1] += diff; + RAW(row,col) = hpred[col & 1]; + if (hpred[col & 1] >> tiff_bps) derror(); + } +} + +void CLASS samsung3_load_raw() +{ + int opt, init, mag, pmode, row, tab, col, pred, diff, i, c; + ushort lent[3][2], len[4], *prow[2]; + + order = 0x4949; + fseek (ifp, 9, SEEK_CUR); + opt = fgetc(ifp); + init = (get2(),get2()); + for (row=0; row < raw_height; row++) { + fseek (ifp, (data_offset-ftell(ifp)) & 15, SEEK_CUR); + ph1_bits(-1); + mag = 0; pmode = 7; + FORC(6) ((ushort *)lent)[c] = row < 2 ? 7:4; + prow[ row & 1] = &RAW(row-1,1-((row & 1) << 1)); // green + prow[~row & 1] = &RAW(row-2,0); // red and blue + for (tab=0; tab+15 < raw_width; tab+=16) { + if (~opt & 4 && !(tab & 63)) { + i = ph1_bits(2); + mag = i < 3 ? mag-'2'+"204"[i] : ph1_bits(12); + } + if (opt & 2) + pmode = 7 - 4*ph1_bits(1); + else if (!ph1_bits(1)) + pmode = ph1_bits(3); + if (opt & 1 || !ph1_bits(1)) { + FORC4 len[c] = ph1_bits(2); + FORC4 { + i = ((row & 1) << 1 | (c & 1)) % 3; + len[c] = len[c] < 3 ? lent[i][0]-'1'+"120"[len[c]] : ph1_bits(4); + lent[i][0] = lent[i][1]; + lent[i][1] = len[c]; + } + } + FORC(16) { + col = tab + (((c & 7) << 1)^(c >> 3)^(row & 1)); + pred = (pmode == 7 || row < 2) + ? (tab ? RAW(row,tab-2+(col & 1)) : init) + : (prow[col & 1][col-'4'+"0224468"[pmode]] + + prow[col & 1][col-'4'+"0244668"[pmode]] + 1) >> 1; + diff = ph1_bits (i = len[c >> 2]); + if (diff >> (i-1)) diff -= 1 << i; + diff = diff * (mag*2+1) + mag; + RAW(row,col) = pred + diff; + } + } + } +} + +#define HOLE(row) ((holes >> (((row) - raw_height) & 7)) & 1) + +#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 7)) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Warray-bounds" +#endif +/* Kudos to Rich Taylor for figuring out SMaL's compression algorithm. */ +void CLASS smal_decode_segment (unsigned seg[2][2], int holes) +{ + uchar hist[3][13] = { + { 7, 7, 0, 0, 63, 55, 47, 39, 31, 23, 15, 7, 0 }, + { 7, 7, 0, 0, 63, 55, 47, 39, 31, 23, 15, 7, 0 }, + { 3, 3, 0, 0, 63, 47, 31, 15, 0 } }; + unsigned pix; + int low, high=0xff, carry=0, nbits=8; + int s, count, bin, next, i, sym[3]; + uchar diff, pred[]={0,0}; + ushort data=0, range=0; + + fseek (ifp, seg[0][1]+1, SEEK_SET); + getbits(-1); + if (seg[1][0] > (unsigned) raw_width*raw_height) + seg[1][0] = raw_width*raw_height; + for (pix=seg[0][0]; pix < seg[1][0]; pix++) { + for (s=0; s < 3; s++) { + data = data << nbits | getbits(nbits); + if (carry < 0) + carry = (nbits += carry+1) < 1 ? nbits-1 : 0; + while (--nbits >= 0) + if ((data >> nbits & 0xff) == 0xff) break; + if (nbits > 0) + data = ((data & ((1 << (nbits-1)) - 1)) << 1) | + ((data + (((data & (1 << (nbits-1)))) << 1)) & (-1 << nbits)); + if (nbits >= 0) { + data += getbits(1); + carry = nbits - 8; + } + count = ((((data-range+1) & 0xffff) << 2) - 1) / (high >> 4); + for (bin=0; hist[s][bin+5] > count; bin++); + low = hist[s][bin+5] * (high >> 4) >> 2; + if (bin) high = hist[s][bin+4] * (high >> 4) >> 2; + high -= low; + for (nbits=0; high << nbits < 128; nbits++); + range = (range+low) << nbits; + high <<= nbits; + next = hist[s][1]; + if (++hist[s][2] > hist[s][3]) { + next = (next+1) & hist[s][0]; + hist[s][3] = (hist[s][next+4] - hist[s][next+5]) >> 2; + hist[s][2] = 1; + } + if (hist[s][hist[s][1]+4] - hist[s][hist[s][1]+5] > 1) { + if (bin < hist[s][1]) + for (i=bin; i < hist[s][1]; i++) hist[s][i+5]--; + else if (next <= bin) + for (i=hist[s][1]; i < bin; i++) hist[s][i+5]++; + } + hist[s][1] = next; + sym[s] = bin; + } + diff = sym[2] << 5 | sym[1] << 2 | (sym[0] & 3); + if (sym[0] & 4) + diff = diff ? -diff : 0x80; + if (ftell(ifp) + 12 >= (int) seg[1][1]) + diff = 0; + if(pix>=raw_width*raw_height) + derror(); + else + raw_image[pix] = pred[pix & 1] += diff; + if (!(pix & 1) && HOLE(pix / raw_width)) pix += 2; + } + maximum = 0xff; +} +#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 7)) +#pragma GCC diagnostic pop +#endif + +void CLASS smal_v6_load_raw() +{ + unsigned seg[2][2]; + + fseek (ifp, 16, SEEK_SET); + seg[0][0] = 0; + seg[0][1] = get2(); + seg[1][0] = raw_width * raw_height; + seg[1][1] = INT_MAX; + smal_decode_segment (seg, 0); +} + +int CLASS median4 (int *p) +{ + int min, max, sum, i; + + min = max = sum = p[0]; + for (i=1; i < 4; i++) { + sum += p[i]; + if (min > p[i]) min = p[i]; + if (max < p[i]) max = p[i]; + } + return (sum - min - max) >> 1; +} + +void CLASS fill_holes (int holes) +{ + int row, col, val[4]; + + for (row=2; row < height-2; row++) { + if (!HOLE(row)) continue; + for (col=1; col < width-1; col+=4) { + val[0] = RAW(row-1,col-1); + val[1] = RAW(row-1,col+1); + val[2] = RAW(row+1,col-1); + val[3] = RAW(row+1,col+1); + RAW(row,col) = median4(val); + } + for (col=2; col < width-2; col+=4) + if (HOLE(row-2) || HOLE(row+2)) + RAW(row,col) = (RAW(row,col-2) + RAW(row,col+2)) >> 1; + else { + val[0] = RAW(row,col-2); + val[1] = RAW(row,col+2); + val[2] = RAW(row-2,col); + val[3] = RAW(row+2,col); + RAW(row,col) = median4(val); + } + } +} + +void CLASS smal_v9_load_raw() +{ + unsigned seg[256][2], offset, nseg, holes, i; + + fseek (ifp, 67, SEEK_SET); + offset = get4(); + nseg = (uchar) fgetc(ifp); + fseek (ifp, offset, SEEK_SET); + for (i=0; i < nseg*2; i++) + ((unsigned *)seg)[i] = get4() + data_offset*(i & 1); + fseek (ifp, 78, SEEK_SET); + holes = fgetc(ifp); + fseek (ifp, 88, SEEK_SET); + seg[nseg][0] = raw_height * raw_width; + seg[nseg][1] = get4() + data_offset; + for (i=0; i < nseg; i++) + smal_decode_segment (seg+i, holes); + if (holes) fill_holes (holes); +} + +void CLASS redcine_load_raw() +{ +#ifdef HAVE_LIBJASPER + int c, row, col; + jas_stream_t *in; + jas_image_t *jimg; + jas_matrix_t *jmat; + jas_seqent_t *data; + ushort *img, *pix; + + jas_init(); + in = jas_stream_fopen (ifname, "rb"); + jas_stream_seek (in, data_offset+20, SEEK_SET); + jimg = jas_image_decode (in, -1, 0); + if (!jimg) longjmp (failure, 3); + jmat = jas_matrix_create (height/2, width/2); + merror (jmat, "redcine_load_raw()"); + img = (ushort *) calloc ((height+2), (width+2)*2); + merror (img, "redcine_load_raw()"); + FORC4 { + jas_image_readcmpt (jimg, c, 0, 0, width/2, height/2, jmat); + data = jas_matrix_getref (jmat, 0, 0); + for (row = c >> 1; row < height; row+=2) + for (col = c & 1; col < width; col+=2) + img[(row+1)*(width+2)+col+1] = data[(row/2)*(width/2)+col/2]; + } + for (col=1; col <= width; col++) { + img[col] = img[2*(width+2)+col]; + img[(height+1)*(width+2)+col] = img[(height-1)*(width+2)+col]; + } + for (row=0; row < height+2; row++) { + img[row*(width+2)] = img[row*(width+2)+2]; + img[(row+1)*(width+2)-1] = img[(row+1)*(width+2)-3]; + } + for (row=1; row <= height; row++) { + pix = img + row*(width+2) + (col = 1 + (FC(row,1) & 1)); + for ( ; col <= width; col+=2, pix+=2) { + c = (((pix[0] - 0x800) << 3) + + pix[-(width+2)] + pix[width+2] + pix[-1] + pix[1]) >> 2; + pix[0] = LIM(c,0,4095); + } + } + for (row=0; row < height; row++) + for (col=0; col < width; col++) + RAW(row,col) = curve[img[(row+1)*(width+2)+col+1]]; + free (img); + jas_matrix_destroy (jmat); + jas_image_destroy (jimg); + jas_stream_close (in); +#endif +} + +/* RESTRICTED code starts here */ + +void CLASS foveon_decoder (int size, unsigned code) +{ + // TODO: The following static variable is not thread-safe + static unsigned huff[1024]; + struct decode *cur; + int i, len; + + if (!code) { + for (i=0; i < size; i++) + huff[i] = get4(); + memset (first_decode, 0, sizeof first_decode); + free_decode = first_decode; + } + cur = free_decode++; + if (free_decode > first_decode+2048) { + dcraw_message (DCRAW_ERROR,_("%s: decoder table overflow\n"), ifname_display); + longjmp (failure, 2); + } + if (code) + for (i=0; i < size; i++) + if (huff[i] == code) { + cur->leaf = i; + return; + } + if ((len = code >> 27) > 26) return; + code = (len+1) << 27 | (code & 0x3ffffff) << 1; + + cur->branch[0] = free_decode; + foveon_decoder (size, code); + cur->branch[1] = free_decode; + foveon_decoder (size, code+1); +} + +void CLASS foveon_thumb() +{ + unsigned bwide, row, col, bitbuf=0, bit=1, c, i; + char *buf; + struct decode *dindex; + short pred[3]; + + bwide = get4(); + fprintf (ofp, "P6\n%d %d\n255\n", thumb_width, thumb_height); + if (bwide > 0) { + if (bwide < thumb_width*3) return; + buf = (char *) malloc (bwide); + merror (buf, "foveon_thumb()"); + for (row=0; row < thumb_height; row++) { + fread (buf, 1, bwide, ifp); + fwrite (buf, 3, thumb_width, ofp); + } + free (buf); + return; + } + foveon_decoder (256, 0); + + for (row=0; row < thumb_height; row++) { + memset (pred, 0, sizeof pred); + if (!bit) get4(); + for (bit=col=0; col < thumb_width; col++) + FORC3 { + for (dindex=first_decode; dindex->branch[0]; ) { + if ((bit = (bit-1) & 31) == 31) + for (i=0; i < 4; i++) + bitbuf = (bitbuf << 8) + fgetc(ifp); + dindex = dindex->branch[bitbuf >> bit & 1]; + } + pred[c] += dindex->leaf; + fputc (pred[c], ofp); + } + } +} + +void CLASS foveon_sd_load_raw() +{ + struct decode *dindex; + short diff[1024]; + unsigned bitbuf=0; + int pred[3], row, col, bit=-1, c, i; + + read_shorts ((ushort *) diff, 1024); + if (!load_flags) foveon_decoder (1024, 0); + + for (row=0; row < height; row++) { + memset (pred, 0, sizeof pred); + if (!bit && !load_flags && atoi(model+2) < 14) get4(); + for (col=bit=0; col < width; col++) { + if (load_flags) { + bitbuf = get4(); + FORC3 pred[2-c] += diff[bitbuf >> c*10 & 0x3ff]; + } + else FORC3 { + for (dindex=first_decode; dindex->branch[0]; ) { + if ((bit = (bit-1) & 31) == 31) + for (i=0; i < 4; i++) + bitbuf = (bitbuf << 8) + fgetc(ifp); + dindex = dindex->branch[bitbuf >> bit & 1]; + } + pred[c] += diff[dindex->leaf]; + if (pred[c] >> 16 && ~pred[c] >> 16) derror(); + } + FORC3 image[row*width+col][c] = pred[c]; + } + } +} + +void CLASS foveon_huff (ushort *huff) +{ + int i, j, clen, code; + + huff[0] = 8; + for (i=0; i < 13; i++) { + clen = getc(ifp); + code = getc(ifp); + for (j=0; j < 256 >> clen; ) + huff[code+ ++j] = clen << 8 | i; + } + get2(); +} + +void CLASS foveon_dp_load_raw() +{ + unsigned c, roff[4], row, col, diff; + ushort huff[512], vpred[2][2], hpred[2]; + + fseek (ifp, 8, SEEK_CUR); + foveon_huff (huff); + roff[0] = 48; + FORC3 roff[c+1] = -(-(roff[c] + get4()) & -16); + FORC3 { + fseek (ifp, data_offset+roff[c], SEEK_SET); + getbits(-1); + vpred[0][0] = vpred[0][1] = vpred[1][0] = vpred[1][1] = 512; + for (row=0; row < height; row++) { + for (col=0; col < width; col++) { + diff = ljpeg_diff(huff); + if (col < 2) hpred[col] = vpred[row & 1][col] += diff; + else hpred[col & 1] += diff; + image[row*width+col][c] = hpred[col & 1]; + } + } + } +} + +void CLASS foveon_load_camf() +{ + unsigned type, wide, high, i, j, row, col, diff; + ushort huff[258], vpred[2][2] = {{512,512},{512,512}}, hpred[2]; + + fseek (ifp, meta_offset, SEEK_SET); + type = get4(); get4(); get4(); + wide = get4(); + high = get4(); + if (type == 2) { + fread (meta_data, 1, meta_length, ifp); + for (i=0; i < meta_length; i++) { + high = (high * 1597 + 51749) % 244944; + wide = high * (INT64) 301593171 >> 24; + meta_data[i] ^= ((((high << 8) - wide) >> 1) + wide) >> 17; + } + } else if (type == 4) { + free (meta_data); + meta_data = (char *) malloc (meta_length = wide*high*3/2); + merror (meta_data, "foveon_load_camf()"); + foveon_huff (huff); + get4(); + getbits(-1); + for (j=row=0; row < high; row++) { + for (col=0; col < wide; col++) { + diff = ljpeg_diff(huff); + if (col < 2) hpred[col] = vpred[row & 1][col] += diff; + else hpred[col & 1] += diff; + if (col & 1) { + meta_data[j++] = hpred[0] >> 4; + meta_data[j++] = hpred[0] << 4 | hpred[1] >> 8; + meta_data[j++] = hpred[1]; + } + } + } + } else + dcraw_message (DCRAW_ERROR,_("%s has unknown CAMF type %d.\n"), ifname_display, type); +} + +const char * CLASS foveon_camf_param (const char *block, const char *param) +{ + unsigned idx, num; + char *pos, *cp, *dp; + + for (idx=0; idx < meta_length; idx += sget4(pos+8)) { + pos = meta_data + idx; + if (strncmp (pos, "CMb", 3)) break; + if (pos[3] != 'P') continue; + if (strcmp (block, pos+sget4(pos+12))) continue; + cp = pos + sget4(pos+16); + num = sget4(cp); + dp = pos + sget4(cp+4); + while (num--) { + cp += 8; + if (!strcmp (param, dp+sget4(cp))) + return dp+sget4(cp+4); + } + } + return 0; +} + +void * CLASS foveon_camf_matrix (unsigned dim[3], const char *name) +{ + unsigned i, idx, type, ndim, size, *mat; + char *pos, *cp, *dp; + double dsize; + + for (idx=0; idx < meta_length; idx += sget4(pos+8)) { + pos = meta_data + idx; + if (strncmp (pos, "CMb", 3)) break; + if (pos[3] != 'M') continue; + if (strcmp (name, pos+sget4(pos+12))) continue; + dim[0] = dim[1] = dim[2] = 1; + cp = pos + sget4(pos+16); + type = sget4(cp); + if ((ndim = sget4(cp+4)) > 3) break; + dp = pos + sget4(cp+8); + for (i=ndim; i--; ) { + cp += 12; + dim[i] = sget4(cp); + } + if ((dsize = (double) dim[0]*dim[1]*dim[2]) > meta_length/4) break; + mat = (unsigned *) malloc ((size = dsize) * 4); + merror (mat, "foveon_camf_matrix()"); + for (i=0; i < size; i++) + if (type && type != 6) + mat[i] = sget4(dp + i*4); + else + mat[i] = sget4(dp + i*2) & 0xffff; + return mat; + } + dcraw_message (DCRAW_WARNING,_("%s: \"%s\" matrix not found!\n"), ifname_display, name); + return 0; +} + +int CLASS foveon_fixed (void *ptr, int size, const char *name) +{ + void *dp; + unsigned dim[3]; + + if (!name) return 0; + dp = foveon_camf_matrix (dim, name); + if (!dp) return 0; + memcpy (ptr, dp, size*4); + free (dp); + return 1; +} + +#if defined(__GNUC__) && (__GNUC__ == 4 && __GNUC_MINOR__ > 6) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#endif +float CLASS foveon_avg (short *pix, int range[2], float cfilt) +{ + int i; + float val, min=FLT_MAX, max=-FLT_MAX, sum=0; + + for (i=range[0]; i <= range[1]; i++) { + sum += val = pix[i*4] + (pix[i*4]-pix[(i-1)*4]) * cfilt; + if (min > val) min = val; + if (max < val) max = val; + } + if (range[1] - range[0] == 1) return sum/2; + return (sum - min - max) / (range[1] - range[0] - 1); +} +#if defined(__GNUC__) && (__GNUC__ == 4 && __GNUC_MINOR__ > 6) +#pragma GCC diagnostic pop +#endif + +short * CLASS foveon_make_curve (double max, double mul, double filt) +{ + short *curve; + unsigned i, size; + double x; + + if (!filt) filt = 0.8; + size = 4*M_PI*max / filt; + if (size == UINT_MAX) size--; + curve = (short *) calloc (size+1, sizeof *curve); + merror (curve, "foveon_make_curve()"); + curve[0] = size; + for (i=0; i < size; i++) { + x = i*filt/max/4; + curve[i+1] = (cos(x)+1)/2 * tanh(i*filt/mul) * mul + 0.5; + } + return curve; +} + +void CLASS foveon_make_curves + (short **curvep, float dq[3], float div[3], float filt) +{ + double mul[3], max=0; + int c; + + FORC3 mul[c] = dq[c]/div[c]; + FORC3 if (max < mul[c]) max = mul[c]; + FORC3 curvep[c] = foveon_make_curve (max, mul[c], filt); +} + +int CLASS foveon_apply_curve (short *curve, int i) +{ + if (abs(i) >= curve[0]) return 0; + return i < 0 ? -curve[1-i] : curve[1+i]; +} + +#define image ((short (*)[4]) image) + +#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 6)) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#endif +void CLASS sigma_true_ii_interpolate() +{ + static const short hood[] = { -1,-1, -1,0, -1,1, 0,-1, 0,1, 1,-1, 1,0, 1,1 }; + short *pix, *curve[8]; + float cfilt=0, ddft[3][3][2]; + float cam_xyz[3][3], correct[3][3], last[3][3]; + float chroma_dq[3], color_dq[3], diag[3][3], div[3], tempgainfact[3]; + float fsum[3], num; + int row, col, c, i, j, sum, min, max, limit; + int dscr[2][2], dstb[4], (*smrow[7])[3], total[4], ipix[3]; + int smlast, smred, smred_p=0, dev[3]; + int satlev[3], keep[4], active[4], version[2], dp1=0; + unsigned dim[3], *badpix; + double dsum=0; + const char* cp; + + dcraw_message (DCRAW_VERBOSE,_("Sigma TRUE II interpolation...\n")); + + foveon_load_camf(); + foveon_fixed (version, 2, "ContentVersionNumber"); + if (version[1] == 70) dp1=1; + if (!dp1) simple_coeff(4); + foveon_fixed (dscr, 4, "DarkShieldColRange"); + foveon_fixed (keep, 4, "KeepImageArea"); + foveon_fixed (active, 4, "ActiveImageArea"); + if (foveon_camf_param ("IncludeBlocks", "ChromaDQ")) + foveon_fixed (chroma_dq, 3, "ChromaDQ"); + foveon_fixed (color_dq, 3, + foveon_camf_param ("IncludeBlocks", "ColorDQ") ? + "ColorDQ" : "ColorDQCamRGB"); + if (foveon_camf_param ("IncludeBlocks", "ColumnFilter")) + foveon_fixed (&cfilt, 1, "ColumnFilter"); + + memset (ddft, 0, sizeof ddft); + if (!foveon_camf_param ("IncludeBlocks", "DarkDrift") + || !foveon_fixed (ddft[1][0], 12, "DarkDrift")) + for (i=0; i < 2; i++) { + foveon_fixed (dstb, 4, i ? "DarkShieldBottom":"DarkShieldTop"); + for (row = dstb[1]; row <= dstb[3]; row++) + for (col = dstb[0]; col <= dstb[2]; col++) + FORC3 ddft[i+1][c][1] += (short) image[row*width+col][c]; + FORC3 ddft[i+1][c][1] /= (dstb[3]-dstb[1]+1) * (dstb[2]-dstb[0]+1); + } + + if (dp1) { + if (!(cp = foveon_camf_param ("DP1_WhiteBalanceColorCorrections", model2))) + { dcraw_message (DCRAW_ERROR,_("%s: Invalid white balance \"%s\"\n"), ifname_display, model2); + return; } + } else { + if (!strcmp(model2, "Daylight")) strcpy(model2, "Sunlight"); + if (!(cp = foveon_camf_param ("WhiteBalanceColorCorrections", model2))) + { dcraw_message (DCRAW_ERROR,_("%s: Invalid white balance \"%s\"\n"), ifname_display, model2); + return; } + } + foveon_fixed (cam_xyz, 9, cp); + if (foveon_camf_param ("IncludeBlocks", "WhiteBalanceCorrections")) + foveon_fixed (correct, 9, foveon_camf_param ("WhiteBalanceCorrections", model2)); + else if (foveon_camf_param ("IncludeBlocks", "ColorModeCompensations")) + foveon_fixed (correct, 9, foveon_camf_param ("ColorModeCompensations", cm_desc)); + memset (last, 0, sizeof last); + for (i=0; i < 3; i++) + for (j=0; j < 3; j++) + FORC3 last[i][j] += correct[i][c] * cam_xyz[c][j]; + + #define LAST(x,y) last[(i+x)%3][(c+y)%3] + for (i=0; i < 3; i++) + FORC3 diag[c][i] = LAST(1,1)*LAST(2,2) - LAST(1,2)*LAST(2,1); + #undef LAST + FORC3 div[c] = diag[c][0]*0.3127 + diag[c][1]*0.329 + diag[c][2]*0.3583; + if (dp1) { + if (foveon_camf_param ("IncludeBlocks", "DP1_WhiteBalanceGains")) + foveon_fixed (div, 3, foveon_camf_param ("DP1_WhiteBalanceGains", model2)); + } else { + if (foveon_camf_param ("IncludeBlocks", "WhiteBalanceGains")) + foveon_fixed (div, 3, foveon_camf_param ("WhiteBalanceGains", model2)); + } + if (foveon_camf_param("IncludeBlocks", "TempGainFact")) { + foveon_fixed(tempgainfact, 3, "TempGainFact"); + FORC3 div[c]*=tempgainfact[c]; + } + if (foveon_camf_param("IncludeBlocks", "SensorAdjustmentGainFact")) { + foveon_fixed(tempgainfact, 3, "SensorAdjustmentGainFact"); + FORC3 div[c]*=tempgainfact[c]; + } + if (foveon_camf_param("IncludeBlocks", "CorrectColorGain_BR")) { + foveon_fixed(tempgainfact, 3, "CorrectColorGain_BR"); + FORC3 div[c]*=tempgainfact[c]; + } + if (foveon_camf_param("IncludeBlocks", "CorrectColorGain_GR")) { + foveon_fixed(tempgainfact, 3, "CorrectColorGain_GR"); + FORC3 div[c]*=tempgainfact[c]; + } + if (foveon_camf_param("IncludeBlocks", "CorrectColorGain_RR")) { + foveon_fixed(tempgainfact, 3, "CorrectColorGain_RR"); + FORC3 div[c]*=tempgainfact[c]; + } + if (foveon_camf_param("IncludeBlocks", "DespAdjust")) { + foveon_fixed(tempgainfact, 3, "DespAdjust"); + FORC3 div[c]*=tempgainfact[c]; + } + num = 0; + FORC3 if (num < div[c]) num = div[c]; + FORC3 div[c] /= num; + + foveon_make_curves (curve, color_dq, div, cfilt); + FORC3 chroma_dq[c] /= 3; + foveon_make_curves (curve+3, chroma_dq, div, cfilt); + FORC3 dsum += chroma_dq[c] / div[c]; + curve[6] = foveon_make_curve (dsum, dsum, cfilt); + curve[7] = foveon_make_curve (dsum*2, dsum*2, cfilt); + + if (foveon_camf_param ("IncludeBlocks", "BadPixels")) { + badpix = (unsigned *) foveon_camf_matrix (dim, "BadPixels"); + for (i=0; i < (int) dim[0]; i++) { + col = (badpix[i] >> 8 & 0xfff) - keep[0]; + row = (badpix[i] >> 20 ) - keep[1]; + if (row-1 < 0 || row-1 > height-3 || col-1 < 0 || col-1 > width-3) + continue; + memset (fsum, 0, sizeof fsum); + for (sum=j=0; j < 8; j++) + if (badpix[i] & (1 << j)) { + FORC3 fsum[c] += (short) + image[(row+hood[j*2])*width+col+hood[j*2+1]][c]; + sum++; + } + if (sum) FORC3 image[row*width+col][c] = fsum[c]/sum; + } + free (badpix); + } + + /* Array for 5x5 Gaussian averaging of red values */ + smrow[6] = (int (*)[3]) calloc (width*5, sizeof **smrow); + merror (smrow[6], "sigma_true_ii_interpolate()"); + for (i=0; i < 5; i++) + smrow[i] = smrow[6] + i*width; + + /* Sharpen the reds against these Gaussian averages */ + for (smlast=-1, row=2; row < height-2; row++) { + while (smlast < row+2) { + for (i=0; i < 6; i++) + smrow[(i+5) % 6] = smrow[i]; + pix = image[++smlast*width+2]; + for (col=2; col < width-2; col++) { + smrow[4][col][0] = + (pix[0]*6 + (pix[-4]+pix[4])*4 + pix[-8]+pix[8] + 8) >> 4; + pix += 4; + } + } + pix = image[row*width+2]; + for (col=2; col < width-2; col++) { + smred = ( 6 * smrow[2][col][0] + + 4 * (smrow[1][col][0] + smrow[3][col][0]) + + smrow[0][col][0] + smrow[4][col][0] + 8 ) >> 4; + if (col == 2) + smred_p = smred; + i = pix[0] + ((pix[0] - ((smred*7 + smred_p) >> 3)) >> 3); + if (i > 32000) i = 32000; + pix[0] = i; + smred_p = smred; + pix += 4; + } + } + + /* Adjust the brighter pixels for better linearity */ + if (foveon_camf_param ("IncludeBlocks", "SaturationLevel")) { + foveon_fixed (satlev, 3, "SaturationLevel"); + min = 0xffff; + FORC3 { + i = satlev[c] / div[c]; + if (min > i) min = i; + } + limit = min * 9 >> 4; + for (pix=image[0]; pix < image[height*width]; pix+=4) { + if (pix[0] <= limit || pix[1] <= limit || pix[2] <= limit) + continue; + min = max = pix[0]; + for (c=1; c < 3; c++) { + if (min > pix[c]) min = pix[c]; + if (max < pix[c]) max = pix[c]; + } + if (min >= limit*2) { + pix[0] = pix[1] = pix[2] = max; + } else { + i = 0x4000 - ((min - limit) << 14) / limit; + i = 0x4000 - (i*i >> 14); + i = i*i >> 14; + FORC3 pix[c] += (max - pix[c]) * i >> 14; + } + } + } +/* + Because photons that miss one detector often hit another, + the sum R+G+B is much less noisy than the individual colors. + So smooth the hues without smoothing the total. + */ + for (smlast=-1, row=2; row < height-2; row++) { + while (smlast < row+2) { + for (i=0; i < 6; i++) + smrow[(i+5) % 6] = smrow[i]; + pix = image[++smlast*width+2]; + for (col=2; col < width-2; col++) { + FORC3 smrow[4][col][c] = (pix[c-4]+2*pix[c]+pix[c+4]+2) >> 2; + pix += 4; + } + } + pix = image[row*width+2]; + for (col=2; col < width-2; col++) { + FORC3 dev[c] = -foveon_apply_curve (curve[7], pix[c] - + ((smrow[1][col][c] + 2*smrow[2][col][c] + smrow[3][col][c]) >> 2)); + sum = (dev[0] + dev[1] + dev[2]) >> 3; + FORC3 pix[c] += dev[c] - sum; + pix += 4; + } + } + for (smlast=-1, row=2; row < height-2; row++) { + while (smlast < row+2) { + for (i=0; i < 6; i++) + smrow[(i+5) % 6] = smrow[i]; + pix = image[++smlast*width+2]; + for (col=2; col < width-2; col++) { + FORC3 smrow[4][col][c] = + (pix[c-8]+pix[c-4]+pix[c]+pix[c+4]+pix[c+8]+2) >> 2; + pix += 4; + } + } + pix = image[row*width+2]; + for (col=2; col < width-2; col++) { + for (total[3]=375, sum=60, c=0; c < 3; c++) { + for (total[c]=i=0; i < 5; i++) + total[c] += smrow[i][col][c]; + total[3] += total[c]; + sum += pix[c]; + } + if (sum < 0) sum = 0; + j = total[3] > 375 ? (sum << 16) / total[3] : sum * 174; + FORC3 pix[c] += foveon_apply_curve (curve[6], + ((j*total[c] + 0x8000) >> 16) - pix[c]); + pix += 4; + } + } + + /* Transform the image to a different colorspace */ + min = 0xffff; + max = 0; + for (pix=image[0]; pix < image[height*width]; pix+=4) { + FORC3 pix[c] -= foveon_apply_curve (curve[c], pix[c]); + sum = (pix[0]+pix[1]+pix[1]+pix[2]) >> 2; + FORC3 pix[c] -= foveon_apply_curve (curve[c], pix[c]-sum); + FORC3 { + for (dsum=i=0; i < 3; i++) + dsum += rgb_cam[c][i] * last[c][i] * div[i] * pix[i]; + if (dsum < 0) dsum = 0; + if (dsum > 24000) dsum = 24000; + ipix[c] = dsum + 0.5; + } + FORC3 { + pix[c] = ipix[c]; + if (pix[c] < min) min = pix[c]; + if (pix[c] > max) max = pix[c]; + } + } + for (i=0; i < 8; i++) + free (curve[i]); + + /* Trim off the black border */ + active[1] -= keep[1]; + active[3] -= 2; + i = active[2] - active[0]; + for (row=0; row < active[3]-active[1]; row++) + memcpy (image[row*i], image[(row+active[1])*width+active[0]], + i * sizeof *image); + width = i; + height = row; +} + +void CLASS foveon_interpolate() +{ + static const short hood[] = { -1,-1, -1,0, -1,1, 0,-1, 0,1, 1,-1, 1,0, 1,1 }; + short *pix, prev[3], *curve[8], (*shrink)[3]; + float cfilt=0, ddft[3][3][2], ppm[3][3][3]; + float cam_xyz[3][3], correct[3][3], last[3][3], trans[3][3]; + float chroma_dq[3], color_dq[3], diag[3][3], div[3]; + float (*black)[3], (*sgain)[3], (*sgrow)[3]; + float fsum[3], val, frow, num; + int row, col, c, i, j, diff, sgx, irow, sum, min, max, limit; + int dscr[2][2], dstb[4], (*smrow[7])[3], total[4], ipix[3]; + int work[3][3], smlast, smred, smred_p=0, dev[3]; + int satlev[3], keep[4], active[4], version[2], x530=0; + unsigned dim[3], *badpix; + double dsum=0, trsum[3]; + char str[128]; + const char* cp; + + dcraw_message (DCRAW_VERBOSE,_("Foveon interpolation...\n")); + + foveon_load_camf(); + foveon_fixed (version, 2, "ContentVersionNumber"); + if (version[0]==1) x530=1; + foveon_fixed (dscr, 4, "DarkShieldColRange"); + foveon_fixed (ppm[0][0], 27, "PostPolyMatrix"); + foveon_fixed (satlev, 3, "SaturationLevel"); + foveon_fixed (keep, 4, "KeepImageArea"); + foveon_fixed (active, 4, "ActiveImageArea"); + foveon_fixed (chroma_dq, 3, "ChromaDQ"); + foveon_fixed (color_dq, 3, + foveon_camf_param ("IncludeBlocks", "ColorDQ") ? + "ColorDQ" : "ColorDQCamRGB"); + if (foveon_camf_param ("IncludeBlocks", "ColumnFilter")) + foveon_fixed (&cfilt, 1, "ColumnFilter"); + + memset (ddft, 0, sizeof ddft); + if (!x530) { + if (foveon_camf_param ("IncludeBlocks", "DarkDrift")) + foveon_fixed (ddft[1][0], 12, "DarkDrift"); + } else { + for (i=0; i < 2; i++) { + foveon_fixed (dstb, 4, i ? "DarkShieldBottom":"DarkShieldTop"); + for (row = dstb[1]; row <= dstb[3]; row++) + for (col = dstb[0]; col <= dstb[2]; col++) + FORC3 ddft[i+1][c][1] += (short) image[row*width+col][c]; + FORC3 ddft[i+1][c][1] /= (dstb[3]-dstb[1]+1) * (dstb[2]-dstb[0]+1); + } + } + + if (!(cp = foveon_camf_param ("WhiteBalanceIlluminants", model2))) + { dcraw_message (DCRAW_ERROR,_("%s: Invalid white balance \"%s\"\n"), ifname_display, model2); + return; } + foveon_fixed (cam_xyz, 9, cp); + foveon_fixed (correct, 9, + foveon_camf_param ("WhiteBalanceCorrections", model2)); + memset (last, 0, sizeof last); + for (i=0; i < 3; i++) + for (j=0; j < 3; j++) + FORC3 last[i][j] += correct[i][c] * cam_xyz[c][j]; + + #define LAST(x,y) last[(i+x)%3][(c+y)%3] + for (i=0; i < 3; i++) + FORC3 diag[c][i] = LAST(1,1)*LAST(2,2) - LAST(1,2)*LAST(2,1); + #undef LAST + FORC3 div[c] = diag[c][0]*0.3127 + diag[c][1]*0.329 + diag[c][2]*0.3583; + if (!x530) { + sprintf (str, "%sRGBNeutral", model2); + if (foveon_camf_param ("IncludeBlocks", str)) + foveon_fixed (div, 3, str); + } + num = 0; + FORC3 if (num < div[c]) num = div[c]; + FORC3 div[c] /= num; + + memset (trans, 0, sizeof trans); + for (i=0; i < 3; i++) + for (j=0; j < 3; j++) + FORC3 trans[i][j] += rgb_cam[i][c] * last[c][j] * div[j]; + FORC3 trsum[c] = trans[c][0] + trans[c][1] + trans[c][2]; + dsum = (6*trsum[0] + 11*trsum[1] + 3*trsum[2]) / 20; + for (i=0; i < 3; i++) + FORC3 last[i][c] = trans[i][c] * dsum / trsum[i]; + memset (trans, 0, sizeof trans); + for (i=0; i < 3; i++) + for (j=0; j < 3; j++) + FORC3 trans[i][j] += (i==c ? 32 : -1) * last[c][j] / 30; + + foveon_make_curves (curve, color_dq, div, cfilt); + FORC3 chroma_dq[c] /= 3; + foveon_make_curves (curve+3, chroma_dq, div, cfilt); + FORC3 dsum += chroma_dq[c] / div[c]; + curve[6] = foveon_make_curve (dsum, dsum, cfilt); + curve[7] = foveon_make_curve (dsum*2, dsum*2, cfilt); + + sgain = (float (*)[3]) foveon_camf_matrix (dim, "SpatialGain"); + if (!sgain) return; + sgrow = (float (*)[3]) calloc (dim[1], sizeof *sgrow); + sgx = (width + dim[1]-2) / (dim[1]-1); + + black = (float (*)[3]) calloc (height, sizeof *black); + for (row=0; row < height; row++) { + for (i=0; i < 3; i++) + for (j=0; j < 2; j++) + ((float *)ddft[0])[i] = ((float *)ddft[1])[i] + + row / (height-1.0) * (((float *)ddft[2])[i] - ((float *)ddft[1])[i]); + FORC3 black[row][c] = + ( foveon_avg (image[row*width]+c, dscr[0], cfilt) + + foveon_avg (image[row*width]+c, dscr[1], cfilt) * 3 + - ddft[0][c][0] ) / 4 - ddft[0][c][1]; + } + memcpy (black, black+8, sizeof *black*8); + memcpy (black+height-11, black+height-22, 11*sizeof *black); + memcpy (last, black, sizeof last); + + for (row=1; row < height-1; row++) { + FORC3 if (last[1][c] > last[0][c]) { + if (last[1][c] > last[2][c]) + black[row][c] = (last[0][c] > last[2][c]) ? last[0][c]:last[2][c]; + } else + if (last[1][c] < last[2][c]) + black[row][c] = (last[0][c] < last[2][c]) ? last[0][c]:last[2][c]; + memmove (last, last+1, 2*sizeof last[0]); + memcpy (last[2], black[row+1], sizeof last[2]); + } + FORC3 black[row][c] = (last[0][c] + last[1][c])/2; + FORC3 black[0][c] = (black[1][c] + black[3][c])/2; + + val = 1 - exp(-1/24.0); + memcpy (fsum, black, sizeof fsum); + for (row=1; row < height; row++) + FORC3 fsum[c] += black[row][c] = + (black[row][c] - black[row-1][c])*val + black[row-1][c]; + memcpy (last[0], black[height-1], sizeof last[0]); + FORC3 fsum[c] /= height; + for (row = height; row--; ) + FORC3 last[0][c] = black[row][c] = + (black[row][c] - fsum[c] - last[0][c])*val + last[0][c]; + + memset (total, 0, sizeof total); + for (row=2; row < height; row+=4) + for (col=2; col < width; col+=4) { + FORC3 total[c] += (short) image[row*width+col][c]; + total[3]++; + } + for (row=0; row < height; row++) + FORC3 black[row][c] += fsum[c]/2 + total[c]/(total[3]*100.0); + + for (row=0; row < height; row++) { + for (i=0; i < 3; i++) + for (j=0; j < 2; j++) + ((float *)ddft[0])[i] = ((float *)ddft[1])[i] + + row / (height-1.0) * (((float *)ddft[2])[i] - ((float *)ddft[1])[i]); + pix = image[row*width]; + memcpy (prev, pix, sizeof prev); + frow = row / (height-1.0) * (dim[2]-1); + if ((irow = frow) == (int) dim[2]-1) irow--; + frow -= irow; + for (i=0; i < (int) dim[1]; i++) + FORC3 sgrow[i][c] = sgain[ irow *dim[1]+i][c] * (1-frow) + + sgain[(irow+1)*dim[1]+i][c] * frow; + for (col=0; col < width; col++) { + FORC3 { + diff = pix[c] - prev[c]; + prev[c] = pix[c]; + ipix[c] = pix[c] + floor ((diff + (diff*diff >> 14)) * cfilt + - ddft[0][c][1] - ddft[0][c][0] * ((float) col/width - 0.5) + - black[row][c] ); + } + FORC3 { + work[0][c] = ipix[c] * ipix[c] >> 14; + work[2][c] = ipix[c] * work[0][c] >> 14; + work[1][2-c] = ipix[(c+1) % 3] * ipix[(c+2) % 3] >> 14; + } + FORC3 { + for (val=i=0; i < 3; i++) + for ( j=0; j < 3; j++) + val += ppm[c][i][j] * work[i][j]; + ipix[c] = floor ((ipix[c] + floor(val)) * + ( sgrow[col/sgx ][c] * (sgx - col%sgx) + + sgrow[col/sgx+1][c] * (col%sgx) ) / sgx / div[c]); + if (ipix[c] > 32000) ipix[c] = 32000; + pix[c] = ipix[c]; + } + pix += 4; + } + } + free (black); + free (sgrow); + free (sgain); + + if ((badpix = (unsigned *) foveon_camf_matrix (dim, "BadPixels"))) { + for (i=0; i < (int) dim[0]; i++) { + col = (badpix[i] >> 8 & 0xfff) - keep[0]; + row = (badpix[i] >> 20 ) - keep[1]; + if (row-1 < 0 || row-1 > height-3 || col-1 < 0 || col-1 > width-3) + continue; + memset (fsum, 0, sizeof fsum); + for (sum=j=0; j < 8; j++) + if (badpix[i] & (1 << j)) { + FORC3 fsum[c] += (short) + image[(row+hood[j*2])*width+col+hood[j*2+1]][c]; + sum++; + } + if (sum) FORC3 image[row*width+col][c] = fsum[c]/sum; + } + free (badpix); + } + + /* Array for 5x5 Gaussian averaging of red values */ + smrow[6] = (int (*)[3]) calloc (width*5, sizeof **smrow); + merror (smrow[6], "foveon_interpolate()"); + for (i=0; i < 5; i++) + smrow[i] = smrow[6] + i*width; + + /* Sharpen the reds against these Gaussian averages */ + for (smlast=-1, row=2; row < height-2; row++) { + while (smlast < row+2) { + for (i=0; i < 6; i++) + smrow[(i+5) % 6] = smrow[i]; + pix = image[++smlast*width+2]; + for (col=2; col < width-2; col++) { + smrow[4][col][0] = + (pix[0]*6 + (pix[-4]+pix[4])*4 + pix[-8]+pix[8] + 8) >> 4; + pix += 4; + } + } + pix = image[row*width+2]; + for (col=2; col < width-2; col++) { + smred = ( 6 * smrow[2][col][0] + + 4 * (smrow[1][col][0] + smrow[3][col][0]) + + smrow[0][col][0] + smrow[4][col][0] + 8 ) >> 4; + if (col == 2) + smred_p = smred; + i = pix[0] + ((pix[0] - ((smred*7 + smred_p) >> 3)) >> 3); + if (i > 32000) i = 32000; + pix[0] = i; + smred_p = smred; + pix += 4; + } + } + + /* Adjust the brighter pixels for better linearity */ + min = 0xffff; + FORC3 { + i = satlev[c] / div[c]; + if (min > i) min = i; + } + limit = min * 9 >> 4; + for (pix=image[0]; pix < image[height*width]; pix+=4) { + if (pix[0] <= limit || pix[1] <= limit || pix[2] <= limit) + continue; + min = max = pix[0]; + for (c=1; c < 3; c++) { + if (min > pix[c]) min = pix[c]; + if (max < pix[c]) max = pix[c]; + } + if (min >= limit*2) { + pix[0] = pix[1] = pix[2] = max; + } else { + i = 0x4000 - ((min - limit) << 14) / limit; + i = 0x4000 - (i*i >> 14); + i = i*i >> 14; + FORC3 pix[c] += (max - pix[c]) * i >> 14; + } + } +/* + Because photons that miss one detector often hit another, + the sum R+G+B is much less noisy than the individual colors. + So smooth the hues without smoothing the total. + */ + for (smlast=-1, row=2; row < height-2; row++) { + while (smlast < row+2) { + for (i=0; i < 6; i++) + smrow[(i+5) % 6] = smrow[i]; + pix = image[++smlast*width+2]; + for (col=2; col < width-2; col++) { + FORC3 smrow[4][col][c] = (pix[c-4]+2*pix[c]+pix[c+4]+2) >> 2; + pix += 4; + } + } + pix = image[row*width+2]; + for (col=2; col < width-2; col++) { + FORC3 dev[c] = -foveon_apply_curve (curve[7], pix[c] - + ((smrow[1][col][c] + 2*smrow[2][col][c] + smrow[3][col][c]) >> 2)); + sum = (dev[0] + dev[1] + dev[2]) >> 3; + FORC3 pix[c] += dev[c] - sum; + pix += 4; + } + } + for (smlast=-1, row=2; row < height-2; row++) { + while (smlast < row+2) { + for (i=0; i < 6; i++) + smrow[(i+5) % 6] = smrow[i]; + pix = image[++smlast*width+2]; + for (col=2; col < width-2; col++) { + FORC3 smrow[4][col][c] = + (pix[c-8]+pix[c-4]+pix[c]+pix[c+4]+pix[c+8]+2) >> 2; + pix += 4; + } + } + pix = image[row*width+2]; + for (col=2; col < width-2; col++) { + for (total[3]=375, sum=60, c=0; c < 3; c++) { + for (total[c]=i=0; i < 5; i++) + total[c] += smrow[i][col][c]; + total[3] += total[c]; + sum += pix[c]; + } + if (sum < 0) sum = 0; + j = total[3] > 375 ? (sum << 16) / total[3] : sum * 174; + FORC3 pix[c] += foveon_apply_curve (curve[6], + ((j*total[c] + 0x8000) >> 16) - pix[c]); + pix += 4; + } + } + + /* Transform the image to a different colorspace */ + for (pix=image[0]; pix < image[height*width]; pix+=4) { + FORC3 pix[c] -= foveon_apply_curve (curve[c], pix[c]); + sum = (pix[0]+pix[1]+pix[1]+pix[2]) >> 2; + FORC3 pix[c] -= foveon_apply_curve (curve[c], pix[c]-sum); + FORC3 { + for (dsum=i=0; i < 3; i++) + dsum += trans[c][i] * pix[i]; + if (dsum < 0) dsum = 0; + if (dsum > 24000) dsum = 24000; + ipix[c] = dsum + 0.5; + } + FORC3 pix[c] = ipix[c]; + } + + /* Smooth the image bottom-to-top and save at 1/4 scale */ + shrink = (short (*)[3]) calloc ((height/4), (width/4)*sizeof *shrink); + merror (shrink, "foveon_interpolate()"); + for (row = height/4; row--; ) + for (col=0; col < width/4; col++) { + ipix[0] = ipix[1] = ipix[2] = 0; + for (i=0; i < 4; i++) + for (j=0; j < 4; j++) + FORC3 ipix[c] += image[(row*4+i)*width+col*4+j][c]; + FORC3 + if (row+2 > height/4) + shrink[row*(width/4)+col][c] = ipix[c] >> 4; + else + shrink[row*(width/4)+col][c] = + (shrink[(row+1)*(width/4)+col][c]*1840 + ipix[c]*141 + 2048) >> 12; + } + /* From the 1/4-scale image, smooth right-to-left */ + for (row=0; row < (height & ~3); row++) { + ipix[0] = ipix[1] = ipix[2] = 0; + if ((row & 3) == 0) + for (col = width & ~3 ; col--; ) + FORC3 smrow[0][col][c] = ipix[c] = + (shrink[(row/4)*(width/4)+col/4][c]*1485 + ipix[c]*6707 + 4096) >> 13; + + /* Then smooth left-to-right */ + ipix[0] = ipix[1] = ipix[2] = 0; + for (col=0; col < (width & ~3); col++) + FORC3 smrow[1][col][c] = ipix[c] = + (smrow[0][col][c]*1485 + ipix[c]*6707 + 4096) >> 13; + + /* Smooth top-to-bottom */ + if (row == 0) + memcpy (smrow[2], smrow[1], sizeof **smrow * width); + else + for (col=0; col < (width & ~3); col++) + FORC3 smrow[2][col][c] = + (smrow[2][col][c]*6707 + smrow[1][col][c]*1485 + 4096) >> 13; + + /* Adjust the chroma toward the smooth values */ + for (col=0; col < (width & ~3); col++) { + for (i=j=30, c=0; c < 3; c++) { + i += smrow[2][col][c]; + j += image[row*width+col][c]; + } + j = (j << 16) / i; + for (sum=c=0; c < 3; c++) { + ipix[c] = foveon_apply_curve (curve[c+3], + ((smrow[2][col][c] * j + 0x8000) >> 16) - image[row*width+col][c]); + sum += ipix[c]; + } + sum >>= 3; + FORC3 { + i = image[row*width+col][c] + ipix[c] - sum; + if (i < 0) i = 0; + image[row*width+col][c] = i; + } + } + } + free (shrink); + free (smrow[6]); + for (i=0; i < 8; i++) + free (curve[i]); + + /* Trim off the black border */ + active[1] -= keep[1]; + active[3] -= 2; + i = active[2] - active[0]; + for (row=0; row < active[3]-active[1]; row++) + memcpy (image[row*i], image[(row+active[1])*width+active[0]], + i * sizeof *image); + width = i; + height = row; +} +#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 6)) +#pragma GCC diagnostic pop +#endif +#undef image + +/* RESTRICTED code ends here */ + +void CLASS crop_masked_pixels() +{ + int row, col; + unsigned r, c, m, mblack[8], zero, val; + + if (load_raw == &CLASS phase_one_load_raw || + load_raw == &CLASS phase_one_load_raw_c) + phase_one_correct(); + if (fuji_width) { + for (row=0; row < raw_height-top_margin*2; row++) { + for (col=0; col < fuji_width << !fuji_layout; col++) { + if (fuji_layout) { + r = fuji_width - 1 - col + (row >> 1); + c = col + ((row+1) >> 1); + } else { + r = fuji_width - 1 + row - (col >> 1); + c = row + ((col+1) >> 1); + } + if (r < height && c < width) + BAYER(r,c) = RAW(row+top_margin,col+left_margin); + } + } + } else { + for (row=0; row < height; row++) + for (col=0; col < width; col++) + BAYER2(row,col) = RAW(row+top_margin,col+left_margin); + } + if (mask[0][3] > 0) goto mask_set; + if (load_raw == &CLASS canon_load_raw || + load_raw == &CLASS lossless_jpeg_load_raw) { + mask[0][1] = mask[1][1] += 2; + mask[0][3] -= 2; + goto sides; + } + if (load_raw == &CLASS canon_600_load_raw || + load_raw == &CLASS sony_load_raw || + (load_raw == &CLASS eight_bit_load_raw && strncmp(model,"DC2",3)) || + load_raw == &CLASS kodak_262_load_raw || + (load_raw == &CLASS packed_load_raw && (load_flags & 256))) { +sides: + mask[0][0] = mask[1][0] = top_margin; + mask[0][2] = mask[1][2] = top_margin+height; + mask[0][3] += left_margin; + mask[1][1] += left_margin+width; + mask[1][3] += raw_width; + } + if (load_raw == &CLASS nokia_load_raw) { + mask[0][2] = top_margin; + mask[0][3] = width; + } +mask_set: + memset (mblack, 0, sizeof mblack); + for (zero=m=0; m < 8; m++) + for (row=MAX(mask[m][0],0); row < MIN(mask[m][2],raw_height); row++) + for (col=MAX(mask[m][1],0); col < MIN(mask[m][3],raw_width); col++) { + c = FC(row-top_margin,col-left_margin); + mblack[c] += val = RAW(row,col); + mblack[4+c]++; + zero += !val; + } + if (load_raw == &CLASS canon_600_load_raw && width < raw_width) { + black = (mblack[0]+mblack[1]+mblack[2]+mblack[3]) / + (mblack[4]+mblack[5]+mblack[6]+mblack[7]) - 4; + canon_600_correct(); + } else if (zero < mblack[4] && mblack[5] && mblack[6] && mblack[7]) { + FORC4 cblack[c] = mblack[c] / mblack[4+c]; + cblack[4] = cblack[5] = cblack[6] = 0; + } +} + +void CLASS remove_zeroes() +{ + unsigned row, col, tot, n, r, c; + + for (row=0; row < height; row++) + for (col=0; col < width; col++) + if (BAYER(row,col) == 0) { + tot = n = 0; + for (r = row-2; r <= row+2; r++) + for (c = col-2; c <= col+2; c++) + if (r < height && c < width && + FC(r,c) == FC(row,col) && BAYER(r,c)) + tot += (n++,BAYER(r,c)); + if (n) BAYER(row,col) = tot/n; + } +} + +/* + Seach from the current directory up to the root looking for + a ".badpixels" file, and fix those pixels now. + */ +void CLASS bad_pixels (const char *cfname) +{ + FILE *fp=0; + char *fname, *cp, line[128]; + int len, time, row, col, r, c, rad, tot, n, fixed=0; + + if (!filters) return; + if (cfname) + fp = fopen (cfname, "r"); + else { + for (len=32 ; ; len *= 2) { + fname = (char *) malloc (len); + if (!fname) return; + if (getcwd (fname, len-16)) break; + free (fname); + if (errno != ERANGE) return; + } +#if defined(_WIN32) || defined(DJGPP) + if (fname[1] == ':') + memmove (fname, fname+2, len-2); + for (cp=fname; *cp; cp++) + if (*cp == '\\') *cp = '/'; +#endif + cp = fname + strlen(fname); + if (cp[-1] == '/') cp--; + while (*fname == '/') { + strcpy (cp, "/.badpixels"); + if ((fp = fopen (fname, "r"))) break; + if (cp == fname) break; + while (*--cp != '/'); + } + free (fname); + } + if (!fp) return; + while (::fgets (line, 128, fp)) { + cp = strchr (line, '#'); + if (cp) *cp = 0; + if (sscanf (line, "%d %d %d", &col, &row, &time) != 3) continue; + if ((unsigned) col >= width || (unsigned) row >= height) continue; + if (time > timestamp) continue; + for (tot=n=0, rad=1; rad < 3 && n==0; rad++) + for (r = row-rad; r <= row+rad; r++) + for (c = col-rad; c <= col+rad; c++) + if ((unsigned) r < height && (unsigned) c < width && + (r != row || c != col) && fcol(r,c) == fcol(row,col)) { + tot += BAYER2(r,c); + n++; + } + BAYER2(row,col) = tot/n; + if (!fixed++) dcraw_message(DCRAW_VERBOSE,_("Fixed dead pixels at:")); + dcraw_message(DCRAW_VERBOSE, " %d,%d", col, row); + } + if (fixed) dcraw_message(DCRAW_VERBOSE, "\n"); + fclose (fp); +} + +void CLASS subtract (const char *fname) +{ + FILE *fp; + int dim[3]={0,0,0}, comment=0, number=0, error=0, nd=0, c, row, col; + ushort *pixel; + + if (!(fp = fopen (fname, "rb"))) { + perror (fname); return; + } + if (fgetc(fp) != 'P' || fgetc(fp) != '5') error = 1; + while (!error && nd < 3 && (c = fgetc(fp)) != EOF) { + if (c == '#') comment = 1; + if (c == '\n') comment = 0; + if (comment) continue; + if (isdigit(c)) number = 1; + if (number) { + if (isdigit(c)) dim[nd] = dim[nd]*10 + c -'0'; + else if (isspace(c)) { + number = 0; nd++; + } else error = 1; + } + } + if (error || nd < 3) { + dcraw_message (DCRAW_ERROR,_("%s is not a valid PGM file!\n"), fname); + fclose (fp); return; + } else if (dim[0] != width || dim[1] != height || dim[2] != 65535) { + dcraw_message (DCRAW_ERROR,_("%s has the wrong dimensions!\n"), fname); + fclose (fp); return; + } + pixel = (ushort *) calloc (width, sizeof *pixel); + merror (pixel, "subtract()"); + for (row=0; row < height; row++) { + fread (pixel, 2, width, fp); + for (col=0; col < width; col++) + BAYER(row,col) = MAX (BAYER(row,col) - ntohs(pixel[col]), 0); + } + free (pixel); + fclose (fp); + memset (cblack, 0, sizeof cblack); + black = 0; +} + +void CLASS gamma_curve (double pwr, double ts, int mode, int imax) +{ + int i; + double g[6], bnd[2]={0,0}, r; + + g[0] = pwr; + g[1] = ts; + g[2] = g[3] = g[4] = 0; + bnd[g[1] >= 1] = 1; + if (g[1] && (g[1]-1)*(g[0]-1) <= 0) { + for (i=0; i < 48; i++) { + g[2] = (bnd[0] + bnd[1])/2; + if (g[0]) bnd[(pow(g[2]/g[1],-g[0]) - 1)/g[0] - 1/g[2] > -1] = g[2]; + else bnd[g[2]/exp(1-1/g[2]) < g[1]] = g[2]; + } + g[3] = g[2] / g[1]; + if (g[0]) g[4] = g[2] * (1/g[0] - 1); + } + if (g[0]) g[5] = 1 / (g[1]*SQR(g[3])/2 - g[4]*(1 - g[3]) + + (1 - pow(g[3],1+g[0]))*(1 + g[4])/(1 + g[0])) - 1; + else g[5] = 1 / (g[1]*SQR(g[3])/2 + 1 + - g[2] - g[3] - g[2]*g[3]*(log(g[3]) - 1)) - 1; + if (!mode--) { + memcpy (gamm, g, sizeof gamm); + return; + } + for (i=0; i < 0x10000; i++) { + curve[i] = 0xffff; + if ((r = (double) i / imax) < 1) + curve[i] = 0x10000 * ( mode + ? (r < g[3] ? r*g[1] : (g[0] ? pow( r,g[0])*(1+g[4])-g[4] : log(r)*g[2]+1)) + : (r < g[2] ? r/g[1] : (g[0] ? pow((r+g[4])/(1+g[4]),1/g[0]) : exp((r-1)/g[2])))); + } +} + +void CLASS pseudoinverse (double (*in)[3], double (*out)[3], int size) +{ + double work[3][6], num; + int i, j, k; + + for (i=0; i < 3; i++) { + for (j=0; j < 6; j++) + work[i][j] = j == i+3; + for (j=0; j < 3; j++) + for (k=0; k < size; k++) + work[i][j] += in[k][i] * in[k][j]; + } + for (i=0; i < 3; i++) { + num = work[i][i]; + for (j=0; j < 6; j++) + work[i][j] /= num; + for (k=0; k < 3; k++) { + if (k==i) continue; + num = work[k][i]; + for (j=0; j < 6; j++) + work[k][j] -= work[i][j] * num; + } + } + for (i=0; i < size; i++) + for (j=0; j < 3; j++) + for (out[i][j]=k=0; k < 3; k++) + out[i][j] += work[j][k+3] * in[i][k]; +} + +void CLASS cam_xyz_coeff (float rgb_cam[3][4], double cam_xyz[4][3]) +{ + double cam_rgb[4][3], inverse[4][3], num; + unsigned i, j, k; + + for (i=0; i < colors; i++) /* Multiply out XYZ colorspace */ + for (j=0; j < 3; j++) + for (cam_rgb[i][j] = k=0; k < 3; k++) + cam_rgb[i][j] += cam_xyz[i][k] * xyz_rgb[k][j]; + + for (i=0; i < colors; i++) { /* Normalize cam_rgb so that */ + for (num=j=0; j < 3; j++) /* cam_rgb * (1,1,1) is (1,1,1,1) */ + num += cam_rgb[i][j]; + for (j=0; j < 3; j++) + cam_rgb[i][j] /= num; + pre_mul[i] = 1 / num; + } + pseudoinverse (cam_rgb, inverse, colors); + for (i=0; i < 3; i++) + for (j=0; j < colors; j++) + rgb_cam[i][j] = inverse[j][i]; +} + +#ifdef COLORCHECK +void CLASS colorcheck() +{ +#define NSQ 24 +// Coordinates of the GretagMacbeth ColorChecker squares +// width, height, 1st_column, 1st_row + int cut[NSQ][4]; // you must set these +// ColorChecker Chart under 6500-kelvin illumination + static const double gmb_xyY[NSQ][3] = { + { 0.400, 0.350, 10.1 }, // Dark Skin + { 0.377, 0.345, 35.8 }, // Light Skin + { 0.247, 0.251, 19.3 }, // Blue Sky + { 0.337, 0.422, 13.3 }, // Foliage + { 0.265, 0.240, 24.3 }, // Blue Flower + { 0.261, 0.343, 43.1 }, // Bluish Green + { 0.506, 0.407, 30.1 }, // Orange + { 0.211, 0.175, 12.0 }, // Purplish Blue + { 0.453, 0.306, 19.8 }, // Moderate Red + { 0.285, 0.202, 6.6 }, // Purple + { 0.380, 0.489, 44.3 }, // Yellow Green + { 0.473, 0.438, 43.1 }, // Orange Yellow + { 0.187, 0.129, 6.1 }, // Blue + { 0.305, 0.478, 23.4 }, // Green + { 0.539, 0.313, 12.0 }, // Red + { 0.448, 0.470, 59.1 }, // Yellow + { 0.364, 0.233, 19.8 }, // Magenta + { 0.196, 0.252, 19.8 }, // Cyan + { 0.310, 0.316, 90.0 }, // White + { 0.310, 0.316, 59.1 }, // Neutral 8 + { 0.310, 0.316, 36.2 }, // Neutral 6.5 + { 0.310, 0.316, 19.8 }, // Neutral 5 + { 0.310, 0.316, 9.0 }, // Neutral 3.5 + { 0.310, 0.316, 3.1 } }; // Black + double gmb_cam[NSQ][4], gmb_xyz[NSQ][3]; + double inverse[NSQ][3], cam_xyz[4][3], balance[4], num; + int c, i, j, k, sq, row, col, pass, count[4]; + + memset (gmb_cam, 0, sizeof gmb_cam); + for (sq=0; sq < NSQ; sq++) { + FORCC count[c] = 0; + for (row=cut[sq][3]; row < cut[sq][3]+cut[sq][1]; row++) + for (col=cut[sq][2]; col < cut[sq][2]+cut[sq][0]; col++) { + c = FC(row,col); + if (c >= colors) c -= 2; + gmb_cam[sq][c] += BAYER2(row,col); + BAYER2(row,col) = black + (BAYER2(row,col)-black)/2; + count[c]++; + } + FORCC gmb_cam[sq][c] = gmb_cam[sq][c]/count[c] - black; + gmb_xyz[sq][0] = gmb_xyY[sq][2] * gmb_xyY[sq][0] / gmb_xyY[sq][1]; + gmb_xyz[sq][1] = gmb_xyY[sq][2]; + gmb_xyz[sq][2] = gmb_xyY[sq][2] * + (1 - gmb_xyY[sq][0] - gmb_xyY[sq][1]) / gmb_xyY[sq][1]; + } + pseudoinverse (gmb_xyz, inverse, NSQ); + for (pass=0; pass < 2; pass++) { + for (raw_color = i=0; i < colors; i++) + for (j=0; j < 3; j++) + for (cam_xyz[i][j] = k=0; k < NSQ; k++) + cam_xyz[i][j] += gmb_cam[k][i] * inverse[k][j]; + cam_xyz_coeff (rgb_cam, cam_xyz); + FORCC balance[c] = pre_mul[c] * gmb_cam[20][c]; + for (sq=0; sq < NSQ; sq++) + FORCC gmb_cam[sq][c] *= balance[c]; + } + if (verbose) { + dcraw_message (DCRAW_VERBOSE, " { \"%s %s\", %d,\n\t{", make, model, black); + num = 10000 / (cam_xyz[1][0] + cam_xyz[1][1] + cam_xyz[1][2]); + FORCC for (j=0; j < 3; j++) + dcraw_message (DCRAW_VERBOSE, "%c%d", (c | j) ? ',':' ', (int) (cam_xyz[c][j] * num + 0.5)); + dcraw_message (DCRAW_VERBOSE, " } },\n"); + } +#undef NSQ +} +#endif + +/* Start of functions copied to dcraw_indi.c (UF) */ +void CLASS hat_transform (float *temp, float *base, int st, int size, int sc) +{ + int i; + for (i=0; i < sc; i++) + temp[i] = 2*base[st*i] + base[st*(sc-i)] + base[st*(i+sc)]; + for (; i+sc < size; i++) + temp[i] = 2*base[st*i] + base[st*(i-sc)] + base[st*(i+sc)]; + for (; i < size; i++) + temp[i] = 2*base[st*i] + base[st*(i-sc)] + base[st*(2*size-2-(i+sc))]; +} + +void CLASS wavelet_denoise() +{ + float *fimg=0, *temp, thold, mul[2], avg, diff; + int scale=1, size, lev, hpass, lpass, row, col, nc, c, i, wlast, blk[2]; + ushort *window[4]; + static const float noise[] = + { 0.8002,0.2735,0.1202,0.0585,0.0291,0.0152,0.0080,0.0044 }; + + dcraw_message (DCRAW_VERBOSE,_("Wavelet denoising...\n")); + + while (maximum << scale < 0x10000) scale++; + maximum <<= --scale; + black <<= scale; + FORC4 cblack[c] <<= scale; + if ((size = iheight*iwidth) < 0x15550000) + fimg = (float *) malloc ((size*3 + iheight + iwidth) * sizeof *fimg); + merror (fimg, "wavelet_denoise()"); + temp = fimg + size*3; + if ((nc = colors) == 3 && filters) nc++; + FORC(nc) { /* denoise R,G1,B,G3 individually */ + for (i=0; i < size; i++) + fimg[i] = 256 * sqrt((float)(image[i][c] << scale)); + for (hpass=lev=0; lev < 5; lev++) { + lpass = size*((lev & 1)+1); + for (row=0; row < iheight; row++) { + hat_transform (temp, fimg+hpass+row*iwidth, 1, iwidth, 1 << lev); + for (col=0; col < iwidth; col++) + fimg[lpass + row*iwidth + col] = temp[col] * 0.25; + } + for (col=0; col < iwidth; col++) { + hat_transform (temp, fimg+lpass+col, iwidth, iheight, 1 << lev); + for (row=0; row < iheight; row++) + fimg[lpass + row*iwidth + col] = temp[row] * 0.25; + } + thold = threshold * noise[lev]; + for (i=0; i < size; i++) { + fimg[hpass+i] -= fimg[lpass+i]; + if (fimg[hpass+i] < -thold) fimg[hpass+i] += thold; + else if (fimg[hpass+i] > thold) fimg[hpass+i] -= thold; + else fimg[hpass+i] = 0; + if (hpass) fimg[i] += fimg[hpass+i]; + } + hpass = lpass; + } + for (i=0; i < size; i++) + image[i][c] = CLIP(SQR(fimg[i]+fimg[lpass+i])/0x10000); + } + if (filters && colors == 3) { /* pull G1 and G3 closer together */ + for (row=0; row < 2; row++) { + mul[row] = 0.125 * pre_mul[FC(row+1,0) | 1] / pre_mul[FC(row,0) | 1]; + blk[row] = cblack[FC(row,0) | 1]; + } + for (i=0; i < 4; i++) + window[i] = (ushort *) fimg + width*i; + for (wlast=-1, row=1; row < height-1; row++) { + while (wlast < row+1) { + for (wlast++, i=0; i < 4; i++) + window[(i+3) & 3] = window[i]; + for (col = FC(wlast,1) & 1; col < width; col+=2) + window[2][col] = BAYER(wlast,col); + } + thold = threshold/512; + for (col = (FC(row,0) & 1)+1; col < width-1; col+=2) { + avg = ( window[0][col-1] + window[0][col+1] + + window[2][col-1] + window[2][col+1] - blk[~row & 1]*4 ) + * mul[row & 1] + (window[1][col] + blk[row & 1]) * 0.5; + avg = avg < 0 ? 0 : sqrt(avg); + diff = sqrt((float) BAYER(row,col)) - avg; + if (diff < -thold) diff += thold; + else if (diff > thold) diff -= thold; + else diff = 0; + BAYER(row,col) = CLIP(SQR(avg+diff) + 0.5); + } + } + } + free (fimg); +} + +void CLASS scale_colors() +{ + unsigned bottom, right, size, row, col, i, x, y, c, sum[8]; + int val, dark, sat, ur, uc; + double dsum[8], dmin, dmax; + float scale_mul[4], fr, fc; + ushort *img=0, *pix; + + if (user_mul[0]) + memcpy (pre_mul, user_mul, sizeof pre_mul); + if (use_auto_wb || (use_camera_wb && cam_mul[0] == -1)) { + memset (dsum, 0, sizeof dsum); + bottom = MIN (greybox[1]+greybox[3], height); + right = MIN (greybox[0]+greybox[2], width); + for (row=greybox[1]; row < bottom; row += 8) + for (col=greybox[0]; col < right; col += 8) { + memset (sum, 0, sizeof sum); + for (y=row; y < row+8 && y < bottom; y++) + for (x=col; x < col+8 && x < right; x++) + FORC4 { + if (filters) { + c = fcol(y,x); + val = BAYER2(y,x); + } else + val = image[y*width+x][c]; + if (val > (int)(maximum-25)) goto skip_block; + if ((val -= cblack[c]) < 0) val = 0; + sum[c] += val; + sum[c+4]++; + if (filters) break; + } + FORC(8) dsum[c] += sum[c]; +skip_block: ; + } + FORC4 if (dsum[c]) pre_mul[c] = dsum[c+4] / dsum[c]; + } + if (use_camera_wb && cam_mul[0] != -1) { + memset (sum, 0, sizeof sum); + for (row=0; row < 8; row++) + for (col=0; col < 8; col++) { + c = FC(row,col); + if ((val = white[row][col] - cblack[c]) > 0) + sum[c] += val; + sum[c+4]++; + } + if (sum[0] && sum[1] && sum[2] && sum[3]) + FORC4 pre_mul[c] = (float) sum[c+4] / sum[c]; + else if (cam_mul[0] && cam_mul[2]) + memcpy (pre_mul, cam_mul, sizeof pre_mul); + else + dcraw_message (DCRAW_NO_CAMERA_WB,_("%s: Cannot use camera white balance.\n"), ifname_display); + } + if (pre_mul[1] == 0) pre_mul[1] = 1; + if (pre_mul[3] == 0) pre_mul[3] = colors < 4 ? pre_mul[1] : 1; + dark = black; + sat = maximum; + if (threshold) wavelet_denoise(); + maximum -= black; + for (dmin=DBL_MAX, dmax=c=0; c < 4; c++) { + if (dmin > pre_mul[c]) + dmin = pre_mul[c]; + if (dmax < pre_mul[c]) + dmax = pre_mul[c]; + } + if (!highlight) dmax = dmin; + FORC4 scale_mul[c] = (pre_mul[c] /= dmax) * 65535.0 / maximum; + dcraw_message(DCRAW_VERBOSE, + _("Scaling with darkness %d, saturation %d, and\nmultipliers"), dark, sat); + FORC4 dcraw_message(DCRAW_VERBOSE, " %f", pre_mul[c]); + dcraw_message(DCRAW_VERBOSE, "\n"); + if (filters > 1000 && (cblack[4]+1)/2 == 1 && (cblack[5]+1)/2 == 1) { + FORC4 cblack[FC(c/2,c%2)] += + cblack[6 + c/2 % cblack[4] * cblack[5] + c%2 % cblack[5]]; + cblack[4] = cblack[5] = 0; + } + size = iheight*iwidth; + for (i=0; i < size*4; i++) { + if (!(val = ((ushort *)image)[i])) continue; + if (cblack[4] && cblack[5]) + val -= cblack[6 + i/4 / iwidth % cblack[4] * cblack[5] + + i/4 % iwidth % cblack[5]]; + val -= cblack[i & 3]; + val *= scale_mul[i & 3]; + ((ushort *)image)[i] = CLIP(val); + } + if ((aber[0] != 1 || aber[2] != 1) && colors == 3) { + dcraw_message (DCRAW_VERBOSE,_("Correcting chromatic aberration...\n")); + for (c=0; c < 4; c+=2) { + if (aber[c] == 1) continue; + img = (ushort *) malloc (size * sizeof *img); + merror (img, "scale_colors()"); + for (i=0; i < size; i++) + img[i] = image[i][c]; + for (row=0; row < iheight; row++) { + ur = fr = (row - iheight*0.5) * aber[c] + iheight*0.5; + if (ur > iheight-2) continue; + fr -= ur; + for (col=0; col < iwidth; col++) { + uc = fc = (col - iwidth*0.5) * aber[c] + iwidth*0.5; + if (uc > iwidth-2) continue; + fc -= uc; + pix = img + ur*iwidth + uc; + image[row*iwidth+col][c] = + (pix[ 0]*(1-fc) + pix[ 1]*fc) * (1-fr) + + (pix[iwidth]*(1-fc) + pix[iwidth+1]*fc) * fr; + } + } + free(img); + } + } +} +/* End of functions copied to dcraw_indi.c (UF) */ + +void CLASS pre_interpolate() +{ + ushort (*img)[4]; + int row, col, c; + + if (shrink) { + if (half_size) { + height = iheight; + width = iwidth; + if (filters == 9) { + for (row=0; row < 3; row++) + for (col=1; col < 4; col++) + if (!(image[row*width+col][0] | image[row*width+col][2])) + goto break2; break2: + for ( ; row < height; row+=3) + for (col=(col-1)%3+1; col < width-1; col+=3) { + img = image + row*width+col; + for (c=0; c < 3; c+=2) + img[0][c] = (img[-1][c] + img[1][c]) >> 1; + } + } + } else { + img = (ushort (*)[4]) calloc (height, width*sizeof *img); + merror (img, "pre_interpolate()"); + for (row=0; row < height; row++) + for (col=0; col < width; col++) { + c = fcol(row,col); + img[row*width+col][c] = image[(row >> 1)*iwidth+(col >> 1)][c]; + } + free (image); + image = img; + shrink = 0; + } + } + if (filters > 1000 && colors == 3) { + mix_green = four_color_rgb ^ half_size; + if (four_color_rgb | half_size) colors++; + else { + for (row = FC(1,0) >> 1; row < height; row+=2) + for (col = FC(row,1) & 1; col < width; col+=2) + image[row*width+col][1] = image[row*width+col][3]; + filters &= ~((filters & 0x55555555) << 1); + } + } + if (half_size) filters = 0; +} + +/* Start of functions copied to dcraw_indi.c (UF) */ +void CLASS border_interpolate (unsigned border) +{ + unsigned row, col, y, x, f, c, sum[8]; + + for (row=0; row < height; row++) + for (col=0; col < width; col++) { + if (col==border && row >= border && row < height-border) + col = width-border; + memset (sum, 0, sizeof sum); + for (y=row-1; y != row+2; y++) + for (x=col-1; x != col+2; x++) + if (y < height && x < width) { + f = fcol(y,x); + sum[f] += image[y*width+x][f]; + sum[f+4]++; + } + f = fcol(row,col); + FORCC if (c != f && sum[c+4]) + image[row*width+col][c] = sum[c] / sum[c+4]; + } +} + +void CLASS lin_interpolate() +{ + int code[16][16][32], size=16, *ip, sum[4]; + unsigned c; + int f, i, x, y, row, col, shift, color; + ushort *pix; + + dcraw_message (DCRAW_VERBOSE,_("Bilinear interpolation...\n")); + if (filters == 9) size = 6; + border_interpolate(1); + for (row=0; row < size; row++) + for (col=0; col < size; col++) { + ip = code[row][col]+1; + f = fcol(row,col); + memset (sum, 0, sizeof sum); + for (y=-1; y <= 1; y++) + for (x=-1; x <= 1; x++) { + shift = (y==0) + (x==0); + color = fcol(row+y,col+x); + if (color == f) continue; + *ip++ = (width*y + x)*4 + color; + *ip++ = shift; + *ip++ = color; + sum[color] += 1 << shift; + } + code[row][col][0] = (ip - code[row][col]) / 3; + FORCC + if ((int) c != f) { + *ip++ = c; + *ip++ = 256 / sum[c]; + } + } + for (row=1; row < height-1; row++) + for (col=1; col < width-1; col++) { + pix = image[row*width+col]; + ip = code[row % size][col % size]; + memset (sum, 0, sizeof sum); + for (i=*ip++; i--; ip+=3) + sum[ip[2]] += pix[ip[0]] << ip[1]; + for (i=colors; --i; ip+=2) + pix[ip[0]] = sum[ip[0]] * ip[1] >> 8; + } +} + +/* + This algorithm is officially called: + + "Interpolation using a Threshold-based variable number of gradients" + + described in http://scien.stanford.edu/pages/labsite/1999/psych221/projects/99/tingchen/algodep/vargra.html + + I've extended the basic idea to work with non-Bayer filter arrays. + Gradients are numbered clockwise from NW=0 to W=7. + */ +void CLASS vng_interpolate() +{ + static const signed char *cp, terms[] = { + -2,-2,+0,-1,0,0x01, -2,-2,+0,+0,1,0x01, -2,-1,-1,+0,0,0x01, + -2,-1,+0,-1,0,0x02, -2,-1,+0,+0,0,0x03, -2,-1,+0,+1,1,0x01, + -2,+0,+0,-1,0,0x06, -2,+0,+0,+0,1,0x02, -2,+0,+0,+1,0,0x03, + -2,+1,-1,+0,0,0x04, -2,+1,+0,-1,1,0x04, -2,+1,+0,+0,0,0x06, + -2,+1,+0,+1,0,0x02, -2,+2,+0,+0,1,0x04, -2,+2,+0,+1,0,0x04, + -1,-2,-1,+0,0,static_cast(0x80), -1,-2,+0,-1,0,0x01, -1,-2,+1,-1,0,0x01, + -1,-2,+1,+0,1,0x01, -1,-1,-1,+1,0,static_cast(0x88), -1,-1,+1,-2,0,0x40, + -1,-1,+1,-1,0,0x22, -1,-1,+1,+0,0,0x33, -1,-1,+1,+1,1,0x11, + -1,+0,-1,+2,0,0x08, -1,+0,+0,-1,0,0x44, -1,+0,+0,+1,0,0x11, + -1,+0,+1,-2,1,0x40, -1,+0,+1,-1,0,0x66, -1,+0,+1,+0,1,0x22, + -1,+0,+1,+1,0,0x33, -1,+0,+1,+2,1,0x10, -1,+1,+1,-1,1,0x44, + -1,+1,+1,+0,0,0x66, -1,+1,+1,+1,0,0x22, -1,+1,+1,+2,0,0x10, + -1,+2,+0,+1,0,0x04, -1,+2,+1,+0,1,0x04, -1,+2,+1,+1,0,0x04, + +0,-2,+0,+0,1,static_cast(0x80), +0,-1,+0,+1,1,static_cast(0x88), +0,-1,+1,-2,0,0x40, + +0,-1,+1,+0,0,0x11, +0,-1,+2,-2,0,0x40, +0,-1,+2,-1,0,0x20, + +0,-1,+2,+0,0,0x30, +0,-1,+2,+1,1,0x10, +0,+0,+0,+2,1,0x08, + +0,+0,+2,-2,1,0x40, +0,+0,+2,-1,0,0x60, +0,+0,+2,+0,1,0x20, + +0,+0,+2,+1,0,0x30, +0,+0,+2,+2,1,0x10, +0,+1,+1,+0,0,0x44, + +0,+1,+1,+2,0,0x10, +0,+1,+2,-1,1,0x40, +0,+1,+2,+0,0,0x60, + +0,+1,+2,+1,0,0x20, +0,+1,+2,+2,0,0x10, +1,-2,+1,+0,0,static_cast(0x80), + +1,-1,+1,+1,0,static_cast(0x88), +1,+0,+1,+2,0,0x08, +1,+0,+2,-1,0,0x40, + +1,+0,+2,+1,0,0x10 + }, chood[] = { -1,-1, -1,0, -1,+1, 0,+1, +1,+1, +1,0, +1,-1, 0,-1 }; + ushort (*brow[5])[4], *pix; + unsigned c; + int prow=8, pcol=2, *ip, *code[16][16], gval[8], gmin, gmax, sum[4]; + int row, col, x, y, x1, x2, y1, y2, t, weight, grads, color, diag; + int g, diff, thold, num; + + lin_interpolate(); + dcraw_message (DCRAW_VERBOSE,_("VNG interpolation...\n")); + + if (filters == 1) prow = pcol = 16; + if (filters == 9) prow = pcol = 6; + ip = (int *) calloc (prow*pcol, 1280); + merror (ip, "vng_interpolate()"); + for (row=0; row < prow; row++) /* Precalculate for VNG */ + for (col=0; col < pcol; col++) { + code[row][col] = ip; + for (cp=terms, t=0; t < 64; t++) { + y1 = *cp++; x1 = *cp++; + y2 = *cp++; x2 = *cp++; + weight = *cp++; + grads = *cp++; + color = fcol(row+y1,col+x1); + if (fcol(row+y2,col+x2) != color) continue; + diag = (fcol(row,col+1) == color && fcol(row+1,col) == color) ? 2:1; + if (abs(y1-y2) == diag && abs(x1-x2) == diag) continue; + *ip++ = (y1*width + x1)*4 + color; + *ip++ = (y2*width + x2)*4 + color; + *ip++ = weight; + for (g=0; g < 8; g++) + if (grads & 1< gval[g]) gmin = gval[g]; + if (gmax < gval[g]) gmax = gval[g]; + } + if (gmax == 0) { + memcpy (brow[2][col], pix, sizeof *image); + continue; + } + thold = gmin + (gmax >> 1); + memset (sum, 0, sizeof sum); + color = fcol(row,col); + for (num=g=0; g < 8; g++,ip+=2) { /* Average the neighbors */ + if (gval[g] <= thold) { + FORCC + if ((int) c == color && ip[1]) + sum[c] += (pix[c] + pix[ip[1]]) >> 1; + else + sum[c] += pix[ip[0] + c]; + num++; + } + } + FORCC { /* Save to buffer */ + t = pix[color]; + if ((int) c != color) + t += (sum[c] - sum[color]) / num; + brow[2][col][c] = CLIP(t); + } + } + if (row > 3) /* Write buffer to image */ + memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image); + for (g=0; g < 4; g++) + brow[(g-1) & 3] = brow[g]; + } + memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image); + memcpy (image[(row-1)*width+2], brow[1]+2, (width-4)*sizeof *image); + free (brow[4]); + free (code[0][0]); +} + +/* + Patterned Pixel Grouping Interpolation by Alain Desbiolles +*/ +void CLASS ppg_interpolate() +{ + int dir[5] = { 1, width, -1, -width, 1 }; + int row, col, diff[2] = { 0, 0 }, guess[2], c, d, i; + ushort (*pix)[4]; + + border_interpolate(3); + dcraw_message (DCRAW_VERBOSE,_("PPG interpolation...\n")); + +/* Fill in the green layer with gradients and pattern recognition: */ + for (row=3; row < height-3; row++) + for (col=3+(FC(row,3) & 1), c=FC(row,col); col < width-3; col+=2) { + pix = image + row*width+col; + for (i=0; (d=dir[i]) > 0; i++) { + guess[i] = (pix[-d][1] + pix[0][c] + pix[d][1]) * 2 + - pix[-2*d][c] - pix[2*d][c]; + diff[i] = ( ABS(pix[-2*d][c] - pix[ 0][c]) + + ABS(pix[ 2*d][c] - pix[ 0][c]) + + ABS(pix[ -d][1] - pix[ d][1]) ) * 3 + + ( ABS(pix[ 3*d][1] - pix[ d][1]) + + ABS(pix[-3*d][1] - pix[-d][1]) ) * 2; + } + d = dir[i = diff[0] > diff[1]]; + pix[0][1] = ULIM(guess[i] >> 2, pix[d][1], pix[-d][1]); + } +/* Calculate red and blue for each green pixel: */ + for (row=1; row < height-1; row++) + for (col=1+(FC(row,2) & 1), c=FC(row,col+1); col < width-1; col+=2) { + pix = image + row*width+col; + for (i=0; (d=dir[i]) > 0; c=2-c, i++) + pix[0][c] = CLIP((pix[-d][c] + pix[d][c] + 2*pix[0][1] + - pix[-d][1] - pix[d][1]) >> 1); + } +/* Calculate blue for red pixels and vice versa: */ + for (row=1; row < height-1; row++) + for (col=1+(FC(row,1) & 1), c=2-FC(row,col); col < width-1; col+=2) { + pix = image + row*width+col; + for (i=0; (d=dir[i]+dir[i+1]) > 0; i++) { + diff[i] = ABS(pix[-d][c] - pix[d][c]) + + ABS(pix[-d][1] - pix[0][1]) + + ABS(pix[ d][1] - pix[0][1]); + guess[i] = pix[-d][c] + pix[d][c] + 2*pix[0][1] + - pix[-d][1] - pix[d][1]; + } + if (diff[0] != diff[1]) + pix[0][c] = CLIP(guess[diff[0] > diff[1]] >> 1); + else + pix[0][c] = CLIP((guess[0]+guess[1]) >> 2); + } +} + +void CLASS cielab (ushort rgb[3], short lab[3]) +{ + unsigned c, i, j, k; + float r, xyz[3]; + static float cbrt[0x10000], xyz_cam[3][4]; + + if (!rgb) { + for (i=0; i < 0x10000; i++) { + r = i / 65535.0; + cbrt[i] = r > 0.008856 ? pow(r, (float)(1/3.0)) : 7.787*r + 16/116.0; + } + for (i=0; i < 3; i++) + for (j=0; j < colors; j++) + for (xyz_cam[i][j] = k=0; k < 3; k++) + xyz_cam[i][j] += xyz_rgb[i][k] * rgb_cam[k][j] / d65_white[i]; + return; + } + xyz[0] = xyz[1] = xyz[2] = 0.5; + FORCC { + xyz[0] += xyz_cam[0][c] * rgb[c]; + xyz[1] += xyz_cam[1][c] * rgb[c]; + xyz[2] += xyz_cam[2][c] * rgb[c]; + } + xyz[0] = cbrt[CLIP((int) xyz[0])]; + xyz[1] = cbrt[CLIP((int) xyz[1])]; + xyz[2] = cbrt[CLIP((int) xyz[2])]; + lab[0] = 64 * (116 * xyz[1] - 16); + lab[1] = 64 * 500 * (xyz[0] - xyz[1]); + lab[2] = 64 * 200 * (xyz[1] - xyz[2]); +} + +#define TS 512 /* Tile Size */ +#define fcol(row,col) xtrans[(row+6) % 6][(col+6) % 6] + +/* + Frank Markesteijn's algorithm for Fuji X-Trans sensors + */ +void CLASS xtrans_interpolate (int passes) +{ + int c, d, f, g, h, i, v, ng, row, col, top, left, mrow, mcol; + int val, ndir, pass, hm[8], avg[4], color[3][8]; + static const short orth[12] = { 1,0,0,1,-1,0,0,-1,1,0,0,1 }, + patt[2][16] = { { 0,1,0,-1,2,0,-1,0,1,1,1,-1,0,0,0,0 }, + { 0,1,0,-2,1,0,-2,0,1,1,-2,-2,1,-1,-1,1 } }, + dir[4] = { 1,TS,TS+1,TS-1 }; + short allhex[3][3][2][8], *hex; + ushort min, max, sgrow = 0, sgcol = 0; + ushort (*rgb)[TS][TS][3], (*rix)[3], (*pix)[4]; + short (*lab) [TS][3], (*lix)[3]; + float (*drv)[TS][TS], diff[6], tr; + char (*homo)[TS][TS], *buffer; + + dcraw_message (DCRAW_VERBOSE,_("%d-pass X-Trans interpolation...\n"), passes); + + cielab (0,0); + ndir = 4 << (passes > 1); + buffer = (char *) malloc (TS*TS*(ndir*11+6)); + merror (buffer, "xtrans_interpolate()"); + rgb = (ushort(*)[TS][TS][3]) buffer; + lab = (short (*) [TS][3])(buffer + TS*TS*(ndir*6)); + drv = (float (*)[TS][TS]) (buffer + TS*TS*(ndir*6+6)); + homo = (char (*)[TS][TS]) (buffer + TS*TS*(ndir*10+6)); + +/* Map a green hexagon around each non-green pixel and vice versa: */ + for (row=0; row < 3; row++) + for (col=0; col < 3; col++) + for (ng=d=0; d < 10; d+=2) { + g = fcol(row,col) == 1; + if (fcol(row+orth[d],col+orth[d+2]) == 1) ng=0; else ng++; + if (ng == 4) { sgrow = row; sgcol = col; } + if (ng == g+1) FORC(8) { + v = orth[d ]*patt[g][c*2] + orth[d+1]*patt[g][c*2+1]; + h = orth[d+2]*patt[g][c*2] + orth[d+3]*patt[g][c*2+1]; + allhex[row][col][0][c^(g*2 & d)] = h + v*width; + allhex[row][col][1][c^(g*2 & d)] = h + v*TS; + } + } + +/* Set green1 and green3 to the minimum and maximum allowed values: */ + for (row=2; row < height-2; row++) + for (min=~(max=0), col=2; col < width-2; col++) { + if (fcol(row,col) == 1 && (min=~(max=0))) continue; + pix = image + row*width + col; + hex = allhex[row % 3][col % 3][0]; + if (!max) FORC(6) { + val = pix[hex[c]][1]; + if (min > val) min = val; + if (max < val) max = val; + } + pix[0][1] = min; + pix[0][3] = max; + switch ((row-sgrow) % 3) { + case 1: if (row < height-3) { row++; col--; } break; + case 2: if ((min=~(max=0)) && (col+=2) < width-3 && row > 2) row--; + } + } + + for (top=3; top < height-19; top += TS-16) + for (left=3; left < width-19; left += TS-16) { + mrow = MIN (top+TS, height-3); + mcol = MIN (left+TS, width-3); + for (row=top; row < mrow; row++) + for (col=left; col < mcol; col++) + memcpy (rgb[0][row-top][col-left], image[row*width+col], 6); + FORC3 memcpy (rgb[c+1], rgb[0], sizeof *rgb); + +/* Interpolate green horizontally, vertically, and along both diagonals: */ + for (row=top; row < mrow; row++) + for (col=left; col < mcol; col++) { + if ((f = fcol(row,col)) == 1) continue; + pix = image + row*width + col; + hex = allhex[row % 3][col % 3][0]; + color[1][0] = 174 * (pix[ hex[1]][1] + pix[ hex[0]][1]) - + 46 * (pix[2*hex[1]][1] + pix[2*hex[0]][1]); + color[1][1] = 223 * pix[ hex[3]][1] + pix[ hex[2]][1] * 33 + + 92 * (pix[ 0 ][f] - pix[ -hex[2]][f]); + FORC(2) color[1][2+c] = + 164 * pix[hex[4+c]][1] + 92 * pix[-2*hex[4+c]][1] + 33 * + (2*pix[0][f] - pix[3*hex[4+c]][f] - pix[-3*hex[4+c]][f]); + FORC4 rgb[c^!((row-sgrow) % 3)][row-top][col-left][1] = + LIM(color[1][c] >> 8,pix[0][1],pix[0][3]); + } + + for (pass=0; pass < passes; pass++) { + if (pass == 1) + memcpy (rgb+=4, buffer, 4*sizeof *rgb); + +/* Recalculate green from interpolated values of closer pixels: */ + if (pass) { + for (row=top+2; row < mrow-2; row++) + for (col=left+2; col < mcol-2; col++) { + if ((f = fcol(row,col)) == 1) continue; + pix = image + row*width + col; + hex = allhex[row % 3][col % 3][1]; + for (d=3; d < 6; d++) { + rix = &rgb[(d-2)^!((row-sgrow) % 3)][row-top][col-left]; + val = rix[-2*hex[d]][1] + 2*rix[hex[d]][1] + - rix[-2*hex[d]][f] - 2*rix[hex[d]][f] + 3*rix[0][f]; + rix[0][1] = LIM(val/3,pix[0][1],pix[0][3]); + } + } + } + +/* Interpolate red and blue values for solitary green pixels: */ + for (row=(top-sgrow+4)/3*3+sgrow; row < mrow-2; row+=3) + for (col=(left-sgcol+4)/3*3+sgcol; col < mcol-2; col+=3) { + rix = &rgb[0][row-top][col-left]; + h = fcol(row,col+1); + memset (diff, 0, sizeof diff); + for (i=1, d=0; d < 6; d++, i^=TS^1, h^=2) { + for (c=0; c < 2; c++, h^=2) { + g = 2*rix[0][1] - rix[i< 1) + diff[d] += SQR (rix[i< 1 && (d & 1)) + if (diff[d-1] < diff[d]) + FORC(2) color[c*2][d] = color[c*2][d-1]; + if (d < 2 || (d & 1)) { + FORC(2) rix[0][c*2] = CLIP(color[c*2][d]/2); + rix += TS*TS; + } + } + } + +/* Interpolate red for blue pixels and vice versa: */ + for (row=top+3; row < mrow-3; row++) + for (col=left+3; col < mcol-3; col++) { + if ((f = 2-fcol(row,col)) == 1) continue; + rix = &rgb[0][row-top][col-left]; + c = (row-sgrow) % 3 ? TS:1; + h = 3 * (c ^ TS ^ 1); + for (d=0; d < 4; d++, rix += TS*TS) { + i = d > 1 || ((d ^ c) & 1) || + ((ABS(rix[0][1]-rix[c][1])+ABS(rix[0][1]-rix[-c][1])) < + 2*(ABS(rix[0][1]-rix[h][1])+ABS(rix[0][1]-rix[-h][1]))) ? c:h; + rix[0][f] = CLIP((rix[i][f] + rix[-i][f] + + 2*rix[0][1] - rix[i][1] - rix[-i][1])/2); + } + } + +/* Fill in red and blue for 2x2 blocks of green: */ + for (row=top+2; row < mrow-2; row++) if ((row-sgrow) % 3) + for (col=left+2; col < mcol-2; col++) if ((col-sgcol) % 3) { + rix = &rgb[0][row-top][col-left]; + hex = allhex[row % 3][col % 3][1]; + for (d=0; d < ndir; d+=2, rix += TS*TS) + if (hex[d] + hex[d+1]) { + g = 3*rix[0][1] - 2*rix[hex[d]][1] - rix[hex[d+1]][1]; + for (c=0; c < 4; c+=2) rix[0][c] = + CLIP((g + 2*rix[hex[d]][c] + rix[hex[d+1]][c])/3); + } else { + g = 2*rix[0][1] - rix[hex[d]][1] - rix[hex[d+1]][1]; + for (c=0; c < 4; c+=2) rix[0][c] = + CLIP((g + rix[hex[d]][c] + rix[hex[d+1]][c])/2); + } + } + } + rgb = (ushort(*)[TS][TS][3]) buffer; + mrow -= top; + mcol -= left; + +/* Convert to CIELab and differentiate in all directions: */ + for (d=0; d < ndir; d++) { + for (row=2; row < mrow-2; row++) + for (col=2; col < mcol-2; col++) + cielab (rgb[d][row][col], lab[row][col]); + for (f=dir[d & 3],row=3; row < mrow-3; row++) + for (col=3; col < mcol-3; col++) { + lix = &lab[row][col]; + g = 2*lix[0][0] - lix[f][0] - lix[-f][0]; + drv[d][row][col] = SQR(g) + + SQR((2*lix[0][1] - lix[f][1] - lix[-f][1] + g*500/232)) + + SQR((2*lix[0][2] - lix[f][2] - lix[-f][2] - g*500/580)); + } + } + +/* Build homogeneity maps from the derivatives: */ + memset(homo, 0, ndir*TS*TS); + for (row=4; row < mrow-4; row++) + for (col=4; col < mcol-4; col++) { + for (tr=FLT_MAX, d=0; d < ndir; d++) + if (tr > drv[d][row][col]) + tr = drv[d][row][col]; + tr *= 8; + for (d=0; d < ndir; d++) + for (v=-1; v <= 1; v++) + for (h=-1; h <= 1; h++) + if (drv[d][row+v][col+h] <= tr) + homo[d][row][col]++; + } + +/* Average the most homogenous pixels for the final result: */ + if (height-top < TS+4) mrow = height-top+2; + if (width-left < TS+4) mcol = width-left+2; + for (row = MIN(top,8); row < mrow-8; row++) + for (col = MIN(left,8); col < mcol-8; col++) { + for (d=0; d < ndir; d++) + for (hm[d]=0, v=-2; v <= 2; v++) + for (h=-2; h <= 2; h++) + hm[d] += homo[d][row+v][col+h]; + for (d=0; d < ndir-4; d++) + if (hm[d] < hm[d+4]) hm[d ] = 0; else + if (hm[d] > hm[d+4]) hm[d+4] = 0; + for (max=hm[0],d=1; d < ndir; d++) + if (max < hm[d]) max = hm[d]; + max -= max >> 3; + memset (avg, 0, sizeof avg); + for (d=0; d < ndir; d++) + if (hm[d] >= max) { + FORC3 avg[c] += rgb[d][row][col][c]; + avg[3]++; + } + FORC3 image[(row+top)*width+col+left][c] = avg[c]/avg[3]; + } + } + free(buffer); + border_interpolate(8); +} +#undef fcol + +/* + Adaptive Homogeneity-Directed interpolation is based on + the work of Keigo Hirakawa, Thomas Parks, and Paul Lee. + */ +void CLASS ahd_interpolate() +{ + int i, j, top, left, row, col, tr, tc, c, d, val, hm[2]; + static const int dir[4] = { -1, 1, -TS, TS }; + unsigned ldiff[2][4], abdiff[2][4], leps, abeps; + ushort (*rgb)[TS][TS][3], (*rix)[3], (*pix)[4]; + short (*lab)[TS][TS][3], (*lix)[3]; + char (*homo)[TS][TS], *buffer; + + dcraw_message (DCRAW_VERBOSE,_("AHD interpolation...\n")); + + cielab (0,0); + border_interpolate(5); + buffer = (char *) malloc (26*TS*TS); + merror (buffer, "ahd_interpolate()"); + rgb = (ushort(*)[TS][TS][3]) buffer; + lab = (short (*)[TS][TS][3])(buffer + 12*TS*TS); + homo = (char (*)[TS][TS]) (buffer + 24*TS*TS); + + for (top=2; top < height-5; top += TS-6) + for (left=2; left < width-5; left += TS-6) { + +/* Interpolate green horizontally and vertically: */ + for (row=top; row < top+TS && row < height-2; row++) { + col = left + (FC(row,left) & 1); + for (c = FC(row,col); col < left+TS && col < width-2; col+=2) { + pix = image + row*width+col; + val = ((pix[-1][1] + pix[0][c] + pix[1][1]) * 2 + - pix[-2][c] - pix[2][c]) >> 2; + rgb[0][row-top][col-left][1] = ULIM(val,pix[-1][1],pix[1][1]); + val = ((pix[-width][1] + pix[0][c] + pix[width][1]) * 2 + - pix[-2*width][c] - pix[2*width][c]) >> 2; + rgb[1][row-top][col-left][1] = ULIM(val,pix[-width][1],pix[width][1]); + } + } +/* Interpolate red and blue, and convert to CIELab: */ + for (d=0; d < 2; d++) + for (row=top+1; row < top+TS-1 && row < height-3; row++) + for (col=left+1; col < left+TS-1 && col < width-3; col++) { + pix = image + row*width+col; + rix = &rgb[d][row-top][col-left]; + lix = &lab[d][row-top][col-left]; + if ((c = 2 - FC(row,col)) == 1) { + c = FC(row+1,col); + val = pix[0][1] + (( pix[-1][2-c] + pix[1][2-c] + - rix[-1][1] - rix[1][1] ) >> 1); + rix[0][2-c] = CLIP(val); + val = pix[0][1] + (( pix[-width][c] + pix[width][c] + - rix[-TS][1] - rix[TS][1] ) >> 1); + } else + val = rix[0][1] + (( pix[-width-1][c] + pix[-width+1][c] + + pix[+width-1][c] + pix[+width+1][c] + - rix[-TS-1][1] - rix[-TS+1][1] + - rix[+TS-1][1] - rix[+TS+1][1] + 1) >> 2); + rix[0][c] = CLIP(val); + c = FC(row,col); + rix[0][c] = pix[0][c]; + cielab (rix[0],lix[0]); + } +/* Build homogeneity maps from the CIELab images: */ + memset (homo, 0, 2*TS*TS); + for (row=top+2; row < top+TS-2 && row < height-4; row++) { + tr = row-top; + for (col=left+2; col < left+TS-2 && col < width-4; col++) { + tc = col-left; + for (d=0; d < 2; d++) { + lix = &lab[d][tr][tc]; + for (i=0; i < 4; i++) { + ldiff[d][i] = ABS(lix[0][0]-lix[dir[i]][0]); + abdiff[d][i] = SQR(lix[0][1]-lix[dir[i]][1]) + + SQR(lix[0][2]-lix[dir[i]][2]); + } + } + leps = MIN(MAX(ldiff[0][0],ldiff[0][1]), + MAX(ldiff[1][2],ldiff[1][3])); + abeps = MIN(MAX(abdiff[0][0],abdiff[0][1]), + MAX(abdiff[1][2],abdiff[1][3])); + for (d=0; d < 2; d++) + for (i=0; i < 4; i++) + if (ldiff[d][i] <= leps && abdiff[d][i] <= abeps) + homo[d][tr][tc]++; + } + } +/* Combine the most homogenous pixels for the final result: */ + for (row=top+3; row < top+TS-3 && row < height-5; row++) { + tr = row-top; + for (col=left+3; col < left+TS-3 && col < width-5; col++) { + tc = col-left; + for (d=0; d < 2; d++) + for (hm[d]=0, i=tr-1; i <= tr+1; i++) + for (j=tc-1; j <= tc+1; j++) + hm[d] += homo[d][i][j]; + if (hm[0] != hm[1]) + FORC3 image[row*width+col][c] = rgb[hm[1] > hm[0]][tr][tc][c]; + else + FORC3 image[row*width+col][c] = + (rgb[0][tr][tc][c] + rgb[1][tr][tc][c]) >> 1; + } + } + } + free (buffer); +} +#undef TS +/* End of functions copied to dcraw_indi.c (UF) */ + +void CLASS median_filter() +{ + ushort (*pix)[4]; + unsigned c, i, j, k; + int pass, med[9]; + static const uchar opt[] = /* Optimal 9-element median search */ + { 1,2, 4,5, 7,8, 0,1, 3,4, 6,7, 1,2, 4,5, 7,8, + 0,3, 5,8, 4,7, 3,6, 1,4, 2,5, 4,7, 4,2, 6,4, 4,2 }; + + for (pass=1; pass <= med_passes; pass++) { + dcraw_message (DCRAW_VERBOSE,_("Median filter pass %d...\n"), pass); + for (c=0; c < 3; c+=2) { + for (pix = image; pix < image+width*height; pix++) + pix[0][3] = pix[0][c]; + for (pix = image+width; pix < image+width*(height-1); pix++) { + if ((pix-image+1) % width < 2) continue; + for (k=0, i = -width; i <= width; i += width) + for (j = i-1; j <= i+1; j++) + med[k++] = pix[j][3] - pix[j][1]; + for (i=0; i < sizeof opt; i+=2) + if (med[opt[i]] > med[opt[i+1]]) + SWAP (med[opt[i]] , med[opt[i+1]]); + pix[0][c] = CLIP(med[4] + pix[0][1]); + } + } + } +} + +#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 8)) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Warray-bounds" +#endif +void CLASS blend_highlights() +{ + unsigned c, j; + int clip=INT_MAX, row, col, i; + static const float trans[2][4][4] = + { { { 1,1,1 }, { 1.7320508,-1.7320508,0 }, { -1,-1,2 } }, + { { 1,1,1,1 }, { 1,-1,1,-1 }, { 1,1,-1,-1 }, { 1,-1,-1,1 } } }; + static const float itrans[2][4][4] = + { { { 1,0.8660254,-0.5 }, { 1,-0.8660254,-0.5 }, { 1,0,1 } }, + { { 1,1,1,1 }, { 1,-1,1,-1 }, { 1,1,-1,-1 }, { 1,-1,-1,1 } } }; + float cam[2][4], lab[2][4], sum[2], chratio; + + if ((unsigned) (colors-3) > 1) return; + dcraw_message (DCRAW_VERBOSE,_("Blending highlights...\n")); + FORCC if (clip > (i = 65535*pre_mul[c])) clip = i; + for (row=0; row < height; row++) + for (col=0; col < width; col++) { + FORCC if (image[row*width+col][c] > clip) break; + if (c == colors) continue; + FORCC { + cam[0][c] = image[row*width+col][c]; + cam[1][c] = MIN(cam[0][c],clip); + } + for (i=0; i < 2; i++) { + FORCC for (lab[i][c]=j=0; j < colors; j++) + lab[i][c] += trans[colors-3][c][j] * cam[i][j]; + for (sum[i]=0,c=1; c < colors; c++) + sum[i] += SQR(lab[i][c]); + } + chratio = sqrt(sum[1]/sum[0]); + for (c=1; c < colors; c++) + lab[0][c] *= chratio; + FORCC for (cam[0][c]=j=0; j < colors; j++) + cam[0][c] += itrans[colors-3][c][j] * lab[0][j]; + FORCC image[row*width+col][c] = cam[0][c] / colors; + } +} +#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 8)) +#pragma GCC diagnostic pop +#endif + +#define SCALE (4 >> shrink) +void CLASS recover_highlights() +{ + float *map, sum, wgt, grow; + int hsat[4], count, spread, change, val; + unsigned high, wide, mrow, mcol, row, col, kc, c, d, y, x, i; + ushort *pixel; + static const signed char dir[8][2] = + { {-1,-1}, {-1,0}, {-1,1}, {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1} }; + + dcraw_message (DCRAW_VERBOSE,_("Rebuilding highlights...\n")); + + grow = pow (2.0, 4-highlight); + FORCC hsat[c] = 32000 * pre_mul[c]; + for (kc=0, c=1; c < colors; c++) + if (pre_mul[kc] < pre_mul[c]) kc = c; + high = height / SCALE; + wide = width / SCALE; + map = (float *) calloc (high, wide*sizeof *map); + merror (map, "recover_highlights()"); + FORCC if (c != kc) { + memset (map, 0, high*wide*sizeof *map); + for (mrow=0; mrow < high; mrow++) + for (mcol=0; mcol < wide; mcol++) { + sum = wgt = count = 0; + for (row = mrow*SCALE; row < (mrow+1)*SCALE; row++) + for (col = mcol*SCALE; col < (mcol+1)*SCALE; col++) { + pixel = image[row*width+col]; + if (pixel[c] / hsat[c] == 1 && pixel[kc] > 24000) { + sum += pixel[c]; + wgt += pixel[kc]; + count++; + } + } + if (count == SCALE*SCALE) + map[mrow*wide+mcol] = sum / wgt; + } + for (spread = 32/grow; spread--; ) { + for (mrow=0; mrow < high; mrow++) + for (mcol=0; mcol < wide; mcol++) { + if (map[mrow*wide+mcol]) continue; + sum = count = 0; + for (d=0; d < 8; d++) { + y = mrow + dir[d][0]; + x = mcol + dir[d][1]; + if (y < high && x < wide && map[y*wide+x] > 0) { + sum += (1 + (d & 1)) * map[y*wide+x]; + count += 1 + (d & 1); + } + } + if (count > 3) + map[mrow*wide+mcol] = - (sum+grow) / (count+grow); + } + for (change=i=0; i < high*wide; i++) + if (map[i] < 0) { + map[i] = -map[i]; + change = 1; + } + if (!change) break; + } + for (i=0; i < high*wide; i++) + if (map[i] == 0) map[i] = 1; + for (mrow=0; mrow < high; mrow++) + for (mcol=0; mcol < wide; mcol++) { + for (row = mrow*SCALE; row < (mrow+1)*SCALE; row++) + for (col = mcol*SCALE; col < (mcol+1)*SCALE; col++) { + pixel = image[row*width+col]; + if (pixel[c] / hsat[c] > 1) { + val = pixel[kc] * map[mrow*wide+mcol]; + if (pixel[c] < val) pixel[c] = CLIP(val); + } + } + } + } + free (map); +} +#undef SCALE + +void CLASS tiff_get (unsigned base, + unsigned *tag, unsigned *type, unsigned *len, unsigned *save) +{ + *tag = get2(); + *type = get2(); + *len = get4(); + *save = ftell(ifp) + 4; + if (*len * ("11124811248484"[*type < 14 ? *type:0]-'0') > 4) + fseek (ifp, get4()+base, SEEK_SET); +} + +void CLASS parse_thumb_note (int base, unsigned toff, unsigned tlen) +{ + unsigned entries, tag, type, len, save; + + entries = get2(); + while (entries--) { + tiff_get (base, &tag, &type, &len, &save); + if (tag == toff) thumb_offset = get4()+base; + if (tag == tlen) thumb_length = get4(); + fseek (ifp, save, SEEK_SET); + } +} + +//int CLASS parse_tiff_ifd (int base); + +void CLASS parse_makernote (int base, int uptag) +{ + static const uchar xlat[2][256] = { + { 0xc1,0xbf,0x6d,0x0d,0x59,0xc5,0x13,0x9d,0x83,0x61,0x6b,0x4f,0xc7,0x7f,0x3d,0x3d, + 0x53,0x59,0xe3,0xc7,0xe9,0x2f,0x95,0xa7,0x95,0x1f,0xdf,0x7f,0x2b,0x29,0xc7,0x0d, + 0xdf,0x07,0xef,0x71,0x89,0x3d,0x13,0x3d,0x3b,0x13,0xfb,0x0d,0x89,0xc1,0x65,0x1f, + 0xb3,0x0d,0x6b,0x29,0xe3,0xfb,0xef,0xa3,0x6b,0x47,0x7f,0x95,0x35,0xa7,0x47,0x4f, + 0xc7,0xf1,0x59,0x95,0x35,0x11,0x29,0x61,0xf1,0x3d,0xb3,0x2b,0x0d,0x43,0x89,0xc1, + 0x9d,0x9d,0x89,0x65,0xf1,0xe9,0xdf,0xbf,0x3d,0x7f,0x53,0x97,0xe5,0xe9,0x95,0x17, + 0x1d,0x3d,0x8b,0xfb,0xc7,0xe3,0x67,0xa7,0x07,0xf1,0x71,0xa7,0x53,0xb5,0x29,0x89, + 0xe5,0x2b,0xa7,0x17,0x29,0xe9,0x4f,0xc5,0x65,0x6d,0x6b,0xef,0x0d,0x89,0x49,0x2f, + 0xb3,0x43,0x53,0x65,0x1d,0x49,0xa3,0x13,0x89,0x59,0xef,0x6b,0xef,0x65,0x1d,0x0b, + 0x59,0x13,0xe3,0x4f,0x9d,0xb3,0x29,0x43,0x2b,0x07,0x1d,0x95,0x59,0x59,0x47,0xfb, + 0xe5,0xe9,0x61,0x47,0x2f,0x35,0x7f,0x17,0x7f,0xef,0x7f,0x95,0x95,0x71,0xd3,0xa3, + 0x0b,0x71,0xa3,0xad,0x0b,0x3b,0xb5,0xfb,0xa3,0xbf,0x4f,0x83,0x1d,0xad,0xe9,0x2f, + 0x71,0x65,0xa3,0xe5,0x07,0x35,0x3d,0x0d,0xb5,0xe9,0xe5,0x47,0x3b,0x9d,0xef,0x35, + 0xa3,0xbf,0xb3,0xdf,0x53,0xd3,0x97,0x53,0x49,0x71,0x07,0x35,0x61,0x71,0x2f,0x43, + 0x2f,0x11,0xdf,0x17,0x97,0xfb,0x95,0x3b,0x7f,0x6b,0xd3,0x25,0xbf,0xad,0xc7,0xc5, + 0xc5,0xb5,0x8b,0xef,0x2f,0xd3,0x07,0x6b,0x25,0x49,0x95,0x25,0x49,0x6d,0x71,0xc7 }, + { 0xa7,0xbc,0xc9,0xad,0x91,0xdf,0x85,0xe5,0xd4,0x78,0xd5,0x17,0x46,0x7c,0x29,0x4c, + 0x4d,0x03,0xe9,0x25,0x68,0x11,0x86,0xb3,0xbd,0xf7,0x6f,0x61,0x22,0xa2,0x26,0x34, + 0x2a,0xbe,0x1e,0x46,0x14,0x68,0x9d,0x44,0x18,0xc2,0x40,0xf4,0x7e,0x5f,0x1b,0xad, + 0x0b,0x94,0xb6,0x67,0xb4,0x0b,0xe1,0xea,0x95,0x9c,0x66,0xdc,0xe7,0x5d,0x6c,0x05, + 0xda,0xd5,0xdf,0x7a,0xef,0xf6,0xdb,0x1f,0x82,0x4c,0xc0,0x68,0x47,0xa1,0xbd,0xee, + 0x39,0x50,0x56,0x4a,0xdd,0xdf,0xa5,0xf8,0xc6,0xda,0xca,0x90,0xca,0x01,0x42,0x9d, + 0x8b,0x0c,0x73,0x43,0x75,0x05,0x94,0xde,0x24,0xb3,0x80,0x34,0xe5,0x2c,0xdc,0x9b, + 0x3f,0xca,0x33,0x45,0xd0,0xdb,0x5f,0xf5,0x52,0xc3,0x21,0xda,0xe2,0x22,0x72,0x6b, + 0x3e,0xd0,0x5b,0xa8,0x87,0x8c,0x06,0x5d,0x0f,0xdd,0x09,0x19,0x93,0xd0,0xb9,0xfc, + 0x8b,0x0f,0x84,0x60,0x33,0x1c,0x9b,0x45,0xf1,0xf0,0xa3,0x94,0x3a,0x12,0x77,0x33, + 0x4d,0x44,0x78,0x28,0x3c,0x9e,0xfd,0x65,0x57,0x16,0x94,0x6b,0xfb,0x59,0xd0,0xc8, + 0x22,0x36,0xdb,0xd2,0x63,0x98,0x43,0xa1,0x04,0x87,0x86,0xf7,0xa6,0x26,0xbb,0xd6, + 0x59,0x4d,0xbf,0x6a,0x2e,0xaa,0x2b,0xef,0xe6,0x78,0xb6,0x4e,0xe0,0x2f,0xdc,0x7c, + 0xbe,0x57,0x19,0x32,0x7e,0x2a,0xd0,0xb8,0xba,0x29,0x00,0x3c,0x52,0x7d,0xa8,0x49, + 0x3b,0x2d,0xeb,0x25,0x49,0xfa,0xa3,0xaa,0x39,0xa7,0xc5,0xa7,0x50,0x11,0x36,0xfb, + 0xc6,0x67,0x4a,0xf5,0xa5,0x12,0x65,0x7e,0xb0,0xdf,0xaf,0x4e,0xb3,0x61,0x7f,0x2f } }; + unsigned offset=0, entries, tag, type, len, save, c; + unsigned ver97=0, serial=0, i, wbi=0, wb[4]={0,0,0,0}; + uchar buf97[324], ci, cj, ck; + short morder, sorder=order; + char buf[10]; +/* + The MakerNote might have its own TIFF header (possibly with + its own byte-order!), or it might just be a table. + */ + if (!strcmp(make,"Nokia")) return; + fread (buf, 1, 10, ifp); + if (!strncmp (buf,"KDK" ,3) || /* these aren't TIFF tables */ + !strncmp (buf,"VER" ,3) || + !strncmp (buf,"IIII",4) || + !strncmp (buf,"MMMM",4)) return; + if (!strncmp (buf,"KC" ,2) || /* Konica KD-400Z, KD-510Z */ + !strncmp (buf,"MLY" ,3)) { /* Minolta DiMAGE G series */ + order = 0x4d4d; + while ((i=ftell(ifp)) < (unsigned) data_offset && i < 16384) { + wb[0] = wb[2]; wb[2] = wb[1]; wb[1] = wb[3]; + wb[3] = get2(); + if (wb[1] == 256 && wb[3] == 256 && + wb[0] > 256 && wb[0] < 640 && wb[2] > 256 && wb[2] < 640) + FORC4 cam_mul[c] = wb[c]; + } + goto quit; + } + if (!strcmp (buf,"Nikon")) { + base = ftell(ifp); + order = get2(); + if (get2() != 42) goto quit; + offset = get4(); + fseek (ifp, offset-8, SEEK_CUR); + } else if (!strcmp (buf,"OLYMPUS") || + !strcmp (buf,"PENTAX ")) { + base = ftell(ifp)-10; + fseek (ifp, -2, SEEK_CUR); + order = get2(); + if (buf[0] == 'O') get2(); + } else if (!strncmp (buf,"SONY",4) || + !strcmp (buf,"Panasonic")) { + goto nf; + } else if (!strncmp (buf,"FUJIFILM",8)) { + base = ftell(ifp)-10; +nf: order = 0x4949; + fseek (ifp, 2, SEEK_CUR); + } else if (!strcmp (buf,"OLYMP") || + !strcmp (buf,"LEICA") || + !strcmp (buf,"Ricoh") || + !strcmp (buf,"EPSON")) + fseek (ifp, -2, SEEK_CUR); + else if (!strcmp (buf,"AOC") || + !strcmp (buf,"QVC")) + fseek (ifp, -4, SEEK_CUR); + else { + fseek (ifp, -10, SEEK_CUR); + if (!strncmp(make,"SAMSUNG",7)) + base = ftell(ifp); + } + entries = get2(); + if (entries > 1000) return; + morder = order; + while (entries--) { + order = morder; + tiff_get (base, &tag, &type, &len, &save); + tag |= uptag << 16; + if (tag == 2 && strstr(make,"NIKON") && !iso_speed) + iso_speed = (get2(),get2()); + if (tag == 4 && len > 26 && len < 35) { + if ((i=(get4(),get2())) != 0x7fff && !iso_speed) + iso_speed = 50 * pow (2, i/32.0 - 4); + if ((i=(get2(),get2())) != 0x7fff && !aperture) + aperture = pow (2, i/64.0); + if ((i=get2()) != 0xffff && !shutter) + shutter = pow (2, (short) i/-32.0); + wbi = (get2(),get2()); + shot_order = (get2(),get2()); + } + if ((tag == 4 || tag == 0x114) && !strncmp(make,"KONICA",6)) { + fseek (ifp, tag == 4 ? 140:160, SEEK_CUR); + switch (get2()) { + case 72: flip = 0; break; + case 76: flip = 6; break; + case 82: flip = 5; break; + } + } + if (tag == 7 && type == 2 && len > 20) + fgets (model2, 64, ifp); + if (tag == 8 && type == 4) + shot_order = get4(); + if (tag == 9 && !strcmp(make,"Canon")) + fread (artist, 64, 1, ifp); + if (tag == 0xc && len == 4) + FORC3 cam_mul[(c << 1 | c >> 1) & 3] = getreal(type); + if (tag == 0xd && type == 7 && get2() == 0xaaaa) { + for (c=i=2; (ushort) c != 0xbbbb && i < len; i++) + c = c << 8 | fgetc(ifp); + while ((i+=4) < len-5) + if (get4() == 257 && (i=len) && (c = (get4(),fgetc(ifp))) < 3) + flip = "065"[c]-'0'; + } + if (tag == 0x10 && type == 4) + unique_id = get4(); + if (tag == 0x11 && is_raw && !strncmp(make,"NIKON",5)) { + fseek (ifp, get4()+base, SEEK_SET); + parse_tiff_ifd (base); + } + if (tag == 0x14 && type == 7) { + if (len == 2560) { + fseek (ifp, 1248, SEEK_CUR); + goto get2_256; + } + fread (buf, 1, 10, ifp); + if (!strncmp(buf,"NRW ",4)) { + fseek (ifp, strcmp(buf+4,"0100") ? 46:1546, SEEK_CUR); + cam_mul[0] = get4() << 2; + cam_mul[1] = get4() + get4(); + cam_mul[2] = get4() << 2; + } + } + if (tag == 0x15 && type == 2 && is_raw) + fread (model, 64, 1, ifp); + if (strstr(make,"PENTAX")) { + if (tag == 0x1b) tag = 0x1018; + if (tag == 0x1c) tag = 0x1017; + } + if (tag == 0x1d) + while ((c = fgetc(ifp)) && c != (unsigned) EOF) + serial = serial*10 + (isdigit(c) ? c - '0' : c % 10); + if (tag == 0x29 && type == 1) { + c = wbi < 18 ? "012347800000005896"[wbi]-'0' : 0; + fseek (ifp, 8 + c*32, SEEK_CUR); + FORC4 cam_mul[c ^ (c >> 1) ^ 1] = get4(); + } + if (tag == 0x3d && type == 3 && len == 4) + FORC4 cblack[c ^ c >> 1] = get2() >> (14-tiff_bps); + if (tag == 0x81) { /* NTC UF*/ + tone_mode_offset = ftell(ifp); + tone_mode_size = len; + } /* NTC UF*/ + if (tag == 0x81 && type == 4) { + data_offset = get4(); + fseek (ifp, data_offset + 41, SEEK_SET); + raw_height = get2() * 2; + raw_width = get2(); + filters = 0x61616161; + } + if ((tag == 0x81 && type == 7) || + (tag == 0x100 && type == 7) || + (tag == 0x280 && type == 1)) { + thumb_offset = ftell(ifp); + thumb_length = len; + } + if (tag == 0x88 && type == 4 && (thumb_offset = get4())) + thumb_offset += base; + if (tag == 0x89 && type == 4) + thumb_length = get4(); + if (tag == 0x8c || tag == 0x96) + meta_offset = ftell(ifp); + if (tag == 0x8c) { /* NTC UF*/ + tone_curve_offset = ftell(ifp); + tone_curve_size = len; + } /* NTC UF*/ + if (tag == 0x97) { + for (i=0; i < 4; i++) + ver97 = ver97 * 10 + fgetc(ifp)-'0'; + switch (ver97) { + case 100: + fseek (ifp, 68, SEEK_CUR); + FORC4 cam_mul[(c >> 1) | ((c & 1) << 1)] = get2(); + break; + case 102: + fseek (ifp, 6, SEEK_CUR); + FORC4 cam_mul[c ^ (c >> 1)] = get2(); + break; + case 103: + fseek (ifp, 16, SEEK_CUR); + FORC4 cam_mul[c] = get2(); + } + if (ver97 >= 200) { + if (ver97 != 205) fseek (ifp, 280, SEEK_CUR); + fread (buf97, 324, 1, ifp); + } + } + if (tag == 0xa1 && type == 7) { + order = 0x4949; + fseek (ifp, 140, SEEK_CUR); + FORC3 cam_mul[c] = get4(); + } + if (tag == 0xa4 && type == 3) { + fseek (ifp, wbi*48, SEEK_CUR); + FORC3 cam_mul[c] = get2(); + } + if (tag == 0xa7 && (unsigned) (ver97-200) < 17) { + ci = xlat[0][serial & 0xff]; + cj = xlat[1][fgetc(ifp)^fgetc(ifp)^fgetc(ifp)^fgetc(ifp)]; + ck = 0x60; + for (i=0; i < 324; i++) + buf97[i] ^= (cj += ci * ck++); + i = "66666>666;6A;:;55"[ver97-200] - '0'; + FORC4 cam_mul[c ^ (c >> 1) ^ (i & 1)] = + sget2 (buf97 + (i & -2) + c*2); + } + if (tag == 0x200 && len == 3) + shot_order = (get4(),get4()); + if (tag == 0x200 && len == 4) + FORC4 cblack[c ^ c >> 1] = get2(); + if (tag == 0x201 && len == 4) + FORC4 cam_mul[c ^ (c >> 1)] = get2(); + if (tag == 0x220 && type == 7) + meta_offset = ftell(ifp); + if (tag == 0x401 && type == 4 && len == 4) + FORC4 cblack[c ^ c >> 1] = get4(); + if (tag == 0xe01) { /* Nikon Capture Note */ + order = 0x4949; + fseek (ifp, 22, SEEK_CUR); + for (offset=22; offset+22 < len; offset += 22+i) { + tag = get4(); + fseek (ifp, 14, SEEK_CUR); + i = get4()-4; + if (tag == 0x76a43207) flip = get2(); + else fseek (ifp, i, SEEK_CUR); + } + } + if (tag == 0xe80 && len == 256 && type == 7) { + fseek (ifp, 48, SEEK_CUR); + cam_mul[0] = get2() * 508 * 1.078 / 0x10000; + cam_mul[2] = get2() * 382 * 1.173 / 0x10000; + } + if (tag == 0xf00 && type == 7) { + if (len == 614) + fseek (ifp, 176, SEEK_CUR); + else if (len == 734 || len == 1502) + fseek (ifp, 148, SEEK_CUR); + else goto next; + goto get2_256; + } + if ((tag == 0x1011 && len == 9) || tag == 0x20400200) + for (i=0; i < 3; i++) + FORC3 cmatrix[i][c] = ((short) get2()) / 256.0; + if ((tag == 0x1012 || tag == 0x20400600) && len == 4) + FORC4 cblack[c ^ c >> 1] = get2(); + if (tag == 0x1017 || tag == 0x20400100) + cam_mul[0] = get2() / 256.0; + if (tag == 0x1018 || tag == 0x20400100) + cam_mul[2] = get2() / 256.0; + if (tag == 0x2011 && len == 2) { +get2_256: + order = 0x4d4d; + cam_mul[0] = get2() / 256.0; + cam_mul[2] = get2() / 256.0; + } + if ((tag | 0x70) == 0x2070 && (type == 4 || type == 13)) + fseek (ifp, get4()+base, SEEK_SET); + if (tag == 0x2020 && !strncmp(buf,"OLYMP",5)) + parse_thumb_note (base, 257, 258); + if (tag == 0x2040) + parse_makernote (base, 0x2040); + if (tag == 0xb028) { + fseek (ifp, get4()+base, SEEK_SET); + parse_thumb_note (base, 136, 137); + } + if (tag == 0x4001 && len > 500) { + i = len == 582 ? 50 : len == 653 ? 68 : len == 5120 ? 142 : 126; + fseek (ifp, i, SEEK_CUR); + FORC4 cam_mul[c ^ (c >> 1)] = get2(); + for (i+=18; i <= len; i+=10) { + get2(); + FORC4 sraw_mul[c ^ (c >> 1)] = get2(); + if (sraw_mul[1] == 1170) break; + } + } + if (tag == 0x4021 && get4() && get4()) + FORC4 cam_mul[c] = 1024; + if (tag == 0xa021) + FORC4 cam_mul[c ^ (c >> 1)] = get4(); + if (tag == 0xa028) + FORC4 cam_mul[c ^ (c >> 1)] -= get4(); + if (tag == 0xb001) + unique_id = get2(); +next: + fseek (ifp, save, SEEK_SET); + } +quit: + order = sorder; +} + +/* + Since the TIFF DateTime string has no timezone information, + assume that the camera's clock was set to Universal Time. + */ +void CLASS get_timestamp (int reversed) +{ + struct tm t; + char str[20]; + int i; + + str[19] = 0; + if (reversed) + for (i=19; i--; ) str[i] = fgetc(ifp); + else + fread (str, 19, 1, ifp); + memset (&t, 0, sizeof t); + if (sscanf (str, "%d:%d:%d %d:%d:%d", &t.tm_year, &t.tm_mon, + &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec) != 6) + return; + t.tm_year -= 1900; + t.tm_mon -= 1; + t.tm_isdst = -1; + if (mktime(&t) > 0) + timestamp = mktime(&t); +} + +void CLASS parse_exif (int base) +{ + unsigned kodak, entries, tag, type, len, save, c; + double expo; + + kodak = !strncmp(make,"EASTMAN",7) && tiff_nifds < 3; + entries = get2(); + while (entries--) { + tiff_get (base, &tag, &type, &len, &save); + switch (tag) { + case 33434: tiff_ifd[tiff_nifds-1].shutter = + shutter = getreal(type); break; + case 33437: aperture = getreal(type); break; + case 34855: iso_speed = get2(); break; + case 36867: + case 36868: get_timestamp(0); break; + case 37377: if ((expo = -getreal(type)) < 128) + tiff_ifd[tiff_nifds-1].shutter = + shutter = pow (2, expo); break; + case 37378: aperture = pow (2, getreal(type)/2); break; + case 37386: focal_len = getreal(type); break; + case 37500: parse_makernote (base, 0); break; + case 40962: if (kodak) raw_width = get4(); break; + case 40963: if (kodak) raw_height = get4(); break; + case 41730: + if (get4() == 0x20002) + for (exif_cfa=c=0; c < 8; c+=2) + exif_cfa |= fgetc(ifp) * 0x01010101 << c; + } + fseek (ifp, save, SEEK_SET); + } +} + +void CLASS parse_gps (int base) +{ + unsigned entries, tag, type, len, save, c; + + entries = get2(); + while (entries--) { + tiff_get (base, &tag, &type, &len, &save); + switch (tag) { + case 1: case 3: case 5: + gpsdata[29+tag/2] = getc(ifp); break; + case 2: case 4: case 7: + FORC(6) gpsdata[tag/3*6+c] = get4(); break; + case 6: + FORC(2) gpsdata[18+c] = get4(); break; + case 18: case 29: + fgets ((char *) (gpsdata+14+tag/3), MIN(len,12), ifp); + } + fseek (ifp, save, SEEK_SET); + } +} + +void CLASS romm_coeff (float romm_cam[3][3]) +{ + static const float rgb_romm[3][3] = /* ROMM == Kodak ProPhoto */ + { { 2.034193, -0.727420, -0.306766 }, + { -0.228811, 1.231729, -0.002922 }, + { -0.008565, -0.153273, 1.161839 } }; + int i, j, k; + + for (i=0; i < 3; i++) + for (j=0; j < 3; j++) + for (cmatrix[i][j] = k=0; k < 3; k++) + cmatrix[i][j] += rgb_romm[i][k] * romm_cam[k][j]; +} + +void CLASS parse_mos (int offset) +{ + char data[40]; + int skip, from, i, c, neut[4], planes=0, frot=0; + static const char *mod[] = + { "","DCB2","Volare","Cantare","CMost","Valeo 6","Valeo 11","Valeo 22", + "Valeo 11p","Valeo 17","","Aptus 17","Aptus 22","Aptus 75","Aptus 65", + "Aptus 54S","Aptus 65S","Aptus 75S","AFi 5","AFi 6","AFi 7", + "AFi-II 7","Aptus-II 7","","Aptus-II 6","","","Aptus-II 10","Aptus-II 5", + "","","","","Aptus-II 10R","Aptus-II 8","","Aptus-II 12","","AFi-II 12" }; + float romm_cam[3][3]; + + fseek (ifp, offset, SEEK_SET); + while (1) { + if (get4() != 0x504b5453) break; + get4(); + fread (data, 1, 40, ifp); + skip = get4(); + from = ftell(ifp); + if (!strcmp(data,"JPEG_preview_data")) { + thumb_offset = from; + thumb_length = skip; + } + if (!strcmp(data,"icc_camera_profile")) { + profile_offset = from; + profile_length = skip; + } + if (!strcmp(data,"ShootObj_back_type")) { + fscanf (ifp, "%d", &i); + if ((unsigned) i < sizeof mod / sizeof (*mod)) + strcpy (model, mod[i]); + } + if (!strcmp(data,"icc_camera_to_tone_matrix")) { + for (i=0; i < 9; i++) + ((float *)romm_cam)[i] = int_to_float(get4()); + romm_coeff (romm_cam); + } + if (!strcmp(data,"CaptProf_color_matrix")) { + for (i=0; i < 9; i++) + fscanf (ifp, "%f", (float *)romm_cam + i); + romm_coeff (romm_cam); + } + if (!strcmp(data,"CaptProf_number_of_planes")) + fscanf (ifp, "%d", &planes); + if (!strcmp(data,"CaptProf_raw_data_rotation")) + fscanf (ifp, "%d", &flip); + if (!strcmp(data,"CaptProf_mosaic_pattern")) + FORC4 { + fscanf (ifp, "%d", &i); + if (i == 1) frot = c ^ (c >> 1); + } + if (!strcmp(data,"ImgProf_rotation_angle")) { + fscanf (ifp, "%d", &i); + flip = i - flip; + } + if (!strcmp(data,"NeutObj_neutrals") && !cam_mul[0]) { + FORC4 fscanf (ifp, "%d", neut+c); + FORC3 cam_mul[c] = (float) neut[0] / neut[c+1]; + } + if (!strcmp(data,"Rows_data")) + load_flags = get4(); + parse_mos (from); + fseek (ifp, skip+from, SEEK_SET); + } + if (planes) + filters = (planes == 1) * 0x01010101 * + (uchar) "\x94\x61\x16\x49"[(flip/90 + frot) & 3]; +} + +void CLASS linear_table (unsigned len) +{ + int i; + if (len > 0x1000) len = 0x1000; + read_shorts (curve, len); + for (i=len; i < 0x1000; i++) + curve[i] = curve[i-1]; + maximum = curve[0xfff]; +} + +void CLASS parse_kodak_ifd (int base) +{ + unsigned entries, tag, type, len, save; + int i, c, wbi=-2, wbtemp=6500; + float mul[3]={1,1,1}, num; + static const unsigned wbtag[] = { 64037,64040,64039,64041,static_cast(-1),static_cast(-1),64042 }; + + entries = get2(); + if (entries > 1024) return; + while (entries--) { + tiff_get (base, &tag, &type, &len, &save); + if (tag == 1020) wbi = getint(type); + if (tag == 1021 && len == 72) { /* WB set in software */ + fseek (ifp, 40, SEEK_CUR); + FORC3 cam_mul[c] = 2048.0 / get2(); + wbi = -2; + } + if (tag == 2118) wbtemp = getint(type); + if (tag == (unsigned)(2120 + wbi) && wbi >= 0) + FORC3 cam_mul[c] = 2048.0 / getreal(type); + if (tag == (unsigned)(2130 + wbi)) + FORC3 mul[c] = getreal(type); + if (tag == (unsigned)(2140 + wbi) && wbi >= 0) + FORC3 { + for (num=i=0; i < 4; i++) + num += getreal(type) * pow (wbtemp/100.0, i); + cam_mul[c] = 2048 / (num * mul[c]); + } + if (tag == 2317) linear_table (len); + if (tag == 6020) iso_speed = getint(type); + if (tag == 64013) wbi = fgetc(ifp); + if ((unsigned) wbi < 7 && tag == wbtag[wbi]) + FORC3 cam_mul[c] = get4(); + if (tag == 64019) width = getint(type); + if (tag == 64020) height = (getint(type)+1) & -2; + fseek (ifp, save, SEEK_SET); + } +} + +//void CLASS parse_minolta (int base); +//int CLASS parse_tiff (int base); + +int CLASS parse_tiff_ifd (int base) +{ + unsigned entries, tag, type, len, plen=16, save, i, j, c; + int ifd, use_cm=0, cfa, ima_len=0; + char software[64], *cbuf, *cp; + uchar cfa_pat[16], cfa_pc[] = { 0,1,2,3 }, tab[256]; + double cc[4][4], cm[4][3], cam_xyz[4][3], num; + double ab[]={ 1,1,1,1 }, asn[] = { 0,0,0,0 }, xyz[] = { 1,1,1 }; + unsigned sony_curve[] = { 0,0,0,0,0,4095 }; + unsigned *buf, sony_offset=0, sony_length=0, sony_key=0; + struct jhead jh; + FILE *sfp; + + if (tiff_nifds >= sizeof tiff_ifd / sizeof tiff_ifd[0]) + return 1; + ifd = tiff_nifds++; + for (j=0; j < 4; j++) + for (i=0; i < 4; i++) + cc[j][i] = i == j; + entries = get2(); + if (entries > 512) return 1; + while (entries--) { + tiff_get (base, &tag, &type, &len, &save); + switch (tag) { + case 5: width = get2(); break; + case 6: height = get2(); break; + case 7: width += get2(); break; + case 9: if ((i = get2())) filters = i; break; + case 17: case 18: + if (type == 3 && len == 1) + cam_mul[(tag-17)*2] = get2() / 256.0; + break; + case 23: + if (type == 3) iso_speed = get2(); + break; + case 28: case 29: case 30: + cblack[tag-28] = get2(); + cblack[3] = cblack[1]; + break; + case 36: case 37: case 38: + cam_mul[tag-36] = get2(); + break; + case 39: + if (len < 50 || cam_mul[0]) break; + fseek (ifp, 12, SEEK_CUR); + FORC3 cam_mul[c] = get2(); + break; + case 46: + if (type != 7 || fgetc(ifp) != 0xff || fgetc(ifp) != 0xd8) break; + thumb_offset = ftell(ifp) - 2; + thumb_length = len; + break; + case 61440: /* Fuji HS10 table */ + fseek (ifp, get4()+base, SEEK_SET); + parse_tiff_ifd (base); + break; + case 2: case 256: case 61441: /* ImageWidth */ + tiff_ifd[ifd].width = getint(type); + break; + case 3: case 257: case 61442: /* ImageHeight */ + tiff_ifd[ifd].height = getint(type); + break; + case 258: /* BitsPerSample */ + case 61443: + tiff_ifd[ifd].samples = len & 7; + if ((tiff_ifd[ifd].bps = getint(type)) > 32) + tiff_ifd[ifd].bps = 8; + if (tiff_bps < tiff_ifd[ifd].bps) + tiff_bps = tiff_ifd[ifd].bps; + break; + case 61446: + raw_height = 0; + load_flags = get4() ? 24:80; + break; + case 259: /* Compression */ + tiff_ifd[ifd].comp = getint(type); + break; + case 262: /* PhotometricInterpretation */ + tiff_ifd[ifd].phint = get2(); + break; + case 270: /* ImageDescription */ + fread (desc, 512, 1, ifp); + break; + case 271: /* Make */ + fgets (make, 64, ifp); + break; + case 272: /* Model */ + fgets (model, 64, ifp); + break; + case 280: /* Panasonic RW2 offset */ + if (type != 4) break; + load_raw = &CLASS panasonic_load_raw; + load_flags = 0x2008; + case 273: /* StripOffset */ + case 513: /* JpegIFOffset */ + case 61447: + tiff_ifd[ifd].offset = get4()+base; + if (!tiff_ifd[ifd].bps && tiff_ifd[ifd].offset > 0) { + fseek (ifp, tiff_ifd[ifd].offset, SEEK_SET); + if (ljpeg_start (&jh, 1)) { + tiff_ifd[ifd].comp = 6; + tiff_ifd[ifd].width = jh.wide; + tiff_ifd[ifd].height = jh.high; + tiff_ifd[ifd].bps = jh.bits; + tiff_ifd[ifd].samples = jh.clrs; + if (!(jh.sraw || (jh.clrs & 1))) + tiff_ifd[ifd].width *= jh.clrs; + if ((tiff_ifd[ifd].width > 4*tiff_ifd[ifd].height) & ~jh.clrs) { + tiff_ifd[ifd].width /= 2; + tiff_ifd[ifd].height *= 2; + } + i = order; + parse_tiff (tiff_ifd[ifd].offset + 12); + order = i; + } + } + break; + case 274: /* Orientation */ + tiff_ifd[ifd].flip = "50132467"[get2() & 7]-'0'; + break; + case 277: /* SamplesPerPixel */ + tiff_ifd[ifd].samples = getint(type) & 7; + break; + case 279: /* StripByteCounts */ + case 514: + case 61448: + tiff_ifd[ifd].bytes = get4(); + break; + case 61454: + FORC3 cam_mul[(4-c) % 3] = getint(type); + break; + case 305: case 11: /* Software */ + fgets (software, 64, ifp); + if (!strncmp(software,"Adobe",5) || + !strncmp(software,"dcraw",5) || + !strncmp(software,"UFRaw",5) || + !strncmp(software,"Bibble",6) || + !strncmp(software,"Nikon Scan",10) || + !strcmp (software,"Digital Photo Professional")) + is_raw = 0; + break; + case 306: /* DateTime */ + get_timestamp(0); + break; + case 315: /* Artist */ + fread (artist, 64, 1, ifp); + break; + case 322: /* TileWidth */ + tiff_ifd[ifd].tile_width = getint(type); + break; + case 323: /* TileLength */ + tiff_ifd[ifd].tile_length = getint(type); + break; + case 324: /* TileOffsets */ + tiff_ifd[ifd].offset = len > 1 ? ftell(ifp) : get4(); + if (len == 1) + tiff_ifd[ifd].tile_width = tiff_ifd[ifd].tile_length = 0; + if (len == 4) { + load_raw = &CLASS sinar_4shot_load_raw; + is_raw = 5; + } + break; + case 330: /* SubIFDs */ + if (!strcmp(model,"DSLR-A100") && tiff_ifd[ifd].width == 3872) { + load_raw = &CLASS sony_arw_load_raw; + data_offset = get4()+base; + ifd++; break; + } + if(len > 1000) len = 1000; /* 1000 SubIFDs are enough */ + while (len--) { + i = ftell(ifp); + fseek (ifp, get4()+base, SEEK_SET); + if (parse_tiff_ifd (base)) break; + fseek (ifp, i+4, SEEK_SET); + } + break; + case 400: + strcpy (make, "Sarnoff"); + maximum = 0xfff; + break; + case 28688: + FORC4 sony_curve[c+1] = get2() >> 2 & 0xfff; + for (i=0; i < 5; i++) + for (j = sony_curve[i]+1; j <= sony_curve[i+1]; j++) + curve[j] = curve[j-1] + (1 << i); + break; + case 29184: sony_offset = get4(); break; + case 29185: sony_length = get4(); break; + case 29217: sony_key = get4(); break; + case 29264: + parse_minolta (ftell(ifp)); + raw_width = 0; + break; + case 29443: + FORC4 cam_mul[c ^ (c < 2)] = get2(); + break; + case 29459: + FORC4 cam_mul[c] = get2(); + i = (cam_mul[1] == 1024 && cam_mul[2] == 1024) << 1; + SWAP (cam_mul[i],cam_mul[i+1]) + break; + case 33405: /* Model2 */ + fgets (model2, 64, ifp); + break; + case 33421: /* CFARepeatPatternDim */ + if (get2() == 6 && get2() == 6) + filters = 9; + break; + case 33422: /* CFAPattern */ + if (filters == 9) { + FORC(36) ((char *)xtrans)[c] = fgetc(ifp) & 3; + break; + } + case 64777: /* Kodak P-series */ + if ((plen=len) > 16) plen = 16; + fread (cfa_pat, 1, plen, ifp); + for (colors=cfa=i=0; i < plen && colors < 4; i++) { + colors += !(cfa & (1 << cfa_pat[i])); + cfa |= 1 << cfa_pat[i]; + } + if (cfa == 070) memcpy (cfa_pc,"\003\004\005",3); /* CMY */ + if (cfa == 072) memcpy (cfa_pc,"\005\003\004\001",4); /* GMCY */ + goto guess_cfa_pc; + case 33424: + case 65024: + fseek (ifp, get4()+base, SEEK_SET); + parse_kodak_ifd (base); + break; + case 33434: /* ExposureTime */ + tiff_ifd[ifd].shutter = shutter = getreal(type); + break; + case 33437: /* FNumber */ + aperture = getreal(type); + break; + case 34306: /* Leaf white balance */ + FORC4 cam_mul[c ^ 1] = 4096.0 / get2(); + break; + case 34307: /* Leaf CatchLight color matrix */ + fread (software, 1, 7, ifp); + if (strncmp(software,"MATRIX",6)) break; + colors = 4; + for (raw_color = i=0; i < 3; i++) { + FORC4 fscanf (ifp, "%f", &rgb_cam[i][c^1]); + if (!use_camera_wb) continue; + num = 0; + FORC4 num += rgb_cam[i][c]; + FORC4 rgb_cam[i][c] /= num; + } + break; + case 34310: /* Leaf metadata */ + parse_mos (ftell(ifp)); + case 34303: + strcpy (make, "Leaf"); + break; + case 34665: /* EXIF tag */ + fseek (ifp, get4()+base, SEEK_SET); + parse_exif (base); + break; + case 34853: /* GPSInfo tag */ + fseek (ifp, get4()+base, SEEK_SET); + parse_gps (base); + break; + case 34675: /* InterColorProfile */ + case 50831: /* AsShotICCProfile */ + profile_offset = ftell(ifp); + profile_length = len; + break; + case 37122: /* CompressedBitsPerPixel */ + kodak_cbpp = get4(); + break; + case 37386: /* FocalLength */ + focal_len = getreal(type); + break; + case 37393: /* ImageNumber */ + shot_order = getint(type); + break; + case 37400: /* old Kodak KDC tag */ + for (raw_color = i=0; i < 3; i++) { + getreal(type); + FORC3 rgb_cam[i][c] = getreal(type); + } + break; + case 40976: + strip_offset = get4(); + switch (tiff_ifd[ifd].comp) { + case 32770: load_raw = &CLASS samsung_load_raw; break; + case 32772: load_raw = &CLASS samsung2_load_raw; break; + case 32773: load_raw = &CLASS samsung3_load_raw; break; + } + break; + case 46275: /* Imacon tags */ + strcpy (make, "Imacon"); + data_offset = ftell(ifp); + ima_len = len; + break; + case 46279: + if (!ima_len) break; + fseek (ifp, 38, SEEK_CUR); + case 46274: + fseek (ifp, 40, SEEK_CUR); + raw_width = get4(); + raw_height = get4(); + left_margin = get4() & 7; + width = raw_width - left_margin - (get4() & 7); + top_margin = get4() & 7; + height = raw_height - top_margin - (get4() & 7); + if (raw_width == 7262) { + height = 5444; + width = 7244; + left_margin = 7; + } + fseek (ifp, 52, SEEK_CUR); + FORC3 cam_mul[c] = getreal(11); + fseek (ifp, 114, SEEK_CUR); + flip = (get2() >> 7) * 90; + if (width * height * 6 == ima_len) { + if (flip % 180 == 90) SWAP(width,height); + raw_width = width; + raw_height = height; + left_margin = top_margin = filters = flip = 0; + } + sprintf (model, "Ixpress %d-Mp", height*width/1000000); + load_raw = &CLASS imacon_full_load_raw; + if (filters) { + if (left_margin & 1) filters = 0x61616161; + load_raw = &CLASS unpacked_load_raw; + } + maximum = 0xffff; + break; + case 50454: /* Sinar tag */ + case 50455: + if (!(cbuf = (char *) malloc(len))) break; + fread (cbuf, 1, len, ifp); + for (cp = cbuf-1; cp && cp < cbuf+len; cp = strchr(cp,'\n')) + if (!strncmp (++cp,"Neutral ",8)) + sscanf (cp+8, "%f %f %f", cam_mul, cam_mul+1, cam_mul+2); + free (cbuf); + break; + case 50458: + if (!make[0]) strcpy (make, "Hasselblad"); + break; + case 50459: /* Hasselblad tag */ + i = order; + j = ftell(ifp); + c = tiff_nifds; + order = get2(); + fseek (ifp, j+(get2(),get4()), SEEK_SET); + parse_tiff_ifd (j); + maximum = 0xffff; + tiff_nifds = c; + order = i; + break; + case 50706: /* DNGVersion */ + FORC4 dng_version = (dng_version << 8) + fgetc(ifp); + if (!make[0]) strcpy (make, "DNG"); + is_raw = 1; + break; + case 50708: /* UniqueCameraModel */ + if (model[0]) break; + fgets (make, 64, ifp); + if ((cp = strchr(make,' '))) { + strcpy(model,cp+1); + *cp = 0; + } + break; + case 50710: /* CFAPlaneColor */ + if (filters == 9) break; + if (len > 4) len = 4; + colors = len; + fread (cfa_pc, 1, colors, ifp); +guess_cfa_pc: + FORCC tab[cfa_pc[c]] = c; + cdesc[c] = 0; + for (i=16; i--; ) + filters = filters << 2 | tab[cfa_pat[i % plen]]; + filters -= !filters; + break; + case 50711: /* CFALayout */ + if (get2() == 2) fuji_width = 1; + break; + case 291: + case 50712: /* LinearizationTable */ + linear_table (len); + break; + case 50713: /* BlackLevelRepeatDim */ + cblack[4] = get2(); + cblack[5] = get2(); + if ((unsigned)(cblack[4] * cblack[5]) > sizeof cblack / sizeof *cblack - 6) + cblack[4] = cblack[5] = 1; + break; + case 61450: + cblack[4] = cblack[5] = MIN(sqrt(len),64); + if (filters == UINT_MAX) filters = 0x94949494; + case 50714: /* BlackLevel */ + if (!(cblack[4] * cblack[5])) + cblack[4] = cblack[5] = 1; + FORC ((unsigned)(cblack[4] * cblack[5])) + cblack[6+c] = getreal(type); + black = 0; + break; + case 50715: /* BlackLevelDeltaH */ + case 50716: /* BlackLevelDeltaV */ + for (num=i=0; i < (len & 0xffff); i++) + num += getreal(type); + black += num/len + 0.5; + break; + case 50717: /* WhiteLevel */ + maximum = getint(type); + break; + case 50718: /* DefaultScale */ + pixel_aspect = getreal(type); + pixel_aspect /= getreal(type); + break; + case 50721: /* ColorMatrix1 */ + if (use_cm) break; /* Prioritize Matrix2 over Matrix1 (UF) */ + case 50722: /* ColorMatrix2 */ + FORCC for (j=0; j < 3; j++) + cm[c][j] = getreal(type); + use_cm = 1; + break; + case 50723: /* CameraCalibration1 */ + case 50724: /* CameraCalibration2 */ + for (i=0; i < colors; i++) + FORCC cc[i][c] = getreal(type); + break; + case 50727: /* AnalogBalance */ + FORCC ab[c] = getreal(type); + break; + case 50728: /* AsShotNeutral */ + FORCC asn[c] = getreal(type); + break; + case 50729: /* AsShotWhiteXY */ + xyz[0] = getreal(type); + xyz[1] = getreal(type); + xyz[2] = 1 - xyz[0] - xyz[1]; + FORC3 xyz[c] /= d65_white[c]; + break; + case 50740: /* DNGPrivateData */ + if (dng_version) break; + parse_minolta (j = get4()+base); + fseek (ifp, j, SEEK_SET); + parse_tiff_ifd (base); + break; + case 50752: + read_shorts (cr2_slice, 3); + break; + case 50829: /* ActiveArea */ + top_margin = getint(type); + left_margin = getint(type); + height = getint(type) - top_margin; + width = getint(type) - left_margin; + break; + case 50830: /* MaskedAreas */ + for (i=0; i < len && i < 32; i++) + ((int *)mask)[i] = getint(type); + black = 0; + break; + case 51009: /* OpcodeList2 */ + meta_offset = ftell(ifp); + break; + case 64772: /* Kodak P-series */ + if (len < 13) break; + fseek (ifp, 16, SEEK_CUR); + data_offset = get4(); + fseek (ifp, 28, SEEK_CUR); + data_offset += get4(); + load_raw = &CLASS packed_load_raw; + break; + case 65026: + if (type == 2) fgets (model2, 64, ifp); + } + fseek (ifp, save, SEEK_SET); + } + if (sony_length && (buf = (unsigned *) malloc(sony_length))) { + fseek (ifp, sony_offset, SEEK_SET); + fread (buf, sony_length, 1, ifp); + sony_decrypt (buf, sony_length/4, 1, sony_key); + sfp = ifp; + if ((ifp = tmpfile())) { + fwrite (buf, sony_length, 1, ifp); + fseek (ifp, 0, SEEK_SET); + parse_tiff_ifd (-sony_offset); + fclose (ifp); + } + ifp = sfp; + free (buf); + } + for (i=0; i < colors; i++) + FORCC cc[i][c] *= ab[i]; + if (use_cm) { + FORCC for (i=0; i < 3; i++) + for (cam_xyz[c][i]=j=0; j < colors; j++) + cam_xyz[c][i] += cc[c][j] * cm[j][i] * xyz[i]; + cam_xyz_coeff (cmatrix, cam_xyz); + } + if (asn[0]) { + cam_mul[3] = 0; + FORCC cam_mul[c] = 1 / asn[c]; + } + if (!use_cm) + FORCC pre_mul[c] /= cc[c][c]; + return 0; +} + +int CLASS parse_tiff (int base) +{ + int doff; + + fseek (ifp, base, SEEK_SET); + order = get2(); + if (order != 0x4949 && order != 0x4d4d) return 0; + get2(); + while ((doff = get4())) { + fseek (ifp, doff+base, SEEK_SET); + if (parse_tiff_ifd (base)) break; + } + return 1; +} + +void CLASS apply_tiff() +{ + unsigned ties=0, i; + int max_samp=0, os, ns, raw=-1, thm=-1; + struct jhead jh; + + thumb_misc = 16; + if (thumb_offset) { + fseek (ifp, thumb_offset, SEEK_SET); + if (ljpeg_start (&jh, 1)) { + if ((unsigned)jh.bits < 17 && (unsigned)jh.wide < 0x10000 && + (unsigned)jh.high < 0x10000) + { + thumb_misc = jh.bits; + thumb_width = jh.wide; + thumb_height = jh.high; + } + } + } + for (i=tiff_nifds; i--; ) { + if (tiff_ifd[i].shutter) + shutter = tiff_ifd[i].shutter; + tiff_ifd[i].shutter = shutter; + } + for (i=0; i < tiff_nifds; i++) { + if (max_samp < tiff_ifd[i].samples) + max_samp = tiff_ifd[i].samples; + if (max_samp > 3) max_samp = 3; + os = raw_width*raw_height; + ns = tiff_ifd[i].width*tiff_ifd[i].height; + if (tiff_bps) { + os *= tiff_bps; + ns *= tiff_ifd[i].bps; + } + if ((tiff_ifd[i].comp != 6 || tiff_ifd[i].samples != 3) && + (tiff_ifd[i].width | tiff_ifd[i].height) < 0x10000 && + (unsigned)tiff_ifd[i].bps < 33 && (unsigned)tiff_ifd[i].samples < 13 && + ns && ((ns > os && (ties = 1)) || + (ns == os && shot_select == ties++))) { + raw_width = tiff_ifd[i].width; + raw_height = tiff_ifd[i].height; + tiff_bps = tiff_ifd[i].bps; + tiff_compress = tiff_ifd[i].comp; + data_offset = tiff_ifd[i].offset; + tiff_flip = tiff_ifd[i].flip; + tiff_samples = tiff_ifd[i].samples; + tile_width = tiff_ifd[i].tile_width; + tile_length = tiff_ifd[i].tile_length; + shutter = tiff_ifd[i].shutter; + raw = i; + } + } + if (is_raw == 1 && ties) is_raw = ties; + if (!tile_width ) tile_width = INT_MAX; + if (!tile_length) tile_length = INT_MAX; + for (i=tiff_nifds; i--; ) + if (tiff_ifd[i].flip) tiff_flip = tiff_ifd[i].flip; + if (raw >= 0 && !load_raw) + switch (tiff_compress) { + case 32767: + if (tiff_ifd[raw].bytes == raw_width*raw_height) { + tiff_bps = 12; + maximum = 4095; + load_raw = &CLASS sony_arw2_load_raw; break; + } + if (tiff_ifd[raw].bytes*8 != (int)(raw_width*raw_height*tiff_bps)) { + raw_height += 8; + load_raw = &CLASS sony_arw_load_raw; break; + } + load_flags = 79; + case 32769: + load_flags++; + case 32770: + case 32773: goto slr; + case 0: case 1: + if (!strncmp(make,"OLYMPUS",7) && + tiff_ifd[raw].bytes*2 == raw_width*raw_height*3) + load_flags = 24; + if (!strcmp(make,"SONY") && tiff_bps < 14 && + tiff_ifd[raw].bytes == raw_width*raw_height*2) + tiff_bps = 14; + if (tiff_ifd[raw].bytes*5 == raw_width*raw_height*8) { + load_flags = 81; + tiff_bps = 12; + } slr: + switch (tiff_bps) { + case 8: load_raw = &CLASS eight_bit_load_raw; break; + case 12: if (tiff_ifd[raw].phint == 2) + load_flags = 6; + load_raw = &CLASS packed_load_raw; break; + case 14: load_raw = &CLASS packed_load_raw; + if (tiff_ifd[raw].bytes*4 == raw_width*raw_height*7) break; + load_flags = 0; + case 16: load_raw = &CLASS unpacked_load_raw; + if (!strncmp(make,"OLYMPUS",7) && + tiff_ifd[raw].bytes*7 > raw_width*raw_height) + load_raw = &CLASS olympus_load_raw; + } + if (filters == 9 && tiff_ifd[raw].bytes*8 < raw_width*raw_height*tiff_bps) + load_raw = &CLASS fuji_xtrans_load_raw; + break; + case 6: case 7: case 99: + load_raw = &CLASS lossless_jpeg_load_raw; break; + case 262: + load_raw = &CLASS kodak_262_load_raw; break; + case 34713: + if ((raw_width+9)/10*16*raw_height == tiff_ifd[raw].bytes) { + load_raw = &CLASS packed_load_raw; + load_flags = 1; + } else if (raw_width*raw_height*3 == tiff_ifd[raw].bytes*2) { + load_raw = &CLASS packed_load_raw; + if (model[0] == 'N') load_flags = 80; + } else if (raw_width*raw_height*3 == tiff_ifd[raw].bytes) { + load_raw = &CLASS nikon_yuv_load_raw; + gamma_curve (1/2.4, 12.92, 1, 4095); + memset (cblack, 0, sizeof cblack); + filters = 0; + } else if (raw_width*raw_height*2 == tiff_ifd[raw].bytes) { + load_raw = &CLASS unpacked_load_raw; + load_flags = 4; + order = 0x4d4d; + } else + load_raw = &CLASS nikon_load_raw; break; + case 65535: + load_raw = &CLASS pentax_load_raw; break; + case 65000: + switch (tiff_ifd[raw].phint) { + case 2: load_raw = &CLASS kodak_rgb_load_raw; filters = 0; break; + case 6: load_raw = &CLASS kodak_ycbcr_load_raw; filters = 0; break; + case 32803: load_raw = &CLASS kodak_65000_load_raw; + } + case 32867: case 34892: break; + default: is_raw = 0; + } + if (!dng_version) + if ( (tiff_samples == 3 && tiff_ifd[raw].bytes && tiff_bps != 14 && + (tiff_compress & -16) != 32768) + || (tiff_bps == 8 && strncmp(make,"Phase",5) && + !strcasestr(make,"Kodak") && !strstr(model2,"DEBUG RAW"))) + is_raw = 0; + for (i=0; i < tiff_nifds; i++) + if ((int) i != raw && tiff_ifd[i].samples == max_samp && + tiff_ifd[i].bps > 0 && tiff_ifd[i].bps < 33 && + ((unsigned)(tiff_ifd[i].width | tiff_ifd[i].height)) < 0x10000 && + tiff_ifd[i].width * tiff_ifd[i].height / (SQR(tiff_ifd[i].bps)+1) > + (int)(thumb_width * thumb_height / (SQR(thumb_misc)+1)) + && tiff_ifd[i].comp != 34892) { + thumb_width = tiff_ifd[i].width; + thumb_height = tiff_ifd[i].height; + thumb_offset = tiff_ifd[i].offset; + thumb_length = tiff_ifd[i].bytes; + thumb_misc = tiff_ifd[i].bps; + thm = i; + } + if (thm >= 0) { + thumb_misc |= tiff_ifd[thm].samples << 5; + switch (tiff_ifd[thm].comp) { + case 0: + write_thumb = &CLASS layer_thumb; + break; + case 1: + if (tiff_ifd[thm].bps <= 8) + write_thumb = &CLASS ppm_thumb; + else if (!strcmp(make,"Imacon")) + write_thumb = &CLASS ppm16_thumb; + else + thumb_load_raw = &CLASS kodak_thumb_load_raw; + break; + case 65000: + thumb_load_raw = tiff_ifd[thm].phint == 6 ? + &CLASS kodak_ycbcr_load_raw : &CLASS kodak_rgb_load_raw; + } + } +} + +void CLASS parse_minolta (int base) +{ + int save, tag, len, offset, high=0, wide=0, i, c; + short sorder=order; + + fseek (ifp, base, SEEK_SET); + if (fgetc(ifp) || fgetc(ifp)-'M' || fgetc(ifp)-'R') return; + order = fgetc(ifp) * 0x101; + offset = base + get4() + 8; + while ((save=ftell(ifp)) < offset) { + for (tag=i=0; i < 4; i++) + tag = tag << 8 | fgetc(ifp); + len = get4(); + switch (tag) { + case 0x505244: /* PRD */ + fseek (ifp, 8, SEEK_CUR); + high = get2(); + wide = get2(); + break; + case 0x574247: /* WBG */ + get4(); + i = strcmp(model,"DiMAGE A200") ? 0:3; + FORC4 cam_mul[c ^ (c >> 1) ^ i] = get2(); + break; + case 0x545457: /* TTW */ + parse_tiff (ftell(ifp)); + data_offset = offset; + } + fseek (ifp, save+len+8, SEEK_SET); + } + raw_height = high; + raw_width = wide; + order = sorder; +} + +/* + Many cameras have a "debug mode" that writes JPEG and raw + at the same time. The raw file has no header, so try to + to open the matching JPEG file and read its metadata. + */ +void CLASS parse_external_jpeg() +{ + const char *file, *ext; + char *jname, *jfile, *jext; + FILE *save=ifp; + + ext = strrchr (ifname, '.'); + file = strrchr (ifname, '/'); + if (!file) file = strrchr (ifname, '\\'); + if (!file) file = ifname-1; + file++; + if (!ext || strlen(ext) != 4 || ext-file != 8) return; + jname = (char *) malloc (strlen(ifname) + 1); + merror (jname, "parse_external_jpeg()"); + strcpy (jname, ifname); + jfile = file - ifname + jname; + jext = ext - ifname + jname; + if (strcasecmp (ext, ".jpg")) { + strcpy (jext, isupper(ext[1]) ? ".JPG":".jpg"); + if (isdigit(*file)) { + memcpy (jfile, file+4, 4); + memcpy (jfile+4, file, 4); + } + } else + while (isdigit(*--jext)) { + if (*jext != '9') { + (*jext)++; + break; + } + *jext = '0'; + } + if (strcmp (jname, ifname)) { + if ((ifp = fopen (jname, "rb"))) { + dcraw_message (DCRAW_VERBOSE,_("Reading metadata from %s ...\n"), jname); + parse_tiff (12); + thumb_offset = 0; + is_raw = 1; + fclose (ifp); + } + } + if (!timestamp) + dcraw_message (DCRAW_WARNING,_("Failed to read metadata from %s\n"), jname); + free (jname); + ifp = save; +} + +/* + CIFF block 0x1030 contains an 8x8 white sample. + Load this into white[][] for use in scale_colors(). + */ +void CLASS ciff_block_1030() +{ + static const ushort key[] = { 0x410, 0x45f3 }; + int i, bpp, row, col, vbits=0; + unsigned long bitbuf=0; + + if ((get2(),get4()) != 0x80008 || !get4()) return; + bpp = get2(); + if (bpp != 10 && bpp != 12) return; + for (i=row=0; row < 8; row++) + for (col=0; col < 8; col++) { + if (vbits < bpp) { + bitbuf = bitbuf << 16 | (get2() ^ key[i++ & 1]); + vbits += 16; + } + white[row][col] = bitbuf >> (vbits -= bpp) & ~(-1 << bpp); + } +} + +/* + Parse a CIFF file, better known as Canon CRW format. + */ +void CLASS parse_ciff (int offset, int length, int depth) +{ + int tboff, nrecs, c, type, len, save, wbi=-1; + ushort key[] = { 0x410, 0x45f3 }; + + fseek (ifp, offset+length-4, SEEK_SET); + tboff = get4() + offset; + fseek (ifp, tboff, SEEK_SET); + nrecs = get2(); + if ((nrecs | depth) > 127) return; + while (nrecs--) { + type = get2(); + len = get4(); + save = ftell(ifp) + 4; + fseek (ifp, offset+get4(), SEEK_SET); + if ((((type >> 8) + 8) | 8) == 0x38) + parse_ciff (ftell(ifp), len, depth+1); /* Parse a sub-table */ + if (type == 0x0810) + fread (artist, 64, 1, ifp); + if (type == 0x080a) { + fread (make, 64, 1, ifp); + fseek (ifp, strlen(make) - 63, SEEK_CUR); + fread (model, 64, 1, ifp); + } + if (type == 0x1810) { + width = get4(); + height = get4(); + pixel_aspect = int_to_float(get4()); + flip = get4(); + } + if (type == 0x1835) /* Get the decoder table */ + tiff_compress = get4(); + if (type == 0x2007) { + thumb_offset = ftell(ifp); + thumb_length = len; + } + if (type == 0x1818) { + shutter = pow (2, -int_to_float((get4(),get4()))); + aperture = pow (2, int_to_float(get4())/2); + } + if (type == 0x102a) { + iso_speed = pow (2, (get4(),get2())/32.0 - 4) * 50; + aperture = pow (2, (get2(),(short)get2())/64.0); + shutter = pow (2,-((short)get2())/32.0); + wbi = (get2(),get2()); + if (wbi > 17) wbi = 0; + fseek (ifp, 32, SEEK_CUR); + if (shutter > 1e6) shutter = get2()/10.0; + } + if (type == 0x102c) { + if (get2() > 512) { /* Pro90, G1 */ + fseek (ifp, 118, SEEK_CUR); + FORC4 cam_mul[c ^ 2] = get2(); + } else { /* G2, S30, S40 */ + fseek (ifp, 98, SEEK_CUR); + FORC4 cam_mul[c ^ (c >> 1) ^ 1] = get2(); + } + } + if (type == 0x0032) { + if (len == 768) { /* EOS D30 */ + fseek (ifp, 72, SEEK_CUR); + FORC4 cam_mul[c ^ (c >> 1)] = 1024.0 / get2(); + if (!wbi) cam_mul[0] = -1; /* use my auto white balance */ + } else if (!cam_mul[0]) { + if (get2() == key[0]) /* Pro1, G6, S60, S70 */ + c = (strstr(model,"Pro1") ? + "012346000000000000":"01345:000000006008")[wbi]-'0'+ 2; + else { /* G3, G5, S45, S50 */ + c = "023457000000006000"[wbi]-'0'; + key[0] = key[1] = 0; + } + fseek (ifp, 78 + c*8, SEEK_CUR); + FORC4 cam_mul[c ^ (c >> 1) ^ 1] = get2() ^ key[c & 1]; + if (!wbi) cam_mul[0] = -1; + } + } + if (type == 0x10a9) { /* D60, 10D, 300D, and clones */ + if (len > 66) wbi = "0134567028"[wbi]-'0'; + fseek (ifp, 2 + wbi*8, SEEK_CUR); + FORC4 cam_mul[c ^ (c >> 1)] = get2(); + } + if (type == 0x1030 && (0x18040 >> wbi & 1)) + ciff_block_1030(); /* all that don't have 0x10a9 */ + if (type == 0x1031) { + raw_width = (get2(),get2()); + raw_height = get2(); + } + if (type == 0x5029) { + focal_len = len >> 16; + if ((len & 0xffff) == 2) focal_len /= 32; + } + if (type == 0x5813) flash_used = int_to_float(len); + if (type == 0x5814) canon_ev = int_to_float(len); + if (type == 0x5817) shot_order = len; + if (type == 0x5834) unique_id = len; + if (type == 0x580e) timestamp = len; + if (type == 0x180e) timestamp = get4(); +#ifdef LOCALTIME + if ((type | 0x4000) == 0x580e) + timestamp = mktime (gmtime (×tamp)); +#endif + fseek (ifp, save, SEEK_SET); + } +} + +void CLASS parse_rollei() +{ + char line[128], *val; + struct tm t; + + fseek (ifp, 0, SEEK_SET); + memset (&t, 0, sizeof t); + do { + fgets (line, 128, ifp); + if ((val = strchr(line,'='))) + *val++ = 0; + else + val = line + strlen(line); + if (!strcmp(line,"DAT")) + sscanf (val, "%d.%d.%d", &t.tm_mday, &t.tm_mon, &t.tm_year); + if (!strcmp(line,"TIM")) + sscanf (val, "%d:%d:%d", &t.tm_hour, &t.tm_min, &t.tm_sec); + if (!strcmp(line,"HDR")) + thumb_offset = atoi(val); + if (!strcmp(line,"X ")) + raw_width = atoi(val); + if (!strcmp(line,"Y ")) + raw_height = atoi(val); + if (!strcmp(line,"TX ")) + thumb_width = atoi(val); + if (!strcmp(line,"TY ")) + thumb_height = atoi(val); + } while (strncmp(line,"EOHD",4)); + data_offset = thumb_offset + thumb_width * thumb_height * 2; + t.tm_year -= 1900; + t.tm_mon -= 1; + if (mktime(&t) > 0) + timestamp = mktime(&t); + strcpy (make, "Rollei"); + strcpy (model,"d530flex"); + write_thumb = &CLASS rollei_thumb; +} + +void CLASS parse_sinar_ia() +{ + int entries, off; + char str[8], *cp; + + order = 0x4949; + fseek (ifp, 4, SEEK_SET); + entries = get4(); + fseek (ifp, get4(), SEEK_SET); + while (entries--) { + off = get4(); get4(); + fread (str, 8, 1, ifp); + if (!strcmp(str,"META")) meta_offset = off; + if (!strcmp(str,"THUMB")) thumb_offset = off; + if (!strcmp(str,"RAW0")) data_offset = off; + } + fseek (ifp, meta_offset+20, SEEK_SET); + fread (make, 64, 1, ifp); + make[63] = 0; + if ((cp = strchr(make,' '))) { + strcpy (model, cp+1); + *cp = 0; + } + raw_width = get2(); + raw_height = get2(); + load_raw = &CLASS unpacked_load_raw; + thumb_width = (get4(),get2()); + thumb_height = get2(); + write_thumb = &CLASS ppm_thumb; + maximum = 0x3fff; +} + +void CLASS parse_phase_one (int base) +{ + unsigned entries, tag, len, data, save, i, c; + float romm_cam[3][3]; + char *cp; + + memset (&ph1, 0, sizeof ph1); + fseek (ifp, base, SEEK_SET); + order = get4() & 0xffff; + if (get4() >> 8 != 0x526177) return; /* "Raw" */ + fseek (ifp, get4()+base, SEEK_SET); + entries = get4(); + get4(); + while (entries--) { + tag = get4(); + fseek (ifp, 4, SEEK_CUR); + len = get4(); + data = get4(); + save = ftell(ifp); + fseek (ifp, base+data, SEEK_SET); + switch (tag) { + case 0x100: flip = "0653"[data & 3]-'0'; break; + case 0x106: + for (i=0; i < 9; i++) + ((float *)romm_cam)[i] = getreal(11); + romm_coeff (romm_cam); + break; + case 0x107: + FORC3 cam_mul[c] = getreal(11); + break; + case 0x108: raw_width = data; break; + case 0x109: raw_height = data; break; + case 0x10a: left_margin = data; break; + case 0x10b: top_margin = data; break; + case 0x10c: width = data; break; + case 0x10d: height = data; break; + case 0x10e: ph1.format = data; break; + case 0x10f: data_offset = data+base; break; + case 0x110: meta_offset = data+base; + meta_length = len; break; + case 0x112: ph1.key_off = save - 4; break; + case 0x210: ph1.tag_210 = int_to_float(data); break; + case 0x21a: ph1.tag_21a = data; break; + case 0x21c: strip_offset = data+base; break; + case 0x21d: ph1.black = data; break; + case 0x222: ph1.split_col = data; break; + case 0x223: ph1.black_col = data+base; break; + case 0x224: ph1.split_row = data; break; + case 0x225: ph1.black_row = data+base; break; + case 0x301: + model[63] = 0; + fread (model, 1, 63, ifp); + if ((cp = strstr(model," camera"))) *cp = 0; + } + fseek (ifp, save, SEEK_SET); + } + load_raw = ph1.format < 3 ? + &CLASS phase_one_load_raw : &CLASS phase_one_load_raw_c; + maximum = 0xffff; + strcpy (make, "Phase One"); + if (model[0]) return; + switch (raw_height) { + case 2060: strcpy (model,"LightPhase"); break; + case 2682: strcpy (model,"H 10"); break; + case 4128: strcpy (model,"H 20"); break; + case 5488: strcpy (model,"H 25"); break; + } +} + +void CLASS parse_fuji (int offset) +{ + unsigned entries, tag, len, save, i, c; + + fseek (ifp, offset, SEEK_SET); + entries = get4(); + if (entries > 255) return; + while (entries--) { + tag = get2(); + len = get2(); + save = ftell(ifp); + if (tag == 0x100) { + raw_height = get2(); + raw_width = get2(); + } else if (tag == 0x121) { + height = get2(); + if ((width = get2()) == 4284) width += 3; + } else if (tag == 0x130) { + fuji_layout = fgetc(ifp) >> 7; + fuji_width = !(fgetc(ifp) & 8); + } else if (tag == 0x131) { + filters = 9; + for (i=0; i < 6; i++) + FORC(6) xtrans_abs[5-i][5-c] = fgetc(ifp) & 3; + } else if (tag == 0x2ff0) { + FORC4 cam_mul[c ^ 1] = get2(); + } else if (tag == 0x9650) { /* FUJIFILM exposure bias - NKBJ */ + fuji_dr = get2(); + } else if (tag == 0xc000 && len > 20000) { + c = order; + order = 0x4949; + while ((tag = get4()) > raw_width); + width = tag; + height = get4(); + order = c; + } + fseek (ifp, save+len, SEEK_SET); + } + height <<= fuji_layout; + width >>= fuji_layout; +} + +int CLASS parse_jpeg (int offset) +{ + int len, save, hlen, mark; + + fseek (ifp, offset, SEEK_SET); + if (fgetc(ifp) != 0xff || fgetc(ifp) != 0xd8) return 0; + + while (fgetc(ifp) == 0xff && (mark = fgetc(ifp)) != 0xda) { + order = 0x4d4d; + len = get2() - 2; + save = ftell(ifp); + if (mark == 0xc0 || mark == 0xc3 || mark == 0xc9) { + fgetc(ifp); + raw_height = get2(); + raw_width = get2(); + } + order = get2(); + hlen = get4(); + if (get4() == 0x48454150) /* "HEAP" */ + parse_ciff (save+hlen, len-hlen, 0); + if (parse_tiff (save+6)) apply_tiff(); + fseek (ifp, save+len, SEEK_SET); + } + return 1; +} + +void CLASS parse_riff() +{ + unsigned i, size, end; + char tag[4], date[64], month[64]; + static const char mon[12][4] = + { "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" }; + struct tm t; + + order = 0x4949; + fread (tag, 4, 1, ifp); + size = get4(); + end = ftell(ifp) + size; + if (!memcmp(tag,"RIFF",4) || !memcmp(tag,"LIST",4)) { + get4(); + while ((unsigned) ftell(ifp)+7 < end && !feof(ifp)) + parse_riff(); + } else if (!memcmp(tag,"nctg",4)) { + while ((unsigned) ftell(ifp)+7 < end) { + i = get2(); + size = get2(); + if ((i+1) >> 1 == 10 && size == 20) + get_timestamp(0); + else fseek (ifp, size, SEEK_CUR); + } + } else if (!memcmp(tag,"IDIT",4) && size < 64) { + fread (date, 64, 1, ifp); + date[size] = 0; + memset (&t, 0, sizeof t); + if (sscanf (date, "%*s %s %d %d:%d:%d %d", month, &t.tm_mday, + &t.tm_hour, &t.tm_min, &t.tm_sec, &t.tm_year) == 6) { + for (i=0; i < 12 && strcasecmp(mon[i],month); i++); + t.tm_mon = i; + t.tm_year -= 1900; + if (mktime(&t) > 0) + timestamp = mktime(&t); + } + } else + fseek (ifp, size, SEEK_CUR); +} + +void CLASS parse_crx (int end) +{ + unsigned i, save, size, tag, base; + static int index=0, wide, high, off, len; + + order = 0x4d4d; + while (ftell(ifp)+7 < end) { + save = ftell(ifp); + if ((size = get4()) < 8) break; + switch (tag = get4()) { + case 0x6d6f6f76: /* moov */ + case 0x7472616b: /* trak */ + case 0x6d646961: /* mdia */ + case 0x6d696e66: /* minf */ + case 0x7374626c: /* stbl */ + parse_crx (save+size); + break; + case 0x75756964: /* uuid */ + switch (i=get4()) { + case 0xeaf42b5e: fseek (ifp, 8, SEEK_CUR); + case 0x85c0b687: fseek (ifp, 12, SEEK_CUR); + parse_crx (save+size); + } + break; + case 0x434d5431: /* CMT1 */ + case 0x434d5432: /* CMT2 */ + base = ftell(ifp); + order = get2(); + fseek (ifp, 6, SEEK_CUR); + tag & 1 ? (void)parse_tiff_ifd (base) : parse_exif (base); + order = 0x4d4d; + break; + case 0x746b6864: /* tkhd */ + fseek (ifp, 12, SEEK_CUR); + index = get4(); + fseek (ifp, 58, SEEK_CUR); + wide = get4(); + high = get4(); + break; + case 0x7374737a: /* stsz */ + len = (get4(),get4()); + break; + case 0x636f3634: /* co64 */ + fseek (ifp, 12, SEEK_CUR); + off = get4(); + switch (index) { + case 1: /* 1 = full size, 2 = 27% size */ + thumb_width = wide; + thumb_height = high; + thumb_length = len; + thumb_offset = off; + break; + case 3: + raw_width = wide; + raw_height = high; + data_offset = off; + load_raw = &CLASS canon_crx_load_raw; + } + break; + case 0x50525657: /* PRVW */ + fseek (ifp, 6, SEEK_CUR); + } + fseek (ifp, save+size, SEEK_SET); + } +} + +void CLASS parse_qt (int end) +{ + unsigned save, size; + char tag[4]; + + order = 0x4d4d; + while (ftell(ifp)+7 < end) { + save = ftell(ifp); + if ((size = get4()) < 8) return; + fread (tag, 4, 1, ifp); + if (!memcmp(tag,"moov",4) || + !memcmp(tag,"udta",4) || + !memcmp(tag,"CNTH",4)) + parse_qt (save+size); + if (!memcmp(tag,"CNDA",4)) + parse_jpeg (ftell(ifp)); + fseek (ifp, save+size, SEEK_SET); + } +} + +void CLASS parse_smal (int offset, unsigned fsize) +{ + int ver; + + fseek (ifp, offset+2, SEEK_SET); + order = 0x4949; + ver = fgetc(ifp); + if (ver == 6) + fseek (ifp, 5, SEEK_CUR); + if (get4() != fsize) return; + if (ver > 6) data_offset = get4(); + raw_height = height = get2(); + raw_width = width = get2(); + strcpy (make, "SMaL"); + sprintf (model, "v%d %dx%d", ver, width, height); + if (ver == 6) load_raw = &CLASS smal_v6_load_raw; + if (ver == 9) load_raw = &CLASS smal_v9_load_raw; +} + +void CLASS parse_cine() +{ + unsigned off_head, off_setup, off_image, i; + + order = 0x4949; + fseek (ifp, 4, SEEK_SET); + is_raw = get2() == 2; + fseek (ifp, 14, SEEK_CUR); + is_raw *= get4(); + off_head = get4(); + off_setup = get4(); + off_image = get4(); + timestamp = get4(); + if ((i = get4())) timestamp = i; + fseek (ifp, off_head+4, SEEK_SET); + raw_width = get4(); + raw_height = get4(); + switch (get2(),get2()) { + case 8: load_raw = &CLASS eight_bit_load_raw; break; + case 16: load_raw = &CLASS unpacked_load_raw; + } + fseek (ifp, off_setup+792, SEEK_SET); + strcpy (make, "CINE"); + sprintf (model, "%d", get4()); + fseek (ifp, 12, SEEK_CUR); + switch ((i=get4()) & 0xffffff) { + case 3: filters = 0x94949494; break; + case 4: filters = 0x49494949; break; + default: is_raw = 0; + } + fseek (ifp, 72, SEEK_CUR); + switch ((get4()+3600) % 360) { + case 270: flip = 4; break; + case 180: flip = 1; break; + case 90: flip = 7; break; + case 0: flip = 2; + } + cam_mul[0] = getreal(11); + cam_mul[2] = getreal(11); + maximum = ~(-1 << get4()); + fseek (ifp, 668, SEEK_CUR); + shutter = get4()/1000000000.0; + fseek (ifp, off_image, SEEK_SET); + if (shot_select < is_raw) + fseek (ifp, shot_select*8, SEEK_CUR); + data_offset = (INT64) get4() + 8; + data_offset += (INT64) get4() << 32; +} + +void CLASS parse_redcine() +{ + unsigned i, len, rdvo; + + order = 0x4d4d; + is_raw = 0; + fseek (ifp, 52, SEEK_SET); + width = get4(); + height = get4(); + fseek (ifp, 0, SEEK_END); +#ifdef HAVE_FSEEKO + fseek (ifp, -(i = ftello(ifp) & 511), SEEK_CUR); +#else + fseek (ifp, -(i = ftell(ifp) & 511), SEEK_CUR); +#endif + if (get4() != i || get4() != 0x52454f42) { + dcraw_message (DCRAW_WARNING, + _("%s: Tail is missing, parsing from head...\n"), ifname_display); + fseek (ifp, 0, SEEK_SET); + while ((len = get4()) != (unsigned) EOF) { + if (get4() == 0x52454456) + if (is_raw++ == shot_select) +#ifdef HAVE_FSEEKO + data_offset = ftello(ifp) - 8; +#else + data_offset = ftell(ifp) - 8; +#endif + fseek (ifp, len-8, SEEK_CUR); + } + } else { + rdvo = get4(); + fseek (ifp, 12, SEEK_CUR); + is_raw = get4(); +#ifdef HAVE_FSEEKO + fseeko (ifp, rdvo+8 + shot_select*4, SEEK_SET); +#else + fseek (ifp, rdvo+8 + shot_select*4, SEEK_SET); +#endif + data_offset = get4(); + } +} + +char * CLASS foveon_gets (int offset, char *str, int len) +{ + int i; + fseek (ifp, offset, SEEK_SET); + for (i=0; i < len-1; i++) + if ((str[i] = get2()) == 0) break; + str[i] = 0; + return str; +} + +void CLASS parse_foveon() +{ + unsigned len; + int entries, img=0, off, tag, save, i, wide, high, pent, poff[256][2]; + char name[64], value[64]; + + order = 0x4949; /* Little-endian */ + fseek (ifp, 36, SEEK_SET); + flip = get4(); + fseek (ifp, -4, SEEK_END); + fseek (ifp, get4(), SEEK_SET); + if (get4() != 0x64434553) return; /* SECd */ + entries = (get4(),get4()); + while (entries--) { + off = get4(); + len = get4(); + tag = get4(); + save = ftell(ifp); + fseek (ifp, off, SEEK_SET); + if (get4() != (unsigned)(0x20434553 | (tag << 24))) return; + switch (tag) { + case 0x47414d49: /* IMAG */ + case 0x32414d49: /* IMA2 */ + fseek (ifp, 8, SEEK_CUR); + pent = get4(); + wide = get4(); + high = get4(); + if (wide > raw_width && high > raw_height) { + switch (pent) { + case 5: load_flags = 1; + case 6: load_raw = &CLASS foveon_sd_load_raw; break; + case 30: load_raw = &CLASS foveon_dp_load_raw; break; + default: load_raw = 0; + } + raw_width = wide; + raw_height = high; + data_offset = off+28; + is_foveon = 1; + } + fseek (ifp, off+28, SEEK_SET); + if (fgetc(ifp) == 0xff && fgetc(ifp) == 0xd8 + && thumb_length < len-28) { + thumb_offset = off+28; + thumb_length = len-28; + write_thumb = &CLASS jpeg_thumb; + } + if (++img == 2 && !thumb_length) { + thumb_offset = off+24; + thumb_width = wide; + thumb_height = high; + write_thumb = &CLASS foveon_thumb; + } + break; + case 0x464d4143: /* CAMF */ + meta_offset = off+8; + meta_length = len-28; + break; + case 0x504f5250: /* PROP */ + pent = (get4(),get4()); + fseek (ifp, 12, SEEK_CUR); + off += pent*8 + 24; + if ((unsigned) pent > 256) pent=256; + for (i=0; i < pent*2; i++) + ((int *)poff)[i] = off + get4()*2; + for (i=0; i < pent; i++) { + foveon_gets (poff[i][0], name, 64); + foveon_gets (poff[i][1], value, 64); + if (!strcmp (name, "ISO")) + iso_speed = atoi(value); + if (!strcmp (name, "CAMMANUF")) + strcpy (make, value); + if (!strcmp (name, "CAMMODEL")) + strcpy (model, value); + if (!strcmp (name, "WB_DESC")) + strcpy (model2, value); + if (!strcmp (name, "CM_DESC")) + strcpy (cm_desc, value); + if (!strcmp (name, "TIME")) + timestamp = atoi(value); + if (!strcmp (name, "EXPTIME")) + shutter = atoi(value) / 1000000.0; + if (!strcmp (name, "APERTURE")) + aperture = atof(value); + if (!strcmp (name, "FLENGTH")) + focal_len = atof(value); + } +#ifdef LOCALTIME + timestamp = mktime (gmtime (×tamp)); +#endif + } + fseek (ifp, save, SEEK_SET); + } +} + +/* + All matrices are from Adobe DNG Converter unless otherwise noted. + */ +void CLASS adobe_coeff (const char *make, const char *model) +{ + static const struct { + const char *prefix; + int black, maximum, trans[12]; + } table[] = { + { "AgfaPhoto DC-833m", 0, 0, /* DJC */ + { 11438,-3762,-1115,-2409,9914,2497,-1227,2295,5300 } }, + { "Apple QuickTake", 0, 0, /* DJC */ + { 21392,-5653,-3353,2406,8010,-415,7166,1427,2078 } }, + { "Canon EOS D2000", 0, 0, + { 24542,-10860,-3401,-1490,11370,-297,2858,-605,3225 } }, + { "Canon EOS D6000", 0, 0, + { 20482,-7172,-3125,-1033,10410,-285,2542,226,3136 } }, + { "Canon EOS D30", 0, 0, + { 9805,-2689,-1312,-5803,13064,3068,-2438,3075,8775 } }, + { "Canon EOS D60", 0, 0xfa0, + { 6188,-1341,-890,-7168,14489,2937,-2640,3228,8483 } }, + { "Canon EOS 5DS", 0, 0x3c96, + { 6250,-711,-808,-5153,12794,2636,-1249,2198,5610 } }, + { "Canon EOS 5D Mark IV", 0, 0, + { 6446,-366,-864,-4436,12204,2513,-952,2496,6348 } }, + { "Canon EOS 5D Mark III", 0, 0x3c80, + { 6722,-635,-963,-4287,12460,2028,-908,2162,5668 } }, + { "Canon EOS 5D Mark II", 0, 0x3cf0, + { 4716,603,-830,-7798,15474,2480,-1496,1937,6651 } }, + { "Canon EOS 5D", 0, 0xe6c, + { 6347,-479,-972,-8297,15954,2480,-1968,2131,7649 } }, + { "Canon EOS 6D Mark II", 0, 0, + { 6875,-970,-932,-4691,12459,2501,-874,1953,5809 } }, + { "Canon EOS 6D", 0, 0x3c82, + { 7034,-804,-1014,-4420,12564,2058,-851,1994,5758 } }, + { "Canon EOS 7D Mark II", 0, 0x3510, + { 7268,-1082,-969,-4186,11839,2663,-825,2029,5839 } }, + { "Canon EOS 7D", 0, 0x3510, + { 6844,-996,-856,-3876,11761,2396,-593,1772,6198 } }, + { "Canon EOS 10D", 0, 0xfa0, + { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } }, + { "Canon EOS 20Da", 0, 0, + { 14155,-5065,-1382,-6550,14633,2039,-1623,1824,6561 } }, + { "Canon EOS 20D", 0, 0xfff, + { 6599,-537,-891,-8071,15783,2424,-1983,2234,7462 } }, + { "Canon EOS 30D", 0, 0, + { 6257,-303,-1000,-7880,15621,2396,-1714,1904,7046 } }, + { "Canon EOS 40D", 0, 0x3f60, + { 6071,-747,-856,-7653,15365,2441,-2025,2553,7315 } }, + { "Canon EOS 50D", 0, 0x3d93, + { 4920,616,-593,-6493,13964,2784,-1774,3178,7005 } }, + { "Canon EOS 60D", 0, 0x2ff7, + { 6719,-994,-925,-4408,12426,2211,-887,2129,6051 } }, + { "Canon EOS 70D", 0, 0x3bc7, + { 7034,-804,-1014,-4420,12564,2058,-851,1994,5758 } }, + { "Canon EOS 77D", 0, 0, + { 7377,-742,-998,-4235,11981,2549,-673,1918,5538 } }, + { "Canon EOS 80D", 0, 0, + { 7457,-671,-937,-4849,12495,2643,-1213,2354,5492 } }, + { "Canon EOS 100D", 0, 0x350f, + { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } }, + { "Canon EOS 200D", 0, 0, + { 7377,-742,-998,-4235,11981,2549,-673,1918,5538 } }, + { "Canon EOS 300D", 0, 0xfa0, + { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } }, + { "Canon EOS 350D", 0, 0xfff, + { 6018,-617,-965,-8645,15881,2975,-1530,1719,7642 } }, + { "Canon EOS 400D", 0, 0xe8e, + { 7054,-1501,-990,-8156,15544,2812,-1278,1414,7796 } }, + { "Canon EOS 450D", 0, 0x390d, + { 5784,-262,-821,-7539,15064,2672,-1982,2681,7427 } }, + { "Canon EOS 500D", 0, 0x3479, + { 4763,712,-646,-6821,14399,2640,-1921,3276,6561 } }, + { "Canon EOS 550D", 0, 0x3dd7, + { 6941,-1164,-857,-3825,11597,2534,-416,1540,6039 } }, + { "Canon EOS 600D", 0, 0x3510, + { 6461,-907,-882,-4300,12184,2378,-819,1944,5931 } }, + { "Canon EOS 650D", 0, 0x354d, + { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } }, + { "Canon EOS 700D", 0, 0x3c00, + { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } }, + { "Canon EOS 750D", 0, 0x368e, + { 6362,-823,-847,-4426,12109,2616,-743,1857,5635 } }, + { "Canon EOS 760D", 0, 0x350f, + { 6362,-823,-847,-4426,12109,2616,-743,1857,5635 } }, + { "Canon EOS 800D", 0, 0, + { 6970,-512,-968,-4425,12161,2553,-739,1982,5601 } }, + { "Canon EOS 1000D", 0, 0xe43, + { 6771,-1139,-977,-7818,15123,2928,-1244,1437,7533 } }, + { "Canon EOS 1100D", 0, 0x3510, + { 6444,-904,-893,-4563,12308,2535,-903,2016,6728 } }, + { "Canon EOS 1200D", 0, 0x37c2, + { 6461,-907,-882,-4300,12184,2378,-819,1944,5931 } }, + { "Canon EOS 1300D", 0, 0x3510, + { 6939,-1016,-866,-4428,12473,2177,-1175,2178,6162 } }, + { "Canon EOS 1500D", 0, 0, + { 8532,-701,-1167,-4095,11879,2508,-797,2424,7010 } }, + { "Canon EOS 3000D", 0, 0, + { 6939,-1016,-866,-4428,12473,2177,-1175,2178,6162 } }, + { "Canon EOS M6", 0, 0, + { 8532,-701,-1167,-4095,11879,2508,-797,2424,7010 } }, + { "Canon EOS M5", 0, 0, /* also M50 */ + { 8532,-701,-1167,-4095,11879,2508,-797,2424,7010 } }, + { "Canon EOS M3", 0, 0, + { 6362,-823,-847,-4426,12109,2616,-743,1857,5635 } }, + { "Canon EOS M100", 0, 0, + { 8532,-701,-1167,-4095,11879,2508,-797,2424,7010 } }, + { "Canon EOS M10", 0, 0, + { 6400,-480,-888,-5294,13416,2047,-1296,2203,6137 } }, + { "Canon EOS M", 0, 0, + { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } }, + { "Canon EOS-1Ds Mark III", 0, 0x3bb0, + { 5859,-211,-930,-8255,16017,2353,-1732,1887,7448 } }, + { "Canon EOS-1Ds Mark II", 0, 0xe80, + { 6517,-602,-867,-8180,15926,2378,-1618,1771,7633 } }, + { "Canon EOS-1D Mark IV", 0, 0x3bb0, + { 6014,-220,-795,-4109,12014,2361,-561,1824,5787 } }, + { "Canon EOS-1D Mark III", 0, 0x3bb0, + { 6291,-540,-976,-8350,16145,2311,-1714,1858,7326 } }, + { "Canon EOS-1D Mark II N", 0, 0xe80, + { 6240,-466,-822,-8180,15825,2500,-1801,1938,8042 } }, + { "Canon EOS-1D Mark II", 0, 0xe80, + { 6264,-582,-724,-8312,15948,2504,-1744,1919,8664 } }, + { "Canon EOS-1DS", 0, 0xe20, + { 4374,3631,-1743,-7520,15212,2472,-2892,3632,8161 } }, + { "Canon EOS-1D C", 0, 0x3c4e, + { 6847,-614,-1014,-4669,12737,2139,-1197,2488,6846 } }, + { "Canon EOS-1D X Mark II", 0, 0, + { 7596,-978,-967,-4808,12571,2503,-1398,2567,5752 } }, + { "Canon EOS-1D X", 0, 0x3c4e, + { 6847,-614,-1014,-4669,12737,2139,-1197,2488,6846 } }, + { "Canon EOS-1D", 0, 0xe20, + { 6806,-179,-1020,-8097,16415,1687,-3267,4236,7690 } }, + { "Canon EOS C500", 853, 0, /* DJC */ + { 17851,-10604,922,-7425,16662,763,-3660,3636,22278 } }, + { "Canon PowerShot A530", 0, 0, + { 0 } }, /* don't want the A5 matrix */ + { "Canon PowerShot A50", 0, 0, + { -5300,9846,1776,3436,684,3939,-5540,9879,6200,-1404,11175,217 } }, + { "Canon PowerShot A5", 0, 0, + { -4801,9475,1952,2926,1611,4094,-5259,10164,5947,-1554,10883,547 } }, + { "Canon PowerShot G10", 0, 0, + { 11093,-3906,-1028,-5047,12492,2879,-1003,1750,5561 } }, + { "Canon PowerShot G11", 0, 0, + { 12177,-4817,-1069,-1612,9864,2049,-98,850,4471 } }, + { "Canon PowerShot G12", 0, 0, + { 13244,-5501,-1248,-1508,9858,1935,-270,1083,4366 } }, + { "Canon PowerShot G15", 0, 0, + { 7474,-2301,-567,-4056,11456,2975,-222,716,4181 } }, + { "Canon PowerShot G16", 0, 0, + { 8020,-2687,-682,-3704,11879,2052,-965,1921,5556 } }, + { "Canon PowerShot G1 X Mark III", 0, 0, + { 8532,-701,-1167,-4095,11879,2508,-797,2424,7010 } }, + { "Canon PowerShot G1 X", 0, 0, + { 7378,-1255,-1043,-4088,12251,2048,-876,1946,5805 } }, + { "Canon PowerShot G1", 0, 0, + { -4778,9467,2172,4743,-1141,4344,-5146,9908,6077,-1566,11051,557 } }, + { "Canon PowerShot G2", 0, 0, + { 9087,-2693,-1049,-6715,14382,2537,-2291,2819,7790 } }, + { "Canon PowerShot G3 X", 0, 0, + { 9701,-3857,-921,-3149,11537,1817,-786,1817,5147 } }, + { "Canon PowerShot G3", 0, 0, + { 9212,-2781,-1073,-6573,14189,2605,-2300,2844,7664 } }, + { "Canon PowerShot G5 X", 0, 0, + { 9602,-3823,-937,-2984,11495,1675,-407,1415,5049 } }, + { "Canon PowerShot G5", 0, 0, + { 9757,-2872,-933,-5972,13861,2301,-1622,2328,7212 } }, + { "Canon PowerShot G6", 0, 0, + { 9877,-3775,-871,-7613,14807,3072,-1448,1305,7485 } }, + { "Canon PowerShot G7 X", 0, 0, + { 9602,-3823,-937,-2984,11495,1675,-407,1415,5049 } }, + { "Canon PowerShot G9 X Mark II", 0, 0, + { 10056,-4131,-944,-2576,11143,1625,-238,1294,5179 } }, + { "Canon PowerShot G9 X", 0, 0, + { 9602,-3823,-937,-2984,11495,1675,-407,1415,5049 } }, + { "Canon PowerShot G9", 0, 0, + { 7368,-2141,-598,-5621,13254,2625,-1418,1696,5743 } }, + { "Canon PowerShot Pro1", 0, 0, + { 10062,-3522,-999,-7643,15117,2730,-765,817,7323 } }, + { "Canon PowerShot Pro70", 34, 0, + { -4155,9818,1529,3939,-25,4522,-5521,9870,6610,-2238,10873,1342 } }, + { "Canon PowerShot Pro90", 0, 0, + { -4963,9896,2235,4642,-987,4294,-5162,10011,5859,-1770,11230,577 } }, + { "Canon PowerShot S30", 0, 0, + { 10566,-3652,-1129,-6552,14662,2006,-2197,2581,7670 } }, + { "Canon PowerShot S40", 0, 0, + { 8510,-2487,-940,-6869,14231,2900,-2318,2829,9013 } }, + { "Canon PowerShot S45", 0, 0, + { 8163,-2333,-955,-6682,14174,2751,-2077,2597,8041 } }, + { "Canon PowerShot S50", 0, 0, + { 8882,-2571,-863,-6348,14234,2288,-1516,2172,6569 } }, + { "Canon PowerShot S60", 0, 0, + { 8795,-2482,-797,-7804,15403,2573,-1422,1996,7082 } }, + { "Canon PowerShot S70", 0, 0, + { 9976,-3810,-832,-7115,14463,2906,-901,989,7889 } }, + { "Canon PowerShot S90", 0, 0, + { 12374,-5016,-1049,-1677,9902,2078,-83,852,4683 } }, + { "Canon PowerShot S95", 0, 0, + { 13440,-5896,-1279,-1236,9598,1931,-180,1001,4651 } }, + { "Canon PowerShot S100", 0, 0, + { 7968,-2565,-636,-2873,10697,2513,180,667,4211 } }, + { "Canon PowerShot S110", 0, 0, + { 8039,-2643,-654,-3783,11230,2930,-206,690,4194 } }, + { "Canon PowerShot S120", 0, 0, + { 6961,-1685,-695,-4625,12945,1836,-1114,2152,5518 } }, + { "Canon PowerShot SX1 IS", 0, 0, + { 6578,-259,-502,-5974,13030,3309,-308,1058,4970 } }, + { "Canon PowerShot SX50 HS", 0, 0, + { 12432,-4753,-1247,-2110,10691,1629,-412,1623,4926 } }, + { "Canon PowerShot SX60 HS", 0, 0, + { 13161,-5451,-1344,-1989,10654,1531,-47,1271,4955 } }, + { "Canon PowerShot A3300", 0, 0, /* DJC */ + { 10826,-3654,-1023,-3215,11310,1906,0,999,4960 } }, + { "Canon PowerShot A470", 0, 0, /* DJC */ + { 12513,-4407,-1242,-2680,10276,2405,-878,2215,4734 } }, + { "Canon PowerShot A610", 0, 0, /* DJC */ + { 15591,-6402,-1592,-5365,13198,2168,-1300,1824,5075 } }, + { "Canon PowerShot A620", 0, 0, /* DJC */ + { 15265,-6193,-1558,-4125,12116,2010,-888,1639,5220 } }, + { "Canon PowerShot A630", 0, 0, /* DJC */ + { 14201,-5308,-1757,-6087,14472,1617,-2191,3105,5348 } }, + { "Canon PowerShot A640", 0, 0, /* DJC */ + { 13124,-5329,-1390,-3602,11658,1944,-1612,2863,4885 } }, + { "Canon PowerShot A650", 0, 0, /* DJC */ + { 9427,-3036,-959,-2581,10671,1911,-1039,1982,4430 } }, + { "Canon PowerShot A720", 0, 0, /* DJC */ + { 14573,-5482,-1546,-1266,9799,1468,-1040,1912,3810 } }, + { "Canon PowerShot S3 IS", 0, 0, /* DJC */ + { 14062,-5199,-1446,-4712,12470,2243,-1286,2028,4836 } }, + { "Canon PowerShot SX110 IS", 0, 0, /* DJC */ + { 14134,-5576,-1527,-1991,10719,1273,-1158,1929,3581 } }, + { "Canon PowerShot SX220", 0, 0, /* DJC */ + { 13898,-5076,-1447,-1405,10109,1297,-244,1860,3687 } }, + { "Canon IXUS 160", 0, 0, /* DJC */ + { 11657,-3781,-1136,-3544,11262,2283,-160,1219,4700 } }, + { "Casio EX-S20", 0, 0, /* DJC */ + { 11634,-3924,-1128,-4968,12954,2015,-1588,2648,7206 } }, + { "Casio EX-Z750", 0, 0, /* DJC */ + { 10819,-3873,-1099,-4903,13730,1175,-1755,3751,4632 } }, + { "Casio EX-Z10", 128, 0xfff, /* DJC */ + { 9790,-3338,-603,-2321,10222,2099,-344,1273,4799 } }, + { "CINE 650", 0, 0, + { 3390,480,-500,-800,3610,340,-550,2336,1192 } }, + { "CINE 660", 0, 0, + { 3390,480,-500,-800,3610,340,-550,2336,1192 } }, + { "CINE", 0, 0, + { 20183,-4295,-423,-3940,15330,3985,-280,4870,9800 } }, + { "Contax N Digital", 0, 0xf1e, + { 7777,1285,-1053,-9280,16543,2916,-3677,5679,7060 } }, + { "DXO ONE", 0, 0, + { 6596,-2079,-562,-4782,13016,1933,-970,1581,5181 } }, + { "Epson R-D1", 0, 0, + { 6827,-1878,-732,-8429,16012,2564,-704,592,7145 } }, + { "Fujifilm E550", 0, 0, + { 11044,-3888,-1120,-7248,15168,2208,-1531,2277,8069 } }, + { "Fujifilm E900", 0, 0, + { 9183,-2526,-1078,-7461,15071,2574,-2022,2440,8639 } }, + { "Fujifilm F5", 0, 0, + { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } }, + { "Fujifilm F6", 0, 0, + { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } }, + { "Fujifilm F77", 0, 0xfe9, + { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } }, + { "Fujifilm F7", 0, 0, + { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } }, + { "Fujifilm F8", 0, 0, + { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } }, + { "Fujifilm GFX 50S", 0, 0, + { 11756,-4754,-874,-3056,11045,2305,-381,1457,6006 } }, + { "Fujifilm S100FS", 514, 0, + { 11521,-4355,-1065,-6524,13767,3058,-1466,1984,6045 } }, + { "Fujifilm S1", 0, 0, + { 12297,-4882,-1202,-2106,10691,1623,-88,1312,4790 } }, + { "Fujifilm S20Pro", 0, 0, + { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } }, + { "Fujifilm S20", 512, 0x3fff, + { 11401,-4498,-1312,-5088,12751,2613,-838,1568,5941 } }, + { "Fujifilm S2Pro", 128, 0xf15, + { 12492,-4690,-1402,-7033,15423,1647,-1507,2111,7697 } }, + { "Fujifilm S3Pro", 0, 0x3dff, + { 11807,-4612,-1294,-8927,16968,1988,-2120,2741,8006 } }, + { "Fujifilm S5Pro", 0, 0, + { 12300,-5110,-1304,-9117,17143,1998,-1947,2448,8100 } }, + { "Fujifilm S5000", 0, 0, + { 8754,-2732,-1019,-7204,15069,2276,-1702,2334,6982 } }, + { "Fujifilm S5100", 0, 0, + { 11940,-4431,-1255,-6766,14428,2542,-993,1165,7421 } }, + { "Fujifilm S5500", 0, 0, + { 11940,-4431,-1255,-6766,14428,2542,-993,1165,7421 } }, + { "Fujifilm S5200", 0, 0, + { 9636,-2804,-988,-7442,15040,2589,-1803,2311,8621 } }, + { "Fujifilm S5600", 0, 0, + { 9636,-2804,-988,-7442,15040,2589,-1803,2311,8621 } }, + { "Fujifilm S6", 0, 0, + { 12628,-4887,-1401,-6861,14996,1962,-2198,2782,7091 } }, + { "Fujifilm S7000", 0, 0, + { 10190,-3506,-1312,-7153,15051,2238,-2003,2399,7505 } }, + { "Fujifilm S9000", 0, 0, + { 10491,-3423,-1145,-7385,15027,2538,-1809,2275,8692 } }, + { "Fujifilm S9500", 0, 0, + { 10491,-3423,-1145,-7385,15027,2538,-1809,2275,8692 } }, + { "Fujifilm S9100", 0, 0, + { 12343,-4515,-1285,-7165,14899,2435,-1895,2496,8800 } }, + { "Fujifilm S9600", 0, 0, + { 12343,-4515,-1285,-7165,14899,2435,-1895,2496,8800 } }, + { "Fujifilm SL1000", 0, 0, + { 11705,-4262,-1107,-2282,10791,1709,-555,1713,4945 } }, + { "Fujifilm IS-1", 0, 0, + { 21461,-10807,-1441,-2332,10599,1999,289,875,7703 } }, + { "Fujifilm IS Pro", 0, 0, + { 12300,-5110,-1304,-9117,17143,1998,-1947,2448,8100 } }, + { "Fujifilm HS10 HS11", 0, 0xf68, + { 12440,-3954,-1183,-1123,9674,1708,-83,1614,4086 } }, + { "Fujifilm HS2", 0, 0xfef, + { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } }, + { "Fujifilm HS3", 0, 0, + { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } }, + { "Fujifilm HS50EXR", 0, 0, + { 12085,-4727,-953,-3257,11489,2002,-511,2046,4592 } }, + { "Fujifilm F900EXR", 0, 0, + { 12085,-4727,-953,-3257,11489,2002,-511,2046,4592 } }, + { "Fujifilm X100F", 0, 0, + { 11434,-4948,-1210,-3746,12042,1903,-666,1479,5235 } }, + { "Fujifilm X100S", 0, 0, + { 10592,-4262,-1008,-3514,11355,2465,-870,2025,6386 } }, + { "Fujifilm X100T", 0, 0, + { 10592,-4262,-1008,-3514,11355,2465,-870,2025,6386 } }, + { "Fujifilm X100", 0, 0, + { 12161,-4457,-1069,-5034,12874,2400,-795,1724,6904 } }, + { "Fujifilm X10", 0, 0, + { 13509,-6199,-1254,-4430,12733,1865,-331,1441,5022 } }, + { "Fujifilm X20", 0, 0, + { 11768,-4971,-1133,-4904,12927,2183,-480,1723,4605 } }, + { "Fujifilm X30", 0, 0, + { 12328,-5256,-1144,-4469,12927,1675,-87,1291,4351 } }, + { "Fujifilm X70", 0, 0, + { 10450,-4329,-878,-3217,11105,2421,-752,1758,6519 } }, + { "Fujifilm X-Pro1", 0, 0, + { 10413,-3996,-993,-3721,11640,2361,-733,1540,6011 } }, + { "Fujifilm X-Pro2", 0, 0, + { 11434,-4948,-1210,-3746,12042,1903,-666,1479,5235 } }, + { "Fujifilm X-A10", 0, 0, + { 11540,-4999,-991,-2949,10963,2278,-382,1049,5605 } }, + { "Fujifilm X-A20", 0, 0, + { 11540,-4999,-991,-2949,10963,2278,-382,1049,5605 } }, + { "Fujifilm X-A1", 0, 0, + { 11086,-4555,-839,-3512,11310,2517,-815,1341,5940 } }, + { "Fujifilm X-A2", 0, 0, + { 10763,-4560,-917,-3346,11311,2322,-475,1135,5843 } }, + { "Fujifilm X-A3", 0, 0, + { 12407,-5222,-1086,-2971,11116,2120,-294,1029,5284 } }, + { "Fujifilm X-A5", 0, 0, + { 11673,-4760,-1041,-3988,12058,2166,-771,1417,5569 } }, + { "Fujifilm X-E1", 0, 0, + { 10413,-3996,-993,-3721,11640,2361,-733,1540,6011 } }, + { "Fujifilm X-E2S", 0, 0, + { 11562,-5118,-961,-3022,11007,2311,-525,1569,6097 } }, + { "Fujifilm X-E2", 0, 0, + { 8458,-2451,-855,-4597,12447,2407,-1475,2482,6526 } }, + { "Fujifilm X-E3", 0, 0, + { 11434,-4948,-1210,-3746,12042,1903,-666,1479,5235 } }, + { "Fujifilm X-H1", 0, 0, + { 11434,-4948,-1210,-3746,12042,1903,-666,1479,5235 } }, + { "Fujifilm X-M1", 0, 0, + { 10413,-3996,-993,-3721,11640,2361,-733,1540,6011 } }, + { "Fujifilm X-S1", 0, 0, + { 13509,-6199,-1254,-4430,12733,1865,-331,1441,5022 } }, + { "Fujifilm X-T1", 0, 0, /* also X-T10 */ + { 8458,-2451,-855,-4597,12447,2407,-1475,2482,6526 } }, + { "Fujifilm X-T2", 0, 0, /* also X-T20 */ + { 11434,-4948,-1210,-3746,12042,1903,-666,1479,5235 } }, + { "Fujifilm XF1", 0, 0, + { 13509,-6199,-1254,-4430,12733,1865,-331,1441,5022 } }, + { "Fujifilm XQ", 0, 0, /* XQ1 and XQ2 */ + { 9252,-2704,-1064,-5893,14265,1717,-1101,2341,4349 } }, + { "GoPro HERO5 Black", 0, 0, + { 10344,-4210,-620,-2315,10625,1948,93,1058,5541 } }, + { "Imacon Ixpress", 0, 0, /* DJC */ + { 7025,-1415,-704,-5188,13765,1424,-1248,2742,6038 } }, + { "Kodak NC2000", 0, 0, + { 13891,-6055,-803,-465,9919,642,2121,82,1291 } }, + { "Kodak DCS315C", 8, 0, + { 17523,-4827,-2510,756,8546,-137,6113,1649,2250 } }, + { "Kodak DCS330C", 8, 0, + { 20620,-7572,-2801,-103,10073,-396,3551,-233,2220 } }, + { "Kodak DCS420", 0, 0, + { 10868,-1852,-644,-1537,11083,484,2343,628,2216 } }, + { "Kodak DCS460", 0, 0, + { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } }, + { "Kodak EOSDCS1", 0, 0, + { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } }, + { "Kodak EOSDCS3B", 0, 0, + { 9898,-2700,-940,-2478,12219,206,1985,634,1031 } }, + { "Kodak DCS520C", 178, 0, + { 24542,-10860,-3401,-1490,11370,-297,2858,-605,3225 } }, + { "Kodak DCS560C", 177, 0, + { 20482,-7172,-3125,-1033,10410,-285,2542,226,3136 } }, + { "Kodak DCS620C", 177, 0, + { 23617,-10175,-3149,-2054,11749,-272,2586,-489,3453 } }, + { "Kodak DCS620X", 176, 0, + { 13095,-6231,154,12221,-21,-2137,895,4602,2258 } }, + { "Kodak DCS660C", 173, 0, + { 18244,-6351,-2739,-791,11193,-521,3711,-129,2802 } }, + { "Kodak DCS720X", 0, 0, + { 11775,-5884,950,9556,1846,-1286,-1019,6221,2728 } }, + { "Kodak DCS760C", 0, 0, + { 16623,-6309,-1411,-4344,13923,323,2285,274,2926 } }, + { "Kodak DCS Pro SLR", 0, 0, + { 5494,2393,-232,-6427,13850,2846,-1876,3997,5445 } }, + { "Kodak DCS Pro 14nx", 0, 0, + { 5494,2393,-232,-6427,13850,2846,-1876,3997,5445 } }, + { "Kodak DCS Pro 14", 0, 0, + { 7791,3128,-776,-8588,16458,2039,-2455,4006,6198 } }, + { "Kodak ProBack645", 0, 0, + { 16414,-6060,-1470,-3555,13037,473,2545,122,4948 } }, + { "Kodak ProBack", 0, 0, + { 21179,-8316,-2918,-915,11019,-165,3477,-180,4210 } }, + { "Kodak P712", 0, 0, + { 9658,-3314,-823,-5163,12695,2768,-1342,1843,6044 } }, + { "Kodak P850", 0, 0xf7c, + { 10511,-3836,-1102,-6946,14587,2558,-1481,1792,6246 } }, + { "Kodak P880", 0, 0xfff, + { 12805,-4662,-1376,-7480,15267,2360,-1626,2194,7904 } }, + { "Kodak EasyShare Z980", 0, 0, + { 11313,-3559,-1101,-3893,11891,2257,-1214,2398,4908 } }, + { "Kodak EasyShare Z981", 0, 0, + { 12729,-4717,-1188,-1367,9187,2582,274,860,4411 } }, + { "Kodak EasyShare Z990", 0, 0xfed, + { 11749,-4048,-1309,-1867,10572,1489,-138,1449,4522 } }, + { "Kodak EASYSHARE Z1015", 0, 0xef1, + { 11265,-4286,-992,-4694,12343,2647,-1090,1523,5447 } }, + { "Leaf CMost", 0, 0, + { 3952,2189,449,-6701,14585,2275,-4536,7349,6536 } }, + { "Leaf Valeo 6", 0, 0, + { 3952,2189,449,-6701,14585,2275,-4536,7349,6536 } }, + { "Leaf Aptus 54S", 0, 0, + { 8236,1746,-1314,-8251,15953,2428,-3673,5786,5771 } }, + { "Leaf Aptus 65", 0, 0, + { 7914,1414,-1190,-8777,16582,2280,-2811,4605,5562 } }, + { "Leaf Aptus 75", 0, 0, + { 7914,1414,-1190,-8777,16582,2280,-2811,4605,5562 } }, + { "Leaf", 0, 0, + { 8236,1746,-1314,-8251,15953,2428,-3673,5786,5771 } }, + { "Mamiya ZD", 0, 0, + { 7645,2579,-1363,-8689,16717,2015,-3712,5941,5961 } }, + { "Micron 2010", 110, 0, /* DJC */ + { 16695,-3761,-2151,155,9682,163,3433,951,4904 } }, + { "Minolta DiMAGE 5", 0, 0xf7d, + { 8983,-2942,-963,-6556,14476,2237,-2426,2887,8014 } }, + { "Minolta DiMAGE 7Hi", 0, 0xf7d, + { 11368,-3894,-1242,-6521,14358,2339,-2475,3056,7285 } }, + { "Minolta DiMAGE 7", 0, 0xf7d, + { 9144,-2777,-998,-6676,14556,2281,-2470,3019,7744 } }, + { "Minolta DiMAGE A1", 0, 0xf8b, + { 9274,-2547,-1167,-8220,16323,1943,-2273,2720,8340 } }, + { "Minolta DiMAGE A200", 0, 0, + { 8560,-2487,-986,-8112,15535,2771,-1209,1324,7743 } }, + { "Minolta DiMAGE A2", 0, 0xf8f, + { 9097,-2726,-1053,-8073,15506,2762,-966,981,7763 } }, + { "Minolta DiMAGE Z2", 0, 0, /* DJC */ + { 11280,-3564,-1370,-4655,12374,2282,-1423,2168,5396 } }, + { "Minolta DYNAX 5", 0, 0xffb, + { 10284,-3283,-1086,-7957,15762,2316,-829,882,6644 } }, + { "Minolta DYNAX 7", 0, 0xffb, + { 10239,-3104,-1099,-8037,15727,2451,-927,925,6871 } }, + { "Motorola PIXL", 0, 0, /* DJC */ + { 8898,-989,-1033,-3292,11619,1674,-661,3178,5216 } }, + { "Nikon D100", 0, 0, + { 5902,-933,-782,-8983,16719,2354,-1402,1455,6464 } }, + { "Nikon D1H", 0, 0, + { 7577,-2166,-926,-7454,15592,1934,-2377,2808,8606 } }, + { "Nikon D1X", 0, 0, + { 7702,-2245,-975,-9114,17242,1875,-2679,3055,8521 } }, + { "Nikon D1", 0, 0, /* multiplied by 2.218750, 1.0, 1.148438 */ + { 16772,-4726,-2141,-7611,15713,1972,-2846,3494,9521 } }, + { "Nikon D200", 0, 0xfbc, + { 8367,-2248,-763,-8758,16447,2422,-1527,1550,8053 } }, + { "Nikon D2H", 0, 0, + { 5710,-901,-615,-8594,16617,2024,-2975,4120,6830 } }, + { "Nikon D2X", 0, 0, + { 10231,-2769,-1255,-8301,15900,2552,-797,680,7148 } }, + { "Nikon D3000", 0, 0, + { 8736,-2458,-935,-9075,16894,2251,-1354,1242,8263 } }, + { "Nikon D3100", 0, 0, + { 7911,-2167,-813,-5327,13150,2408,-1288,2483,7968 } }, + { "Nikon D3200", 0, 0xfb9, + { 7013,-1408,-635,-5268,12902,2640,-1470,2801,7379 } }, + { "Nikon D3300", 0, 0, + { 6988,-1384,-714,-5631,13410,2447,-1485,2204,7318 } }, + { "Nikon D3400", 0, 0, + { 6988,-1384,-714,-5631,13410,2447,-1485,2204,7318 } }, + { "Nikon D300", 0, 0, + { 9030,-1992,-715,-8465,16302,2255,-2689,3217,8069 } }, + { "Nikon D3X", 0, 0, + { 7171,-1986,-648,-8085,15555,2718,-2170,2512,7457 } }, + { "Nikon D3S", 0, 0, + { 8828,-2406,-694,-4874,12603,2541,-660,1509,7587 } }, + { "Nikon D3", 0, 0, + { 8139,-2171,-663,-8747,16541,2295,-1925,2008,8093 } }, + { "Nikon D40X", 0, 0, + { 8819,-2543,-911,-9025,16928,2151,-1329,1213,8449 } }, + { "Nikon D40", 0, 0, + { 6992,-1668,-806,-8138,15748,2543,-874,850,7897 } }, + { "Nikon D4S", 0, 0, + { 8598,-2848,-857,-5618,13606,2195,-1002,1773,7137 } }, + { "Nikon D4", 0, 0, + { 8598,-2848,-857,-5618,13606,2195,-1002,1773,7137 } }, + { "Nikon Df", 0, 0, + { 8598,-2848,-857,-5618,13606,2195,-1002,1773,7137 } }, + { "Nikon D5000", 0, 0xf00, + { 7309,-1403,-519,-8474,16008,2622,-2433,2826,8064 } }, + { "Nikon D5100", 0, 0x3de6, + { 8198,-2239,-724,-4871,12389,2798,-1043,2050,7181 } }, + { "Nikon D5200", 0, 0, + { 8322,-3112,-1047,-6367,14342,2179,-988,1638,6394 } }, + { "Nikon D5300", 0, 0, + { 6988,-1384,-714,-5631,13410,2447,-1485,2204,7318 } }, + { "Nikon D5500", 0, 0, + { 8821,-2938,-785,-4178,12142,2287,-824,1651,6860 } }, + { "Nikon D5600", 0, 0, + { 8821,-2938,-785,-4178,12142,2287,-824,1651,6860 } }, + { "Nikon D500", 0, 0, + { 8813,-3210,-1036,-4703,12868,2021,-1054,1940,6129 } }, + { "Nikon D50", 0, 0, + { 7732,-2422,-789,-8238,15884,2498,-859,783,7330 } }, + { "Nikon D5", 0, 0, + { 9200,-3522,-992,-5755,13803,2117,-753,1486,6338 } }, + { "Nikon D600", 0, 0x3e07, + { 8178,-2245,-609,-4857,12394,2776,-1207,2086,7298 } }, + { "Nikon D610", 0, 0, + { 8178,-2245,-609,-4857,12394,2776,-1207,2086,7298 } }, + { "Nikon D60", 0, 0, + { 8736,-2458,-935,-9075,16894,2251,-1354,1242,8263 } }, + { "Nikon D7000", 0, 0, + { 8198,-2239,-724,-4871,12389,2798,-1043,2050,7181 } }, + { "Nikon D7100", 0, 0, + { 8322,-3112,-1047,-6367,14342,2179,-988,1638,6394 } }, + { "Nikon D7200", 0, 0, + { 8322,-3112,-1047,-6367,14342,2179,-988,1638,6394 } }, + { "Nikon D7500", 0, 0, + { 8813,-3210,-1036,-4703,12868,2021,-1054,1940,6129 } }, + { "Nikon D750", 0, 0, + { 9020,-2890,-715,-4535,12436,2348,-934,1919,7086 } }, + { "Nikon D700", 0, 0, + { 8139,-2171,-663,-8747,16541,2295,-1925,2008,8093 } }, + { "Nikon D70", 0, 0, + { 7732,-2422,-789,-8238,15884,2498,-859,783,7330 } }, + { "Nikon D850", 0, 0, + { 10405,-3755,-1270,-5461,13787,1793,-1040,2015,6785 } }, + { "Nikon D810", 0, 0, + { 9369,-3195,-791,-4488,12430,2301,-893,1796,6872 } }, + { "Nikon D800", 0, 0, + { 7866,-2108,-555,-4869,12483,2681,-1176,2069,7501 } }, + { "Nikon D80", 0, 0, + { 8629,-2410,-883,-9055,16940,2171,-1490,1363,8520 } }, + { "Nikon D90", 0, 0xf00, + { 7309,-1403,-519,-8474,16008,2622,-2434,2826,8064 } }, + { "Nikon E700", 0, 0x3dd, /* DJC */ + { -3746,10611,1665,9621,-1734,2114,-2389,7082,3064,3406,6116,-244 } }, + { "Nikon E800", 0, 0x3dd, /* DJC */ + { -3746,10611,1665,9621,-1734,2114,-2389,7082,3064,3406,6116,-244 } }, + { "Nikon E950", 0, 0x3dd, /* DJC */ + { -3746,10611,1665,9621,-1734,2114,-2389,7082,3064,3406,6116,-244 } }, + { "Nikon E995", 0, 0, /* copied from E5000 */ + { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, + { "Nikon E2100", 0, 0, /* copied from Z2, new white balance */ + { 13142,-4152,-1596,-4655,12374,2282,-1769,2696,6711} }, + { "Nikon E2500", 0, 0, + { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, + { "Nikon E3200", 0, 0, /* DJC */ + { 9846,-2085,-1019,-3278,11109,2170,-774,2134,5745 } }, + { "Nikon E4300", 0, 0, /* copied from Minolta DiMAGE Z2 */ + { 11280,-3564,-1370,-4655,12374,2282,-1423,2168,5396 } }, + { "Nikon E4500", 0, 0, + { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, + { "Nikon E5000", 0, 0, + { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, + { "Nikon E5400", 0, 0, + { 9349,-2987,-1001,-7919,15766,2266,-2098,2680,6839 } }, + { "Nikon E5700", 0, 0, + { -5368,11478,2368,5537,-113,3148,-4969,10021,5782,778,9028,211 } }, + { "Nikon E8400", 0, 0, + { 7842,-2320,-992,-8154,15718,2599,-1098,1342,7560 } }, + { "Nikon E8700", 0, 0, + { 8489,-2583,-1036,-8051,15583,2643,-1307,1407,7354 } }, + { "Nikon E8800", 0, 0, + { 7971,-2314,-913,-8451,15762,2894,-1442,1520,7610 } }, + { "Nikon COOLPIX A", 0, 0, + { 8198,-2239,-724,-4871,12389,2798,-1043,2050,7181 } }, + { "Nikon COOLPIX B700", 200, 0, + { 14387,-6014,-1299,-1357,9975,1616,467,1047,4744 } }, + { "Nikon COOLPIX P330", 200, 0, + { 10321,-3920,-931,-2750,11146,1824,-442,1545,5539 } }, + { "Nikon COOLPIX P340", 200, 0, + { 10321,-3920,-931,-2750,11146,1824,-442,1545,5539 } }, + { "Nikon COOLPIX P6000", 0, 0, + { 9698,-3367,-914,-4706,12584,2368,-837,968,5801 } }, + { "Nikon COOLPIX P7000", 0, 0, + { 11432,-3679,-1111,-3169,11239,2202,-791,1380,4455 } }, + { "Nikon COOLPIX P7100", 0, 0, + { 11053,-4269,-1024,-1976,10182,2088,-526,1263,4469 } }, + { "Nikon COOLPIX P7700", 200, 0, + { 10321,-3920,-931,-2750,11146,1824,-442,1545,5539 } }, + { "Nikon COOLPIX P7800", 200, 0, + { 10321,-3920,-931,-2750,11146,1824,-442,1545,5539 } }, + { "Nikon 1 V3", 0, 0, + { 5958,-1559,-571,-4021,11453,2939,-634,1548,5087 } }, + { "Nikon 1 J4", 0, 0, + { 5958,-1559,-571,-4021,11453,2939,-634,1548,5087 } }, + { "Nikon 1 J5", 0, 0, + { 7520,-2518,-645,-3844,12102,1945,-913,2249,6835 } }, + { "Nikon 1 S2", 200, 0, + { 6612,-1342,-618,-3338,11055,2623,-174,1792,5075 } }, + { "Nikon 1 V2", 0, 0, + { 6588,-1305,-693,-3277,10987,2634,-355,2016,5106 } }, + { "Nikon 1 J3", 0, 0, + { 6588,-1305,-693,-3277,10987,2634,-355,2016,5106 } }, + { "Nikon 1 AW1", 0, 0, + { 6588,-1305,-693,-3277,10987,2634,-355,2016,5106 } }, + { "Nikon 1 ", 0, 0, /* J1, J2, S1, V1 */ + { 8994,-2667,-865,-4594,12324,2552,-699,1786,6260 } }, + { "Olympus AIR A01", 0, 0, + { 8992,-3093,-639,-2563,10721,2122,-437,1270,5473 } }, + { "Olympus C5050", 0, 0, + { 10508,-3124,-1273,-6079,14294,1901,-1653,2306,6237 } }, + { "Olympus C5060", 0, 0, + { 10445,-3362,-1307,-7662,15690,2058,-1135,1176,7602 } }, + { "Olympus C7070", 0, 0, + { 10252,-3531,-1095,-7114,14850,2436,-1451,1723,6365 } }, + { "Olympus C70", 0, 0, + { 10793,-3791,-1146,-7498,15177,2488,-1390,1577,7321 } }, + { "Olympus C80", 0, 0, + { 8606,-2509,-1014,-8238,15714,2703,-942,979,7760 } }, + { "Olympus E-10", 0, 0xffc, + { 12745,-4500,-1416,-6062,14542,1580,-1934,2256,6603 } }, + { "Olympus E-1", 0, 0, + { 11846,-4767,-945,-7027,15878,1089,-2699,4122,8311 } }, + { "Olympus E-20", 0, 0xffc, + { 13173,-4732,-1499,-5807,14036,1895,-2045,2452,7142 } }, + { "Olympus E-300", 0, 0, + { 7828,-1761,-348,-5788,14071,1830,-2853,4518,6557 } }, + { "Olympus E-330", 0, 0, + { 8961,-2473,-1084,-7979,15990,2067,-2319,3035,8249 } }, + { "Olympus E-30", 0, 0xfbc, + { 8144,-1861,-1111,-7763,15894,1929,-1865,2542,7607 } }, + { "Olympus E-3", 0, 0xf99, + { 9487,-2875,-1115,-7533,15606,2010,-1618,2100,7389 } }, + { "Olympus E-400", 0, 0, + { 6169,-1483,-21,-7107,14761,2536,-2904,3580,8568 } }, + { "Olympus E-410", 0, 0xf6a, + { 8856,-2582,-1026,-7761,15766,2082,-2009,2575,7469 } }, + { "Olympus E-420", 0, 0xfd7, + { 8746,-2425,-1095,-7594,15612,2073,-1780,2309,7416 } }, + { "Olympus E-450", 0, 0xfd2, + { 8745,-2425,-1095,-7594,15613,2073,-1780,2309,7416 } }, + { "Olympus E-500", 0, 0, + { 8136,-1968,-299,-5481,13742,1871,-2556,4205,6630 } }, + { "Olympus E-510", 0, 0xf6a, + { 8785,-2529,-1033,-7639,15624,2112,-1783,2300,7817 } }, + { "Olympus E-520", 0, 0xfd2, + { 8344,-2322,-1020,-7596,15635,2048,-1748,2269,7287 } }, + { "Olympus E-5", 0, 0xeec, + { 11200,-3783,-1325,-4576,12593,2206,-695,1742,7504 } }, + { "Olympus E-600", 0, 0xfaf, + { 8453,-2198,-1092,-7609,15681,2008,-1725,2337,7824 } }, + { "Olympus E-620", 0, 0xfaf, + { 8453,-2198,-1092,-7609,15681,2008,-1725,2337,7824 } }, + { "Olympus E-P1", 0, 0xffd, + { 8343,-2050,-1021,-7715,15705,2103,-1831,2380,8235 } }, + { "Olympus E-P2", 0, 0xffd, + { 8343,-2050,-1021,-7715,15705,2103,-1831,2380,8235 } }, + { "Olympus E-P3", 0, 0, + { 7575,-2159,-571,-3722,11341,2725,-1434,2819,6271 } }, + { "Olympus E-P5", 0, 0, + { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, + { "Olympus E-PL1s", 0, 0, + { 11409,-3872,-1393,-4572,12757,2003,-709,1810,7415 } }, + { "Olympus E-PL1", 0, 0, + { 11408,-4289,-1215,-4286,12385,2118,-387,1467,7787 } }, + { "Olympus E-PL2", 0, 0xcf3, + { 15030,-5552,-1806,-3987,12387,1767,-592,1670,7023 } }, + { "Olympus E-PL3", 0, 0, + { 7575,-2159,-571,-3722,11341,2725,-1434,2819,6271 } }, + { "Olympus E-PL5", 0, 0xfcb, + { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, + { "Olympus E-PL6", 0, 0, + { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, + { "Olympus E-PL7", 0, 0, + { 9197,-3190,-659,-2606,10830,2039,-458,1250,5458 } }, + { "Olympus E-PL8", 0, 0, + { 9197,-3190,-659,-2606,10830,2039,-458,1250,5458 } }, + { "Olympus E-PL9", 0, 0, + { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, + { "Olympus E-PM1", 0, 0, + { 7575,-2159,-571,-3722,11341,2725,-1434,2819,6271 } }, + { "Olympus E-PM2", 0, 0, + { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, + { "Olympus E-M10", 0, 0, /* also E-M10 Mark II & III */ + { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, + { "Olympus E-M1Mark II", 0, 0, + { 9383,-3170,-763,-2457,10702,2020,-384,1236,5552 } }, + { "Olympus E-M1", 0, 0, + { 7687,-1984,-606,-4327,11928,2721,-1381,2339,6452 } }, + { "Olympus E-M5MarkII", 0, 0, + { 9422,-3258,-711,-2655,10898,2015,-512,1354,5512 } }, + { "Olympus E-M5", 0, 0xfe1, + { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, + { "Olympus PEN-F", 0, 0, + { 9476,-3182,-765,-2613,10958,1893,-449,1315,5268 } }, + { "Olympus SH-2", 0, 0, + { 10156,-3425,-1077,-2611,11177,1624,-385,1592,5080 } }, + { "Olympus SP350", 0, 0, + { 12078,-4836,-1069,-6671,14306,2578,-786,939,7418 } }, + { "Olympus SP3", 0, 0, + { 11766,-4445,-1067,-6901,14421,2707,-1029,1217,7572 } }, + { "Olympus SP500UZ", 0, 0xfff, + { 9493,-3415,-666,-5211,12334,3260,-1548,2262,6482 } }, + { "Olympus SP510UZ", 0, 0xffe, + { 10593,-3607,-1010,-5881,13127,3084,-1200,1805,6721 } }, + { "Olympus SP550UZ", 0, 0xffe, + { 11597,-4006,-1049,-5432,12799,2957,-1029,1750,6516 } }, + { "Olympus SP560UZ", 0, 0xff9, + { 10915,-3677,-982,-5587,12986,2911,-1168,1968,6223 } }, + { "Olympus SP570UZ", 0, 0, + { 11522,-4044,-1146,-4736,12172,2904,-988,1829,6039 } }, + { "Olympus STYLUS1", 0, 0, + { 8360,-2420,-880,-3928,12353,1739,-1381,2416,5173 } }, + { "Olympus TG-4", 0, 0, + { 11426,-4159,-1126,-2066,10678,1593,-120,1327,4998 } }, + { "Olympus TG-5", 0, 0, + { 10899,-3833,-1082,-2112,10736,1575,-267,1452,5269 } }, + { "Olympus XZ-10", 0, 0, + { 9777,-3483,-925,-2886,11297,1800,-602,1663,5134 } }, + { "Olympus XZ-1", 0, 0, + { 10901,-4095,-1074,-1141,9208,2293,-62,1417,5158 } }, + { "Olympus XZ-2", 0, 0, + { 9777,-3483,-925,-2886,11297,1800,-602,1663,5134 } }, + { "OmniVision", 0, 0, /* DJC */ + { 12782,-4059,-379,-478,9066,1413,1340,1513,5176 } }, + { "Pentax *ist DL2", 0, 0, + { 10504,-2438,-1189,-8603,16207,2531,-1022,863,12242 } }, + { "Pentax *ist DL", 0, 0, + { 10829,-2838,-1115,-8339,15817,2696,-837,680,11939 } }, + { "Pentax *ist DS2", 0, 0, + { 10504,-2438,-1189,-8603,16207,2531,-1022,863,12242 } }, + { "Pentax *ist DS", 0, 0, + { 10371,-2333,-1206,-8688,16231,2602,-1230,1116,11282 } }, + { "Pentax *ist D", 0, 0, + { 9651,-2059,-1189,-8881,16512,2487,-1460,1345,10687 } }, + { "Pentax K10D", 0, 0, + { 9566,-2863,-803,-7170,15172,2112,-818,803,9705 } }, + { "Pentax K1", 0, 0, + { 11095,-3157,-1324,-8377,15834,2720,-1108,947,11688 } }, + { "Pentax K20D", 0, 0, + { 9427,-2714,-868,-7493,16092,1373,-2199,3264,7180 } }, + { "Pentax K200D", 0, 0, + { 9186,-2678,-907,-8693,16517,2260,-1129,1094,8524 } }, + { "Pentax K2000", 0, 0, + { 11057,-3604,-1155,-5152,13046,2329,-282,375,8104 } }, + { "Pentax K-m", 0, 0, + { 11057,-3604,-1155,-5152,13046,2329,-282,375,8104 } }, + { "Pentax K-x", 0, 0, + { 8843,-2837,-625,-5025,12644,2668,-411,1234,7410 } }, + { "Pentax K-r", 0, 0, + { 9895,-3077,-850,-5304,13035,2521,-883,1768,6936 } }, + { "Pentax K-1", 0, 0, + { 8596,-2981,-639,-4202,12046,2431,-685,1424,6122 } }, + { "Pentax K-30", 0, 0, + { 8710,-2632,-1167,-3995,12301,1881,-981,1719,6535 } }, + { "Pentax K-3 II", 0, 0, + { 8626,-2607,-1155,-3995,12301,1881,-1039,1822,6925 } }, + { "Pentax K-3", 0, 0, + { 7415,-2052,-721,-5186,12788,2682,-1446,2157,6773 } }, + { "Pentax K-5 II", 0, 0, + { 8170,-2725,-639,-4440,12017,2744,-771,1465,6599 } }, + { "Pentax K-5", 0, 0, + { 8713,-2833,-743,-4342,11900,2772,-722,1543,6247 } }, + { "Pentax K-70", 0, 0, + { 8270,-2117,-1299,-4359,12953,1515,-1078,1933,5975 } }, + { "Pentax K-7", 0, 0, + { 9142,-2947,-678,-8648,16967,1663,-2224,2898,8615 } }, + { "Pentax K-S1", 0, 0, + { 8512,-3211,-787,-4167,11966,2487,-638,1288,6054 } }, + { "Pentax K-S2", 0, 0, + { 8662,-3280,-798,-3928,11771,2444,-586,1232,6054 } }, + { "Pentax KP", 0, 0, + { 8617,-3228,-1034,-4674,12821,2044,-803,1577,5728 } }, + { "Pentax Q-S1", 0, 0, + { 12995,-5593,-1107,-1879,10139,2027,-64,1233,4919 } }, + { "Pentax 645D", 0, 0x3e00, + { 10646,-3593,-1158,-3329,11699,1831,-667,2874,6287 } }, + { "Panasonic DMC-CM1", 15, 0, + { 8770,-3194,-820,-2871,11281,1803,-513,1552,4434 } }, + { "Panasonic DC-FZ80", 0, 0, + { 8550,-2908,-842,-3195,11529,1881,-338,1603,4631 } }, + { "Panasonic DMC-FZ8", 0, 0xf7f, + { 8986,-2755,-802,-6341,13575,3077,-1476,2144,6379 } }, + { "Panasonic DMC-FZ18", 0, 0, + { 9932,-3060,-935,-5809,13331,2753,-1267,2155,5575 } }, + { "Panasonic DMC-FZ28", 15, 0xf96, + { 10109,-3488,-993,-5412,12812,2916,-1305,2140,5543 } }, + { "Panasonic DMC-FZ2500", 15, 0, + { 7386,-2443,-743,-3437,11864,1757,-608,1660,4766 } }, + { "Panasonic DMC-FZ330", 15, 0, + { 8378,-2798,-769,-3068,11410,1877,-538,1792,4623 } }, + { "Panasonic DMC-FZ300", 15, 0, + { 8378,-2798,-769,-3068,11410,1877,-538,1792,4623 } }, + { "Panasonic DMC-FZ30", 0, 0xf94, + { 10976,-4029,-1141,-7918,15491,2600,-1670,2071,8246 } }, + { "Panasonic DMC-FZ3", 15, 0, /* FZ35, FZ38 */ + { 9938,-2780,-890,-4604,12393,2480,-1117,2304,4620 } }, + { "Panasonic DMC-FZ4", 15, 0, /* FZ40, FZ45 */ + { 13639,-5535,-1371,-1698,9633,2430,316,1152,4108 } }, + { "Panasonic DMC-FZ50", 0, 0, + { 7906,-2709,-594,-6231,13351,3220,-1922,2631,6537 } }, + { "Panasonic DMC-FZ7", 15, 0, /* FZ70, FZ72 */ + { 11532,-4324,-1066,-2375,10847,1749,-564,1699,4351 } }, + { "Leica V-LUX1", 0, 0, + { 7906,-2709,-594,-6231,13351,3220,-1922,2631,6537 } }, + { "Panasonic DMC-L10", 15, 0xf96, + { 8025,-1942,-1050,-7920,15904,2100,-2456,3005,7039 } }, + { "Panasonic DMC-L1", 0, 0xf7f, + { 8054,-1885,-1025,-8349,16367,2040,-2805,3542,7629 } }, + { "Leica DIGILUX 3", 0, 0xf7f, + { 8054,-1885,-1025,-8349,16367,2040,-2805,3542,7629 } }, + { "Panasonic DMC-LC1", 0, 0, + { 11340,-4069,-1275,-7555,15266,2448,-2960,3426,7685 } }, + { "Leica DIGILUX 2", 0, 0, + { 11340,-4069,-1275,-7555,15266,2448,-2960,3426,7685 } }, + { "Panasonic DMC-LX100", 15, 0, + { 8844,-3538,-768,-3709,11762,2200,-698,1792,5220 } }, + { "Leica D-LUX (Typ 109)", 15, 0, + { 8844,-3538,-768,-3709,11762,2200,-698,1792,5220 } }, + { "Panasonic DMC-LF1", 15, 0, + { 9379,-3267,-816,-3227,11560,1881,-926,1928,5340 } }, + { "Leica C (Typ 112)", 15, 0, + { 9379,-3267,-816,-3227,11560,1881,-926,1928,5340 } }, + { "Panasonic DMC-LX1", 0, 0xf7f, + { 10704,-4187,-1230,-8314,15952,2501,-920,945,8927 } }, + { "Leica D-LUX2", 0, 0xf7f, + { 10704,-4187,-1230,-8314,15952,2501,-920,945,8927 } }, + { "Panasonic DMC-LX2", 0, 0, + { 8048,-2810,-623,-6450,13519,3272,-1700,2146,7049 } }, + { "Leica D-LUX3", 0, 0, + { 8048,-2810,-623,-6450,13519,3272,-1700,2146,7049 } }, + { "Panasonic DMC-LX3", 15, 0, + { 8128,-2668,-655,-6134,13307,3161,-1782,2568,6083 } }, + { "Leica D-LUX 4", 15, 0, + { 8128,-2668,-655,-6134,13307,3161,-1782,2568,6083 } }, + { "Panasonic DMC-LX5", 15, 0, + { 10909,-4295,-948,-1333,9306,2399,22,1738,4582 } }, + { "Leica D-LUX 5", 15, 0, + { 10909,-4295,-948,-1333,9306,2399,22,1738,4582 } }, + { "Panasonic DMC-LX7", 15, 0, + { 10148,-3743,-991,-2837,11366,1659,-701,1893,4899 } }, + { "Leica D-LUX 6", 15, 0, + { 10148,-3743,-991,-2837,11366,1659,-701,1893,4899 } }, + { "Panasonic DMC-LX9", 15, 0, + { 7790,-2736,-755,-3452,11870,1769,-628,1647,4898 } }, + { "Panasonic DMC-FZ1000", 15, 0, + { 7830,-2696,-763,-3325,11667,1866,-641,1712,4824 } }, + { "Leica V-LUX (Typ 114)", 15, 0, + { 7830,-2696,-763,-3325,11667,1866,-641,1712,4824 } }, + { "Panasonic DMC-FZ100", 15, 0xfff, + { 16197,-6146,-1761,-2393,10765,1869,366,2238,5248 } }, + { "Leica V-LUX 2", 15, 0xfff, + { 16197,-6146,-1761,-2393,10765,1869,366,2238,5248 } }, + { "Panasonic DMC-FZ150", 15, 0xfff, + { 11904,-4541,-1189,-2355,10899,1662,-296,1586,4289 } }, + { "Leica V-LUX 3", 15, 0xfff, + { 11904,-4541,-1189,-2355,10899,1662,-296,1586,4289 } }, + { "Panasonic DMC-FZ200", 15, 0xfff, + { 8112,-2563,-740,-3730,11784,2197,-941,2075,4933 } }, + { "Leica V-LUX 4", 15, 0xfff, + { 8112,-2563,-740,-3730,11784,2197,-941,2075,4933 } }, + { "Panasonic DMC-FX150", 15, 0xfff, + { 9082,-2907,-925,-6119,13377,3058,-1797,2641,5609 } }, + { "Panasonic DMC-G10", 0, 0, + { 10113,-3400,-1114,-4765,12683,2317,-377,1437,6710 } }, + { "Panasonic DMC-G1", 15, 0xf94, + { 8199,-2065,-1056,-8124,16156,2033,-2458,3022,7220 } }, + { "Panasonic DMC-G2", 15, 0xf3c, + { 10113,-3400,-1114,-4765,12683,2317,-377,1437,6710 } }, + { "Panasonic DMC-G3", 15, 0xfff, + { 6763,-1919,-863,-3868,11515,2684,-1216,2387,5879 } }, + { "Panasonic DMC-G5", 15, 0xfff, + { 7798,-2562,-740,-3879,11584,2613,-1055,2248,5434 } }, + { "Panasonic DMC-G6", 15, 0xfff, + { 8294,-2891,-651,-3869,11590,2595,-1183,2267,5352 } }, + { "Panasonic DMC-G7", 15, 0xfff, + { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, + { "Panasonic DMC-G8", 15, 0xfff, /* G8, G80, G81, G85 */ + { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, + { "Panasonic DC-G9", 15, 0xfff, + { 7685,-2375,-634,-3687,11700,2249,-748,1546,5111 } }, + { "Panasonic DMC-GF1", 15, 0xf92, + { 7888,-1902,-1011,-8106,16085,2099,-2353,2866,7330 } }, + { "Panasonic DMC-GF2", 15, 0xfff, + { 7888,-1902,-1011,-8106,16085,2099,-2353,2866,7330 } }, + { "Panasonic DMC-GF3", 15, 0xfff, + { 9051,-2468,-1204,-5212,13276,2121,-1197,2510,6890 } }, + { "Panasonic DMC-GF5", 15, 0xfff, + { 8228,-2945,-660,-3938,11792,2430,-1094,2278,5793 } }, + { "Panasonic DMC-GF6", 15, 0, + { 8130,-2801,-946,-3520,11289,2552,-1314,2511,5791 } }, + { "Panasonic DMC-GF7", 15, 0, + { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, + { "Panasonic DMC-GF8", 15, 0, + { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, + { "Panasonic DC-GF9", 15, 0, + { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, + { "Panasonic DMC-GH1", 15, 0xf92, + { 6299,-1466,-532,-6535,13852,2969,-2331,3112,5984 } }, + { "Panasonic DMC-GH2", 15, 0xf95, + { 7780,-2410,-806,-3913,11724,2484,-1018,2390,5298 } }, + { "Panasonic DMC-GH3", 15, 0, + { 6559,-1752,-491,-3672,11407,2586,-962,1875,5130 } }, + { "Panasonic DMC-GH4", 15, 0, + { 7122,-2108,-512,-3155,11201,2231,-541,1423,5045 } }, + { "Panasonic DC-GH5S", 15, 0, + { 6929,-2355,-708,-4192,12534,1828,-1097,1989,5195 } }, + { "Panasonic DC-GH5", 15, 0, + { 7641,-2336,-605,-3218,11299,2187,-485,1338,5121 } }, + { "Panasonic DMC-GM1", 15, 0, + { 6770,-1895,-744,-5232,13145,2303,-1664,2691,5703 } }, + { "Panasonic DMC-GM5", 15, 0, + { 8238,-3244,-679,-3921,11814,2384,-836,2022,5852 } }, + { "Panasonic DMC-GX1", 15, 0, + { 6763,-1919,-863,-3868,11515,2684,-1216,2387,5879 } }, + { "Panasonic DMC-GX7", 15, 0, + { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, + { "Panasonic DMC-GX85", 15, 0, + { 7771,-3020,-629,-4029,11950,2345,-821,1977,6119 } }, + { "Panasonic DMC-GX8", 15, 0, + { 7564,-2263,-606,-3148,11239,2177,-540,1435,4853 } }, + { "Panasonic DC-GX9", 15, 0, + { 7564,-2263,-606,-3148,11239,2177,-540,1435,4853 } }, + { "Panasonic DMC-ZS100", 15, 0, + { 7790,-2736,-755,-3452,11870,1769,-628,1647,4898 } }, + { "Panasonic DC-ZS200", 15, 0, + { 7790,-2736,-755,-3452,11870,1769,-628,1647,4898 } }, + { "Panasonic DMC-ZS40", 15, 0, + { 8607,-2822,-808,-3755,11930,2049,-820,2060,5224 } }, + { "Panasonic DMC-ZS50", 15, 0, + { 8802,-3135,-789,-3151,11468,1904,-550,1745,4810 } }, + { "Panasonic DMC-TZ82", 15, 0, + { 8550,-2908,-842,-3195,11529,1881,-338,1603,4631 } }, + { "Panasonic DMC-ZS6", 15, 0, + { 8550,-2908,-842,-3195,11529,1881,-338,1603,4631 } }, + { "Panasonic DMC-ZS70", 15, 0, + { 9052,-3117,-883,-3045,11346,1927,-205,1520,4730 } }, + { "Leica S (Typ 007)", 0, 0, + { 6063,-2234,-231,-5210,13787,1500,-1043,2866,6997 } }, + { "Leica X", 0, 0, /* X and X-U, both (Typ 113) */ + { 7712,-2059,-653,-3882,11494,2726,-710,1332,5958 } }, + { "Leica Q (Typ 116)", 0, 0, + { 11865,-4523,-1441,-5423,14458,935,-1587,2687,4830 } }, + { "Leica M (Typ 262)", 0, 0, + { 6653,-1486,-611,-4221,13303,929,-881,2416,7226 } }, + { "Leica SL (Typ 601)", 0, 0, + { 11865,-4523,-1441,-5423,14458,935,-1587,2687,4830 } }, + { "Leica TL2", 0, 0, + { 5836,-1626,-647,-5384,13326,2261,-1207,2129,5861 } }, + { "Leica TL", 0, 0, + { 5463,-988,-364,-4634,12036,2946,-766,1389,6522 } }, + { "Leica CL", 0, 0, + { 7414,-2393,-840,-5127,13180,2138,-1585,2468,5064 } }, + { "Leica M10", 0, 0, + { 8249,-2849,-620,-5415,14756,565,-957,3074,6517 } }, + { "Phase One H 20", 0, 0, /* DJC */ + { 1313,1855,-109,-6715,15908,808,-327,1840,6020 } }, + { "Phase One H 25", 0, 0, + { 2905,732,-237,-8134,16626,1476,-3038,4253,7517 } }, + { "Phase One P 2", 0, 0, + { 2905,732,-237,-8134,16626,1476,-3038,4253,7517 } }, + { "Phase One P 30", 0, 0, + { 4516,-245,-37,-7020,14976,2173,-3206,4671,7087 } }, + { "Phase One P 45", 0, 0, + { 5053,-24,-117,-5684,14076,1702,-2619,4492,5849 } }, + { "Phase One P40", 0, 0, + { 8035,435,-962,-6001,13872,2320,-1159,3065,5434 } }, + { "Phase One P65", 0, 0, + { 8035,435,-962,-6001,13872,2320,-1159,3065,5434 } }, + { "Photron BC2-HD", 0, 0, /* DJC */ + { 14603,-4122,-528,-1810,9794,2017,-297,2763,5936 } }, + { "Red One", 704, 0xffff, /* DJC */ + { 21014,-7891,-2613,-3056,12201,856,-2203,5125,8042 } }, + { "Ricoh GR II", 0, 0, + { 4630,-834,-423,-4977,12805,2417,-638,1467,6115 } }, + { "Ricoh GR", 0, 0, + { 3708,-543,-160,-5381,12254,3556,-1471,1929,8234 } }, + { "Samsung EX1", 0, 0x3e00, + { 8898,-2498,-994,-3144,11328,2066,-760,1381,4576 } }, + { "Samsung EX2F", 0, 0x7ff, + { 10648,-3897,-1055,-2022,10573,1668,-492,1611,4742 } }, + { "Samsung EK-GN120", 0, 0, + { 7557,-2522,-739,-4679,12949,1894,-840,1777,5311 } }, + { "Samsung NX mini", 0, 0, + { 5222,-1196,-550,-6540,14649,2009,-1666,2819,5657 } }, + { "Samsung NX3300", 0, 0, + { 8060,-2933,-761,-4504,12890,1762,-630,1489,5227 } }, + { "Samsung NX3000", 0, 0, + { 8060,-2933,-761,-4504,12890,1762,-630,1489,5227 } }, + { "Samsung NX30", 0, 0, /* NX30, NX300, NX300M */ + { 7557,-2522,-739,-4679,12949,1894,-840,1777,5311 } }, + { "Samsung NX2000", 0, 0, + { 7557,-2522,-739,-4679,12949,1894,-840,1777,5311 } }, + { "Samsung NX2", 0, 0xfff, /* NX20, NX200, NX210 */ + { 6933,-2268,-753,-4921,13387,1647,-803,1641,6096 } }, + { "Samsung NX1000", 0, 0, + { 6933,-2268,-753,-4921,13387,1647,-803,1641,6096 } }, + { "Samsung NX1100", 0, 0, + { 6933,-2268,-753,-4921,13387,1647,-803,1641,6096 } }, + { "Samsung NX11", 0, 0, + { 10332,-3234,-1168,-6111,14639,1520,-1352,2647,8331 } }, + { "Samsung NX10", 0, 0, /* also NX100 */ + { 10332,-3234,-1168,-6111,14639,1520,-1352,2647,8331 } }, + { "Samsung NX500", 0, 0, + { 10686,-4042,-1052,-3595,13238,276,-464,1259,5931 } }, + { "Samsung NX5", 0, 0, + { 10332,-3234,-1168,-6111,14639,1520,-1352,2647,8331 } }, + { "Samsung NX1", 0, 0, + { 10686,-4042,-1052,-3595,13238,276,-464,1259,5931 } }, + { "Samsung WB2000", 0, 0xfff, + { 12093,-3557,-1155,-1000,9534,1733,-22,1787,4576 } }, + { "Samsung GX-1", 0, 0, + { 10504,-2438,-1189,-8603,16207,2531,-1022,863,12242 } }, + { "Samsung GX20", 0, 0, /* copied from Pentax K20D */ + { 9427,-2714,-868,-7493,16092,1373,-2199,3264,7180 } }, + { "Samsung S85", 0, 0, /* DJC */ + { 11885,-3968,-1473,-4214,12299,1916,-835,1655,5549 } }, + { "Sinar", 0, 0, /* DJC */ + { 16442,-2956,-2422,-2877,12128,750,-1136,6066,4559 } }, + { "Sony DSC-F828", 0, 0, + { 7924,-1910,-777,-8226,15459,2998,-1517,2199,6818,-7242,11401,3481 } }, + { "Sony DSC-R1", 0, 0, + { 8512,-2641,-694,-8042,15670,2526,-1821,2117,7414 } }, + { "Sony DSC-V3", 0, 0, + { 7511,-2571,-692,-7894,15088,3060,-948,1111,8128 } }, + { "Sony DSC-RX100M", 0, 0, /* M2, M3, M4, and M5 */ + { 6596,-2079,-562,-4782,13016,1933,-970,1581,5181 } }, + { "Sony DSC-RX100", 0, 0, + { 8651,-2754,-1057,-3464,12207,1373,-568,1398,4434 } }, + { "Sony DSC-RX10M4", 0, 0, + { 7699,-2566,-629,-2967,11270,1928,-378,1286,4807 } }, + { "Sony DSC-RX10", 0, 0, /* also RX10M2, RX10M3 */ + { 6679,-1825,-745,-5047,13256,1953,-1580,2422,5183 } }, + { "Sony DSC-RX1RM2", 0, 0, + { 6629,-1900,-483,-4618,12349,2550,-622,1381,6514 } }, + { "Sony DSC-RX1", 0, 0, + { 6344,-1612,-462,-4863,12477,2681,-865,1786,6899 } }, + { "Sony DSC-RX0", 200, 0, + { 9396,-3507,-843,-2497,11111,1572,-343,1355,5089 } }, + { "Sony DSLR-A100", 0, 0xfeb, + { 9437,-2811,-774,-8405,16215,2290,-710,596,7181 } }, + { "Sony DSLR-A290", 0, 0, + { 6038,-1484,-579,-9145,16746,2512,-875,746,7218 } }, + { "Sony DSLR-A2", 0, 0, + { 9847,-3091,-928,-8485,16345,2225,-715,595,7103 } }, + { "Sony DSLR-A300", 0, 0, + { 9847,-3091,-928,-8485,16345,2225,-715,595,7103 } }, + { "Sony DSLR-A330", 0, 0, + { 9847,-3091,-929,-8485,16346,2225,-714,595,7103 } }, + { "Sony DSLR-A350", 0, 0xffc, + { 6038,-1484,-578,-9146,16746,2513,-875,746,7217 } }, + { "Sony DSLR-A380", 0, 0, + { 6038,-1484,-579,-9145,16746,2512,-875,746,7218 } }, + { "Sony DSLR-A390", 0, 0, + { 6038,-1484,-579,-9145,16746,2512,-875,746,7218 } }, + { "Sony DSLR-A450", 0, 0xfeb, + { 4950,-580,-103,-5228,12542,3029,-709,1435,7371 } }, + { "Sony DSLR-A580", 0, 0xfeb, + { 5932,-1492,-411,-4813,12285,2856,-741,1524,6739 } }, + { "Sony DSLR-A500", 0, 0xfeb, + { 6046,-1127,-278,-5574,13076,2786,-691,1419,7625 } }, + { "Sony DSLR-A5", 0, 0xfeb, + { 4950,-580,-103,-5228,12542,3029,-709,1435,7371 } }, + { "Sony DSLR-A700", 0, 0, + { 5775,-805,-359,-8574,16295,2391,-1943,2341,7249 } }, + { "Sony DSLR-A850", 0, 0, + { 5413,-1162,-365,-5665,13098,2866,-608,1179,8440 } }, + { "Sony DSLR-A900", 0, 0, + { 5209,-1072,-397,-8845,16120,2919,-1618,1803,8654 } }, + { "Sony ILCA-68", 0, 0, + { 6435,-1903,-536,-4722,12449,2550,-663,1363,6517 } }, + { "Sony ILCA-77M2", 0, 0, + { 5991,-1732,-443,-4100,11989,2381,-704,1467,5992 } }, + { "Sony ILCA-99M2", 0, 0, + { 6660,-1918,-471,-4613,12398,2485,-649,1433,6447 } }, + { "Sony ILCE-6", 0, 0, /* 6300, 6500 */ + { 5973,-1695,-419,-3826,11797,2293,-639,1398,5789 } }, + { "Sony ILCE-7M2", 0, 0, + { 5271,-712,-347,-6153,13653,2763,-1601,2366,7242 } }, + { "Sony ILCE-7M3", 0, 0, + { 7374,-2389,-551,-5435,13162,2519,-1006,1795,6552 } }, + { "Sony ILCE-7S", 0, 0, /* also ILCE-7SM2 */ + { 5838,-1430,-246,-3497,11477,2297,-748,1885,5778 } }, + { "Sony ILCE-7RM3", 0, 0, + { 6640,-1847,-503,-5238,13010,2474,-993,1673,6527 } }, + { "Sony ILCE-7RM2", 0, 0, + { 6629,-1900,-483,-4618,12349,2550,-622,1381,6514 } }, + { "Sony ILCE-7R", 0, 0, + { 4913,-541,-202,-6130,13513,2906,-1564,2151,7183 } }, + { "Sony ILCE-7", 0, 0, + { 5271,-712,-347,-6153,13653,2763,-1601,2366,7242 } }, + { "Sony ILCE-9", 0, 0, + { 6389,-1703,-378,-4562,12265,2587,-670,1489,6550 } }, + { "Sony ILCE", 0, 0, /* 3000, 5000, 5100, 6000, and QX1 */ + { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, + { "Sony NEX-5N", 0, 0, + { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, + { "Sony NEX-5R", 0, 0, + { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, + { "Sony NEX-5T", 0, 0, + { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, + { "Sony NEX-3N", 0, 0, + { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, + { "Sony NEX-3", 138, 0, /* DJC */ + { 6907,-1256,-645,-4940,12621,2320,-1710,2581,6230 } }, + { "Sony NEX-5", 116, 0, /* DJC */ + { 6807,-1350,-342,-4216,11649,2567,-1089,2001,6420 } }, + { "Sony NEX-3", 0, 0, /* Adobe */ + { 6549,-1550,-436,-4880,12435,2753,-854,1868,6976 } }, + { "Sony NEX-5", 0, 0, /* Adobe */ + { 6549,-1550,-436,-4880,12435,2753,-854,1868,6976 } }, + { "Sony NEX-6", 0, 0, + { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, + { "Sony NEX-7", 0, 0, + { 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 } }, + { "Sony NEX", 0, 0, /* NEX-C3, NEX-F3 */ + { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, + { "Sony SLT-A33", 0, 0, + { 6069,-1221,-366,-5221,12779,2734,-1024,2066,6834 } }, + { "Sony SLT-A35", 0, 0, + { 5986,-1618,-415,-4557,11820,3120,-681,1404,6971 } }, + { "Sony SLT-A37", 0, 0, + { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, + { "Sony SLT-A55", 0, 0, + { 5932,-1492,-411,-4813,12285,2856,-741,1524,6739 } }, + { "Sony SLT-A57", 0, 0, + { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, + { "Sony SLT-A58", 0, 0, + { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, + { "Sony SLT-A65", 0, 0, + { 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 } }, + { "Sony SLT-A77", 0, 0, + { 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 } }, + { "Sony SLT-A99", 0, 0, + { 6344,-1612,-462,-4863,12477,2681,-865,1786,6899 } }, + { "YI M1", 0, 0, + { 7712,-2059,-653,-3882,11494,2726,-710,1332,5958 } }, + }; + double cam_xyz[4][3]; + char name[130]; + unsigned i, j; + + sprintf (name, "%s %s", make, model); + for (i=0; i < sizeof table / sizeof *table; i++) + if (!strncmp (name, table[i].prefix, strlen(table[i].prefix))) { + if (table[i].black) black = (ushort) table[i].black; + if (table[i].maximum) maximum = (ushort) table[i].maximum; + if (table[i].trans[0]) { + for (raw_color = j=0; j < 12; j++) + ((double *)cam_xyz)[j] = table[i].trans[j] / 10000.0; + cam_xyz_coeff (rgb_cam, cam_xyz); + } + break; + } +} + +void CLASS simple_coeff (int index) +{ + static const float table[][12] = { + /* index 0 -- Older Foveon cameras including Sigma DP1/DP1S */ + { 1.4032,-0.2231,-0.1016,-0.5263,1.4816,0.017,-0.0112,0.0183,0.9113 }, + /* index 1 -- Kodak DC20 and DC25 */ + { 2.25,0.75,-1.75,-0.25,-0.25,0.75,0.75,-0.25,-0.25,-1.75,0.75,2.25 }, + /* index 2 -- Logitech Fotoman Pixtura */ + { 1.893,-0.418,-0.476,-0.495,1.773,-0.278,-1.017,-0.655,2.672 }, + /* index 3 -- Nikon E880, E900, and E990 */ + { -1.936280, 1.800443, -1.448486, 2.584324, + 1.405365, -0.524955, -0.289090, 0.408680, + -1.204965, 1.082304, 2.941367, -1.818705 }, + /* index 4 -- Sigma TRUE II cameras except Sigma DP1/DP1S */ + { 1.0832,-0.1931,-0.1016,-0.5763,1.0616,0.017,-0.0612,0.0183,0.8613 } + }; + unsigned i, c; + + for (raw_color = i=0; i < 3; i++) + FORCC rgb_cam[i][c] = table[index][i*colors+c]; +} + +short CLASS guess_byte_order (int words) +{ + uchar test[4][2]; + int t=2, msb; + double diff, sum[2] = {0,0}; + + fread (test[0], 2, 2, ifp); + for (words-=2; words--; ) { + fread (test[t], 2, 1, ifp); + for (msb=0; msb < 2; msb++) { + diff = (test[t^2][msb] << 8 | test[t^2][!msb]) + - (test[t ][msb] << 8 | test[t ][!msb]); + sum[msb] += diff*diff; + } + t = (t+1) & 3; + } + return sum[0] < sum[1] ? 0x4d4d : 0x4949; +} + +float CLASS find_green (int bps, int bite, int off0, int off1) +{ + UINT64 bitbuf=0; + int vbits, col, i, c; + ushort *img; + double sum[]={0,0}; + +#define IMG2D(row,col) \ + img[(row)*width+(col)] + + img = (ushort *) malloc(2*width*sizeof(ushort)); + merror (img, "find_green()"); + + FORC(2) { + fseek (ifp, c ? off1:off0, SEEK_SET); + for (vbits=col=0; col < width; col++) { + for (vbits -= bps; vbits < 0; vbits += bite) { + bitbuf <<= bite; + for (i=0; i < bite; i+=8) + bitbuf |= (unsigned) (fgetc(ifp) << i); + } + IMG2D(c,col) = bitbuf << (64-bps-vbits) >> (64-bps); + } + } + FORC(width-1) { + sum[ c & 1] += ABS(IMG2D(0,c)-IMG2D(1,c+1)); + sum[~c & 1] += ABS(IMG2D(1,c)-IMG2D(0,c+1)); + } + free(img); + return 100 * log(sum[0]/sum[1]); +} + +/* + Identify which camera created this file, and set global variables + accordingly. + */ +void CLASS identify() +{ + static const short pana[][6] = { + { 3130, 1743, 4, 0, -6, 0 }, + { 3130, 2055, 4, 0, -6, 0 }, + { 3130, 2319, 4, 0, -6, 0 }, + { 3170, 2103, 18, 0,-42, 20 }, + { 3170, 2367, 18, 13,-42,-21 }, + { 3177, 2367, 0, 0, -1, 0 }, + { 3304, 2458, 0, 0, -1, 0 }, + { 3330, 2463, 9, 0, -5, 0 }, + { 3330, 2479, 9, 0,-17, 4 }, + { 3370, 1899, 15, 0,-44, 20 }, + { 3370, 2235, 15, 0,-44, 20 }, + { 3370, 2511, 15, 10,-44,-21 }, + { 3690, 2751, 3, 0, -8, -3 }, + { 3710, 2751, 0, 0, -3, 0 }, + { 3724, 2450, 0, 0, 0, -2 }, + { 3770, 2487, 17, 0,-44, 19 }, + { 3770, 2799, 17, 15,-44,-19 }, + { 3880, 2170, 6, 0, -6, 0 }, + { 4060, 3018, 0, 0, 0, -2 }, + { 4290, 2391, 3, 0, -8, -1 }, + { 4330, 2439, 17, 15,-44,-19 }, + { 4508, 2962, 0, 0, -3, -4 }, + { 4508, 3330, 0, 0, -3, -6 }, + }; + static const ushort canon[][11] = { + { 1944, 1416, 0, 0, 48, 0 }, + { 2144, 1560, 4, 8, 52, 2, 0, 0, 0, 25 }, + { 2224, 1456, 48, 6, 0, 2 }, + { 2376, 1728, 12, 6, 52, 2 }, + { 2672, 1968, 12, 6, 44, 2 }, + { 3152, 2068, 64, 12, 0, 0, 16 }, + { 3160, 2344, 44, 12, 4, 4 }, + { 3344, 2484, 4, 6, 52, 6 }, + { 3516, 2328, 42, 14, 0, 0 }, + { 3596, 2360, 74, 12, 0, 0 }, + { 3744, 2784, 52, 12, 8, 12 }, + { 3944, 2622, 30, 18, 6, 2 }, + { 3948, 2622, 42, 18, 0, 2 }, + { 3984, 2622, 76, 20, 0, 2, 14 }, + { 4104, 3048, 48, 12, 24, 12 }, + { 4116, 2178, 4, 2, 0, 0 }, + { 4152, 2772, 192, 12, 0, 0 }, + { 4160, 3124, 104, 11, 8, 65 }, + { 4176, 3062, 96, 17, 8, 0, 0, 16, 0, 7, 0x49 }, + { 4192, 3062, 96, 17, 24, 0, 0, 16, 0, 0, 0x49 }, + { 4312, 2876, 22, 18, 0, 2 }, + { 4352, 2874, 62, 18, 0, 0 }, + { 4476, 2954, 90, 34, 0, 0 }, + { 4480, 3348, 12, 10, 36, 12, 0, 0, 0, 18, 0x49 }, + { 4480, 3366, 80, 50, 0, 0 }, + { 4496, 3366, 80, 50, 12, 0 }, + { 4768, 3516, 96, 16, 0, 0, 0, 16 }, + { 4832, 3204, 62, 26, 0, 0 }, + { 4832, 3228, 62, 51, 0, 0 }, + { 5108, 3349, 98, 13, 0, 0 }, + { 5120, 3318, 142, 45, 62, 0 }, + { 5280, 3528, 72, 52, 0, 0 }, + { 5344, 3516, 142, 51, 0, 0 }, + { 5344, 3584, 126,100, 0, 2 }, + { 5360, 3516, 158, 51, 0, 0 }, + { 5568, 3708, 72, 38, 0, 0 }, + { 5632, 3710, 96, 17, 0, 0, 0, 16, 0, 0, 0x49 }, + { 5712, 3774, 62, 20, 10, 2 }, + { 5792, 3804, 158, 51, 0, 0 }, + { 5920, 3950, 122, 80, 2, 0 }, + { 6096, 4051, 76, 35, 0, 0 }, + { 6096, 4056, 72, 34, 0, 0 }, + { 6288, 4056, 264, 36, 0, 0 }, + { 6384, 4224, 120, 44, 0, 0 }, + { 6880, 4544, 136, 42, 0, 0 }, + { 8896, 5920, 160, 64, 0, 0 }, + }; + static const struct { + ushort id; + char model[20]; + } unique[] = { + { 0x168, "EOS 10D" }, { 0x001, "EOS-1D" }, + { 0x175, "EOS 20D" }, { 0x174, "EOS-1D Mark II" }, + { 0x234, "EOS 30D" }, { 0x232, "EOS-1D Mark II N" }, + { 0x190, "EOS 40D" }, { 0x169, "EOS-1D Mark III" }, + { 0x261, "EOS 50D" }, { 0x281, "EOS-1D Mark IV" }, + { 0x287, "EOS 60D" }, { 0x167, "EOS-1DS" }, + { 0x325, "EOS 70D" }, + { 0x408, "EOS 77D" }, { 0x331, "EOS M" }, + { 0x350, "EOS 80D" }, { 0x328, "EOS-1D X Mark II" }, + { 0x346, "EOS 100D" }, + { 0x417, "EOS 200D" }, + { 0x170, "EOS 300D" }, { 0x188, "EOS-1Ds Mark II" }, + { 0x176, "EOS 450D" }, { 0x215, "EOS-1Ds Mark III" }, + { 0x189, "EOS 350D" }, { 0x324, "EOS-1D C" }, + { 0x236, "EOS 400D" }, { 0x269, "EOS-1D X" }, + { 0x252, "EOS 500D" }, { 0x213, "EOS 5D" }, + { 0x270, "EOS 550D" }, { 0x218, "EOS 5D Mark II" }, + { 0x286, "EOS 600D" }, { 0x285, "EOS 5D Mark III" }, + { 0x301, "EOS 650D" }, { 0x302, "EOS 6D" }, + { 0x326, "EOS 700D" }, { 0x250, "EOS 7D" }, + { 0x393, "EOS 750D" }, { 0x289, "EOS 7D Mark II" }, + { 0x347, "EOS 760D" }, { 0x406, "EOS 6D Mark II" }, + { 0x405, "EOS 800D" }, { 0x349, "EOS 5D Mark IV" }, + { 0x254, "EOS 1000D" }, + { 0x288, "EOS 1100D" }, + { 0x327, "EOS 1200D" }, { 0x382, "EOS 5DS" }, + { 0x404, "EOS 1300D" }, { 0x401, "EOS 5DS R" }, + { 0x422, "EOS 1500D" }, + { 0x432, "EOS 3000D" }, + }, sonique[] = { + { 0x002, "DSC-R1" }, { 0x100, "DSLR-A100" }, + { 0x101, "DSLR-A900" }, { 0x102, "DSLR-A700" }, + { 0x103, "DSLR-A200" }, { 0x104, "DSLR-A350" }, + { 0x105, "DSLR-A300" }, { 0x108, "DSLR-A330" }, + { 0x109, "DSLR-A230" }, { 0x10a, "DSLR-A290" }, + { 0x10d, "DSLR-A850" }, { 0x111, "DSLR-A550" }, + { 0x112, "DSLR-A500" }, { 0x113, "DSLR-A450" }, + { 0x116, "NEX-5" }, { 0x117, "NEX-3" }, + { 0x118, "SLT-A33" }, { 0x119, "SLT-A55V" }, + { 0x11a, "DSLR-A560" }, { 0x11b, "DSLR-A580" }, + { 0x11c, "NEX-C3" }, { 0x11d, "SLT-A35" }, + { 0x11e, "SLT-A65V" }, { 0x11f, "SLT-A77V" }, + { 0x120, "NEX-5N" }, { 0x121, "NEX-7" }, + { 0x123, "SLT-A37" }, { 0x124, "SLT-A57" }, + { 0x125, "NEX-F3" }, { 0x126, "SLT-A99V" }, + { 0x127, "NEX-6" }, { 0x128, "NEX-5R" }, + { 0x129, "DSC-RX100" }, { 0x12a, "DSC-RX1" }, + { 0x12e, "ILCE-3000" }, { 0x12f, "SLT-A58" }, + { 0x131, "NEX-3N" }, { 0x132, "ILCE-7" }, + { 0x133, "NEX-5T" }, { 0x134, "DSC-RX100M2" }, + { 0x135, "DSC-RX10" }, { 0x136, "DSC-RX1R" }, + { 0x137, "ILCE-7R" }, { 0x138, "ILCE-6000" }, + { 0x139, "ILCE-5000" }, { 0x13d, "DSC-RX100M3" }, + { 0x13e, "ILCE-7S" }, { 0x13f, "ILCA-77M2" }, + { 0x153, "ILCE-5100" }, { 0x154, "ILCE-7M2" }, + { 0x155, "DSC-RX100M4" },{ 0x156, "DSC-RX10M2" }, + { 0x158, "DSC-RX1RM2" }, { 0x15a, "ILCE-QX1" }, + { 0x15b, "ILCE-7RM2" }, { 0x15e, "ILCE-7SM2" }, + { 0x161, "ILCA-68" }, { 0x162, "ILCA-99M2" }, + { 0x163, "DSC-RX10M3" }, { 0x164, "DSC-RX100M5" }, + { 0x165, "ILCE-6300" }, { 0x166, "ILCE-9" }, + { 0x168, "ILCE-6500" }, { 0x16a, "ILCE-7RM3" }, + { 0x16b, "ILCE-7M3" }, { 0x16c, "DSC-RX0" }, + { 0x16d, "DSC-RX10M4" }, + }; + static const char *orig, panalias[][12] = { + "@DC-FZ80", "DC-FZ82", "DC-FZ85", + "@DC-FZ81", "DC-FZ83", + "@DC-GF9", "DC-GX800", "DC-GX850", + "@DC-GF10", "DC-GF90", + "@DC-GX9", "DC-GX7MK3", + "@DC-ZS70", "DC-TZ90", "DC-TZ91", "DC-TZ92", "DC-TZ93", + "@DMC-FZ40", "DMC-FZ45", + "@DMC-FZ2500", "DMC-FZ2000", "DMC-FZH1", + "@DMC-G8", "DMC-G80", "DMC-G81", "DMC-G85", + "@DMC-GX85", "DMC-GX80", "DMC-GX7MK2", + "@DMC-LX9", "DMC-LX10", "DMC-LX15", + "@DMC-ZS40", "DMC-TZ60", "DMC-TZ61", + "@DMC-ZS50", "DMC-TZ70", "DMC-TZ71", + "@DMC-ZS60", "DMC-TZ80", "DMC-TZ81", "DMC-TZ85", + "@DMC-ZS100", "DMC-ZS110", "DMC-TZ100", "DMC-TZ101", "DMC-TZ110", "DMC-TX1", + "@DC-ZS200", "DC-TX2", "DC-TZ200", "DC-TZ202", "DC-TZ220", "DC-ZS220", + }; + static const struct { + unsigned fsize; + ushort rw, rh; + uchar lm, tm, rm, bm, lf, cf, max, flags; + char make[10], model[20]; + ushort offset; + } table[] = { + { 786432,1024, 768, 0, 0, 0, 0, 0,0x94,0,0,"AVT","F-080C",0 }, + { 1447680,1392,1040, 0, 0, 0, 0, 0,0x94,0,0,"AVT","F-145C",0 }, + { 1920000,1600,1200, 0, 0, 0, 0, 0,0x94,0,0,"AVT","F-201C",0 }, + { 5067304,2588,1958, 0, 0, 0, 0, 0,0x94,0,0,"AVT","F-510C",0 }, + { 5067316,2588,1958, 0, 0, 0, 0, 0,0x94,0,0,"AVT","F-510C",12 }, + { 10134608,2588,1958, 0, 0, 0, 0, 9,0x94,0,0,"AVT","F-510C",0 }, + { 10134620,2588,1958, 0, 0, 0, 0, 9,0x94,0,0,"AVT","F-510C",12 }, + { 16157136,3272,2469, 0, 0, 0, 0, 9,0x94,0,0,"AVT","F-810C",0 }, + { 15980544,3264,2448, 0, 0, 0, 0, 8,0x61,0,1,"AgfaPhoto","DC-833m",0 }, + { 9631728,2532,1902, 0, 0, 0, 0,96,0x61,0,0,"Alcatel","5035D",0 }, + { 2868726,1384,1036, 0, 0, 0, 0,64,0x49,0,8,"Baumer","TXG14",1078 }, + { 5298000,2400,1766,12,12,44, 2, 8,0x94,0,2,"Canon","PowerShot SD300",0 }, + { 6553440,2664,1968, 4, 4,44, 4, 8,0x94,0,2,"Canon","PowerShot A460",0 }, + { 6573120,2672,1968,12, 8,44, 0, 8,0x94,0,2,"Canon","PowerShot A610",0 }, + { 6653280,2672,1992,10, 6,42, 2, 8,0x94,0,2,"Canon","PowerShot A530",0 }, + { 7710960,2888,2136,44, 8, 4, 0, 8,0x94,0,2,"Canon","PowerShot S3 IS",0 }, + { 9219600,3152,2340,36,12, 4, 0, 8,0x94,0,2,"Canon","PowerShot A620",0 }, + { 9243240,3152,2346,12, 7,44,13, 8,0x49,0,2,"Canon","PowerShot A470",0 }, + { 10341600,3336,2480, 6, 5,32, 3, 8,0x94,0,2,"Canon","PowerShot A720 IS",0 }, + { 10383120,3344,2484,12, 6,44, 6, 8,0x94,0,2,"Canon","PowerShot A630",0 }, + { 12945240,3736,2772,12, 6,52, 6, 8,0x94,0,2,"Canon","PowerShot A640",0 }, + { 15636240,4104,3048,48,12,24,12, 8,0x94,0,2,"Canon","PowerShot A650",0 }, + { 15467760,3720,2772, 6,12,30, 0, 8,0x94,0,2,"Canon","PowerShot SX110 IS",0 }, + { 15534576,3728,2778,12, 9,44, 9, 8,0x94,0,2,"Canon","PowerShot SX120 IS",0 }, + { 18653760,4080,3048,24,12,24,12, 8,0x94,0,2,"Canon","PowerShot SX20 IS",0 }, + { 19131120,4168,3060,92,16, 4, 1, 8,0x94,0,2,"Canon","PowerShot SX220 HS",0 }, + { 21936096,4464,3276,25,10,73,12, 8,0x16,0,2,"Canon","PowerShot SX30 IS",0 }, + { 24724224,4704,3504, 8,16,56, 8, 8,0x94,0,2,"Canon","PowerShot A3300 IS",0 }, + { 30858240,5248,3920, 8,16,56,16, 8,0x94,0,2,"Canon","IXUS 160",0 }, + { 1976352,1632,1211, 0, 2, 0, 1, 0,0x94,0,1,"Casio","QV-2000UX",0 }, + { 3217760,2080,1547, 0, 0,10, 1, 0,0x94,0,1,"Casio","QV-3*00EX",0 }, + { 6218368,2585,1924, 0, 0, 9, 0, 0,0x94,0,1,"Casio","QV-5700",0 }, + { 7816704,2867,2181, 0, 0,34,36, 0,0x16,0,1,"Casio","EX-Z60",0 }, + { 2937856,1621,1208, 0, 0, 1, 0, 0,0x94,7,13,"Casio","EX-S20",0 }, + { 4948608,2090,1578, 0, 0,32,34, 0,0x94,7,1,"Casio","EX-S100",0 }, + { 6054400,2346,1720, 2, 0,32, 0, 0,0x94,7,1,"Casio","QV-R41",0 }, + { 7426656,2568,1928, 0, 0, 0, 0, 0,0x94,0,1,"Casio","EX-P505",0 }, + { 7530816,2602,1929, 0, 0,22, 0, 0,0x94,7,1,"Casio","QV-R51",0 }, + { 7542528,2602,1932, 0, 0,32, 0, 0,0x94,7,1,"Casio","EX-Z50",0 }, + { 7562048,2602,1937, 0, 0,25, 0, 0,0x16,7,1,"Casio","EX-Z500",0 }, + { 7753344,2602,1986, 0, 0,32,26, 0,0x94,7,1,"Casio","EX-Z55",0 }, + { 9313536,2858,2172, 0, 0,14,30, 0,0x94,7,1,"Casio","EX-P600",0 }, + { 10834368,3114,2319, 0, 0,27, 0, 0,0x94,0,1,"Casio","EX-Z750",0 }, + { 10843712,3114,2321, 0, 0,25, 0, 0,0x94,0,1,"Casio","EX-Z75",0 }, + { 10979200,3114,2350, 0, 0,32,32, 0,0x94,7,1,"Casio","EX-P700",0 }, + { 12310144,3285,2498, 0, 0, 6,30, 0,0x94,0,1,"Casio","EX-Z850",0 }, + { 12489984,3328,2502, 0, 0,47,35, 0,0x94,0,1,"Casio","EX-Z8",0 }, + { 15499264,3754,2752, 0, 0,82, 0, 0,0x94,0,1,"Casio","EX-Z1050",0 }, + { 18702336,4096,3044, 0, 0,24, 0,80,0x94,7,1,"Casio","EX-ZR100",0 }, + { 7684000,2260,1700, 0, 0, 0, 0,13,0x94,0,1,"Casio","QV-4000",0 }, + { 787456,1024, 769, 0, 1, 0, 0, 0,0x49,0,0,"Creative","PC-CAM 600",0 }, + { 28829184,4384,3288, 0, 0, 0, 0,36,0x61,0,0,"DJI","",0 }, + { 15151104,4608,3288, 0, 0, 0, 0, 0,0x94,0,0,"Matrix","",0 }, + { 3840000,1600,1200, 0, 0, 0, 0,65,0x49,0,0,"Foculus","531C",0 }, + { 307200, 640, 480, 0, 0, 0, 0, 0,0x94,0,0,"Generic","",0 }, + { 62464, 256, 244, 1, 1, 6, 1, 0,0x8d,0,0,"Kodak","DC20",0 }, + { 124928, 512, 244, 1, 1,10, 1, 0,0x8d,0,0,"Kodak","DC20",0 }, + { 1652736,1536,1076, 0,52, 0, 0, 0,0x61,0,0,"Kodak","DCS200",0 }, + { 4159302,2338,1779, 1,33, 1, 2, 0,0x94,0,0,"Kodak","C330",0 }, + { 4162462,2338,1779, 1,33, 1, 2, 0,0x94,0,0,"Kodak","C330",3160 }, + { 2247168,1232, 912, 0, 0,16, 0, 0,0x00,0,0,"Kodak","C330",0 }, + { 3370752,1232, 912, 0, 0,16, 0, 0,0x00,0,0,"Kodak","C330",0 }, + { 6163328,2864,2152, 0, 0, 0, 0, 0,0x94,0,0,"Kodak","C603",0 }, + { 6166488,2864,2152, 0, 0, 0, 0, 0,0x94,0,0,"Kodak","C603",3160 }, + { 460800, 640, 480, 0, 0, 0, 0, 0,0x00,0,0,"Kodak","C603",0 }, + { 9116448,2848,2134, 0, 0, 0, 0, 0,0x00,0,0,"Kodak","C603",0 }, + { 12241200,4040,3030, 2, 0, 0,13, 0,0x49,0,0,"Kodak","12MP",0 }, + { 12272756,4040,3030, 2, 0, 0,13, 0,0x49,0,0,"Kodak","12MP",31556 }, + { 18000000,4000,3000, 0, 0, 0, 0, 0,0x00,0,0,"Kodak","12MP",0 }, + { 614400, 640, 480, 0, 3, 0, 0,64,0x94,0,0,"Kodak","KAI-0340",0 }, + { 15360000,3200,2400, 0, 0, 0, 0,96,0x16,0,0,"Lenovo","A820",0 }, + { 3884928,1608,1207, 0, 0, 0, 0,96,0x16,0,0,"Micron","2010",3212 }, + { 1138688,1534, 986, 0, 0, 0, 0, 0,0x61,0,0,"Minolta","RD175",513 }, + { 1581060,1305, 969, 0, 0,18, 6, 6,0x1e,4,1,"Nikon","E900",0 }, + { 2465792,1638,1204, 0, 0,22, 1, 6,0x4b,5,1,"Nikon","E950",0 }, + { 2940928,1616,1213, 0, 0, 0, 7,30,0x94,0,1,"Nikon","E2100",0 }, + { 4771840,2064,1541, 0, 0, 0, 1, 6,0xe1,0,1,"Nikon","E990",0 }, + { 4775936,2064,1542, 0, 0, 0, 0,30,0x94,0,1,"Nikon","E3700",0 }, + { 5865472,2288,1709, 0, 0, 0, 1, 6,0xb4,0,1,"Nikon","E4500",0 }, + { 5869568,2288,1710, 0, 0, 0, 0, 6,0x16,0,1,"Nikon","E4300",0 }, + { 7438336,2576,1925, 0, 0, 0, 1, 6,0xb4,0,1,"Nikon","E5000",0 }, + { 8998912,2832,2118, 0, 0, 0, 0,30,0x94,7,1,"Nikon","COOLPIX S6",0 }, + { 5939200,2304,1718, 0, 0, 0, 0,30,0x16,0,0,"Olympus","C770UZ",0 }, + { 3178560,2064,1540, 0, 0, 0, 0, 0,0x94,0,1,"Pentax","Optio S",0 }, + { 4841984,2090,1544, 0, 0,22, 0, 0,0x94,7,1,"Pentax","Optio S",0 }, + { 6114240,2346,1737, 0, 0,22, 0, 0,0x94,7,1,"Pentax","Optio S4",0 }, + { 10702848,3072,2322, 0, 0, 0,21,30,0x94,0,1,"Pentax","Optio 750Z",0 }, + { 4147200,1920,1080, 0, 0, 0, 0, 0,0x49,0,0,"Photron","BC2-HD",0 }, + { 4151666,1920,1080, 0, 0, 0, 0, 0,0x49,0,0,"Photron","BC2-HD",8 }, + { 13248000,2208,3000, 0, 0, 0, 0,13,0x61,0,0,"Pixelink","A782",0 }, + { 6291456,2048,1536, 0, 0, 0, 0,96,0x61,0,0,"RoverShot","3320AF",0 }, + { 311696, 644, 484, 0, 0, 0, 0, 0,0x16,0,8,"ST Micro","STV680 VGA",0 }, + { 16098048,3288,2448, 0, 0,24, 0, 9,0x94,0,1,"Samsung","S85",0 }, + { 16215552,3312,2448, 0, 0,48, 0, 9,0x94,0,1,"Samsung","S85",0 }, + { 20487168,3648,2808, 0, 0, 0, 0,13,0x94,5,1,"Samsung","WB550",0 }, + { 24000000,4000,3000, 0, 0, 0, 0,13,0x94,5,1,"Samsung","WB550",0 }, + { 12582980,3072,2048, 0, 0, 0, 0,33,0x61,0,0,"Sinar","",68 }, + { 33292868,4080,4080, 0, 0, 0, 0,33,0x61,0,0,"Sinar","",68 }, + { 44390468,4080,5440, 0, 0, 0, 0,33,0x61,0,0,"Sinar","",68 }, + { 1409024,1376,1024, 0, 0, 1, 0, 0,0x49,0,0,"Sony","XCD-SX910CR",0 }, + { 2818048,1376,1024, 0, 0, 1, 0,97,0x49,0,0,"Sony","XCD-SX910CR",0 }, + { 17496000,4320,3240, 0, 0, 0,0,224,0x94,0,0,"Xiro","Xplorer V",0 }, + }; + static const char *corp[] = + { "AgfaPhoto", "Canon", "Casio", "Epson", "Fujifilm", + "Mamiya", "Minolta", "Motorola", "Kodak", "Konica", "Leica", + "Nikon", "Nokia", "Olympus", "Ricoh", "Pentax", "Phase One", + "Samsung", "Sigma", "Sinar", "Sony", "YI" }; + char head[32], *cp; + unsigned fsize; + int hlen, flen, zero_fsize=1, i, c; + struct jhead jh; + + tiff_flip = flip = filters = UINT_MAX; /* unknown */ + raw_height = raw_width = fuji_width = fuji_layout = cr2_slice[0] = 0; + maximum = height = width = top_margin = left_margin = 0; + cdesc[0] = desc[0] = artist[0] = make[0] = model[0] = model2[0] = 0; + iso_speed = shutter = aperture = focal_len = unique_id = 0; + tiff_nifds = 0; + memset (tiff_ifd, 0, sizeof tiff_ifd); + memset (gpsdata, 0, sizeof gpsdata); + memset (cblack, 0, sizeof cblack); + memset (white, 0, sizeof white); + memset (mask, 0, sizeof mask); + thumb_offset = thumb_length = thumb_width = thumb_height = 0; + load_raw = thumb_load_raw = 0; + write_thumb = &CLASS jpeg_thumb; + data_offset = meta_offset = meta_length = tiff_bps = tiff_compress = 0; + kodak_cbpp = zero_after_ff = dng_version = load_flags = 0; + timestamp = shot_order = tiff_samples = black = is_foveon = 0; + mix_green = profile_length = data_error = zero_is_bad = 0; + pixel_aspect = is_raw = raw_color = 1; + tile_width = tile_length = 0; + for (i=0; i < 4; i++) { + cam_mul[i] = i == 1; + pre_mul[i] = i < 3; + FORC3 cmatrix[c][i] = 0; + FORC3 rgb_cam[c][i] = c == i; + } + colors = 3; + for (i=0; i < 0x10000; i++) curve[i] = i; + + order = get2(); + hlen = get4(); + fseek (ifp, 0, SEEK_SET); + fread (head, 1, 32, ifp); + fseek (ifp, 0, SEEK_END); + flen = fsize = ftell(ifp); + if ((cp = (char *) memmem (head, 32, "MMMM", 4)) || + (cp = (char *) memmem (head, 32, "IIII", 4))) { + parse_phase_one (cp-head); + if (cp-head && parse_tiff(0)) apply_tiff(); + } else if (order == 0x4949 || order == 0x4d4d) { + if (!memcmp (head+6,"HEAPCCDR",8)) { + data_offset = hlen; + parse_ciff (hlen, flen-hlen, 0); + load_raw = &CLASS canon_load_raw; + } else if (parse_tiff(0)) apply_tiff(); + } else if (!memcmp (head,"\xff\xd8\xff\xe1",4) && + !memcmp (head+6,"Exif",4)) { + fseek (ifp, 4, SEEK_SET); + data_offset = 4 + get2(); + fseek (ifp, data_offset, SEEK_SET); + if (fgetc(ifp) != 0xff) + parse_tiff(12); + thumb_offset = 0; + } else if (!memcmp (head+25,"ARECOYK",7)) { + strcpy (make, "Contax"); + strcpy (model,"N Digital"); + fseek (ifp, 33, SEEK_SET); + get_timestamp(1); + fseek (ifp, 60, SEEK_SET); + FORC4 cam_mul[c ^ (c >> 1)] = get4(); + } else if (!strcmp (head, "PXN")) { + strcpy (make, "Logitech"); + strcpy (model,"Fotoman Pixtura"); + } else if (!strcmp (head, "qktk")) { + strcpy (make, "Apple"); + strcpy (model,"QuickTake 100"); + load_raw = &CLASS quicktake_100_load_raw; + } else if (!strcmp (head, "qktn")) { + strcpy (make, "Apple"); + strcpy (model,"QuickTake 150"); + load_raw = &CLASS kodak_radc_load_raw; + } else if (!memcmp (head,"FUJIFILM",8)) { + fseek (ifp, 84, SEEK_SET); + thumb_offset = get4(); + thumb_length = get4(); + fseek (ifp, 92, SEEK_SET); + parse_fuji (get4()); + if (thumb_offset > 120) { + fseek (ifp, 120, SEEK_SET); + is_raw += (i = get4()) && 1; + if (is_raw == 2 && shot_select) + parse_fuji (i); + } + fseek (ifp, 100+28*(shot_select > 0), SEEK_SET); + parse_tiff (data_offset = get4()); + parse_tiff (thumb_offset+12); + apply_tiff(); + if (!load_raw) { + load_raw = &CLASS unpacked_load_raw; + tiff_bps = 14; + } + } else if (!memcmp (head,"RIFF",4)) { + fseek (ifp, 0, SEEK_SET); + parse_riff(); + } else if (!memcmp (head+4,"ftypcrx ",8)) { + fseek (ifp, 0, SEEK_SET); + parse_crx (fsize); + } else if (!memcmp (head+4,"ftypqt ",9)) { + fseek (ifp, 0, SEEK_SET); + parse_qt (fsize); + is_raw = 0; + } else if (!memcmp (head,"\0\001\0\001\0@",6)) { + fseek (ifp, 6, SEEK_SET); + fread (make, 1, 8, ifp); + fread (model, 1, 8, ifp); + fread (model2, 1, 16, ifp); + data_offset = get2(); + get2(); + raw_width = get2(); + raw_height = get2(); + load_raw = &CLASS nokia_load_raw; + filters = 0x61616161; + } else if (!memcmp (head,"NOKIARAW",8)) { + strcpy (make, "NOKIA"); + order = 0x4949; + fseek (ifp, 300, SEEK_SET); + data_offset = get4(); + i = get4(); + width = get2(); + height = get2(); + switch (tiff_bps = i*8 / (width * height)) { + case 8: load_raw = &CLASS eight_bit_load_raw; break; + case 10: load_raw = &CLASS nokia_load_raw; + } + raw_height = height + (top_margin = i / (width * tiff_bps/8) - height); + mask[0][3] = 1; + filters = 0x61616161; + } else if (!memcmp (head,"ARRI",4)) { + order = 0x4949; + fseek (ifp, 20, SEEK_SET); + width = get4(); + height = get4(); + strcpy (make, "ARRI"); + fseek (ifp, 668, SEEK_SET); + fread (model, 1, 64, ifp); + data_offset = 4096; + load_raw = &CLASS packed_load_raw; + load_flags = 88; + filters = 0x61616161; + } else if (!memcmp (head,"XPDS",4)) { + order = 0x4949; + fseek (ifp, 0x800, SEEK_SET); + fread (make, 1, 41, ifp); + raw_height = get2(); + raw_width = get2(); + fseek (ifp, 56, SEEK_CUR); + fread (model, 1, 30, ifp); + data_offset = 0x10000; + load_raw = &CLASS canon_rmf_load_raw; + gamma_curve (0, 12.25, 1, 1023); + } else if (!memcmp (head+4,"RED1",4)) { + strcpy (make, "Red"); + strcpy (model,"One"); + parse_redcine(); + load_raw = &CLASS redcine_load_raw; + gamma_curve (1/2.4, 12.92, 1, 4095); + filters = 0x49494949; + } else if (!memcmp (head,"DSC-Image",9)) + parse_rollei(); + else if (!memcmp (head,"PWAD",4)) + parse_sinar_ia(); + else if (!memcmp (head,"\0MRM",4)) + parse_minolta(0); + else if (!memcmp (head,"FOVb",4)) + parse_foveon(); + else if (!memcmp (head,"CI",2)) + parse_cine(); + if (make[0] == 0) + for (zero_fsize=i=0; i < sizeof table / sizeof *table; i++) + if (fsize == table[i].fsize) { + strcpy (make, table[i].make ); + strcpy (model, table[i].model); + flip = table[i].flags >> 2; + zero_is_bad = table[i].flags & 2; + if (table[i].flags & 1) + parse_external_jpeg(); + data_offset = table[i].offset; + raw_width = table[i].rw; + raw_height = table[i].rh; + left_margin = table[i].lm; + top_margin = table[i].tm; + width = raw_width - left_margin - table[i].rm; + height = raw_height - top_margin - table[i].bm; + filters = 0x1010101 * table[i].cf; + colors = 4 - !((filters & filters >> 1) & 0x5555); + load_flags = table[i].lf; + switch (tiff_bps = (fsize-data_offset)*8 / (raw_width*raw_height)) { + case 6: + load_raw = &CLASS minolta_rd175_load_raw; break; + case 8: + load_raw = &CLASS eight_bit_load_raw; break; + case 10: case 12: + load_flags |= 512; + if (!strcmp(make,"Canon")) load_flags |= 256; + load_raw = &CLASS packed_load_raw; break; + case 16: + order = 0x4949 | 0x404 * (load_flags & 1); + tiff_bps -= load_flags >> 4; + tiff_bps -= load_flags = load_flags >> 1 & 7; + load_raw = &CLASS unpacked_load_raw; + } + maximum = (1 << tiff_bps) - (1 << table[i].max); + } + if (zero_fsize) fsize = 0; + if (make[0] == 0) parse_smal (0, flen); + if (make[0] == 0) { + parse_jpeg(0); + if (!(strncmp(model,"ov",2) && strncmp(model,"RP_OV",5)) && + !fseek (ifp, -6404096, SEEK_END) && + fread (head, 1, 32, ifp) && !strcmp(head,"BRCMn")) { + strcpy (make, "OmniVision"); + data_offset = ftell(ifp) + 0x8000-32; + width = raw_width; + raw_width = 2611; + load_raw = &CLASS nokia_load_raw; + filters = 0x16161616; + } else is_raw = 0; + } + + for (i=0; i < sizeof corp / sizeof *corp; i++) + if (strcasestr (make, corp[i])) /* Simplify company names */ + strcpy (make, corp[i]); + if ((!strcmp(make,"Kodak") || !strcmp(make,"Leica")) && + ((cp = strcasestr(model," DIGITAL CAMERA")) || + (cp = strstr(model,"FILE VERSION")))) + *cp = 0; + if (!strcmp(make,"Pentax") && !strncmp(model,"GR",2)) + strcpy (make, "Ricoh"); /* Ricoh GR not Pentax GR */ + if (!strncasecmp(model,"PENTAX",6)) + strcpy (make, "Pentax"); + cp = make + strlen(make); /* Remove trailing spaces */ + while (cp > make && *--cp == ' ') *cp = 0; + cp = model + strlen(model); + while (cp > model && *--cp == ' ') *cp = 0; + i = strlen(make); /* Remove make from model */ + if (!strncasecmp (model, make, i) && model[i++] == ' ') + memmove (model, model+i, 64-i); + if (!strncmp (model,"FinePix ",8)) + strcpy (model, model+8); + if (!strncmp (model,"Digital Camera ",15)) + strcpy (model, model+15); + desc[511] = artist[63] = make[63] = model[63] = model2[63] = 0; + if (!is_raw) goto notraw; + + if (!height) height = raw_height; + if (!width) width = raw_width; + if (height == 2624 && width == 3936) /* Pentax K10D and Samsung GX10 */ + { height = 2616; width = 3896; } + if (height == 3136 && width == 4864) /* Pentax K20D and Samsung GX20 */ + { height = 3124; width = 4688; filters = 0x16161616; } + if (raw_height == 2868 && (!strcmp(model,"K-r") || !strcmp(model,"K-x"))) + { width = 4309; filters = 0x16161616; } + if (raw_height == 3136 && !strcmp(model,"K-7")) + { height = 3122; width = 4684; filters = 0x16161616; top_margin = 2; } + if (raw_height == 3284 && !strncmp(model,"K-5",3)) + { left_margin = 10; width = 4950; filters = 0x16161616; } + if (raw_height == 3300 && !strncmp(model,"K-50",4)) + { height = 3288, width = 4952; left_margin = 0; top_margin = 12; } + if (raw_height == 3664 && !strncmp(model,"K-S",3)) + { width = 5492; left_margin = 0; } + if (raw_height == 4032 && !strcmp(model,"K-3")) + { height = 4032; width = 6040; left_margin = 4; } + if (raw_height == 4060 && !strcmp(model,"KP")) + { height = 4032; width = 6032; left_margin = 52; top_margin = 28; } + if (raw_height == 4950 && !strcmp(model,"K-1")) + { height = 4932; width = 7380; left_margin = 4; top_margin = 18; } + if (raw_height == 5552 && !strcmp(model,"645D")) + { height = 5502; width = 7328; left_margin = 48; top_margin = 29; + filters = 0x61616161; } + if (height == 3014 && width == 4096) /* Ricoh GX200 */ + width = 4014; + if (dng_version) { + if (filters == UINT_MAX) filters = 0; + if (filters) is_raw *= tiff_samples; + else colors = tiff_samples; + switch (tiff_compress) { + case 0: + case 1: load_raw = &CLASS packed_dng_load_raw; break; + case 7: load_raw = &CLASS lossless_dng_load_raw; break; + case 34892: load_raw = &CLASS lossy_dng_load_raw; break; + default: load_raw = 0; + } + goto dng_skip; + } + if (!strcmp(make,"Canon") && !fsize && tiff_bps != 15) { + if (!load_raw) + load_raw = &CLASS lossless_jpeg_load_raw; + for (i=0; i < sizeof canon / sizeof *canon; i++) + if (raw_width == canon[i][0] && raw_height == canon[i][1]) { + width = raw_width - (left_margin = canon[i][2]); + height = raw_height - (top_margin = canon[i][3]); + width -= canon[i][4]; + height -= canon[i][5]; + mask[0][1] = canon[i][6]; + mask[0][3] = -canon[i][7]; + mask[1][1] = canon[i][8]; + mask[1][3] = -canon[i][9]; + if (canon[i][10]) filters = canon[i][10] * 0x01010101; + } + if ((unique_id | 0x20000) == 0x2720000) { + left_margin = 8; + top_margin = 16; + } + } + for (i=0; i < sizeof unique / sizeof *unique; i++) + if (unique_id == 0x80000000 + unique[i].id) { + adobe_coeff ("Canon", unique[i].model); + if (model[4] == 'K' && strlen(model) == 8) + strcpy (model, unique[i].model); + } + for (i=0; i < sizeof sonique / sizeof *sonique; i++) + if (unique_id == sonique[i].id) + strcpy (model, sonique[i].model); + for (i=0; i < sizeof panalias / sizeof *panalias; i++) + if (panalias[i][0] == '@') orig = panalias[i]+1; + else if (!strcmp(model,panalias[i])) + adobe_coeff ("Panasonic", orig); + if (!strcmp(make,"Nikon")) { + if (!load_raw) + load_raw = &CLASS packed_load_raw; + if (model[0] == 'E') + load_flags |= !data_offset << 2 | 2; + } + +/* Set parameters based on camera name (for non-DNG files). */ + + if (!strcmp(model,"KAI-0340") + && find_green (16, 16, 3840, 5120) < 25) { + height = 480; + top_margin = filters = 0; + strcpy (model,"C603"); + } + if (!strcmp(make,"Sony") && raw_width > 3888) + black = 128 << (tiff_bps - 12); + if (is_foveon) { + if (height*2 < width) pixel_aspect = 0.5; + if (height > width) pixel_aspect = 2; + filters = 0; + simple_coeff(0); + } else if (!strcmp(make,"Canon") && tiff_bps == 15) { + switch (width) { + case 3344: width -= 66; + case 3872: width -= 6; + } + if (height > width) { + SWAP(height,width); + SWAP(raw_height,raw_width); + } + if (width == 7200 && height == 3888) { + raw_width = width = 6480; + raw_height = height = 4320; + } + filters = 0; + tiff_samples = colors = 3; + load_raw = &CLASS canon_sraw_load_raw; + } else if (!strcmp(model,"PowerShot 600")) { + height = 613; + width = 854; + raw_width = 896; + colors = 4; + filters = 0xe1e4e1e4; + load_raw = &CLASS canon_600_load_raw; + } else if (!strcmp(model,"PowerShot A5") || + !strcmp(model,"PowerShot A5 Zoom")) { + height = 773; + width = 960; + raw_width = 992; + pixel_aspect = 256/235.0; + filters = 0x1e4e1e4e; + goto canon_a5; + } else if (!strcmp(model,"PowerShot A50")) { + height = 968; + width = 1290; + raw_width = 1320; + filters = 0x1b4e4b1e; + goto canon_a5; + } else if (!strcmp(model,"PowerShot Pro70")) { + height = 1024; + width = 1552; + filters = 0x1e4b4e1b; +canon_a5: + colors = 4; + tiff_bps = 10; + load_raw = &CLASS packed_load_raw; + load_flags = 264; + } else if (!strcmp(model,"PowerShot Pro90 IS") || + !strcmp(model,"PowerShot G1")) { + colors = 4; + filters = 0xb4b4b4b4; + } else if (!strcmp(model,"PowerShot A610")) { + if (canon_s2is()) strcpy (model+10, "S2 IS"); + } else if (!strcmp(model,"PowerShot SX220 HS")) { + mask[1][3] = -4; + } else if (!strcmp(model,"EOS D2000C")) { + filters = 0x61616161; + black = curve[200]; + } else if (!strcmp(model,"EOS 80D")) { + top_margin -= 2; + height += 2; + } else if (!strcmp(model,"D1")) { + cam_mul[0] *= 256/527.0; + cam_mul[2] *= 256/317.0; + } else if (!strcmp(model,"D1X")) { + width -= 4; + pixel_aspect = 0.5; + } else if (!strcmp(model,"D40X") || + !strcmp(model,"D60") || + !strcmp(model,"D80") || + !strcmp(model,"D3000")) { + height -= 3; + width -= 4; + } else if (!strcmp(model,"D3") || + !strcmp(model,"D3S") || + !strcmp(model,"D700")) { + width -= 4; + left_margin = 2; + } else if (!strcmp(model,"D3100")) { + width -= 28; + left_margin = 6; + } else if (!strcmp(model,"D5000") || + !strcmp(model,"D90")) { + width -= 42; + } else if (!strcmp(model,"D5100") || + !strcmp(model,"D7000") || + !strcmp(model,"COOLPIX A")) { + width -= 44; + } else if (!strcmp(model,"D3200") || + !strncmp(model,"D6",2) || + !strncmp(model,"D800",4)) { + width -= 46; + } else if (!strcmp(model,"D4") || + !strcmp(model,"Df")) { + width -= 52; + left_margin = 2; + } else if (!strncmp(model,"D40",3) || + !strncmp(model,"D50",3) || + !strncmp(model,"D70",3)) { + width--; + } else if (!strcmp(model,"D100")) { + if (load_flags) + raw_width = (width += 3) + 3; + } else if (!strcmp(model,"D200")) { + left_margin = 1; + width -= 4; + filters = 0x94949494; + } else if (!strncmp(model,"D2H",3)) { + left_margin = 6; + width -= 14; + } else if (!strncmp(model,"D2X",3)) { + if (width == 3264) width -= 32; + else width -= 8; + } else if (!strncmp(model,"D300",4)) { + width -= 32; + } else if (!strncmp(model,"COOLPIX B",9)) { + load_flags = 24; + } else if (!strncmp(model,"COOLPIX P",9) && raw_width != 4032) { + load_flags = 24; + filters = 0x94949494; + if (model[9] == '7' && iso_speed >= 400) + black = 255; + } else if (!strncmp(model,"1 ",2)) { + height -= 2; + } else if (fsize == 1581060) { + simple_coeff(3); + pre_mul[0] = 1.2085; + pre_mul[1] = 1.0943; + pre_mul[3] = 1.1103; + } else if (fsize == 3178560) { + cam_mul[0] *= 4; + cam_mul[2] *= 4; + } else if (fsize == 4771840) { + if (!timestamp && nikon_e995()) + strcpy (model, "E995"); + if (strcmp(model,"E995")) { + filters = 0xb4b4b4b4; + simple_coeff(3); + pre_mul[0] = 1.196; + pre_mul[1] = 1.246; + pre_mul[2] = 1.018; + } + } else if (fsize == 2940928) { + if (!timestamp && !nikon_e2100()) + strcpy (model,"E2500"); + if (!strcmp(model,"E2500")) { + height -= 2; + load_flags = 6; + colors = 4; + filters = 0x4b4b4b4b; + } + } else if (fsize == 4775936) { + if (!timestamp) nikon_3700(); + if (model[0] == 'E' && atoi(model+1) < 3700) + filters = 0x49494949; + if (!strcmp(model,"Optio 33WR")) { + flip = 1; + filters = 0x16161616; + } + if (make[0] == 'O') { + float g1 = find_green (12, 32, 1188864, 3576832); + float g2 = find_green (12, 32, 2383920, 2387016); + if (fabsf(g1) < fabsf(g2)) { + SWAP(g1,g2); + load_flags = 24; + } + if (g1 < 0) filters = 0x61616161; + } + } else if (fsize == 5869568) { + if (!timestamp && minolta_z2()) { + strcpy (make, "Minolta"); + strcpy (model,"DiMAGE Z2"); + } + load_flags = 6 + 24*(make[0] == 'M'); + } else if (fsize == 6291456) { + fseek (ifp, 0x300000, SEEK_SET); + if ((order = guess_byte_order(0x10000)) == 0x4d4d) { + height -= (top_margin = 16); + width -= (left_margin = 28); + maximum = 0xf5c0; + strcpy (make, "ISG"); + model[0] = 0; + } + } else if (!strcmp(make,"Fujifilm")) { + if (!strcmp(model+7,"S2Pro")) { + strcpy (model,"S2Pro"); + height = 2144; + width = 2880; + flip = 6; + } + top_margin = (raw_height - height) >> 2 << 1; + left_margin = (raw_width - width ) >> 2 << 1; + if (width == 2848 || width == 3664) filters = 0x16161616; + if (width == 4032 || width == 4952 || width == 6032 || width == 8280) left_margin = 0; + if (width == 3328 && (width -= 66)) left_margin = 34; + if (width == 4936) left_margin = 4; + if (!strcmp(model,"HS50EXR") || + !strcmp(model,"F900EXR")) { + width += 2; + left_margin = 0; + filters = 0x16161616; + } + if (fuji_layout) raw_width *= is_raw; + if (filters == 9) + FORC(36) ((char *)xtrans)[c] = + xtrans_abs[(c/6+top_margin) % 6][(c+left_margin) % 6]; + } else if (!strcmp(model,"KD-400Z")) { + height = 1712; + width = 2312; + raw_width = 2336; + goto konica_400z; + } else if (!strcmp(model,"KD-510Z")) { + goto konica_510z; + } else if (!strcasecmp(make,"Minolta")) { + if (!load_raw && (maximum = 0xfff)) + load_raw = &CLASS unpacked_load_raw; + if (!strncmp(model,"DiMAGE A",8)) { + if (!strcmp(model,"DiMAGE A200")) + filters = 0x49494949; + tiff_bps = 12; + load_raw = &CLASS packed_load_raw; + } else if (!strncmp(model,"ALPHA",5) || + !strncmp(model,"DYNAX",5) || + !strncmp(model,"MAXXUM",6)) { + sprintf (model+20, "DYNAX %-10s", model+6+(model[0]=='M')); + adobe_coeff (make, model+20); + load_raw = &CLASS packed_load_raw; + } else if (!strncmp(model,"DiMAGE G",8)) { + if (model[8] == '4') { + height = 1716; + width = 2304; + } else if (model[8] == '5') { +konica_510z: + height = 1956; + width = 2607; + raw_width = 2624; + } else if (model[8] == '6') { + height = 2136; + width = 2848; + } + data_offset += 14; + filters = 0x61616161; +konica_400z: + load_raw = &CLASS unpacked_load_raw; + maximum = 0x3df; + order = 0x4d4d; + } + } else if (!strcmp(model,"*ist D")) { + load_raw = &CLASS unpacked_load_raw; + data_error = -1; + } else if (!strcmp(model,"*ist DS")) { + height -= 2; + } else if (!strcmp(make,"Samsung") && raw_width == 4704) { + height -= top_margin = 8; + width -= 2 * (left_margin = 8); + load_flags = 256; + } else if (!strcmp(make,"Samsung") && raw_height == 3714) { + height -= top_margin = 18; + left_margin = raw_width - (width = 5536); + if (raw_width != 5600) + left_margin = top_margin = 0; + filters = 0x61616161; + colors = 3; + } else if (!strcmp(make,"Samsung") && raw_width == 5632) { + order = 0x4949; + height = 3694; + top_margin = 2; + width = 5574 - (left_margin = 32 + tiff_bps); + if (tiff_bps == 12) load_flags = 80; + } else if (!strcmp(make,"Samsung") && raw_width == 5664) { + height -= top_margin = 17; + left_margin = 96; + width = 5544; + filters = 0x49494949; + } else if (!strcmp(make,"Samsung") && raw_width == 6496) { + filters = 0x61616161; + black = 1 << (tiff_bps - 7); + } else if (!strcmp(model,"EX1")) { + order = 0x4949; + height -= 20; + top_margin = 2; + if ((width -= 6) > 3682) { + height -= 10; + width -= 46; + top_margin = 8; + } + } else if (!strcmp(model,"WB2000")) { + order = 0x4949; + height -= 3; + top_margin = 2; + if ((width -= 10) > 3718) { + height -= 28; + width -= 56; + top_margin = 8; + } + } else if (strstr(model,"WB550")) { + strcpy (model, "WB550"); + } else if (!strcmp(model,"EX2F")) { + height = 3045; + width = 4070; + top_margin = 3; + order = 0x4949; + filters = 0x49494949; + load_raw = &CLASS unpacked_load_raw; + } else if (!strcmp(model,"STV680 VGA")) { + black = 16; + } else if (!strcmp(model,"N95")) { + height = raw_height - (top_margin = 2); + } else if (!strcmp(model,"640x480")) { + gamma_curve (0.45, 4.5, 1, 255); + } else if (!strcmp(make,"Hasselblad")) { + if (load_raw == &CLASS lossless_jpeg_load_raw) + load_raw = &CLASS hasselblad_load_raw; + if (raw_width == 7262) { + height = 5444; + width = 7248; + top_margin = 4; + left_margin = 7; + filters = 0x61616161; + } else if (raw_width == 7410 || raw_width == 8282) { + height -= 84; + width -= 82; + top_margin = 4; + left_margin = 41; + filters = 0x61616161; + } else if (raw_width == 8384) { + height = 6208; + width = 8280; + top_margin = 96; + left_margin = 46; + } else if (raw_width == 9044) { + height = 6716; + width = 8964; + top_margin = 8; + left_margin = 40; + black += load_flags = 256; + maximum = 0x8101; + } else if (raw_width == 4090) { + strcpy (model, "V96C"); + height -= (top_margin = 6); + width -= (left_margin = 3) + 7; + filters = 0x61616161; + } + if (tiff_samples > 1) { + is_raw = tiff_samples+1; + if (!shot_select && !half_size) filters = 0; + } + } else if (!strcmp(make,"Sinar")) { + if (!load_raw) load_raw = &CLASS unpacked_load_raw; + if (is_raw > 1 && !shot_select && !half_size) filters = 0; + maximum = 0x3fff; + } else if (!strcmp(make,"Leaf")) { + maximum = 0x3fff; + fseek (ifp, data_offset, SEEK_SET); + if (ljpeg_start (&jh, 1) && jh.bits == 15) + maximum = 0x1fff; + if (tiff_samples > 1) filters = 0; + if (tiff_samples > 1 || tile_length < raw_height) { + load_raw = &CLASS leaf_hdr_load_raw; + raw_width = tile_width; + } + if ((width | height) == 2048) { + if (tiff_samples == 1) { + filters = 1; + strcpy (cdesc, "RBTG"); + strcpy (model, "CatchLight"); + top_margin = 8; left_margin = 18; height = 2032; width = 2016; + } else { + strcpy (model, "DCB2"); + top_margin = 10; left_margin = 16; height = 2028; width = 2022; + } + } else if (width+height == 3144+2060) { + if (!model[0]) strcpy (model, "Cantare"); + if (width > height) { + top_margin = 6; left_margin = 32; height = 2048; width = 3072; + filters = 0x61616161; + } else { + left_margin = 6; top_margin = 32; width = 2048; height = 3072; + filters = 0x16161616; + } + if (!cam_mul[0] || model[0] == 'V') filters = 0; + else is_raw = tiff_samples; + } else if (width == 2116) { + strcpy (model, "Valeo 6"); + height -= 2 * (top_margin = 30); + width -= 2 * (left_margin = 55); + filters = 0x49494949; + } else if (width == 3171) { + strcpy (model, "Valeo 6"); + height -= 2 * (top_margin = 24); + width -= 2 * (left_margin = 24); + filters = 0x16161616; + } + } else if (!strcmp(make,"Leica") || !strcmp(make,"Panasonic")) { + if ((flen - data_offset) / (raw_width*8/7) == raw_height) + load_raw = &CLASS panasonic_load_raw; + if (!load_raw) { + load_raw = &CLASS unpacked_load_raw; + load_flags = 4; + } + zero_is_bad = 1; + if ((height += 12) > raw_height) height = raw_height; + for (i=0; i < sizeof pana / sizeof *pana; i++) + if (raw_width == pana[i][0] && raw_height == pana[i][1]) { + left_margin = pana[i][2]; + top_margin = pana[i][3]; + width += pana[i][4]; + height += pana[i][5]; + } + filters = 0x01010101 * (uchar) "\x94\x61\x49\x16" + [((filters-1) ^ (left_margin & 1) ^ (top_margin << 1)) & 3]; + } else if (!strcmp(model,"C770UZ")) { + height = 1718; + width = 2304; + filters = 0x16161616; + load_raw = &CLASS packed_load_raw; + load_flags = 30; + } else if (!strcmp(make,"Olympus")) { + height += height & 1; + if (exif_cfa) filters = exif_cfa; + if (width == 4100) width -= 4; + if (width == 4080) width -= 24; + if (width == 9280) { width -= 6; height -= 6; } + if (load_raw == &CLASS unpacked_load_raw) + load_flags = 4; + tiff_bps = 12; + if (!strcmp(model,"E-300") || + !strcmp(model,"E-500")) { + width -= 20; + if (load_raw == &CLASS unpacked_load_raw) { + maximum = 0xfc3; + memset (cblack, 0, sizeof cblack); + } + } else if (!strcmp(model,"E-330")) { + width -= 30; + if (load_raw == &CLASS unpacked_load_raw) + maximum = 0xf79; + } else if (!strcmp(model,"SP550UZ")) { + thumb_length = flen - (thumb_offset = 0xa39800); + thumb_height = 480; + thumb_width = 640; + } else if (!strcmp(model,"TG-4")) { + width -= 16; + } else if (!strcmp(model,"TG-5")) { + width -= 6; + } + } else if (!strcmp(model,"N Digital")) { + height = 2047; + width = 3072; + filters = 0x61616161; + data_offset = 0x1a00; + load_raw = &CLASS packed_load_raw; + } else if (!strcmp(model,"DSC-F828")) { + width = 3288; + left_margin = 5; + mask[1][3] = -17; + data_offset = 862144; + load_raw = &CLASS sony_load_raw; + filters = 0x9c9c9c9c; + colors = 4; + strcpy (cdesc, "RGBE"); + } else if (!strcmp(model,"DSC-V3")) { + width = 3109; + left_margin = 59; + mask[0][1] = 9; + data_offset = 787392; + load_raw = &CLASS sony_load_raw; + } else if (!strcmp(make,"Sony") && raw_width == 3984) { + width = 3925; + order = 0x4d4d; + } else if (!strcmp(make,"Sony") && raw_width == 4288) { + width -= 32; + } else if (!strcmp(make,"Sony") && raw_width == 4600) { + if (!strcmp(model,"DSLR-A350")) + height -= 4; + black = 0; + } else if (!strcmp(make,"Sony") && raw_width == 4928) { + if (height < 3280) width -= 8; + } else if (!strcmp(make,"Sony") && raw_width == 5504) { + width -= height > 3664 ? 8 : 32; + if (!strncmp(model,"DSC",3)) + black = 200 << (tiff_bps - 12); + } else if (!strcmp(make,"Sony") && raw_width == 6048) { + width -= 24; + if (strstr(model,"RX1") || strstr(model,"A99")) + width -= 6; + } else if (!strcmp(make,"Sony") && raw_width == 7392) { + width -= 30; + } else if (!strcmp(make,"Sony") && raw_width == 8000) { + width -= 32; + } else if (!strcmp(model,"DSLR-A100")) { + if (width == 3880) { + height--; + width = ++raw_width; + } else { + height -= 4; + width -= 4; + order = 0x4d4d; + load_flags = 2; + } + filters = 0x61616161; + } else if (!strcmp(model,"PIXL")) { + height -= top_margin = 4; + width -= left_margin = 32; + gamma_curve (0, 7, 1, 255); + } else if (!strcmp(model,"C603") || !strcmp(model,"C330") + || !strcmp(model,"12MP")) { + order = 0x4949; + if (filters && data_offset) { + fseek (ifp, data_offset < 4096 ? 168 : 5252, SEEK_SET); + read_shorts (curve, 256); + } else gamma_curve (0, 3.875, 1, 255); + load_raw = filters ? &CLASS eight_bit_load_raw : + strcmp(model,"C330") ? &CLASS kodak_c603_load_raw : + &CLASS kodak_c330_load_raw; + load_flags = tiff_bps > 16; + tiff_bps = 8; + } else if (!strncasecmp(model,"EasyShare",9)) { + data_offset = data_offset < 0x15000 ? 0x15000 : 0x17000; + load_raw = &CLASS packed_load_raw; + } else if (!strcasecmp(make,"Kodak")) { + if (filters == UINT_MAX) filters = 0x61616161; + if (!strncmp(model,"NC2000",6) || + !strncmp(model,"EOSDCS",6) || + !strncmp(model,"DCS4",4)) { + width -= 4; + left_margin = 2; + if (model[6] == ' ') model[6] = 0; + if (!strcmp(model,"DCS460A")) goto bw; + } else if (!strcmp(model,"DCS660M")) { + black = 214; + goto bw; + } else if (!strcmp(model,"DCS760M")) { +bw: colors = 1; + filters = 0; + } + if (!strcmp(model+4,"20X")) + strcpy (cdesc, "MYCY"); + if (strstr(model,"DC25")) { + strcpy (model, "DC25"); + data_offset = 15424; + } + if (!strncmp(model,"DC2",3)) { + raw_height = 2 + (height = 242); + if (flen < 100000) { + raw_width = 256; width = 249; + pixel_aspect = (4.0*height) / (3.0*width); + } else { + raw_width = 512; width = 501; + pixel_aspect = (493.0*height) / (373.0*width); + } + top_margin = left_margin = 1; + colors = 4; + filters = 0x8d8d8d8d; + simple_coeff(1); + pre_mul[1] = 1.179; + pre_mul[2] = 1.209; + pre_mul[3] = 1.036; + load_raw = &CLASS eight_bit_load_raw; + } else if (!strcmp(model,"40")) { + strcpy (model, "DC40"); + height = 512; + width = 768; + data_offset = 1152; + load_raw = &CLASS kodak_radc_load_raw; + tiff_bps = 12; + } else if (strstr(model,"DC50")) { + strcpy (model, "DC50"); + height = 512; + width = 768; + data_offset = 19712; + load_raw = &CLASS kodak_radc_load_raw; + } else if (strstr(model,"DC120")) { + strcpy (model, "DC120"); + height = 976; + width = 848; + pixel_aspect = height/0.75/width; + load_raw = tiff_compress == 7 ? + &CLASS kodak_jpeg_load_raw : &CLASS kodak_dc120_load_raw; + } else if (!strcmp(model,"DCS200")) { + thumb_height = 128; + thumb_width = 192; + thumb_offset = 6144; + thumb_misc = 360; + write_thumb = &CLASS layer_thumb; + black = 17; + } + } else if (!strcmp(model,"Fotoman Pixtura")) { + height = 512; + width = 768; + data_offset = 3632; + load_raw = &CLASS kodak_radc_load_raw; + filters = 0x61616161; + simple_coeff(2); + } else if (!strncmp(model,"QuickTake",9)) { + if (head[5]) strcpy (model+10, "200"); + fseek (ifp, 544, SEEK_SET); + height = get2(); + width = get2(); + data_offset = (get4(),get2()) == 30 ? 738:736; + if (height > width) { + SWAP(height,width); + fseek (ifp, data_offset-6, SEEK_SET); + flip = ~get2() & 3 ? 5:6; + } + filters = 0x61616161; + } else if (!strcmp(make,"Rollei") && !load_raw) { + switch (raw_width) { + case 1316: + height = 1030; + width = 1300; + top_margin = 1; + left_margin = 6; + break; + case 2568: + height = 1960; + width = 2560; + top_margin = 2; + left_margin = 8; + } + filters = 0x16161616; + load_raw = &CLASS rollei_load_raw; + } + if (!model[0]) + sprintf (model, "%dx%d", width, height); + if (filters == UINT_MAX) filters = 0x94949494; + if (thumb_offset && !thumb_height) { + fseek (ifp, thumb_offset, SEEK_SET); + if (ljpeg_start (&jh, 1)) { + thumb_width = jh.wide; + thumb_height = jh.high; + } + } +dng_skip: + if ((use_camera_matrix & (use_camera_wb || dng_version)) + && cmatrix[0][0] > 0.125) { + memcpy (rgb_cam, cmatrix, sizeof cmatrix); + raw_color = 0; + } + if (raw_color) adobe_coeff (make, model); + if (load_raw == &CLASS kodak_radc_load_raw) + if (raw_color) adobe_coeff ("Apple","Quicktake"); + if (fuji_width) { + fuji_width = width >> !fuji_layout; + filters = fuji_width & 1 ? 0x94949494 : 0x49494949; + width = (height >> fuji_layout) + fuji_width; + height = width - 1; + pixel_aspect = 1; + } else { + if (raw_height < height) raw_height = height; + if (raw_width < width ) raw_width = width; + } + if (!tiff_bps) tiff_bps = 12; + if (!maximum) maximum = (1 << tiff_bps) - 1; + if (!load_raw || height < 22 || width < 22 || + tiff_bps > 16 || tiff_samples > 6 || colors > 4) + is_raw = 0; +#ifndef HAVE_LIBJASPER + if (load_raw == &CLASS redcine_load_raw) { + dcraw_message (DCRAW_ERROR,_("%s: You must link dcraw with %s!!\n"), + ifname_display, "libjasper"); + is_raw = 0; + } +#endif +#ifndef HAVE_LIBJPEG + if (load_raw == &CLASS kodak_jpeg_load_raw || + load_raw == &CLASS lossy_dng_load_raw) { + dcraw_message (DCRAW_ERROR,_("%s: You must link dcraw with %s!!\n"), + ifname, "libjpeg"); + is_raw = 0; + } +#endif + if (!cdesc[0]) + strcpy (cdesc, colors == 3 ? "RGBG":"GMCY"); + if (!raw_height) raw_height = height; + if (!raw_width ) raw_width = width; + if (filters > 999 && colors == 3) + filters |= ((filters >> 2 & 0x22222222) | + (filters << 2 & 0x88888888)) & filters << 1; +notraw: + if (flip == UINT_MAX) flip = tiff_flip; + if (flip == UINT_MAX) flip = 0; +} + +#ifndef NO_LCMS +#ifdef DCRAW_NOMAIN +extern "C" { char *ufraw_message(int code, const char *format, ...); } +#define UFRAW_ERROR 100 +#endif +static void dcraw_lcms_message (cmsContext ContextID, + cmsUInt32Number ErrorCode, + const char *ErrorText) +{ + (void) ContextID; + /* Possible ErrorCode: see cmsERROR_* in . */ + (void) ErrorCode; + +#ifdef DCRAW_NOMAIN + ufraw_message (UFRAW_ERROR, "%s", ErrorText); +#else + fprintf (stderr, "%s", ErrorText); +#endif +} + +void CLASS apply_profile (const char *input, const char *output) +{ + char *prof; + cmsHPROFILE hInProfile=0, hOutProfile=0; + cmsHTRANSFORM hTransform; + FILE *fp; + unsigned size; + + cmsSetLogErrorHandler (dcraw_lcms_message); + if (strcmp (input, "embed")) + hInProfile = cmsOpenProfileFromFile (input, "r"); + else if (profile_length) { + prof = (char *) malloc (profile_length); + merror (prof, "apply_profile()"); + fseek (ifp, profile_offset, SEEK_SET); + fread (prof, 1, profile_length, ifp); + hInProfile = cmsOpenProfileFromMem (prof, profile_length); + free (prof); + } else + dcraw_message (DCRAW_ERROR,_("%s has no embedded profile.\n"), ifname_display); + if (!hInProfile) return; + if (!output) + hOutProfile = cmsCreate_sRGBProfile(); + else if ((fp = fopen (output, "rb"))) { + fread (&size, 4, 1, fp); + fseek (fp, 0, SEEK_SET); + oprof = (unsigned *) malloc (size = ntohl(size)); + merror (oprof, "apply_profile()"); + fread (oprof, 1, size, fp); + fclose (fp); + if (!(hOutProfile = cmsOpenProfileFromMem (oprof, size))) { + free (oprof); + oprof = 0; + } + } else + dcraw_message (DCRAW_ERROR,_("Cannot open file %s!\n"), output); + if (!hOutProfile) goto quit; + dcraw_message (DCRAW_VERBOSE,_("Applying color profile...\n")); + hTransform = cmsCreateTransform (hInProfile, TYPE_RGBA_16, + hOutProfile, TYPE_RGBA_16, INTENT_PERCEPTUAL, 0); + cmsDoTransform (hTransform, image, image, width*height); + raw_color = 1; /* Don't use rgb_cam with a profile */ + cmsDeleteTransform (hTransform); + cmsCloseProfile (hOutProfile); +quit: + cmsCloseProfile (hInProfile); +} +#endif + +void CLASS convert_to_rgb() +{ + unsigned c, j; + int row, col, i, k; + ushort *img; + float out[3], out_cam[3][4]; + double num, inverse[3][3]; + static const double xyzd50_srgb[3][3] = + { { 0.436083, 0.385083, 0.143055 }, + { 0.222507, 0.716888, 0.060608 }, + { 0.013930, 0.097097, 0.714022 } }; + static const double rgb_rgb[3][3] = + { { 1,0,0 }, { 0,1,0 }, { 0,0,1 } }; + static const double adobe_rgb[3][3] = + { { 0.715146, 0.284856, 0.000000 }, + { 0.000000, 1.000000, 0.000000 }, + { 0.000000, 0.041166, 0.958839 } }; + static const double wide_rgb[3][3] = + { { 0.593087, 0.404710, 0.002206 }, + { 0.095413, 0.843149, 0.061439 }, + { 0.011621, 0.069091, 0.919288 } }; + static const double prophoto_rgb[3][3] = + { { 0.529317, 0.330092, 0.140588 }, + { 0.098368, 0.873465, 0.028169 }, + { 0.016879, 0.117663, 0.865457 } }; + static const double aces_rgb[3][3] = + { { 0.432996, 0.375380, 0.189317 }, + { 0.089427, 0.816523, 0.102989 }, + { 0.019165, 0.118150, 0.941914 } }; + static const double (*out_rgb[])[3] = + { rgb_rgb, adobe_rgb, wide_rgb, prophoto_rgb, xyz_rgb, aces_rgb }; + static const char *name[] = + { "sRGB", "Adobe RGB (1998)", "WideGamut D65", "ProPhoto D65", "XYZ", "ACES" }; + static const int phead[] = + { 1024, 0, 0x2100000, 0x6d6e7472, 0x52474220, 0x58595a20, 0, 0, 0, + 0x61637370, 0, 0, 0x6e6f6e65, 0, 0, 0, 0, 0xf6d6, 0x10000, 0xd32d }; + int pbody[] = + { 10, 0x63707274, 0, 36, /* cprt */ + 0x64657363, 0, 40, /* desc */ + 0x77747074, 0, 20, /* wtpt */ + 0x626b7074, 0, 20, /* bkpt */ + 0x72545243, 0, 14, /* rTRC */ + 0x67545243, 0, 14, /* gTRC */ + 0x62545243, 0, 14, /* bTRC */ + 0x7258595a, 0, 20, /* rXYZ */ + 0x6758595a, 0, 20, /* gXYZ */ + 0x6258595a, 0, 20 }; /* bXYZ */ + static const unsigned pwhite[] = { 0xf351, 0x10000, 0x116cc }; + unsigned pcurve[] = { 0x63757276, 0, 1, 0x1000000 }; + + gamma_curve (gamm[0], gamm[1], 0, 0); + memcpy (out_cam, rgb_cam, sizeof out_cam); + raw_color |= colors == 1 || document_mode || + output_color < 1 || output_color > 6; + if (!raw_color) { + oprof = (unsigned *) calloc (phead[0], 1); + merror (oprof, "convert_to_rgb()"); + memcpy (oprof, phead, sizeof phead); + if (output_color == 5) oprof[4] = oprof[5]; + oprof[0] = 132 + 12*pbody[0]; + for (i=0; i < pbody[0]; i++) { + oprof[oprof[0]/4] = i ? (i > 1 ? 0x58595a20 : 0x64657363) : 0x74657874; + pbody[i*3+2] = oprof[0]; + oprof[0] += (pbody[i*3+3] + 3) & -4; + } + memcpy (oprof+32, pbody, sizeof pbody); + oprof[pbody[5]/4+2] = strlen(name[output_color-1]) + 1; + memcpy ((char *)oprof+pbody[8]+8, pwhite, sizeof pwhite); + pcurve[3] = (short)(256/gamm[5]+0.5) << 16; + for (i=4; i < 7; i++) + memcpy ((char *)oprof+pbody[i*3+2], pcurve, sizeof pcurve); + pseudoinverse ((double (*)[3]) out_rgb[output_color-1], inverse, 3); + for (i=0; i < 3; i++) + for (j=0; j < 3; j++) { + for (num = k=0; k < 3; k++) + num += xyzd50_srgb[i][k] * inverse[j][k]; + oprof[pbody[j*3+23]/4+i+2] = num * 0x10000 + 0.5; + } + for (i=0; i < phead[0]/4; i++) + oprof[i] = htonl(oprof[i]); + strcpy ((char *)oprof+pbody[2]+8, "auto-generated by dcraw"); + strcpy ((char *)oprof+pbody[5]+12, name[output_color-1]); + for (i=0; i < 3; i++) + for (j=0; j < colors; j++) + for (out_cam[i][j] = k=0; k < 3; k++) + out_cam[i][j] += out_rgb[output_color-1][i][k] * rgb_cam[k][j]; + } + dcraw_message (DCRAW_VERBOSE, raw_color ? _("Building histograms...\n") : + _("Converting to %s colorspace...\n"), name[output_color-1]); + + memset (histogram, 0, sizeof histogram); + for (img=image[0], row=0; row < height; row++) + for (col=0; col < width; col++, img+=4) { + if (!raw_color) { + out[0] = out[1] = out[2] = 0; + FORCC { + out[0] += out_cam[0][c] * img[c]; + out[1] += out_cam[1][c] * img[c]; + out[2] += out_cam[2][c] * img[c]; + } + FORC3 img[c] = CLIP((int) out[c]); + } + else if (document_mode) + img[0] = img[fcol(row,col)]; + FORCC histogram[c][img[c] >> 3]++; + } + if (colors == 4 && output_color) colors = 3; + if (document_mode && filters) colors = 1; +} + +/* Start of functions copied to dcraw_indi.c (UF) */ +void CLASS fuji_rotate() +{ + unsigned i; + int row, col; + double step; + float r, c, fr, fc; + int ur, uc; + ushort wide, high, (*img)[4], (*pix)[4]; + + if (!fuji_width) return; + dcraw_message (DCRAW_VERBOSE,_("Rotating image 45 degrees...\n")); + fuji_width = (fuji_width - 1 + shrink) >> shrink; + step = sqrt(0.5); + wide = fuji_width / step; + high = (height - fuji_width) / step; + img = (ushort (*)[4]) calloc (high, wide*sizeof *img); + merror (img, "fuji_rotate()"); + + for (row=0; row < high; row++) + for (col=0; col < wide; col++) { + ur = r = fuji_width + (row-col)*step; + uc = c = (row+col)*step; + if (ur > height-2 || uc > width-2) continue; + fr = r - ur; + fc = c - uc; + pix = image + ur*width + uc; + for (i=0; i < colors; i++) + img[row*wide+col][i] = + (pix[ 0][i]*(1-fc) + pix[ 1][i]*fc) * (1-fr) + + (pix[width][i]*(1-fc) + pix[width+1][i]*fc) * fr; + } + free (image); + width = wide; + height = high; + image = img; + fuji_width = 0; +} +/* End of functions copied to dcraw_indi.c (UF) */ + +void CLASS stretch() +{ + ushort newdim, (*img)[4], *pix0, *pix1; + unsigned c; + int row, col; + double rc, frac; + + if (pixel_aspect == 1) return; + dcraw_message (DCRAW_VERBOSE,_("Stretching the image...\n")); + if (pixel_aspect < 1) { + newdim = height / pixel_aspect + 0.5; + img = (ushort (*)[4]) calloc (width, newdim*sizeof *img); + merror (img, "stretch()"); + for (rc=row=0; row < newdim; row++, rc+=pixel_aspect) { + frac = rc - (c = rc); + pix0 = pix1 = image[c*width]; + if (c+1 < height) pix1 += width*4; + for (col=0; col < width; col++, pix0+=4, pix1+=4) + FORCC img[row*width+col][c] = pix0[c]*(1-frac) + pix1[c]*frac + 0.5; + } + height = newdim; + } else { + newdim = width * pixel_aspect + 0.5; + img = (ushort (*)[4]) calloc (height, newdim*sizeof *img); + merror (img, "stretch()"); + for (rc=col=0; col < newdim; col++, rc+=1/pixel_aspect) { + frac = rc - (c = rc); + pix0 = pix1 = image[c]; + if (c+1 < width) pix1 += 4; + for (row=0; row < height; row++, pix0+=width*4, pix1+=width*4) + FORCC img[row*newdim+col][c] = pix0[c]*(1-frac) + pix1[c]*frac + 0.5; + } + width = newdim; + } + free (image); + image = img; +} + +int CLASS flip_index (int row, int col) +{ + if (flip & 4) SWAP(row,col); + if (flip & 2) row = iheight - 1 - row; + if (flip & 1) col = iwidth - 1 - col; + return row * iwidth + col; +} + +struct tiff_tag { + ushort tag, type; + int count; + union { char c[4]; short s[2]; int i; } val; +}; + +struct tiff_hdr { + ushort order, magic; + int ifd; + ushort pad, ntag; + struct tiff_tag tag[23]; + int nextifd; + ushort pad2, nexif; + struct tiff_tag exif[4]; + ushort pad3, ngps; + struct tiff_tag gpst[10]; + short bps[4]; + int rat[10]; + unsigned gps[26]; + char desc[512], make[64], model[64], soft[32], date[20], artist[64]; +}; + +void CLASS tiff_set (struct tiff_hdr *th, ushort *ntag, + ushort tag, ushort type, int count, int val) +{ + struct tiff_tag *tt; + int c; + + tt = (struct tiff_tag *)(ntag+1) + (*ntag)++; + tt->val.i = val; + if (type == 1 && count <= 4) + FORC(4) tt->val.c[c] = val >> (c << 3); + else if (type == 2) { + count = strnlen((char *)th + val, count-1) + 1; + if (count <= 4) + FORC(4) tt->val.c[c] = ((char *)th)[val+c]; + } else if (type == 3 && count <= 2) + FORC(2) tt->val.s[c] = val >> (c << 4); + tt->count = count; + tt->type = type; + tt->tag = tag; +} + +#define TOFF(ptr) ((char *)(&(ptr)) - (char *)th) + +void CLASS tiff_head (struct tiff_hdr *th, int full) +{ + int c, psize=0; + struct tm *t; + + memset (th, 0, sizeof *th); + th->order = htonl(0x4d4d4949) >> 16; + th->magic = 42; + th->ifd = 10; + th->rat[0] = th->rat[2] = 300; + th->rat[1] = th->rat[3] = 1; + FORC(6) th->rat[4+c] = 1000000; + th->rat[4] *= shutter; + th->rat[6] *= aperture; + th->rat[8] *= focal_len; + strncpy (th->desc, desc, 512); + strncpy (th->make, make, 64); + strncpy (th->model, model, 64); + strcpy (th->soft, "dcraw v" DCRAW_VERSION); + t = localtime (×tamp); + sprintf (th->date, "%04d:%02d:%02d %02d:%02d:%02d", + t->tm_year+1900,t->tm_mon+1,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec); + strncpy (th->artist, artist, 64); + if (full) { + tiff_set (th, &th->ntag, 254, 4, 1, 0); + tiff_set (th, &th->ntag, 256, 4, 1, width); + tiff_set (th, &th->ntag, 257, 4, 1, height); + tiff_set (th, &th->ntag, 258, 3, colors, output_bps); + if (colors > 2) + th->tag[th->ntag-1].val.i = TOFF(th->bps); + FORC4 th->bps[c] = output_bps; + tiff_set (th, &th->ntag, 259, 3, 1, 1); + tiff_set (th, &th->ntag, 262, 3, 1, 1 + (colors > 1)); + } + tiff_set (th, &th->ntag, 270, 2, 512, TOFF(th->desc)); + tiff_set (th, &th->ntag, 271, 2, 64, TOFF(th->make)); + tiff_set (th, &th->ntag, 272, 2, 64, TOFF(th->model)); + if (full) { + if (oprof) psize = ntohl(oprof[0]); + tiff_set (th, &th->ntag, 273, 4, 1, sizeof *th + psize); + tiff_set (th, &th->ntag, 277, 3, 1, colors); + tiff_set (th, &th->ntag, 278, 4, 1, height); + tiff_set (th, &th->ntag, 279, 4, 1, height*width*colors*output_bps/8); + } else + tiff_set (th, &th->ntag, 274, 3, 1, "12435867"[flip]-'0'); + tiff_set (th, &th->ntag, 282, 5, 1, TOFF(th->rat[0])); + tiff_set (th, &th->ntag, 283, 5, 1, TOFF(th->rat[2])); + tiff_set (th, &th->ntag, 284, 3, 1, 1); + tiff_set (th, &th->ntag, 296, 3, 1, 2); + tiff_set (th, &th->ntag, 305, 2, 32, TOFF(th->soft)); + tiff_set (th, &th->ntag, 306, 2, 20, TOFF(th->date)); + tiff_set (th, &th->ntag, 315, 2, 64, TOFF(th->artist)); + tiff_set (th, &th->ntag, 34665, 4, 1, TOFF(th->nexif)); + if (psize) tiff_set (th, &th->ntag, 34675, 7, psize, sizeof *th); + tiff_set (th, &th->nexif, 33434, 5, 1, TOFF(th->rat[4])); + tiff_set (th, &th->nexif, 33437, 5, 1, TOFF(th->rat[6])); + tiff_set (th, &th->nexif, 34855, 3, 1, iso_speed); + tiff_set (th, &th->nexif, 37386, 5, 1, TOFF(th->rat[8])); + if (gpsdata[1]) { + tiff_set (th, &th->ntag, 34853, 4, 1, TOFF(th->ngps)); + tiff_set (th, &th->ngps, 0, 1, 4, 0x202); + tiff_set (th, &th->ngps, 1, 2, 2, gpsdata[29]); + tiff_set (th, &th->ngps, 2, 5, 3, TOFF(th->gps[0])); + tiff_set (th, &th->ngps, 3, 2, 2, gpsdata[30]); + tiff_set (th, &th->ngps, 4, 5, 3, TOFF(th->gps[6])); + tiff_set (th, &th->ngps, 5, 1, 1, gpsdata[31]); + tiff_set (th, &th->ngps, 6, 5, 1, TOFF(th->gps[18])); + tiff_set (th, &th->ngps, 7, 5, 3, TOFF(th->gps[12])); + tiff_set (th, &th->ngps, 18, 2, 12, TOFF(th->gps[20])); + tiff_set (th, &th->ngps, 29, 2, 12, TOFF(th->gps[23])); + memcpy (th->gps, gpsdata, sizeof th->gps); + } +} + +void CLASS jpeg_thumb() +{ + char *thumb; + ushort exif[5]; + struct tiff_hdr th; + + thumb = (char *) malloc (thumb_length); + merror (thumb, "jpeg_thumb()"); + fread (thumb, 1, thumb_length, ifp); + fputc (0xff, ofp); + fputc (0xd8, ofp); + if (strcmp (thumb+6, "Exif")) { + memcpy (exif, "\xff\xe1 Exif\0\0", 10); + exif[1] = htons (8 + sizeof th); + fwrite (exif, 1, sizeof exif, ofp); + tiff_head (&th, 0); + fwrite (&th, 1, sizeof th, ofp); + } + fwrite (thumb+2, 1, thumb_length-2, ofp); + free (thumb); +} + +void CLASS write_ppm_tiff() +{ + struct tiff_hdr th; + uchar *ppm; + ushort *ppm2; + unsigned c; + int row, col, soff, rstep, cstep; + int perc, val, total, white=0x2000; + + perc = width * height * 0.01; /* 99th percentile white level */ + if (fuji_width) perc /= 2; + if (!((highlight & ~2) || no_auto_bright)) + for (white=c=0; c < colors; c++) { + for (val=0x2000, total=0; --val > 32; ) + if ((total += histogram[c][val]) > perc) break; + if (white < val) white = val; + } + gamma_curve (gamm[0], gamm[1], 2, (white << 3)/bright); + iheight = height; + iwidth = width; + if (flip & 4) SWAP(height,width); + ppm = (uchar *) calloc (width, colors*output_bps/8); + ppm2 = (ushort *) ppm; + merror (ppm, "write_ppm_tiff()"); + if (output_tiff) { + tiff_head (&th, 1); + fwrite (&th, sizeof th, 1, ofp); + if (oprof) + fwrite (oprof, ntohl(oprof[0]), 1, ofp); + } else if (colors > 3) + fprintf (ofp, + "P7\nWIDTH %d\nHEIGHT %d\nDEPTH %d\nMAXVAL %d\nTUPLTYPE %s\nENDHDR\n", + width, height, colors, (1 << output_bps)-1, cdesc); + else + fprintf (ofp, "P%d\n%d %d\n%d\n", + colors/2+5, width, height, (1 << output_bps)-1); + soff = flip_index (0, 0); + cstep = flip_index (0, 1) - soff; + rstep = flip_index (1, 0) - flip_index (0, width); + for (row=0; row < height; row++, soff += rstep) { + for (col=0; col < width; col++, soff += cstep) + if (output_bps == 8) + FORCC ppm [col*colors+c] = curve[image[soff][c]] >> 8; + else FORCC ppm2[col*colors+c] = curve[image[soff][c]]; + if (output_bps == 16 && !output_tiff && htons(0x55aa) != 0x55aa) +#if defined(__MINGW64_VERSION_MAJOR) && __MINGW64_VERSION_MAJOR < 4 + swab ((char *) ppm2, (char *) ppm2, width*colors*2); +#else + swab ((const char *) ppm2, (char *) ppm2, width*colors*2); +#endif + fwrite (ppm, colors*output_bps/8, width, ofp); + } + free (ppm); +} + +int CLASS main (int argc, const char **argv) +{ + // The following variables are static to supress clobbering warnings. + // They are not thread-safe, but main() should never be called in a thread. + static unsigned c; + static int arg, status=0, quality, i; + static int timestamp_only=0, thumbnail_only=0, identify_only=0; + static int user_qual=-1, user_black=-1, user_sat=-1, user_flip=-1; + static int use_fuji_rotate=1, write_to_stdout=0, read_from_stdin=0; + static const char *sp, *bpfile=0, *dark_frame=0, *write_ext; + static char opm, opt, *ofname, *cp; + static struct utimbuf ut; +#ifndef NO_LCMS + static const char *cam_profile=0, *out_profile=0; +#endif + +#ifndef LOCALTIME + putenv ((char *) "TZ=UTC"); +#endif +#ifdef LOCALEDIR + setlocale (LC_CTYPE, ""); + setlocale (LC_MESSAGES, ""); + bindtextdomain ("dcraw", LOCALEDIR); + textdomain ("dcraw"); +#endif + + if (argc == 1) { + printf(_("\nRaw photo decoder \"dcraw\" v%s"), DCRAW_VERSION); + printf(_("\nby Dave Coffin, dcoffin a cybercom o net\n")); + printf(_("\nUsage: %s [OPTION]... [FILE]...\n\n"), argv[0]); + puts(_("-v Print verbose messages")); + puts(_("-c Write image data to standard output")); + puts(_("-e Extract embedded thumbnail image")); + puts(_("-i Identify files without decoding them")); + puts(_("-i -v Identify files and show metadata")); + puts(_("-z Change file dates to camera timestamp")); + puts(_("-w Use camera white balance, if possible")); + puts(_("-a Average the whole image for white balance")); + puts(_("-A Average a grey box for white balance")); + puts(_("-r Set custom white balance")); + puts(_("+M/-M Use/don't use an embedded color matrix")); + puts(_("-C Correct chromatic aberration")); + puts(_("-P Fix the dead pixels listed in this file")); + puts(_("-K Subtract dark frame (16-bit raw PGM)")); + puts(_("-k Set the darkness level")); + puts(_("-S Set the saturation level")); + puts(_("-n Set threshold for wavelet denoising")); + puts(_("-H [0-9] Highlight mode (0=clip, 1=unclip, 2=blend, 3+=rebuild)")); + puts(_("-t [0-7] Flip image (0=none, 3=180, 5=90CCW, 6=90CW)")); + puts(_("-o [0-6] Output colorspace (raw,sRGB,Adobe,Wide,ProPhoto,XYZ,ACES)")); +#ifndef NO_LCMS + puts(_("-o Apply output ICC profile from file")); + puts(_("-p Apply camera ICC profile from file or \"embed\"")); +#endif + puts(_("-d Document mode (no color, no interpolation)")); + puts(_("-D Document mode without scaling (totally raw)")); + puts(_("-j Don't stretch or rotate raw pixels")); + puts(_("-W Don't automatically brighten the image")); + puts(_("-b Adjust brightness (default = 1.0)")); + puts(_("-g

Set custom gamma curve (default = 2.222 4.5)")); + puts(_("-q [0-3] Set the interpolation quality")); + puts(_("-h Half-size color image (twice as fast as \"-q 0\")")); + puts(_("-f Interpolate RGGB as four colors")); + puts(_("-m Apply a 3x3 median filter to R-G and B-G")); + puts(_("-s [0..N-1] Select one raw image or \"all\" from each file")); + puts(_("-6 Write 16-bit instead of 8-bit")); + puts(_("-4 Linear 16-bit, same as \"-6 -W -g 1 1\"")); + puts(_("-T Write TIFF instead of PPM")); + puts(""); + return 1; + } + argv[argc] = ""; + for (arg=1; (((opm = argv[arg][0]) - 2) | 2) == '+'; ) { + opt = argv[arg++][1]; + if ((cp = (char *) strchr (sp="nbrkStqmHACg", opt))) + for (i=0; i < "114111111422"[cp-sp]-'0'; i++) + if (!isdigit(argv[arg+i][0])) { + dcraw_message (DCRAW_ERROR,_("Non-numeric argument to \"-%c\"\n"), opt); + return 1; + } + switch (opt) { + case 'n': threshold = atof(argv[arg++]); break; + case 'b': bright = atof(argv[arg++]); break; + case 'r': + FORC4 user_mul[c] = atof(argv[arg++]); break; + case 'C': aber[0] = 1 / atof(argv[arg++]); + aber[2] = 1 / atof(argv[arg++]); break; + case 'g': gamm[0] = atof(argv[arg++]); + gamm[1] = atof(argv[arg++]); + if (gamm[0]) gamm[0] = 1/gamm[0]; break; + case 'k': user_black = atoi(argv[arg++]); break; + case 'S': user_sat = atoi(argv[arg++]); break; + case 't': user_flip = atoi(argv[arg++]); break; + case 'q': user_qual = atoi(argv[arg++]); break; + case 'm': med_passes = atoi(argv[arg++]); break; + case 'H': highlight = atoi(argv[arg++]); break; + case 's': + shot_select = abs(atoi(argv[arg])); + multi_out = !strcmp(argv[arg++],"all"); + break; + case 'o': + if (isdigit(argv[arg][0]) && !argv[arg][1]) + output_color = atoi(argv[arg++]); +#ifndef NO_LCMS + else out_profile = argv[arg++]; + break; + case 'p': cam_profile = argv[arg++]; +#endif + break; + case 'P': bpfile = argv[arg++]; break; + case 'K': dark_frame = argv[arg++]; break; + case 'z': timestamp_only = 1; break; + case 'e': thumbnail_only = 1; break; + case 'i': identify_only = 1; break; + case 'c': write_to_stdout = 1; break; + case 'v': verbose = 1; break; + case 'h': half_size = 1; break; + case 'f': four_color_rgb = 1; break; + case 'A': FORC4 greybox[c] = atoi(argv[arg++]); + case 'a': use_auto_wb = 1; break; + case 'w': use_camera_wb = 1; break; + case 'M': use_camera_matrix = 3 * (opm == '+'); break; + case 'I': read_from_stdin = 1; break; + case 'E': document_mode++; + case 'D': document_mode++; + case 'd': document_mode++; + case 'j': use_fuji_rotate = 0; break; + case 'W': no_auto_bright = 1; break; + case 'T': output_tiff = 1; break; + case '4': gamm[0] = gamm[1] = + no_auto_bright = 1; + case '6': output_bps = 16; break; + default: + dcraw_message (DCRAW_ERROR,_("Unknown option \"-%c\".\n"), opt); + return 1; + } + } + if (arg == argc) { + dcraw_message (DCRAW_ERROR,_("No files to process.\n")); + return 1; + } + if (write_to_stdout) { + if (isatty(1)) { + dcraw_message (DCRAW_ERROR,_("Will not write an image to the terminal!\n")); + return 1; + } +#if defined(_WIN32) || defined(DJGPP) || defined(__CYGWIN__) + if (setmode(1,O_BINARY) < 0) { + perror ("setmode()"); + return 1; + } +#endif + } + for ( ; arg < argc; arg++) { + status = 1; + raw_image = 0; + image = 0; + oprof = 0; + meta_data = ofname = 0; + ofp = stdout; + if (setjmp (failure)) { + if (fileno(ifp) > 2) fclose(ifp); + if (fileno(ofp) > 2) fclose(ofp); + status = 1; + goto cleanup; + } + ifname = const_cast(argv[arg]); + ifname_display = ifname; + if (!(ifp = fopen (ifname, "rb"))) { + perror (ifname); + continue; + } + status = (identify(),!is_raw); + if (user_flip >= 0) + flip = user_flip; + switch ((flip+3600) % 360) { + case 270: flip = 5; break; + case 180: flip = 3; break; + case 90: flip = 6; + } + if (timestamp_only) { + if ((status = !timestamp)) + dcraw_message (DCRAW_ERROR,_("%s has no timestamp.\n"), ifname); + else if (identify_only) + printf ("%10ld%10d %s\n", (long) timestamp, shot_order, ifname); + else { + dcraw_message (DCRAW_VERBOSE,_("%s time set to %d.\n"), ifname, (int) timestamp); + ut.actime = ut.modtime = timestamp; + utime (ifname, &ut); + } + goto next; + } + write_fun = &CLASS write_ppm_tiff; + if (thumbnail_only) { + if ((status = !thumb_offset)) { + dcraw_message (DCRAW_ERROR,_("%s has no thumbnail.\n"), ifname); + goto next; + } else if (thumb_load_raw) { + load_raw = thumb_load_raw; + data_offset = thumb_offset; + height = thumb_height; + width = thumb_width; + filters = 0; + colors = 3; + } else { + fseek (ifp, thumb_offset, SEEK_SET); + write_fun = write_thumb; + goto thumbnail; + } + } + if (load_raw == &CLASS kodak_ycbcr_load_raw) { + height += height & 1; + width += width & 1; + } + if (identify_only && verbose && make[0]) { + printf (_("\nFilename: %s\n"), ifname); + printf (_("Timestamp: %s"), ctime(×tamp)); + printf (_("Camera: %s %s\n"), make, model); + if (artist[0]) + printf (_("Owner: %s\n"), artist); + if (dng_version) { + printf (_("DNG Version: ")); + for (i=24; i >= 0; i -= 8) + printf ("%d%c", dng_version >> i & 255, i ? '.':'\n'); + } + printf (_("ISO speed: %d\n"), (int) iso_speed); + printf (_("Shutter: ")); + if (shutter > 0 && shutter < 1) + shutter = (printf ("1/"), 1 / shutter); + printf (_("%0.1f sec\n"), shutter); + printf (_("Aperture: f/%0.1f\n"), aperture); + printf (_("Focal length: %0.1f mm\n"), focal_len); + printf (_("Embedded ICC profile: %s\n"), profile_length ? _("yes"):_("no")); + printf (_("Number of raw images: %d\n"), is_raw); + if (pixel_aspect != 1) + printf (_("Pixel Aspect Ratio: %0.6f\n"), pixel_aspect); + if (thumb_offset) + printf (_("Thumb size: %4d x %d\n"), thumb_width, thumb_height); + printf (_("Full size: %4d x %d\n"), raw_width, raw_height); + } else if (!is_raw) + dcraw_message (DCRAW_ERROR,_("Cannot decode file %s\n"), ifname); + if (!is_raw) goto next; + shrink = filters && (half_size || (!identify_only && + (threshold || aber[0] != 1 || aber[2] != 1))); + iheight = (height + shrink) >> shrink; + iwidth = (width + shrink) >> shrink; + if (identify_only) { + if (verbose) { + if (document_mode == 3) { + top_margin = left_margin = fuji_width = 0; + height = raw_height; + width = raw_width; + } + iheight = (height + shrink) >> shrink; + iwidth = (width + shrink) >> shrink; + if (use_fuji_rotate) { + if (fuji_width) { + fuji_width = (fuji_width - 1 + shrink) >> shrink; + iwidth = fuji_width / sqrt(0.5); + iheight = (iheight - fuji_width) / sqrt(0.5); + } else { + if (pixel_aspect < 1) iheight = iheight / pixel_aspect + 0.5; + if (pixel_aspect > 1) iwidth = iwidth * pixel_aspect + 0.5; + } + } + if (flip & 4) + SWAP(iheight,iwidth); + printf (_("Image size: %4d x %d\n"), width, height); + printf (_("Output size: %4d x %d\n"), iwidth, iheight); + printf (_("Raw colors: %d"), colors); + if (filters) { + int fhigh = 2, fwide = 2; + if ((filters ^ (filters >> 8)) & 0xff) fhigh = 4; + if ((filters ^ (filters >> 16)) & 0xffff) fhigh = 8; + if (filters == 1) fhigh = fwide = 16; + if (filters == 9) fhigh = fwide = 6; + printf (_("\nFilter pattern: ")); + for (i=0; i < fhigh; i++) + for (c = i && putchar('/') && 0; c < (unsigned) fwide; c++) + putchar (cdesc[fcol(i,c)]); + } + printf (_("\nDaylight multipliers:")); + FORCC printf (" %f", pre_mul[c]); + if (cam_mul[0] > 0) { + printf (_("\nCamera multipliers:")); + FORC4 printf (" %f", cam_mul[c]); + } + putchar ('\n'); + } else + printf (_("%s is a %s %s image.\n"), ifname, make, model); +next: + fclose(ifp); + continue; + } + if (meta_length) { + meta_data = (char *) malloc (meta_length); + merror (meta_data, "main()"); + } + if (filters || colors == 1) { + raw_image = (ushort *) calloc ((raw_height+7), raw_width*2); + merror (raw_image, "main()"); + } else { + image = (ushort (*)[4]) calloc (iheight, iwidth*sizeof *image); + merror (image, "main()"); + } + dcraw_message (DCRAW_VERBOSE,_("Loading %s %s image from %s ...\n"), + make, model, ifname); + if (shot_select >= is_raw) + dcraw_message (DCRAW_ERROR,_("%s: \"-s %d\" requests a nonexistent image!\n"), + ifname, shot_select); +#ifdef HAVE_FSEEKO + fseeko (ifp, data_offset, SEEK_SET); +#else + fseek (ifp, data_offset, SEEK_SET); +#endif + if (raw_image && read_from_stdin) + fread (raw_image, 2, raw_height*raw_width, stdin); + else (*this.*load_raw)(); + if (document_mode == 3) { + top_margin = left_margin = fuji_width = 0; + height = raw_height; + width = raw_width; + } + iheight = (height + shrink) >> shrink; + iwidth = (width + shrink) >> shrink; + if (raw_image) { + image = (ushort (*)[4]) calloc (iheight, iwidth*sizeof *image); + merror (image, "main()"); + crop_masked_pixels(); + free (raw_image); + } + if (zero_is_bad) remove_zeroes(); + bad_pixels (bpfile); + if (dark_frame) subtract (dark_frame); + quality = 2 + !fuji_width; + if (user_qual >= 0) quality = user_qual; + i = cblack[3]; + FORC3 if (i > cblack[c]) i = cblack[c]; + FORC4 cblack[c] -= i; + black += i; + i = cblack[6]; + FORC ((unsigned)(cblack[4] * cblack[5])) + if (i > cblack[6+c]) i = cblack[6+c]; + FORC ((unsigned)(cblack[4] * cblack[5])) + cblack[6+c] -= i; + black += i; + if (user_black >= 0) black = user_black; + FORC4 cblack[c] += black; + if (user_sat > 0) maximum = user_sat; +#ifdef COLORCHECK + colorcheck(); +#endif + if (is_foveon) { + if (document_mode) { + for (i=0; i < height*width*4; i++) + if ((short) image[0][i] < 0) image[0][i] = 0; + } else if (load_raw == &CLASS foveon_dp_load_raw) + sigma_true_ii_interpolate(); + else foveon_interpolate(); + } else if (document_mode < 2) + scale_colors(); + pre_interpolate(); + if (filters && !document_mode) { + if (quality == 0) + lin_interpolate(); + else if (quality == 1 || colors > 3) + vng_interpolate(); + else if (quality == 2 && filters > 1000) + ppg_interpolate(); + else if (filters == 9) + xtrans_interpolate (quality*2-3); + else + ahd_interpolate(); + } + if (mix_green) + for (colors=3, i=0; i < height*width; i++) + image[i][1] = (image[i][1] + image[i][3]) >> 1; + if (!is_foveon && colors == 3) median_filter(); + if (!is_foveon && highlight == 2) blend_highlights(); + if (!is_foveon && highlight > 2) recover_highlights(); + if (use_fuji_rotate) fuji_rotate(); +#ifndef NO_LCMS + if (cam_profile) apply_profile (cam_profile, out_profile); +#endif + convert_to_rgb(); + if (use_fuji_rotate) stretch(); +thumbnail: + if (write_fun == &CLASS jpeg_thumb) + write_ext = ".jpg"; + else if (output_tiff && write_fun == &CLASS write_ppm_tiff) + write_ext = ".tiff"; + else + write_ext = ".pgm\0.ppm\0.ppm\0.pam" + colors*5-5; + ofname = (char *) malloc (strlen(ifname) + 64); + merror (ofname, "main()"); + if (write_to_stdout) + strcpy (ofname,_("standard output")); + else { + strcpy (ofname, ifname); + if ((cp = (char*)strrchr (ofname, '.'))) *cp = 0; + if (multi_out) + sprintf (ofname+strlen(ofname), "_%0*d", + snprintf(0,0,"%d",is_raw-1), shot_select); + if (thumbnail_only) + strcat (ofname, ".thumb"); + strcat (ofname, write_ext); + ofp = fopen (ofname, "wb"); + if (!ofp) { + status = 1; + perror (ofname); + goto cleanup; + } + } + dcraw_message (DCRAW_VERBOSE,_("Writing data to %s ...\n"), ofname); + (*this.*write_fun)(); + fclose(ifp); + if (ofp != stdout) fclose(ofp); +cleanup: + if (meta_data) free (meta_data); + if (ofname) free (ofname); + if (oprof) free (oprof); + if (image) free (image); + if (multi_out) { + if (++shot_select < is_raw) arg--; + else shot_select = 0; + } + } + /* Make sure ifname are not free()'d (UF) */ + ifname = NULL; + ifname_display = NULL; + return status; +} + +#ifndef DCRAW_NOMAIN /*UF*/ +int main(int argc, const char **argv) +{ + DCRaw *d = new DCRaw; + return d->main(argc, argv); +} +#endif /*DCRAW_NOMAIN*/ /*UF*/ diff --git a/plugins/load-dcraw/dcraw.h b/plugins/load-dcraw/dcraw.h new file mode 100644 index 00000000..39e7dfc1 --- /dev/null +++ b/plugins/load-dcraw/dcraw.h @@ -0,0 +1,304 @@ +/* + dcraw.h - Dave Coffin's raw photo decoder - header for C++ adaptation + Copyright 1997-2016 by Dave Coffin, dcoffin a cybercom o net + Copyright 2004-2016 by Udi Fuchs, udifuchs a gmail o com + + 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 is a adaptation of Dave Coffin's original dcraw.c to C++. + It can work as either a command-line tool or called by other programs. + */ + +#if !defined(uchar) +#define uchar unsigned char +#endif +#if !defined(ushort) +#define ushort unsigned short +#endif + +/* + * The following is somewhat ugly because of various requirements: + * 1. The stand-alone dcraw binary should not depend on glib + * 2. The amount of changes to dcraw source code should be minimal + * 3. On win32 fopen needs to be replaced by g_fopen + * 4. On other systems g_fopen is defined as a macro + * 5. g_fopen only exists since glib 2.6 + */ +#if !defined(DCRAW_NOMAIN) && defined(_WIN32) +#include +extern "C" { +#include +} +#define fopen g_fopen +#endif + +class DCRaw +{ +public: + /* All dcraw's global variables are members of this class. */ + FILE *ifp, *ofp; + short order, fuji_dr; + /*const*/ + char *ifname, *ifname_display; + char *meta_data, xtrans[6][6], xtrans_abs[6][6], cdesc[5], desc[512]; + char make[64], model[64], model2[64], cm_desc[64], artist[64]; + float flash_used, canon_ev, iso_speed, shutter, aperture, focal_len; + time_t timestamp; + off_t strip_offset, data_offset; + off_t thumb_offset, meta_offset, profile_offset; + unsigned shot_order, kodak_cbpp, exif_cfa, unique_id; + unsigned thumb_length, meta_length, profile_length; + unsigned thumb_misc, *oprof, fuji_layout, shot_select, multi_out; + unsigned tiff_nifds, tiff_samples, tiff_bps, tiff_compress; + unsigned black, maximum, mix_green, raw_color, zero_is_bad; + unsigned zero_after_ff, is_raw, dng_version, is_foveon, data_error; + unsigned tile_width, tile_length, gpsdata[32], load_flags; + unsigned flip, tiff_flip, filters, colors; + ushort raw_height, raw_width, height, width, top_margin, left_margin; + ushort shrink, iheight, iwidth, fuji_width, thumb_width, thumb_height; + ushort *raw_image, (*image)[4], cblack[4102]; + ushort white[8][8], curve[0x10000], cr2_slice[3], sraw_mul[4]; + double pixel_aspect, aber[4], gamm[6]; + float bright, user_mul[4], threshold; + int mask[8][4]; + int half_size, four_color_rgb, document_mode, highlight; + int verbose, use_auto_wb, use_camera_wb, use_camera_matrix; + int output_color, output_bps, output_tiff, med_passes; + int no_auto_bright; + unsigned greybox[4]; + float cam_mul[4], pre_mul[4], cmatrix[3][4], rgb_cam[3][4]; + int histogram[4][0x2000]; + void (DCRaw::*write_thumb)(), (DCRaw::*write_fun)(); + void (DCRaw::*load_raw)(), (DCRaw::*thumb_load_raw)(); + jmp_buf failure; + + struct decode { + struct decode *branch[2]; + int leaf; + } first_decode[2048], *second_decode, *free_decode; + + struct tiff_ifd { + int width, height, bps, comp, phint, offset, flip, samples, bytes; + int tile_width, tile_length; + float shutter; + } tiff_ifd[10]; + + struct ph1 { + int format, key_off, tag_21a; + int black, split_col, black_col, split_row, black_row; + float tag_210; + } ph1; + + int tone_curve_size, tone_curve_offset; /* Nikon Tone Curves UF*/ + int tone_mode_offset, tone_mode_size; /* Nikon ToneComp UF*/ + + /* Used by dcraw_message() */ + char *messageBuffer; + int lastStatus; + + unsigned ifpReadCount; + unsigned ifpSize; + unsigned ifpStepProgress; + int eofCount; +#define STEPS 50 + void ifpProgress(unsigned readCount); +// Override standard io function for integrity checks and progress report + size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); + size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); + char *fgets(char *s, int size, FILE *stream); + int fgetc(FILE *stream); +// dcraw only calls fscanf for single variables + int fscanf(FILE *stream, const char *format, void *ptr); +// calling with more variables would triger a link error +//int fscanf(FILE *stream, const char *format, void *ptr1, void *ptr2, ...); + + /* Initialization of the variables is done here */ + DCRaw(); + ~DCRaw(); + void dcraw_message(int code, const char *format, ...); + /* All dcraw functions with the CLASS prefix are members of this class. */ + int fcol(int row, int col); + void merror(void *ptr, const char *where); + void derror(); + ushort sget2(uchar *s); + ushort get2(); + unsigned sget4(uchar *s); + unsigned get4(); + unsigned getint(int type); + float int_to_float(int i); + double getreal(int type); + void read_shorts(ushort *pixel, unsigned count); + void cubic_spline(const int *x_, const int *y_, const int len); + void canon_600_fixed_wb(int temp); + int canon_600_color(int ratio[2], int mar); + void canon_600_auto_wb(); + void canon_600_coeff(); + void canon_600_load_raw(); + void canon_600_correct(); + int canon_s2is(); + unsigned getbithuff(int nbits, ushort *huff); + ushort * make_decoder_ref(const uchar **source); + ushort * make_decoder(const uchar *source); + void crw_init_tables(unsigned table, ushort *huff[2]); + int canon_has_lowbits(); + void canon_load_raw(); + int ljpeg_start(struct jhead *jh, int info_only); + void ljpeg_end(struct jhead *jh); + int ljpeg_diff(ushort *huff); + ushort * ljpeg_row(int jrow, struct jhead *jh); + void lossless_jpeg_load_raw(); + void canon_sraw_load_raw(); + void adobe_copy_pixel(unsigned row, unsigned col, ushort **rp); + void ljpeg_idct(struct jhead *jh); + void lossless_dng_load_raw(); + void packed_dng_load_raw(); + void pentax_load_raw(); + void nikon_load_raw(); + void nikon_yuv_load_raw(); + int nikon_e995(); + int nikon_e2100(); + void nikon_3700(); + int minolta_z2(); + void ppm_thumb(); + void ppm16_thumb(); + void layer_thumb(); + void rollei_thumb(); + void rollei_load_raw(); + int raw(unsigned row, unsigned col); + void phase_one_flat_field(int is_float, int nc); + void phase_one_correct(); + void phase_one_load_raw(); + unsigned ph1_bithuff(int nbits, ushort *huff); + void phase_one_load_raw_c(); + void hasselblad_load_raw(); + void leaf_hdr_load_raw(); + void unpacked_load_raw(); + void sinar_4shot_load_raw(); + void imacon_full_load_raw(); + void packed_load_raw(); + void nokia_load_raw(); + void canon_rmf_load_raw(); + unsigned pana_bits(int nbits); + void panasonic_load_raw(); + void olympus_load_raw(); + void minolta_rd175_load_raw(); + void quicktake_100_load_raw(); + void kodak_radc_load_raw(); + void kodak_jpeg_load_raw(); + void lossy_dng_load_raw(); + void kodak_dc120_load_raw(); + void eight_bit_load_raw(); + void kodak_c330_load_raw(); + void kodak_c603_load_raw(); + void kodak_262_load_raw(); + int kodak_65000_decode(short *out, int bsize); + void kodak_65000_load_raw(); + void kodak_ycbcr_load_raw(); + void kodak_rgb_load_raw(); + void kodak_thumb_load_raw(); + void sony_decrypt(unsigned *data, int len, int start, int key); + void sony_load_raw(); + void sony_arw_load_raw(); + void sony_arw2_load_raw(); + void samsung_load_raw(); + void samsung2_load_raw(); + void samsung3_load_raw(); + void smal_decode_segment(unsigned seg[2][2], int holes); + void smal_v6_load_raw(); + int median4(int *p); + void fill_holes(int holes); + void smal_v9_load_raw(); + void redcine_load_raw(); + void foveon_decoder(int size, unsigned code); + void foveon_thumb(); + void foveon_sd_load_raw(); + void foveon_huff(ushort *huff); + void foveon_dp_load_raw(); + void canon_crx_load_raw(); + void fuji_xtrans_load_raw(); + void parse_crx (int end); + void foveon_load_camf(); + const char * foveon_camf_param(const char *block, const char *param); + void * foveon_camf_matrix(unsigned dim[3], const char *name); + int foveon_fixed(void *ptr, int size, const char *name); + float foveon_avg(short *pix, int range[2], float cfilt); + short * foveon_make_curve(double max, double mul, double filt); + void foveon_make_curves + (short **curvep, float dq[3], float div[3], float filt); + int foveon_apply_curve(short *curve, int i); + void sigma_true_ii_interpolate(); + void foveon_interpolate(); + void crop_masked_pixels(); + void remove_zeroes(); + void bad_pixels(const char *fname); + void subtract(const char *fname); + void gamma_curve(double pwr, double ts, int mode, int imax); + void pseudoinverse(double(*in)[3], double(*out)[3], int size); + void cam_xyz_coeff(float rgb_cam[3][4], double cam_xyz[4][3]); + void colorcheck(); + void hat_transform(float *temp, float *base, int st, int size, int sc); + void wavelet_denoise(); + void scale_colors(); + void pre_interpolate(); + void border_interpolate(unsigned border); + void lin_interpolate(); + void vng_interpolate(); + void ppg_interpolate(); + void cielab(ushort rgb[3], short lab[3]); + void xtrans_interpolate(int passes); + void ahd_interpolate(); + void median_filter(); + void blend_highlights(); + void recover_highlights(); + void tiff_get(unsigned base, + unsigned *tag, unsigned *type, unsigned *len, unsigned *save); + void parse_thumb_note(int base, unsigned toff, unsigned tlen); + void parse_makernote(int base, int uptag); + void get_timestamp(int reversed); + void parse_exif(int base); + void parse_gps(int base); + void romm_coeff(float romm_cam[3][3]); + void parse_mos(int offset); + void linear_table(unsigned len); + void parse_kodak_ifd(int base); + int parse_tiff_ifd(int base); + int parse_tiff(int base); + void apply_tiff(); + void parse_minolta(int base); + void parse_external_jpeg(); + void ciff_block_1030(); + void parse_ciff(int offset, int length, int depth); + void parse_rollei(); + void parse_sinar_ia(); + void parse_phase_one(int base); + void parse_fuji(int offset); + int parse_jpeg(int offset); + void parse_riff(); + void parse_qt(int end); + void parse_smal(int offset, unsigned fsize); + void parse_cine(); + void parse_redcine(); + char * foveon_gets(int offset, char *str, int len); + void parse_foveon(); + void adobe_coeff(const char *make, const char *model); + void simple_coeff(int index); + short guess_byte_order(int words); + float find_green(int bps, int bite, int off0, int off1); + void identify(); +#ifndef NO_LCMS + void apply_profile(const char *input, const char *output); +#endif + void convert_to_rgb(); + void fuji_rotate(); + void stretch(); + int flip_index(int row, int col); + void tiff_set(struct tiff_hdr *th, ushort *ntag, + ushort tag, ushort type, int count, int val); + void tiff_head(struct tiff_hdr *th, int full); + void jpeg_thumb(); + void write_ppm_tiff(); + int main(int argc, const char **argv); +}; diff --git a/plugins/load-dcraw/dcraw_api.cc b/plugins/load-dcraw/dcraw_api.cc new file mode 100644 index 00000000..d33f0300 --- /dev/null +++ b/plugins/load-dcraw/dcraw_api.cc @@ -0,0 +1,1058 @@ +/* + * UFRaw - Unidentified Flying Raw converter for digital camera images + * + * dcraw_api.cc - API for DCRaw + * Copyright 2004-2016 by Udi Fuchs + * + * based on dcraw by Dave Coffin + * http://www.cybercom.net/~dcoffin/ + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include /* for sqrt() */ +#include +#include +#include +#include "uf_glib.h" +#include /*For _(String) definition - NKBJ*/ +#include +#include "dcraw_api.h" +#include "dcraw.h" + +#define FORC(cnt) for (c=0; c < cnt; c++) +#define FORC3 FORC(3) +#define FORC4 FORC(4) +#define FORCC FORC(colors) + +#define LIM(x,min,max) MAX(min,MIN(x,max)) +#define CLIP(x) LIM((int)(x),0,65535) + +extern "C" { + int fcol_INDI(const unsigned filters, const int row, const int col, + const int top_margin, const int left_margin, + /*const*/ char xtrans[6][6]); + void wavelet_denoise_INDI(gushort(*image)[4], const int black, + const int iheight, const int iwidth, const int height, const int width, + const int colors, const int shrink, const float pre_mul[4], + const float threshold, const unsigned filters); + void scale_colors_INDI(const int maximum, const int black, + const int use_camera_wb, const float cam_mul[4], const int colors, + float pre_mul[4], const unsigned filters, /*const*/ gushort white[8][8], + const char *ifname_display, void *dcraw); + void lin_interpolate_INDI(gushort(*image)[4], const unsigned filters, + const int width, const int height, + const int colors, void *dcraw, dcraw_data *h); + void vng_interpolate_INDI(gushort(*image)[4], const unsigned filters, + const int width, const int height, const int colors, const int rgb_max, + void *dcraw, dcraw_data *h); + void xtrans_interpolate_INDI(ushort(*image)[4], const unsigned filters, + const int width, const int height, + const int colors, const float rgb_cam[3][4], + void *dcraw, dcraw_data *hh, const int passes); + void ahd_interpolate_INDI(gushort(*image)[4], const unsigned filters, + const int width, const int height, const int colors, float rgb_cam[3][4], + void *dcraw, dcraw_data *h); + void color_smooth(gushort(*image)[4], const int width, const int height, + const int passes); + void ppg_interpolate_INDI(gushort(*image)[4], const unsigned filters, + const int width, const int height, const int colors, void *dcraw, dcraw_data *h); + void flip_image_INDI(gushort(*image)[4], int *height_p, int *width_p, + const int flip); + void fuji_rotate_INDI(gushort(**image_p)[4], int *height_p, int *width_p, + int *fuji_width_p, const int colors, const double step, void *dcraw); + + int dcraw_open(dcraw_data *h, char *filename) + { + DCRaw *d = new DCRaw; + int c, i; + +#ifndef LOCALTIME + putenv(const_cast("TZ=UTC")); +#endif + g_free(d->messageBuffer); + d->messageBuffer = NULL; + d->lastStatus = DCRAW_SUCCESS; + d->verbose = 1; + d->ifname = g_strdup(filename); + d->ifname_display = g_filename_display_name(d->ifname); + if (setjmp(d->failure)) { + d->dcraw_message(DCRAW_ERROR, _("Fatal internal error\n")); + h->message = d->messageBuffer; + delete d; + return DCRAW_ERROR; + } + if (!(d->ifp = g_fopen(d->ifname, "rb"))) { + gchar *err_u8 = g_locale_to_utf8(strerror(errno), -1, NULL, NULL, NULL); + d->dcraw_message(DCRAW_OPEN_ERROR, _("Cannot open file %s: %s\n"), + d->ifname_display, err_u8); + g_free(err_u8); + h->message = d->messageBuffer; + delete d; + return DCRAW_OPEN_ERROR; + } + d->identify(); + /* We first check if dcraw recognizes the file, this is equivalent + * to 'dcraw -i' succeeding */ + if (!d->make[0]) { + d->dcraw_message(DCRAW_OPEN_ERROR, _("%s: unsupported file format.\n"), + d->ifname_display); + fclose(d->ifp); + h->message = d->messageBuffer; + int lastStatus = d->lastStatus; + delete d; + return lastStatus; + } + /* Next we check if dcraw can decode the file */ + if (!d->is_raw) { + d->dcraw_message(DCRAW_OPEN_ERROR, _("Cannot decode file %s\n"), + d->ifname_display); + fclose(d->ifp); + h->message = d->messageBuffer; + int lastStatus = d->lastStatus; + delete d; + return lastStatus; + } + if (d->load_raw == &DCRaw::kodak_ycbcr_load_raw) { + d->height += d->height & 1; + d->width += d->width & 1; + } + /* Pass class variables to the handler on two conditions: + * 1. They are needed at this stage. + * 2. They where set in identify() and won't change in load_raw() */ + h->dcraw = d; + h->ifp = d->ifp; + h->height = d->height; + h->width = d->width; + h->fuji_width = d->fuji_width; + h->fuji_step = sqrt(0.5); + h->fuji_dr = d->fuji_dr; + h->colors = d->colors; + h->filters = d->filters; + h->raw_color = d->raw_color; + h->top_margin = d->top_margin; + h->left_margin = d->left_margin; + memcpy(h->cam_mul, d->cam_mul, sizeof d->cam_mul); + // maximum and black might change during load_raw. We need them for the + // camera-wb. If they'll change we will recalculate the camera-wb. + h->rgbMax = d->maximum; + i = d->cblack[3]; + FORC3 if ((unsigned)i > d->cblack[c]) i = d->cblack[c]; + FORC4 d->cblack[c] -= i; + d->black += i; + i = d->cblack[6]; + FORC(d->cblack[4] * d->cblack[5]) + if (i > d->cblack[6 + c]) i = d->cblack[6 + c]; + FORC(d->cblack[4] * d->cblack[5]) + d->cblack[6 + c] -= i; + d->black += i; + h->black = d->black; + h->shrink = d->shrink = (h->filters == 1 || h->filters > 1000); + h->pixel_aspect = d->pixel_aspect; + /* copied from dcraw's main() */ + switch ((d->flip + 3600) % 360) { + case 270: + d->flip = 5; + break; + case 180: + d->flip = 3; + break; + case 90: + d->flip = 6; + } + h->flip = d->flip; + h->toneCurveSize = d->tone_curve_size; + h->toneCurveOffset = d->tone_curve_offset; + h->toneModeOffset = d->tone_mode_offset; + h->toneModeSize = d->tone_mode_size; + g_strlcpy(h->make, d->make, 80); + g_strlcpy(h->model, d->model, 80); + h->iso_speed = d->iso_speed; + h->shutter = d->shutter; + h->aperture = d->aperture; + h->focal_len = d->focal_len; + h->timestamp = d->timestamp; + h->raw.image = NULL; + h->thumbType = unknown_thumb_type; + h->message = d->messageBuffer; + memcpy(h->xtrans, d->xtrans, sizeof d->xtrans); + return d->lastStatus; + } + + void dcraw_image_dimensions(dcraw_data *raw, int flip, int shrink, + int *height, int *width) + { + // Effect of dcraw_finilize_shrink() + *width = raw->width / shrink; + *height = raw->height / shrink; + // Effect of fuji_rotate_INDI() */ + if (raw->fuji_width) { + int fuji_width = raw->fuji_width / shrink - 1; + *width = fuji_width / raw->fuji_step; + *height = (*height - fuji_width) / raw->fuji_step; + } + // Effect of dcraw_image_stretch() + if (raw->pixel_aspect < 1) + *height = *height / raw->pixel_aspect + 0.5; + if (raw->pixel_aspect > 1) + *width = *width * raw->pixel_aspect + 0.5; + + // Effect of dcraw_flip_image() + if (flip & 4) { + int tmp = *height; + *height = *width; + *width = tmp; + } + } + + void fuji_merge(DCRaw *d, ushort *saved_raw_image, float saved_cam_mul[4], int saved_fuji_dr) + { + int i, j, c, s; + unsigned b; + float S, R, w, l, m, th, tl, mul[4][4]; + + if (d->fuji_width) { /* Super CCD SR */ + + /* Populate a small array for converting the whitebalance */ + /* of the second image to that of the first one. */ + + if (d->fuji_layout) { + /* First generation Super CCD SR (S20Pro, F700, F710) */ + /* Many of these sensors are defective and have a colourcast. */ + + /* RBRB */ + /* GGGG */ + /* BRBR */ + /* GGGG */ + mul[1][1] = mul[1][0] = mul[1][2] = mul[1][3] = 1; + mul[3][1] = mul[3][0] = mul[3][2] = mul[3][3] = 1; + mul[0][0] = mul[0][2] = mul[2][1] = mul[2][3] = d->cam_mul[0] / saved_cam_mul[0]; + mul[0][1] = mul[0][3] = mul[2][0] = mul[2][2] = d->cam_mul[2] / saved_cam_mul[2]; + + } else { /* Super CCD SR II (S3Pro, S5Pro) */ + + /* RGBG */ + /* BGRG */ + /* RGBG */ + /* BGRG */ + mul[0][1] = mul[0][3] = mul[1][1] = mul[1][3] = 1; + mul[2][1] = mul[2][3] = mul[3][1] = mul[3][3] = 1; + mul[0][0] = mul[1][2] = mul[2][0] = mul[3][2] = d->cam_mul[0] / saved_cam_mul[0]; + mul[0][2] = mul[1][0] = mul[2][2] = mul[3][0] = d->cam_mul[2] / saved_cam_mul[2]; + } + + for (i = 0 ; i < d->raw_height; i++) + for (j = 0 ; j < d->raw_width; j++) { + + S = saved_raw_image[i * d->raw_width + j]; + R = d->raw_image[i * d->raw_width + j] * mul[i & 3][j & 3] * 16; + + /* Fade from S to R in one stop. */ + /* Response of these sensors appears to be non-linear, */ + /* causing a slight colourcast in the transition zone. */ + if (S > 0x1f00) { + if (S < 0x3e00) { + w = (S - 0x1f00) / 0x1f00; + S = (1 - w) * S + w * R; + } else + S = R; + } + + d->raw_image[i * d->raw_width + j] = CLIP((S * 0xffff / 0x2f000)); + } + + d->maximum = 0xffff; + + FORC4 d->cam_mul[c] = saved_cam_mul[c]; + + d->fuji_dr = -400; + + } else { /* EXR */ + + if (d->black) + b = d->black; + else + b = d->cblack[6]; + + s = (saved_fuji_dr - d->fuji_dr) / 100; + + + if (s) { /* DR-mode */ + + th = l = d->maximum - b; + m = 1 << s; + tl = th / m; + th += tl; + m += 1; + l *= m; + + for (i = 0 ; i < d->raw_height * d->raw_width; i++) { + + /* Range check to avoid problems when value is below black. */ + S = LIM(saved_raw_image[i], b, d->maximum) - b; + R = LIM(d->raw_image[i], b, d->maximum) - b; + /* Adding R to S pixels reduces noise a bit. */ + S += R; + R *= m; + + /* Fade from S to R in ~1.5 or 2.25 stops. */ + /* Response of EXR sensors appears to be linear. */ + if (S > tl) { + if (S < th) { + w = (S - tl) / (th - tl); + S = (1 - w) * S + w * R; + } else + S = R; + } + + /* l can be larger than 0xffff. */ + d->raw_image[i] = CLIP(S * 0xffff / l); + } + + d->maximum = 0xffff; + d->black = 0; + + for (i = 6 ; i < 10 ; i++) + d->cblack[i] = 0; + + //d->fuji_dr = saved_fuji_dr; + + } else { /* Low-noise-mode */ + + for (i = 0 ; i < d->raw_height * d->raw_width ; i++) + d->raw_image[i] += saved_raw_image[i]; + + d->maximum *= 2; + d->black *= 2; + + for (i = 6 ; i < 10 ; i++) + d->cblack[i] *= 2; + } + } + } + + int dcraw_load_raw(dcraw_data *h) + { + /* 'volatile' supresses clobbering warning */ + DCRaw * volatile d = (DCRaw *)h->dcraw; + int c, i, j; + double dmin; + +start: + g_free(d->messageBuffer); + d->messageBuffer = NULL; + d->lastStatus = DCRAW_SUCCESS; + d->raw_image = 0; + if (setjmp(d->failure)) { + d->dcraw_message(DCRAW_ERROR, _("Fatal internal error\n")); + h->message = d->messageBuffer; + delete d; + return DCRAW_ERROR; + } + h->raw.height = d->iheight = (h->height + h->shrink) >> h->shrink; + h->raw.width = d->iwidth = (h->width + h->shrink) >> h->shrink; + h->raw.colors = d->colors; + h->fourColorFilters = d->filters; + if (d->filters || d->colors == 1) { + if (d->colors == 1 || d->filters == 1 || d->filters > 1000) + d->raw_image = (ushort *) g_malloc((d->raw_height + 7) * d->raw_width * 2); + else + d->raw_image = (ushort *) g_malloc(sizeof(dcraw_image_type) * (d->raw_height + 7) * d->raw_width); + } else { + h->raw.image = d->image = g_new0(dcraw_image_type, d->iheight * d->iwidth + + d->meta_length); + d->meta_data = (char *)(d->image + d->iheight * d->iwidth); + } + d->dcraw_message(DCRAW_VERBOSE, _("Loading %s %s image from %s ...\n"), + d->make, d->model, d->ifname_display); + fseek(d->ifp, 0, SEEK_END); + d->ifpSize = ftell(d->ifp); + fseek(d->ifp, d->data_offset, SEEK_SET); + (d->*d->load_raw)(); + + /* multishot support, for now Pentax only. */ + if (d->is_raw == 4 && !strncasecmp(d->make, "Pentax", 6)) { + + int row, col, i; + int positions[4][2] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}}; + static dcraw_image_type *tmp = NULL; + + if (!tmp) + tmp = d->image = g_new0(dcraw_image_type, d->height * d->width + d->meta_length); + +#ifdef _OPENMP + #pragma omp parallel for private(col) +#endif + for (row = 0 ; row < d->height ; row++) + for (col = 0 ; col < d->width ; col++) + tmp[row * d->width + col][fcol_INDI(d->filters, row + positions[d->shot_select][0], col + positions[d->shot_select][1], d->top_margin, d->left_margin, d->xtrans)] = d->raw_image[(row + d->top_margin + positions[d->shot_select][0]) * d->raw_width + col + d->left_margin + positions[d->shot_select][1]]; + + g_free(d->raw_image); + d->raw_image = NULL; + + if (d->shot_select < 3) { + d->shot_select++; + fseek(d->ifp, 0, SEEK_SET); + d->identify(); + goto start; + } + + if (d->shot_select == 3) /* Just to keep the compiler happy. */ +#ifdef _OPENMP + #pragma omp parallel for +#endif + for (i = 0 ; i < d->height * d->width ; i++) + tmp[i][1] = (tmp[i][1] + tmp[i][3]) / 2; + + d->image = tmp; + d->shot_select = 0; + d->is_raw = 0; + d->filters = 0; + d->shrink = 0; + d->meta_data = (char *)(tmp + d->height * d->width); + + h->raw.image = tmp; + h->filters = 0; + h->shrink = 0; + + tmp = NULL; + } + + /* Fuji Super CCD SR and EXR support */ + if (d->is_raw == 2 && !strncasecmp(d->make, "Fujifilm", 8)) { + + static int saved_fuji_dr; + static float saved_cam_mul[4]; + static guint16 *saved_raw_image = NULL; + + if (!saved_raw_image) { + + saved_raw_image = d->raw_image; + d->raw_image = NULL; + saved_fuji_dr = d->fuji_dr; + FORC4 saved_cam_mul[c] = d->cam_mul[c]; + + d->shot_select++; + fseek(d->ifp, 0, SEEK_SET); + d->identify(); + goto start; + } + + fuji_merge(d, saved_raw_image, saved_cam_mul, saved_fuji_dr); + + free(saved_raw_image); + saved_raw_image = NULL; + d->shot_select--; + + FORC4 h->cam_mul[c] = d->cam_mul[c]; + h->fuji_dr = d->fuji_dr; + h->filters = d->filters; + h->rgbMax = d->maximum; + h->black = d->black; + } + + h->raw.height = d->iheight = (h->height + h->shrink) >> h->shrink; + h->raw.width = d->iwidth = (h->width + h->shrink) >> h->shrink; + if (d->raw_image) { + h->raw.image = d->image = g_new0(dcraw_image_type, d->iheight * d->iwidth + + d->meta_length); + d->meta_data = (char *)(d->image + d->iheight * d->iwidth); + d->crop_masked_pixels(); + g_free(d->raw_image); + + if (d->filters > 1 && d->filters <= 1000) + lin_interpolate_INDI(d->image, d->filters, d->width, d->height, d->colors, d, h); + } + if (!--d->data_error) d->lastStatus = DCRAW_ERROR; + if (d->zero_is_bad) d->remove_zeroes(); + d->bad_pixels(NULL); + if (d->is_foveon) { + if (d->load_raw == &DCRaw::foveon_dp_load_raw) { + d->meta_data = 0; + d->sigma_true_ii_interpolate(); + } else d->foveon_interpolate(); + h->raw.width = h->width = d->width; + h->raw.height = h->height = d->height; + } + fclose(d->ifp); + h->ifp = NULL; + // TODO: Go over the following settings to see if they change during + // load_raw. If they change, document where. If not, move to dcraw_open(). + h->rgbMax = d->maximum; + i = d->cblack[3]; + FORC3 if ((unsigned)i > d->cblack[c]) i = d->cblack[c]; + FORC4 d->cblack[c] -= i; + d->black += i; + i = d->cblack[6]; + FORC(d->cblack[4] * d->cblack[5]) + if (i > d->cblack[6 + c]) i = d->cblack[6 + c]; + FORC(d->cblack[4] * d->cblack[5]) + d->cblack[6 + c] -= i; + d->black += i; + h->black = d->black; + d->dcraw_message(DCRAW_VERBOSE, _("Black: %d, Maximum: %d\n"), + d->black, d->maximum); + dmin = DBL_MAX; + for (i = 0; i < h->colors; i++) if (dmin > d->pre_mul[i]) dmin = d->pre_mul[i]; + for (i = 0; i < h->colors; i++) h->pre_mul[i] = d->pre_mul[i] / dmin; + if (h->colors == 3) h->pre_mul[3] = 0; + memcpy(h->rgb_cam, d->rgb_cam, sizeof d->rgb_cam); + + double rgb_cam_transpose[4][3]; + for (i = 0; i < 4; i++) for (j = 0; j < 3; j++) + rgb_cam_transpose[i][j] = d->rgb_cam[j][i]; + d->pseudoinverse(rgb_cam_transpose, h->cam_rgb, d->colors); + + h->message = d->messageBuffer; + return d->lastStatus; + } + + int dcraw_load_thumb(dcraw_data *h, dcraw_image_data *thumb) + { + DCRaw *d = (DCRaw *)h->dcraw; + + g_free(d->messageBuffer); + d->messageBuffer = NULL; + d->lastStatus = DCRAW_SUCCESS; + + thumb->height = d->thumb_height; + thumb->width = d->thumb_width; + h->thumbOffset = d->thumb_offset; + h->thumbBufferLength = d->thumb_length; + if (d->thumb_offset == 0) { + dcraw_message(d, DCRAW_ERROR, _("%s has no thumbnail."), + d->ifname_display); + } else if (d->thumb_load_raw != NULL) { + dcraw_message(d, DCRAW_ERROR, + _("Unsupported thumb format (load_raw) for %s"), + d->ifname_display); + } else if (d->write_thumb == &DCRaw::jpeg_thumb) { + h->thumbType = jpeg_thumb_type; + } else if (d->write_thumb == &DCRaw::ppm_thumb) { + h->thumbType = ppm_thumb_type; + // Copied from dcraw's ppm_thumb() + h->thumbBufferLength = thumb->width * thumb->height * 3; + } else { + dcraw_message(d, DCRAW_ERROR, + _("Unsupported thumb format for %s"), d->ifname_display); + } + h->message = d->messageBuffer; + return d->lastStatus; + } + + /* Grab a pixel from the raw data, doing dark frame removal on the fly. + * + * The most obvious algorithm for dark frame removal is to simply + * subtract the dark frame from the image (rounding negative values to + * zero). However, this leaves holes in the resulting image that need + * to be interpolated from the surrounding pixels. + * + * The processing works by subtracting the dark frame as usual for most + * pixels. For all pixels where the dark frame is brighter than a given + * threshold, the result is instead calculated as the average of the + * dark-adjusted values of the 4 surrounding pixels. By this method, + * only hot pixels (as determined by the threshold) are examined and + * recalculated. + */ + static int get_dark_pixel(const dcraw_data *h, const dcraw_data *dark, + int i, int cl) + { + return MAX(h->raw.image[i][cl] - dark->raw.image[i][cl], 0); + } + + static int get_pixel(const dcraw_data *h, const dcraw_data *dark, + int i, int cl, int pixels) + { + int pixel = h->raw.image[i][cl]; + if (dark != 0) { + int w = h->raw.width; + pixel = (dark->raw.image[i][cl] <= dark->thresholds[cl]) + ? MAX(pixel - dark->raw.image[i][cl], 0) + : (get_dark_pixel(h, dark, i + ((i >= 1) ? -1 : 1), cl) + + get_dark_pixel(h, dark, i + ((i < pixels - 1) ? 1 : -1), cl) + + get_dark_pixel(h, dark, i + ((i >= w) ? -w : w), cl) + + get_dark_pixel(h, dark, i + ((i < pixels - w) ? w : -w), cl)) + / 4; + } + return pixel; + } + + /* + * fcol_INDI() optimizing wrapper. + * fcol_sequence() cooks up the filter color sequence for a row knowing that + * it doesn't have to store more than 16 values. The result can be indexed + * by the column using fcol_color() and that part must of course be inlined + * for maximum performance. The inner loop for image processing should + * always try to index the column and not the row in order to reduce the + * data cache footprint. + */ + static unsigned fcol_sequence(int filters, int row, int top_margin, + int left_margin, char xtrans[6][6]) + { + unsigned sequence = 0; + int c; + + for (c = 15; c >= 0; --c) + sequence = (sequence << 2) | fcol_INDI(filters, row, c, top_margin, left_margin, xtrans); + return sequence; + } + + /* + * Note: smart compilers will inline anyway in most cases: the "inline" + * below is a comment reminding not to make it an external function. + */ + static inline int fcol_color(unsigned sequence, int col) + { + return (sequence >> ((col << 1) & 0x1f)) & 3; + } + + static inline void shrink_accumulate_row(unsigned *sum, int size, + dcraw_image_type *base, int scale, int color) + { + int i, j; + unsigned v; + + for (i = 0; i < size; ++i) { + v = 0; + for (j = 0; j < scale; ++j) + v += base[i * scale + j][color]; + sum[i] += v; + } + } + + static inline void shrink_row(dcraw_image_type *obase, int osize, + dcraw_image_type *ibase, int isize, int colors, int scale) + { + unsigned *sum; + dcraw_image_type *iptr; + int cl, i; + + sum = (unsigned*) g_malloc(osize * sizeof(unsigned)); + for (cl = 0; cl < colors; ++cl) { + memset(sum, 0, osize * sizeof(unsigned)); + iptr = ibase; + for (i = 0; i < scale; ++i) { + shrink_accumulate_row(sum, osize, iptr, scale, cl); + iptr += isize; + } + for (i = 0; i < osize; ++i) + obase[i][cl] = sum[i] / (scale * scale); + } + g_free(sum); + } + + static inline void shrink_pixel(dcraw_image_type pixp, int row, int col, + dcraw_data *hh, unsigned *fseq, int scale) + { + unsigned sum[4], count[4]; + int ri, ci, cl; + dcraw_image_type *ibase; + + memset(sum, 0, 4 * sizeof(unsigned)); + memset(count, 0, 4 * sizeof(unsigned)); + for (ri = 0; ri < scale; ++ri) { + ibase = hh->raw.image + ((row * scale + ri) / 2) * hh->raw.width; + for (ci = 0; ci < scale; ++ci) { + cl = fcol_color(fseq[ri], col * scale + ci); + sum[cl] += ibase[(col * scale + ci) / 2][cl]; + ++count[cl]; + } + } + for (cl = 0; cl < hh->raw.colors; ++cl) + pixp[cl] = sum[cl] / count[cl]; + } + + int dcraw_finalize_shrink(dcraw_image_data *f, dcraw_data *hh, + int scale) + { + DCRaw *d = (DCRaw *)hh->dcraw; + int h, w, fujiWidth, r, c, ri, recombine, f4; + dcraw_image_type *ibase, *obase; + unsigned *fseq; + unsigned short *pixp; + + g_free(d->messageBuffer); + d->messageBuffer = NULL; + d->lastStatus = DCRAW_SUCCESS; + + recombine = (hh->colors == 3 && hh->raw.colors == 4); + /* the last row/column will be skipped if input is incomplete */ + f->height = h = hh->height / scale; + f->width = w = hh->width / scale; + f->colors = hh->colors; + + /* hh->raw.image is shrunk in half if there are filters. + * If scale is odd we need to "unshrink" it using the info in + * hh->fourColorFilters before scaling it. */ + if ((hh->filters == 1 || hh->filters > 1000) && scale % 2 == 1) { + fujiWidth = hh->fuji_width / scale; + f->image = (dcraw_image_type *) + g_realloc(f->image, h * w * sizeof(dcraw_image_type)); + f4 = hh->fourColorFilters; + +#ifdef _OPENMP + #pragma omp parallel for schedule(static) private(r,ri,fseq,c,pixp) +#endif + for (r = 0; r < h; ++r) { + fseq = (unsigned*) g_malloc(scale * sizeof(unsigned)); + for (ri = 0; ri < scale; ++ri) + fseq[ri] = fcol_sequence(f4, r + ri, hh->top_margin, hh->left_margin, hh->xtrans); + for (c = 0; c < w; ++c) { + pixp = f->image[r * w + c]; + shrink_pixel(pixp, r, c, hh, fseq, scale); + if (recombine) + pixp[1] = (pixp[1] + pixp[3]) / 2; + } + g_free(fseq); + } + } else { + if (hh->filters == 1 || hh->filters > 1000) scale /= 2; + fujiWidth = ((hh->fuji_width + hh->shrink) >> hh->shrink) / scale; + f->image = (dcraw_image_type *)g_realloc( + f->image, h * w * sizeof(dcraw_image_type)); +#ifdef _OPENMP + #pragma omp parallel for schedule(static) private(r,ibase,obase,c) +#endif + for (r = 0; r < h; ++r) { + ibase = hh->raw.image + r * hh->raw.width * scale; + obase = f->image + r * w; + if (scale == 1) + memcpy(obase, ibase, sizeof(dcraw_image_type) * w); + else + shrink_row(obase, w, ibase, hh->raw.width, hh->raw.colors, scale); + if (recombine) { + for (c = 0; c < w; c++) + obase[c][1] = (obase[c][1] + obase[c][3]) / 2; + } + } + } + fuji_rotate_INDI(&f->image, &f->height, &f->width, &fujiWidth, + f->colors, hh->fuji_step, d); + + hh->message = d->messageBuffer; + return d->lastStatus; + } + + int dcraw_image_resize(dcraw_image_data *image, int size) + { + int h, w, wid, r, ri, rii, c, ci, cii, cl, norm; + guint64 riw, riiw, ciw, ciiw; + guint64(*iBuf)[4]; + int mul = size, div = MAX(image->height, image->width); + + if (mul > div) return DCRAW_ERROR; + if (mul == div) return DCRAW_SUCCESS; + /* I'm skiping the last row/column if it is not a full row/column */ + h = image->height * mul / div; + w = image->width * mul / div; + wid = image->width; + iBuf = (guint64(*)[4])g_new0(guint64, h * w * 4); + norm = div * div; + + for (r = 0; r < image->height; r++) { + /* r should be divided between ri and rii */ + ri = r * mul / div; + rii = (r + 1) * mul / div; + /* with weights riw and riiw (riw+riiw==mul) */ + riw = rii * div - r * mul; + riiw = (r + 1) * mul - rii * div; + if (rii >= h) { + rii = h - 1; + riiw = 0; + } + if (ri >= h) { + ri = h - 1; + riw = 0; + } + for (c = 0; c < image->width; c++) { + ci = c * mul / div; + cii = (c + 1) * mul / div; + ciw = cii * div - c * mul; + ciiw = (c + 1) * mul - cii * div; + if (cii >= w) { + cii = w - 1; + ciiw = 0; + } + if (ci >= w) { + ci = w - 1; + ciw = 0; + } + for (cl = 0; cl < image->colors; cl++) { + iBuf[ri * w + ci ][cl] += image->image[r * wid + c][cl] * riw * ciw ; + iBuf[ri * w + cii][cl] += image->image[r * wid + c][cl] * riw * ciiw; + iBuf[rii * w + ci ][cl] += image->image[r * wid + c][cl] * riiw * ciw ; + iBuf[rii * w + cii][cl] += image->image[r * wid + c][cl] * riiw * ciiw; + } + } + } + for (c = 0; c < h * w; c++) for (cl = 0; cl < image->colors; cl++) + image->image[c][cl] = iBuf[c][cl] / norm; + g_free(iBuf); + image->height = h; + image->width = w; + return DCRAW_SUCCESS; + } + + /* Adapted from dcraw.c stretch() - NKBJ */ + int dcraw_image_stretch(dcraw_image_data *image, double pixel_aspect) + { + int newdim, row, col, c, colors = image->colors; + double rc, frac; + ushort *pix0, *pix1; + dcraw_image_type *iBuf; + + if (pixel_aspect == 1) return DCRAW_SUCCESS; + if (pixel_aspect < 1) { + newdim = (int)(image->height / pixel_aspect + 0.5); + iBuf = g_new(dcraw_image_type, image->width * newdim); + for (rc = row = 0; row < newdim; row++, rc += pixel_aspect) { + frac = rc - (c = (int)rc); + pix0 = pix1 = image->image[c * image->width]; + if (c + 1 < image->height) pix1 += image->width * 4; + for (col = 0; col < image->width; col++, pix0 += 4, pix1 += 4) + FORCC iBuf[row * image->width + col][c] = + (guint16)(pix0[c] * (1 - frac) + pix1[c] * frac + 0.5); + } + image->height = newdim; + } else { + newdim = (int)(image->width * pixel_aspect + 0.5); + iBuf = g_new(dcraw_image_type, image->height * newdim); + for (rc = col = 0; col < newdim; col++, rc += 1 / pixel_aspect) { + frac = rc - (c = (int)rc); + pix0 = pix1 = image->image[c]; + if (c + 1 < image->width) pix1 += 4; + for (row = 0; row < image->height; + row++, pix0 += image->width * 4, pix1 += image->width * 4) + FORCC iBuf[row * newdim + col][c] = + (guint16)(pix0[c] * (1 - frac) + pix1[c] * frac + 0.5); + } + image->width = newdim; + } + g_free(image->image); + image->image = iBuf; + return DCRAW_SUCCESS; + } + + int dcraw_flip_image(dcraw_image_data *image, int flip) + { + if (flip) + flip_image_INDI(image->image, &image->height, &image->width, flip); + return DCRAW_SUCCESS; + } + + int dcraw_set_color_scale(dcraw_data *h, int useCameraWB) + { + DCRaw *d = (DCRaw *)h->dcraw; + g_free(d->messageBuffer); + d->messageBuffer = NULL; + d->lastStatus = DCRAW_SUCCESS; + memcpy(h->post_mul, h->pre_mul, sizeof h->post_mul); + if (d->is_foveon) { + // foveon_interpolate() applies the camera-wb already. + for (int c = 0; c < 4; c++) + h->post_mul[c] = 1.0; + } else { + scale_colors_INDI(h->rgbMax, h->black, useCameraWB, h->cam_mul, + h->colors, h->post_mul, h->filters, d->white, + d->ifname_display, d); + } + h->message = d->messageBuffer; + return d->lastStatus; + } + + void dcraw_wavelet_denoise(dcraw_data *h, float threshold) + { + if (threshold) + wavelet_denoise_INDI(h->raw.image, h->black, h->raw.height, + h->raw.width, h->height, h->width, h->colors, h->shrink, + h->post_mul, threshold, h->fourColorFilters); + } + + void dcraw_wavelet_denoise_shrinked(dcraw_image_data *f, float threshold) + { + if (threshold) + wavelet_denoise_INDI(f->image, 0, f->height, f->width, 0, 0, 4, 0, + NULL, threshold, 0); + } + + /* + * Do black level adjustment, dark frame subtraction and white balance + * (plus normalization to use the full 16 bit pixel value range) in one + * pass. + * + * TODO: recode and optimize dark frame path + */ + void dcraw_finalize_raw(dcraw_data *h, dcraw_data *dark, int rgbWB[4]) + { + const int pixels = h->raw.width * h->raw.height; + const unsigned black = dark ? MAX(h->black - dark->black, 0) : h->black; + if (h->colors == 3) + rgbWB[3] = rgbWB[1]; + if (dark) { +#ifdef _OPENMP + #pragma omp parallel for schedule(static) \ + shared(h,dark,rgbWB) +#endif + for (int i = 0; i < pixels; i++) { + int cc; + for (cc = 0; cc < 4; cc++) { + gint32 p = (gint64)(get_pixel(h, dark, i, cc, pixels) - black) * + rgbWB[cc] / 0x10000; + h->raw.image[i][cc] = MIN(MAX(p, 0), 0xFFFF); + } + } + } else { +#ifdef _OPENMP + #pragma omp parallel for schedule(static) \ + shared(h,dark,rgbWB) +#endif + for (int i = 0; i < pixels; i++) { + int cc; + for (cc = 0; cc < 4; cc++) + h->raw.image[i][cc] = MIN(MAX( + ((gint64)h->raw.image[i][cc] - black) * + rgbWB[cc] / 0x10000, 0), 0xFFFF); + } + } + } + + int dcraw_finalize_interpolate(dcraw_image_data *f, dcraw_data *h, + int interpolation, int smoothing) + { + DCRaw *d = (DCRaw *)h->dcraw; + int fujiWidth, i, r, c, cl; + unsigned ff, f4; + + g_free(d->messageBuffer); + d->messageBuffer = NULL; + d->lastStatus = DCRAW_SUCCESS; + + f->width = h->width; + f->height = h->height; + fujiWidth = h->fuji_width; + f->colors = h->colors; + f->image = (dcraw_image_type *) + g_realloc(f->image, f->height * f->width * sizeof(dcraw_image_type)); + memset(f->image, 0, f->height * f->width * sizeof(dcraw_image_type)); + + if (h->filters == 0) + return DCRAW_ERROR; + + cl = h->colors; + if (interpolation == dcraw_four_color_interpolation || h->colors == 4) { + ff = h->fourColorFilters; + cl = 4; + interpolation = dcraw_vng_interpolation; + } else { + ff = h->filters &= ~((h->filters & 0x55555555) << 1); + } + + /* It might be better to report an error here: */ + /* (dcraw also forbids AHD for Fuji rotated images) */ + if (h->filters == 9 && interpolation != dcraw_bilinear_interpolation) + interpolation = dcraw_xtrans_interpolation; + if (interpolation == dcraw_ahd_interpolation && h->colors > 3) + interpolation = dcraw_vng_interpolation; + if (interpolation == dcraw_ppg_interpolation && h->colors > 3) + interpolation = dcraw_vng_interpolation; + f4 = h->fourColorFilters; + if (h->filters == 1 || h->filters > 1000) { + for (r = 0; r < h->height; r++) + for (c = 0; c < h->width; c++) { + int cc = fcol_INDI(f4, r, c, h->top_margin, h->left_margin, h->xtrans); + f->image[r * f->width + c][fcol_INDI(ff, r, c, h->top_margin, h->left_margin, h->xtrans)] = + h->raw.image[r / 2 * h->raw.width + c / 2][cc]; + } + } else + memcpy(f->image, h->raw.image, h->height * h->width * sizeof(dcraw_image_type)); + int smoothPasses = 1; + if (interpolation == dcraw_bilinear_interpolation && (h->filters == 1 || h->filters > 1000)) + lin_interpolate_INDI(f->image, ff, f->width, f->height, cl, d, h); +#ifdef ENABLE_INTERP_NONE + else if (interpolation == dcraw_none_interpolation) + smoothing = 0; +#endif + else if (interpolation == dcraw_vng_interpolation || h->colors > 3) + vng_interpolate_INDI(f->image, ff, f->width, f->height, cl, 0xFFFF, d, h); + else if (interpolation == dcraw_ppg_interpolation && h->filters > 1000) + ppg_interpolate_INDI(f->image, ff, f->width, f->height, cl, d, h); + + else if (interpolation == dcraw_xtrans_interpolation) { + xtrans_interpolate_INDI(f->image, h->filters, f->width, f->height, + h->colors, h->rgb_cam, d, h, 3); + smoothPasses = 3; + } else if (interpolation == dcraw_ahd_interpolation) { + ahd_interpolate_INDI(f->image, ff, f->width, f->height, cl, + h->rgb_cam, d, h); + smoothPasses = 3; + } + if (smoothing) + color_smooth(f->image, f->width, f->height, smoothPasses); + + if (cl == 4 && h->colors == 3) { + for (i = 0; i < f->height * f->width; i++) + f->image[i][1] = (f->image[i][1] + f->image[i][3]) / 2; + } + fuji_rotate_INDI(&f->image, &f->height, &f->width, &fujiWidth, + f->colors, h->fuji_step, d); + + h->message = d->messageBuffer; + return d->lastStatus; + } + + void dcraw_close(dcraw_data *h) + { + DCRaw *d = (DCRaw *)h->dcraw; + g_free(h->raw.image); + delete d; + } + + char *ufraw_message(int code, char *message, ...); + + void DCRaw::dcraw_message(int code, const char *format, ...) + { + char *buf, *message; + va_list ap; + va_start(ap, format); + message = g_strdup_vprintf(format, ap); + va_end(ap); +#ifdef DEBUG + fprintf(stderr, message); +#endif + if (code == DCRAW_VERBOSE) + ufraw_message(code, message); + else { + if (messageBuffer == NULL) messageBuffer = g_strdup(message); + else { + buf = g_strconcat(messageBuffer, message, NULL); + g_free(messageBuffer); + messageBuffer = buf; + } + lastStatus = code; + } + g_free(message); + } + + void dcraw_message(void *dcraw, int code, char *format, ...) + { + char *message; + DCRaw *d = (DCRaw *)dcraw; + va_list ap; + va_start(ap, format); + message = g_strdup_vprintf(format, ap); + d->dcraw_message(code, message); + va_end(ap); + g_free(message); + } + +} /*extern "C"*/ diff --git a/plugins/load-dcraw/dcraw_api.h b/plugins/load-dcraw/dcraw_api.h new file mode 100644 index 00000000..e43b7b8d --- /dev/null +++ b/plugins/load-dcraw/dcraw_api.h @@ -0,0 +1,92 @@ +/* + * UFRaw - Unidentified Flying Raw converter for digital camera images + * + * dcraw_api.h - API for DCRaw + * Copyright 2004-2016 by Udi Fuchs + * + * based on dcraw by Dave Coffin + * http://www.cybercom.net/~dcoffin/ + * + * 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. + */ + +#ifndef _DCRAW_API_H +#define _DCRAW_API_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef guint16 dcraw_image_type[4]; + +typedef struct { + dcraw_image_type *image; + int width, height, colors; +} dcraw_image_data; + +typedef struct { + void *dcraw; + FILE *ifp; + int width, height, colors, fourColorFilters, raw_color; + unsigned filters; + int top_margin, left_margin, flip, shrink; + double pixel_aspect; + dcraw_image_data raw; + dcraw_image_type thresholds; + float pre_mul[4], post_mul[4], cam_mul[4], rgb_cam[3][4]; + double cam_rgb[4][3]; + int rgbMax, black, fuji_width; + double fuji_step; + short fuji_dr; + int toneCurveSize, toneCurveOffset; + int toneModeSize, toneModeOffset; + char *message, xtrans[6][6]; + float iso_speed, shutter, aperture, focal_len; + time_t timestamp; + char make[80], model[80]; + int thumbType, thumbOffset; + size_t thumbBufferLength; +} dcraw_data; + +enum { dcraw_ahd_interpolation, + dcraw_vng_interpolation, dcraw_four_color_interpolation, + dcraw_ppg_interpolation, dcraw_bilinear_interpolation, + dcraw_xtrans_interpolation, dcraw_none_interpolation + }; +enum { unknown_thumb_type, jpeg_thumb_type, ppm_thumb_type }; +int dcraw_open(dcraw_data *h, char *filename); +int dcraw_load_raw(dcraw_data *h); +int dcraw_load_thumb(dcraw_data *h, dcraw_image_data *thumb); +int dcraw_finalize_shrink(dcraw_image_data *f, dcraw_data *h, + int scale); +int dcraw_image_resize(dcraw_image_data *image, int size); +int dcraw_image_stretch(dcraw_image_data *image, double pixel_aspect); +int dcraw_flip_image(dcraw_image_data *image, int flip); +int dcraw_set_color_scale(dcraw_data *h, int useCameraWB); +void dcraw_wavelet_denoise(dcraw_data *h, float threshold); +void dcraw_wavelet_denoise_shrinked(dcraw_image_data *f, float threshold); +void dcraw_finalize_raw(dcraw_data *h, dcraw_data *dark, int rgbWB[4]); +int dcraw_finalize_interpolate(dcraw_image_data *f, dcraw_data *h, + int interpolation, int smoothing); +void dcraw_close(dcraw_data *h); +void dcraw_image_dimensions(dcraw_data *raw, int flip, int shrink, + int *height, int *width); + +#define DCRAW_SUCCESS 0 +#define DCRAW_ERROR 1 +#define DCRAW_UNSUPPORTED 2 +#define DCRAW_NO_CAMERA_WB 3 +#define DCRAW_VERBOSE 4 +#define DCRAW_WARNING 5 +#define DCRAW_OPEN_ERROR 6 + +void dcraw_message(void *dcraw, int code, char *format, ...); + +#ifdef __cplusplus +} +#endif + +#endif /*_DCRAW_API_H*/ diff --git a/plugins/load-dcraw/dcraw_indi.c b/plugins/load-dcraw/dcraw_indi.c new file mode 100644 index 00000000..a6e2a949 --- /dev/null +++ b/plugins/load-dcraw/dcraw_indi.c @@ -0,0 +1,1168 @@ +/* + * UFRaw - Unidentified Flying Raw converter for digital camera images + * + * dcraw_indi.c - DCRaw functions made independent + * Copyright 2004-2016 by Udi Fuchs + * + * based on dcraw by Dave Coffin + * http://www.cybercom.net/~dcoffin/ + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include /*For _(String) definition - NKBJ*/ +#include "dcraw_api.h" +#include "uf_progress.h" + +#ifdef _OPENMP +#include +#define uf_omp_get_thread_num() omp_get_thread_num() +#define uf_omp_get_num_threads() omp_get_num_threads() +#else +#define uf_omp_get_thread_num() 0 +#define uf_omp_get_num_threads() 1 +#endif + +#if !defined(ushort) +#define ushort unsigned short +#endif + +extern const double xyz_rgb[3][3]; +extern const float d65_white[3]; + +#define CLASS + +#define FORC(cnt) for (c=0; c < cnt; c++) +#define FORC3 FORC(3) +#define FORC4 FORC(4) +#define FORCC FORC(colors) + +#define SQR(x) ((x)*(x)) +#define LIM(x,min,max) MAX(min,MIN(x,max)) +#define ULIM(x,y,z) ((y) < (z) ? LIM(x,y,z) : LIM(x,z,y)) +#define CLIP(x) LIM((int)(x),0,65535) +#define SWAP(a,b) { a ^= b; a ^= (b ^= a); } + +/* + In order to inline this calculation, I make the risky + assumption that all filter patterns can be described + by a repeating pattern of eight rows and two columns + + Return values are either 0/1/2/3 = G/M/C/Y or 0/1/2/3 = R/G1/B/G2 + */ +#define FC(row,col) \ + (int)(filters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3) + +#define BAYER(row,col) \ + image[((row) >> shrink)*iwidth + ((col) >> shrink)][FC(row,col)] + +int CLASS fcol_INDI(const unsigned filters, const int row, const int col, + const int top_margin, const int left_margin, + /*const*/ char xtrans[6][6]) +{ + static const char filter[16][16] = { + { 2, 1, 1, 3, 2, 3, 2, 0, 3, 2, 3, 0, 1, 2, 1, 0 }, + { 0, 3, 0, 2, 0, 1, 3, 1, 0, 1, 1, 2, 0, 3, 3, 2 }, + { 2, 3, 3, 2, 3, 1, 1, 3, 3, 1, 2, 1, 2, 0, 0, 3 }, + { 0, 1, 0, 1, 0, 2, 0, 2, 2, 0, 3, 0, 1, 3, 2, 1 }, + { 3, 1, 1, 2, 0, 1, 0, 2, 1, 3, 1, 3, 0, 1, 3, 0 }, + { 2, 0, 0, 3, 3, 2, 3, 1, 2, 0, 2, 0, 3, 2, 2, 1 }, + { 2, 3, 3, 1, 2, 1, 2, 1, 2, 1, 1, 2, 3, 0, 0, 1 }, + { 1, 0, 0, 2, 3, 0, 0, 3, 0, 3, 0, 3, 2, 1, 2, 3 }, + { 2, 3, 3, 1, 1, 2, 1, 0, 3, 2, 3, 0, 2, 3, 1, 3 }, + { 1, 0, 2, 0, 3, 0, 3, 2, 0, 1, 1, 2, 0, 1, 0, 2 }, + { 0, 1, 1, 3, 3, 2, 2, 1, 1, 3, 3, 0, 2, 1, 3, 2 }, + { 2, 3, 2, 0, 0, 1, 3, 0, 2, 0, 1, 2, 3, 0, 1, 0 }, + { 1, 3, 1, 2, 3, 2, 3, 2, 0, 2, 0, 1, 1, 0, 3, 0 }, + { 0, 2, 0, 3, 1, 0, 0, 1, 1, 3, 3, 2, 3, 2, 2, 1 }, + { 2, 1, 3, 2, 3, 1, 2, 1, 0, 3, 0, 2, 0, 2, 0, 2 }, + { 0, 3, 1, 0, 0, 2, 0, 3, 2, 1, 3, 1, 1, 3, 1, 3 } + }; + + if (filters == 1) return filter[(row + top_margin) & 15][(col + left_margin) & 15]; + if (filters == 9) return xtrans[(row + 6) % 6][(col + 6) % 6]; + return FC(row, col); +} + +static void CLASS merror(void *ptr, char *where) +{ + if (ptr) return; + g_error("Out of memory in %s\n", where); +} + +static void CLASS hat_transform(float *temp, float *base, int st, int size, int sc) +{ + int i; + for (i = 0; i < sc; i++) + temp[i] = 2 * base[st * i] + base[st * (sc - i)] + base[st * (i + sc)]; + for (; i + sc < size; i++) + temp[i] = 2 * base[st * i] + base[st * (i - sc)] + base[st * (i + sc)]; + for (; i < size; i++) + temp[i] = 2 * base[st * i] + base[st * (i - sc)] + base[st * (2 * size - 2 - (i + sc))]; +} + +void CLASS wavelet_denoise_INDI(ushort(*image)[4], const int black, + const int iheight, const int iwidth, + const int height, const int width, + const int colors, const int shrink, + const float pre_mul[4], const float threshold, + const unsigned filters) +{ + float *fimg = 0, thold, mul[2], avg, diff; + int size, lev, hpass, lpass, row, col, nc, c, i, wlast; + ushort *window[4]; + static const float noise[] = + { 0.8002, 0.2735, 0.1202, 0.0585, 0.0291, 0.0152, 0.0080, 0.0044 }; + +// dcraw_message (dcraw, DCRAW_VERBOSE,_("Wavelet denoising...\n")); /*UF*/ + + /* Scaling is done somewhere else - NKBJ*/ + size = iheight * iwidth; + float temp[iheight + iwidth]; + if ((nc = colors) == 3 && filters) nc++; + progress(PROGRESS_WAVELET_DENOISE, -nc * 5); +#ifdef _OPENMP +#if defined(__sun) && !defined(__GNUC__) /* Fix bug #3205673 - NKBJ */ + #pragma omp parallel for \ + shared(nc,image,size,noise) \ + private(c,i,hpass,lev,lpass,row,col,thold,fimg,temp) +#else + #pragma omp parallel for \ + shared(nc,image,size) \ + private(c,i,hpass,lev,lpass,row,col,thold,fimg,temp) +#endif +#endif + FORC(nc) { /* denoise R,G1,B,G3 individually */ + fimg = (float *) malloc(size * 3 * sizeof * fimg); + for (i = 0; i < size; i++) + fimg[i] = 256 * sqrt(image[i][c] /*<< scale*/); + for (hpass = lev = 0; lev < 5; lev++) { + progress(PROGRESS_WAVELET_DENOISE, 1); + lpass = size * ((lev & 1) + 1); + for (row = 0; row < iheight; row++) { + hat_transform(temp, fimg + hpass + row * iwidth, 1, iwidth, 1 << lev); + for (col = 0; col < iwidth; col++) + fimg[lpass + row * iwidth + col] = temp[col] * 0.25; + } + for (col = 0; col < iwidth; col++) { + hat_transform(temp, fimg + lpass + col, iwidth, iheight, 1 << lev); + for (row = 0; row < iheight; row++) + fimg[lpass + row * iwidth + col] = temp[row] * 0.25; + } + thold = threshold * noise[lev]; + for (i = 0; i < size; i++) { + fimg[hpass + i] -= fimg[lpass + i]; + if (fimg[hpass + i] < -thold) fimg[hpass + i] += thold; + else if (fimg[hpass + i] > thold) fimg[hpass + i] -= thold; + else fimg[hpass + i] = 0; + if (hpass) fimg[i] += fimg[hpass + i]; + } + hpass = lpass; + } + for (i = 0; i < size; i++) + image[i][c] = CLIP(SQR(fimg[i] + fimg[lpass + i]) / 0x10000); + free(fimg); + } + if (filters && colors == 3) { /* pull G1 and G3 closer together */ + for (row = 0; row < 2; row++) + mul[row] = 0.125 * pre_mul[FC(row + 1, 0) | 1] / pre_mul[FC(row, 0) | 1]; + ushort window_mem[4][width]; + for (i = 0; i < 4; i++) + window[i] = window_mem[i]; /*(ushort *) fimg + width*i;*/ + for (wlast = -1, row = 1; row < height - 1; row++) { + while (wlast < row + 1) { + for (wlast++, i = 0; i < 4; i++) + window[(i + 3) & 3] = window[i]; + for (col = FC(wlast, 1) & 1; col < width; col += 2) + window[2][col] = BAYER(wlast, col); + } + thold = threshold / 512; + for (col = (FC(row, 0) & 1) + 1; col < width - 1; col += 2) { + avg = (window[0][col - 1] + window[0][col + 1] + + window[2][col - 1] + window[2][col + 1] - black * 4) + * mul[row & 1] + (window[1][col] - black) * 0.5 + black; + avg = avg < 0 ? 0 : sqrt(avg); + diff = sqrt(BAYER(row, col)) - avg; + if (diff < -thold) diff += thold; + else if (diff > thold) diff -= thold; + else diff = 0; + BAYER(row, col) = CLIP(SQR(avg + diff) + 0.5); + } + } + } +} + +void CLASS scale_colors_INDI(const int maximum, const int black, + const int use_camera_wb, const float cam_mul[4], const int colors, + float pre_mul[4], const unsigned filters, /*const*/ ushort white[8][8], + const char *ifname_display, void *dcraw) +{ + unsigned row, col, c, sum[8]; + int val; + double dmin, dmax; + + if (use_camera_wb && cam_mul[0] != -1) { + memset(sum, 0, sizeof sum); + for (row = 0; row < 8; row++) + for (col = 0; col < 8; col++) { + c = FC(row, col); + if ((val = white[row][col] - black) > 0) + sum[c] += val; + sum[c + 4]++; + } + if (sum[0] && sum[1] && sum[2] && sum[3]) + FORC4 pre_mul[c] = (float) sum[c + 4] / sum[c]; + else if (cam_mul[0] && cam_mul[2]) + /* 'sizeof pre_mul' does not work because pre_mul is an argument (UF)*/ + memcpy(pre_mul, cam_mul, 4 * sizeof(float)); + else + dcraw_message(dcraw, DCRAW_NO_CAMERA_WB, + _("%s: Cannot use camera white balance.\n"), ifname_display); + } else { + dcraw_message(dcraw, DCRAW_NO_CAMERA_WB, + _("%s: Cannot use camera white balance.\n"), ifname_display); + } + if (pre_mul[1] == 0) pre_mul[1] = 1; + if (pre_mul[3] == 0) pre_mul[3] = colors < 4 ? pre_mul[1] : 1; + for (dmin = DBL_MAX, dmax = c = 0; c < 4; c++) { + if (dmin > pre_mul[c]) + dmin = pre_mul[c]; + if (dmax < pre_mul[c]) + dmax = pre_mul[c]; + } + FORC4 pre_mul[c] /= dmax; + dcraw_message(dcraw, DCRAW_VERBOSE, + _("Scaling with darkness %d, saturation %d, and\nmultipliers"), + black, maximum); + FORC4 dcraw_message(dcraw, DCRAW_VERBOSE, " %f", pre_mul[c]); + dcraw_message(dcraw, DCRAW_VERBOSE, "\n"); + + /* The rest of the scaling is done somewhere else UF*/ +} + +void CLASS border_interpolate_INDI(const int height, const int width, + ushort(*image)[4], const unsigned filters, int colors, int border, dcraw_data *h) +{ + int row, col, y, x, f, c, sum[8]; + + for (row = 0; row < height; row++) + for (col = 0; col < width; col++) { + if (col == border && row >= border && row < height - border) + col = width - border; + memset(sum, 0, sizeof sum); + for (y = row - 1; y != row + 2; y++) + for (x = col - 1; x != col + 2; x++) + if (y >= 0 && y < height && x >= 0 && x < width) { + f = fcol_INDI(filters, y, x, h->top_margin, h->left_margin, h->xtrans); + sum[f] += image[y * width + x][f]; + sum[f + 4]++; + } + f = fcol_INDI(filters, row, col, h->top_margin, h->left_margin, h->xtrans); + FORCC if (c != f && sum[c + 4]) + image[row * width + col][c] = sum[c] / sum[c + 4]; + } +} + +void CLASS lin_interpolate_INDI(ushort(*image)[4], const unsigned filters, + const int width, const int height, const int colors, void *dcraw, dcraw_data *h) /*UF*/ +{ + int code[16][16][32], size = 16, *ip, sum[4]; + int f, c, i, x, y, row, col, shift, color; + ushort *pix; + + dcraw_message(dcraw, DCRAW_VERBOSE, _("Bilinear interpolation...\n")); /*UF*/ + if (filters == 9) size = 6; + border_interpolate_INDI(height, width, image, filters, colors, 1, h); + for (row = 0; row < size; row++) { + for (col = 0; col < size; col++) { + ip = code[row][col] + 1; + f = fcol_INDI(filters, row, col, h->top_margin, h->left_margin, h->xtrans); + memset(sum, 0, sizeof sum); + for (y = -1; y <= 1; y++) + for (x = -1; x <= 1; x++) { + shift = (y == 0) + (x == 0); + color = fcol_INDI(filters, row + y, col + x, h->top_margin, h->left_margin, h->xtrans); + if (color == f) continue; + *ip++ = (width * y + x) * 4 + color; + *ip++ = shift; + *ip++ = color; + sum[color] += 1 << shift; + } + code[row][col][0] = (ip - code[row][col]) / 3; + FORCC + if (c != f) { + *ip++ = c; + *ip++ = 256 / sum[c]; + } + } + } +#ifdef _OPENMP + #pragma omp parallel for default(shared) private(row,col,pix,ip,sum,i) +#endif + for (row = 1; row < height - 1; row++) { + for (col = 1; col < width - 1; col++) { + pix = image[row * width + col]; + ip = code[row % size][col % size]; + memset(sum, 0, sizeof sum); + for (i = *ip++; i--; ip += 3) + sum[ip[2]] += pix[ip[0]] << ip[1]; + for (i = colors; --i; ip += 2) + pix[ip[0]] = sum[ip[0]] * ip[1] >> 8; + } + } +} + +/* + This algorithm is officially called: + + "Interpolation using a Threshold-based variable number of gradients" + + described in http://scien.stanford.edu/class/psych221/projects/99/tingchen/algodep/vargra.html + + I've extended the basic idea to work with non-Bayer filter arrays. + Gradients are numbered clockwise from NW=0 to W=7. + */ +void CLASS vng_interpolate_INDI(ushort(*image)[4], const unsigned filters, + const int width, const int height, const int colors, void *dcraw, dcraw_data *h) /*UF*/ +{ + static const signed char *cp, terms[] = { + -2, -2, +0, -1, 0, 0x01, -2, -2, +0, +0, 1, 0x01, -2, -1, -1, +0, 0, 0x01, + -2, -1, +0, -1, 0, 0x02, -2, -1, +0, +0, 0, 0x03, -2, -1, +0, +1, 1, 0x01, + -2, +0, +0, -1, 0, 0x06, -2, +0, +0, +0, 1, 0x02, -2, +0, +0, +1, 0, 0x03, + -2, +1, -1, +0, 0, 0x04, -2, +1, +0, -1, 1, 0x04, -2, +1, +0, +0, 0, 0x06, + -2, +1, +0, +1, 0, 0x02, -2, +2, +0, +0, 1, 0x04, -2, +2, +0, +1, 0, 0x04, + -1, -2, -1, +0, 0, 0x80, -1, -2, +0, -1, 0, 0x01, -1, -2, +1, -1, 0, 0x01, + -1, -2, +1, +0, 1, 0x01, -1, -1, -1, +1, 0, 0x88, -1, -1, +1, -2, 0, 0x40, + -1, -1, +1, -1, 0, 0x22, -1, -1, +1, +0, 0, 0x33, -1, -1, +1, +1, 1, 0x11, + -1, +0, -1, +2, 0, 0x08, -1, +0, +0, -1, 0, 0x44, -1, +0, +0, +1, 0, 0x11, + -1, +0, +1, -2, 1, 0x40, -1, +0, +1, -1, 0, 0x66, -1, +0, +1, +0, 1, 0x22, + -1, +0, +1, +1, 0, 0x33, -1, +0, +1, +2, 1, 0x10, -1, +1, +1, -1, 1, 0x44, + -1, +1, +1, +0, 0, 0x66, -1, +1, +1, +1, 0, 0x22, -1, +1, +1, +2, 0, 0x10, + -1, +2, +0, +1, 0, 0x04, -1, +2, +1, +0, 1, 0x04, -1, +2, +1, +1, 0, 0x04, + +0, -2, +0, +0, 1, 0x80, +0, -1, +0, +1, 1, 0x88, +0, -1, +1, -2, 0, 0x40, + +0, -1, +1, +0, 0, 0x11, +0, -1, +2, -2, 0, 0x40, +0, -1, +2, -1, 0, 0x20, + +0, -1, +2, +0, 0, 0x30, +0, -1, +2, +1, 1, 0x10, +0, +0, +0, +2, 1, 0x08, + +0, +0, +2, -2, 1, 0x40, +0, +0, +2, -1, 0, 0x60, +0, +0, +2, +0, 1, 0x20, + +0, +0, +2, +1, 0, 0x30, +0, +0, +2, +2, 1, 0x10, +0, +1, +1, +0, 0, 0x44, + +0, +1, +1, +2, 0, 0x10, +0, +1, +2, -1, 1, 0x40, +0, +1, +2, +0, 0, 0x60, + +0, +1, +2, +1, 0, 0x20, +0, +1, +2, +2, 0, 0x10, +1, -2, +1, +0, 0, 0x80, + +1, -1, +1, +1, 0, 0x88, +1, +0, +1, +2, 0, 0x08, +1, +0, +2, -1, 0, 0x40, + +1, +0, +2, +1, 0, 0x10 + }, chood[] = { -1, -1, -1, 0, -1, +1, 0, +1, +1, +1, +1, 0, +1, -1, 0, -1 }; + ushort(*brow[4])[4], *pix; + int prow = 8, pcol = 2, *ip, *code[16][16], gval[8], gmin, gmax, sum[4]; + int row, col, x, y, x1, x2, y1, y2, t, weight, grads, color, diag; + int g, diff, thold, num, c; + ushort rowtmp[4][width * 4]; + + lin_interpolate_INDI(image, filters, width, height, colors, dcraw, h); /*UF*/ + dcraw_message(dcraw, DCRAW_VERBOSE, _("VNG interpolation...\n")); /*UF*/ + + if (filters == 1) prow = pcol = 16; + if (filters == 9) prow = pcol = 6; + int *ipalloc = ip = (int *) calloc(prow * pcol, 1280); + merror(ip, "vng_interpolate()"); + for (row = 0; row < prow; row++) /* Precalculate for VNG */ + for (col = 0; col < pcol; col++) { + code[row][col] = ip; + for (cp = terms, t = 0; t < 64; t++) { + y1 = *cp++; + x1 = *cp++; + y2 = *cp++; + x2 = *cp++; + weight = *cp++; + grads = *cp++; + color = fcol_INDI(filters, row + y1, col + x1, h->top_margin, h->left_margin, h->xtrans); + if (fcol_INDI(filters, row + y2, col + x2, h->top_margin, h->left_margin, h->xtrans) != color) continue; + diag = (fcol_INDI(filters, row, col + 1, h->top_margin, h->left_margin, h->xtrans) == color && fcol_INDI(filters, row + 1, col, h->top_margin, h->left_margin, h->xtrans) == color) ? 2 : 1; + if (abs(y1 - y2) == diag && abs(x1 - x2) == diag) continue; + *ip++ = (y1 * width + x1) * 4 + color; + *ip++ = (y2 * width + x2) * 4 + color; + *ip++ = weight; + for (g = 0; g < 8; g++) + if (grads & 1 << g) *ip++ = g; + *ip++ = -1; + } + *ip++ = INT_MAX; + for (cp = chood, g = 0; g < 8; g++) { + y = *cp++; + x = *cp++; + *ip++ = (y * width + x) * 4; + color = fcol_INDI(filters, row, col, h->top_margin, h->left_margin, h->xtrans); + if (fcol_INDI(filters, row + y, col + x, h->top_margin, h->left_margin, h->xtrans) != color && fcol_INDI(filters, row + y * 2, col + x * 2, h->top_margin, h->left_margin, h->xtrans) == color) + *ip++ = (y * width + x) * 8 + color; + else + *ip++ = 0; + } + } + progress(PROGRESS_INTERPOLATE, -height); +#ifdef _OPENMP + #pragma omp parallel \ + shared(image,code,prow,pcol,h) \ + private(row,col,g,brow,rowtmp,pix,ip,gval,diff,gmin,gmax,thold,sum,color,num,c,t) +#endif + { + int slice = (height - 4) / uf_omp_get_num_threads(); + int start_row = 2 + slice * uf_omp_get_thread_num(); + int end_row = MIN(start_row + slice, height - 2); + for (row = start_row; row < end_row; row++) { /* Do VNG interpolation */ + progress(PROGRESS_INTERPOLATE, 1); + for (g = 0; g < 4; g++) + brow[g] = &rowtmp[(row + g - 2) % 4]; + for (col = 2; col < width - 2; col++) { + pix = image[row * width + col]; + ip = code[row % prow][col % pcol]; + memset(gval, 0, sizeof gval); + while ((g = ip[0]) != INT_MAX) { /* Calculate gradients */ + diff = ABS(pix[g] - pix[ip[1]]) << ip[2]; + gval[ip[3]] += diff; + ip += 5; + if ((g = ip[-1]) == -1) continue; + gval[g] += diff; + while ((g = *ip++) != -1) + gval[g] += diff; + } + ip++; + gmin = gmax = gval[0]; /* Choose a threshold */ + for (g = 1; g < 8; g++) { + if (gmin > gval[g]) gmin = gval[g]; + if (gmax < gval[g]) gmax = gval[g]; + } + if (gmax == 0) { + memcpy(brow[2][col], pix, sizeof * image); + continue; + } + thold = gmin + (gmax >> 1); + memset(sum, 0, sizeof sum); + color = fcol_INDI(filters, row, col, h->top_margin, h->left_margin, h->xtrans); + for (num = g = 0; g < 8; g++, ip += 2) { /* Average the neighbors */ + if (gval[g] <= thold) { + FORCC + if (c == color && ip[1]) + sum[c] += (pix[c] + pix[ip[1]]) >> 1; + else + sum[c] += pix[ip[0] + c]; + num++; + } + } + FORCC { /* Save to buffer */ + t = pix[color]; + if (c != color) + t += (sum[c] - sum[color]) / num; + brow[2][col][c] = CLIP(t); + } + } + /* Write buffer to image */ + if ((row > start_row + 1) || (row == height - 2)) + memcpy(image[(row - 2)*width + 2], brow[0] + 2, (width - 4)*sizeof * image); + if (row == height - 2) { + memcpy(image[(row - 1)*width + 2], brow[1] + 2, (width - 4)*sizeof * image); + break; + } + } + } + free(ipalloc); +} + +/* + Patterned Pixel Grouping Interpolation by Alain Desbiolles +*/ +void CLASS ppg_interpolate_INDI(ushort(*image)[4], const unsigned filters, + const int width, const int height, + const int colors, void *dcraw, dcraw_data *h) +{ + int dir[5] = { 1, width, -1, -width, 1 }; + int row, col, diff[2] = { 0, 0 }, guess[2], c, d, i; + ushort(*pix)[4]; + + border_interpolate_INDI(height, width, image, filters, colors, 3, h); + dcraw_message(dcraw, DCRAW_VERBOSE, _("PPG interpolation...\n")); /*UF*/ + +#ifdef _OPENMP + #pragma omp parallel \ + shared(image,dir,diff) \ + private(row,col,i,d,c,pix,guess) +#endif + { + /* Fill in the green layer with gradients and pattern recognition: */ +#ifdef _OPENMP + #pragma omp for +#endif + for (row = 3; row < height - 3; row++) { + for (col = 3 + (FC(row, 3) & 1), c = FC(row, col); col < width - 3; col += 2) { + pix = image + row * width + col; + for (i = 0; (d = dir[i]) > 0; i++) { + guess[i] = (pix[-d][1] + pix[0][c] + pix[d][1]) * 2 + - pix[-2 * d][c] - pix[2 * d][c]; + diff[i] = (ABS(pix[-2 * d][c] - pix[ 0][c]) + + ABS(pix[ 2 * d][c] - pix[ 0][c]) + + ABS(pix[ -d][1] - pix[ d][1])) * 3 + + (ABS(pix[ 3 * d][1] - pix[ d][1]) + + ABS(pix[-3 * d][1] - pix[-d][1])) * 2; + } + d = dir[i = diff[0] > diff[1]]; + pix[0][1] = ULIM(guess[i] >> 2, pix[d][1], pix[-d][1]); + } + } + /* Calculate red and blue for each green pixel: */ +#ifdef _OPENMP + #pragma omp for +#endif + for (row = 1; row < height - 1; row++) { + for (col = 1 + (FC(row, 2) & 1), c = FC(row, col + 1); col < width - 1; col += 2) { + pix = image + row * width + col; + for (i = 0; (d = dir[i]) > 0; c = 2 - c, i++) + pix[0][c] = CLIP((pix[-d][c] + pix[d][c] + 2 * pix[0][1] + - pix[-d][1] - pix[d][1]) >> 1); + } + } + /* Calculate blue for red pixels and vice versa: */ +#ifdef _OPENMP + #pragma omp for +#endif + for (row = 1; row < height - 1; row++) { + for (col = 1 + (FC(row, 1) & 1), c = 2 - FC(row, col); col < width - 1; col += 2) { + pix = image + row * width + col; + for (i = 0; (d = dir[i] + dir[i + 1]) > 0; i++) { + diff[i] = ABS(pix[-d][c] - pix[d][c]) + + ABS(pix[-d][1] - pix[0][1]) + + ABS(pix[ d][1] - pix[0][1]); + guess[i] = pix[-d][c] + pix[d][c] + 2 * pix[0][1] + - pix[-d][1] - pix[d][1]; + } + if (diff[0] != diff[1]) + pix[0][c] = CLIP(guess[diff[0] > diff[1]] >> 1); + else + pix[0][c] = CLIP((guess[0] + guess[1]) >> 2); + } + } + } +} + +void CLASS cielab_INDI(ushort rgb[3], short lab[3], const int colors, + const float rgb_cam[3][4]) +{ + int c, i, j, k; + float r, xyz[3]; + static float cbrt[0x10000], xyz_cam[3][4]; + + if (!rgb) { + for (i = 0; i < 0x10000; i++) { + r = i / 65535.0; + cbrt[i] = r > 0.008856 ? pow(r, (float)(1 / 3.0)) : 7.787 * r + 16 / 116.0; + } + for (i = 0; i < 3; i++) + for (j = 0; j < colors; j++) + for (xyz_cam[i][j] = k = 0; k < 3; k++) + xyz_cam[i][j] += xyz_rgb[i][k] * rgb_cam[k][j] / d65_white[i]; + return; + } + xyz[0] = xyz[1] = xyz[2] = 0.5; + FORCC { + xyz[0] += xyz_cam[0][c] * rgb[c]; + xyz[1] += xyz_cam[1][c] * rgb[c]; + xyz[2] += xyz_cam[2][c] * rgb[c]; + } + xyz[0] = cbrt[CLIP((int) xyz[0])]; + xyz[1] = cbrt[CLIP((int) xyz[1])]; + xyz[2] = cbrt[CLIP((int) xyz[2])]; + lab[0] = 64 * (116 * xyz[1] - 16); + lab[1] = 64 * 500 * (xyz[0] - xyz[1]); + lab[2] = 64 * 200 * (xyz[1] - xyz[2]); +} + +#define TS 512 /* Tile Size */ +/* + Frank Markesteijn's algorithm for Fuji X-Trans sensors + */ +void CLASS xtrans_interpolate_INDI(ushort(*image)[4], const unsigned filters, + const int width, const int height, + const int colors, const float rgb_cam[3][4], + void *dcraw, dcraw_data *hh, const int passes) +{ + int c, d, f, g, h, i, v, ng, row, col, top, left, mrow, mcol; + int val, ndir, pass, hm[8], avg[4], color[3][8]; + static const short orth[12] = { 1, 0, 0, 1, -1, 0, 0, -1, 1, 0, 0, 1 }, + patt[2][16] = { { 0, 1, 0, -1, 2, 0, -1, 0, 1, 1, 1, -1, 0, 0, 0, 0 }, + { 0, 1, 0, -2, 1, 0, -2, 0, 1, 1, -2, -2, 1, -1, -1, 1 } + }, + dir[4] = { 1, TS, TS + 1, TS - 1 }; + short allhex[3][3][2][8], *hex; + ushort min, max, sgrow = 0, sgcol = 0; + ushort(*rgb)[TS][TS][3], (*rix)[3], (*pix)[4]; + short(*lab) [TS][3], (*lix)[3]; + float(*drv)[TS][TS], diff[6], tr; + char(*homo)[TS][TS], *buffer; + + dcraw_message(dcraw, DCRAW_VERBOSE, _("%d-pass X-Trans interpolation...\n"), passes); /*NKBJ*/ + + cielab_INDI(0, 0, colors, rgb_cam); + ndir = 4 << (passes > 1); + + /* Map a green hexagon around each non-green pixel and vice versa: */ + for (row = 0; row < 3; row++) + for (col = 0; col < 3; col++) + for (ng = d = 0; d < 10; d += 2) { + g = fcol_INDI(filters, row, col, hh->top_margin, hh->left_margin, hh->xtrans) == 1; + if (fcol_INDI(filters, row + orth[d], col + orth[d + 2], hh->top_margin, hh->left_margin, hh->xtrans) == 1) ng = 0; + else ng++; + if (ng == 4) { + sgrow = row; + sgcol = col; + } + if (ng == g + 1) FORC(8) { + v = orth[d ] * patt[g][c * 2] + orth[d + 1] * patt[g][c * 2 + 1]; + h = orth[d + 2] * patt[g][c * 2] + orth[d + 3] * patt[g][c * 2 + 1]; + allhex[row][col][0][c ^ (g * 2 & d)] = h + v * width; + allhex[row][col][1][c ^ (g * 2 & d)] = h + v * TS; + } + } + + /* Set green1 and green3 to the minimum and maximum allowed values: */ + for (row = 2; row < height - 2; row++) + for (min = ~(max = 0), col = 2; col < width - 2; col++) { + if (fcol_INDI(filters, row, col, hh->top_margin, hh->left_margin, hh->xtrans) == 1 && (min = ~(max = 0))) continue; + pix = image + row * width + col; + hex = allhex[row % 3][col % 3][0]; + if (!max) FORC(6) { + val = pix[hex[c]][1]; + if (min > val) min = val; + if (max < val) max = val; + } + pix[0][1] = min; + pix[0][3] = max; + switch ((row - sgrow) % 3) { + case 1: + if (row < height - 3) { + row++; + col--; + } + break; + case 2: + if ((min = ~(max = 0)) && (col += 2) < width - 3 && row > 2) row--; + } + } + + +#ifdef _OPENMP + #pragma omp parallel \ + default(shared) \ + private(top, left, row, col, pix, mrow, mcol, hex, color, c, pass, rix, val, d, f, g, h, i, diff, lix, tr, avg, v, buffer, rgb, lab, drv, homo, hm, max) +#endif + { + buffer = (char *) malloc(TS * TS * (ndir * 11 + 6)); + merror(buffer, "xtrans_interpolate()"); + rgb = (ushort(*)[TS][TS][3]) buffer; + lab = (short(*) [TS][3])(buffer + TS * TS * (ndir * 6)); + drv = (float(*)[TS][TS])(buffer + TS * TS * (ndir * 6 + 6)); + homo = (char(*)[TS][TS])(buffer + TS * TS * (ndir * 10 + 6)); + + progress(PROGRESS_INTERPOLATE, -height); + +#ifdef _OPENMP + #pragma omp for +#endif + + for (top = 3; top < height - 19; top += TS - 16) { + progress(PROGRESS_INTERPOLATE, TS - 16); + for (left = 3; left < width - 19; left += TS - 16) { + mrow = MIN(top + TS, height - 3); + mcol = MIN(left + TS, width - 3); + for (row = top; row < mrow; row++) + for (col = left; col < mcol; col++) + memcpy(rgb[0][row - top][col - left], image[row * width + col], 6); + FORC3 memcpy(rgb[c + 1], rgb[0], sizeof * rgb); + + /* Interpolate green horizontally, vertically, and along both diagonals: */ + for (row = top; row < mrow; row++) + for (col = left; col < mcol; col++) { + if ((f = fcol_INDI(filters, row, col, hh->top_margin, hh->left_margin, hh->xtrans)) == 1) continue; + pix = image + row * width + col; + hex = allhex[row % 3][col % 3][0]; + color[1][0] = 174 * (pix[ hex[1]][1] + pix[ hex[0]][1]) - + 46 * (pix[2 * hex[1]][1] + pix[2 * hex[0]][1]); + color[1][1] = 223 * pix[ hex[3]][1] + pix[ hex[2]][1] * 33 + + 92 * (pix[ 0 ][f] - pix[ -hex[2]][f]); + FORC(2) color[1][2 + c] = + 164 * pix[hex[4 + c]][1] + 92 * pix[-2 * hex[4 + c]][1] + 33 * + (2 * pix[0][f] - pix[3 * hex[4 + c]][f] - pix[-3 * hex[4 + c]][f]); + FORC4 rgb[c ^ !((row - sgrow) % 3)][row - top][col - left][1] = + LIM(color[1][c] >> 8, pix[0][1], pix[0][3]); + } + + for (pass = 0; pass < passes; pass++) { + if (pass == 1) + memcpy(rgb += 4, buffer, 4 * sizeof * rgb); + + /* Recalculate green from interpolated values of closer pixels: */ + if (pass) { + for (row = top + 2; row < mrow - 2; row++) + for (col = left + 2; col < mcol - 2; col++) { + if ((f = fcol_INDI(filters, row, col, hh->top_margin, hh->left_margin, hh->xtrans)) == 1) continue; + pix = image + row * width + col; + hex = allhex[row % 3][col % 3][1]; + for (d = 3; d < 6; d++) { + rix = &rgb[(d - 2) ^ !((row - sgrow) % 3)][row - top][col - left]; + val = rix[-2 * hex[d]][1] + 2 * rix[hex[d]][1] + - rix[-2 * hex[d]][f] - 2 * rix[hex[d]][f] + 3 * rix[0][f]; + rix[0][1] = LIM(val / 3, pix[0][1], pix[0][3]); + } + } + } + + /* Interpolate red and blue values for solitary green pixels: */ + for (row = (top - sgrow + 4) / 3 * 3 + sgrow; row < mrow - 2; row += 3) + for (col = (left - sgcol + 4) / 3 * 3 + sgcol; col < mcol - 2; col += 3) { + rix = &rgb[0][row - top][col - left]; + h = fcol_INDI(filters, row, col + 1, hh->top_margin, hh->left_margin, hh->xtrans); + memset(diff, 0, sizeof diff); + for (i = 1, d = 0; d < 6; d++, i ^= TS ^ 1, h ^= 2) { + for (c = 0; c < 2; c++, h ^= 2) { + g = 2 * rix[0][1] - rix[i << c][1] - rix[-i << c][1]; + color[h][d] = g + rix[i << c][h] + rix[-i << c][h]; + if (d > 1) + diff[d] += SQR(rix[i << c][1] - rix[-i << c][1] + - rix[i << c][h] + rix[-i << c][h]) + SQR(g); + } + if (d > 1 && (d & 1)) + if (diff[d - 1] < diff[d]) + FORC(2) color[c * 2][d] = color[c * 2][d - 1]; + if (d < 2 || (d & 1)) { + FORC(2) rix[0][c * 2] = CLIP(color[c * 2][d] / 2); + rix += TS * TS; + } + } + } + + /* Interpolate red for blue pixels and vice versa: */ + for (row = top + 3; row < mrow - 3; row++) + for (col = left + 3; col < mcol - 3; col++) { + if ((f = 2 - fcol_INDI(filters, row, col, hh->top_margin, hh->left_margin, hh->xtrans)) == 1) continue; + rix = &rgb[0][row - top][col - left]; + c = (row - sgrow) % 3 ? TS : 1; + h = 3 * (c ^ TS ^ 1); + for (d = 0; d < 4; d++, rix += TS * TS) { + i = d > 1 || ((d ^ c) & 1) || + ((ABS(rix[0][1] - rix[c][1]) + ABS(rix[0][1] - rix[-c][1])) < + 2 * (ABS(rix[0][1] - rix[h][1]) + ABS(rix[0][1] - rix[-h][1]))) ? c : h; + rix[0][f] = CLIP((rix[i][f] + rix[-i][f] + + 2 * rix[0][1] - rix[i][1] - rix[-i][1]) / 2); + } + } + + /* Fill in red and blue for 2x2 blocks of green: */ + for (row = top + 2; row < mrow - 2; row++) if ((row - sgrow) % 3) + for (col = left + 2; col < mcol - 2; col++) if ((col - sgcol) % 3) { + rix = &rgb[0][row - top][col - left]; + hex = allhex[row % 3][col % 3][1]; + for (d = 0; d < ndir; d += 2, rix += TS * TS) + if (hex[d] + hex[d + 1]) { + g = 3 * rix[0][1] - 2 * rix[hex[d]][1] - rix[hex[d + 1]][1]; + for (c = 0; c < 4; c += 2) rix[0][c] = + CLIP((g + 2 * rix[hex[d]][c] + rix[hex[d + 1]][c]) / 3); + } else { + g = 2 * rix[0][1] - rix[hex[d]][1] - rix[hex[d + 1]][1]; + for (c = 0; c < 4; c += 2) rix[0][c] = + CLIP((g + rix[hex[d]][c] + rix[hex[d + 1]][c]) / 2); + } + } + } + rgb = (ushort(*)[TS][TS][3]) buffer; + mrow -= top; + mcol -= left; + + /* Convert to CIELab and differentiate in all directions: */ + for (d = 0; d < ndir; d++) { + for (row = 2; row < mrow - 2; row++) + for (col = 2; col < mcol - 2; col++) + cielab_INDI(rgb[d][row][col], lab[row][col], colors, rgb_cam); + for (f = dir[d & 3], row = 3; row < mrow - 3; row++) + for (col = 3; col < mcol - 3; col++) { + lix = &lab[row][col]; + g = 2 * lix[0][0] - lix[f][0] - lix[-f][0]; + drv[d][row][col] = SQR(g) + + SQR((2 * lix[0][1] - lix[f][1] - lix[-f][1] + g * 500 / 232)) + + SQR((2 * lix[0][2] - lix[f][2] - lix[-f][2] - g * 500 / 580)); + } + } + + /* Build homogeneity maps from the derivatives: */ + memset(homo, 0, ndir * TS * TS); + for (row = 4; row < mrow - 4; row++) + for (col = 4; col < mcol - 4; col++) { + for (tr = FLT_MAX, d = 0; d < ndir; d++) + if (tr > drv[d][row][col]) + tr = drv[d][row][col]; + tr *= 8; + for (d = 0; d < ndir; d++) + for (v = -1; v <= 1; v++) + for (h = -1; h <= 1; h++) + if (drv[d][row + v][col + h] <= tr) + homo[d][row][col]++; + } + + /* Average the most homogenous pixels for the final result: */ + if (height - top < TS + 4) mrow = height - top + 2; + if (width - left < TS + 4) mcol = width - left + 2; + for (row = MIN(top, 8); row < mrow - 8; row++) + for (col = MIN(left, 8); col < mcol - 8; col++) { + for (d = 0; d < ndir; d++) + for (hm[d] = 0, v = -2; v <= 2; v++) + for (h = -2; h <= 2; h++) + hm[d] += homo[d][row + v][col + h]; + for (d = 0; d < ndir - 4; d++) + if (hm[d] < hm[d + 4]) hm[d ] = 0; + else if (hm[d] > hm[d + 4]) hm[d + 4] = 0; + for (max = hm[0], d = 1; d < ndir; d++) + if (max < hm[d]) max = hm[d]; + max -= max >> 3; + memset(avg, 0, sizeof avg); + for (d = 0; d < ndir; d++) + if (hm[d] >= max) { + FORC3 avg[c] += rgb[d][row][col][c]; + avg[3]++; + } + FORC3 image[(row + top)*width + col + left][c] = avg[c] / avg[3]; + } + } + } + free(buffer); + } /* _OPENMP */ + border_interpolate_INDI(height, width, image, filters, colors, 8, hh); +} + +/* + Adaptive Homogeneity-Directed interpolation is based on + the work of Keigo Hirakawa, Thomas Parks, and Paul Lee. + */ +void CLASS ahd_interpolate_INDI(ushort(*image)[4], const unsigned filters, + const int width, const int height, + const int colors, const float rgb_cam[3][4], + void *dcraw, dcraw_data *h) +{ + int i, j, top, left, row, col, tr, tc, c, d, val, hm[2]; + static const int dir[4] = { -1, 1, -TS, TS }; + unsigned ldiff[2][4], abdiff[2][4], leps, abeps; + ushort(*rgb)[TS][TS][3], (*rix)[3], (*pix)[4]; + short(*lab)[TS][TS][3], (*lix)[3]; + char(*homo)[TS][TS], *buffer; + + dcraw_message(dcraw, DCRAW_VERBOSE, _("AHD interpolation...\n")); /*UF*/ + +#ifdef _OPENMP + #pragma omp parallel \ + default(shared) \ + private(top, left, row, col, pix, rix, lix, c, val, d, tc, tr, i, j, ldiff, abdiff, leps, abeps, hm, buffer, rgb, lab, homo) +#endif + { + cielab_INDI(0, 0, colors, rgb_cam); + border_interpolate_INDI(height, width, image, filters, colors, 5, h); + buffer = (char *) malloc(26 * TS * TS); + merror(buffer, "ahd_interpolate()"); + rgb = (ushort(*)[TS][TS][3]) buffer; + lab = (short(*)[TS][TS][3])(buffer + 12 * TS * TS); + homo = (char(*)[TS][TS])(buffer + 24 * TS * TS); + + progress(PROGRESS_INTERPOLATE, -height); +#ifdef _OPENMP + #pragma omp for +#endif + for (top = 2; top < height - 5; top += TS - 6) { + progress(PROGRESS_INTERPOLATE, TS - 6); + for (left = 2; left < width - 5; left += TS - 6) { + + /* Interpolate green horizontally and vertically: */ + for (row = top; row < top + TS && row < height - 2; row++) { + col = left + (FC(row, left) & 1); + for (c = FC(row, col); col < left + TS && col < width - 2; col += 2) { + pix = image + row * width + col; + val = ((pix[-1][1] + pix[0][c] + pix[1][1]) * 2 + - pix[-2][c] - pix[2][c]) >> 2; + rgb[0][row - top][col - left][1] = ULIM(val, pix[-1][1], pix[1][1]); + val = ((pix[-width][1] + pix[0][c] + pix[width][1]) * 2 + - pix[-2 * width][c] - pix[2 * width][c]) >> 2; + rgb[1][row - top][col - left][1] = ULIM(val, pix[-width][1], pix[width][1]); + } + } + /* Interpolate red and blue, and convert to CIELab: */ + for (d = 0; d < 2; d++) + for (row = top + 1; row < top + TS - 1 && row < height - 3; row++) + for (col = left + 1; col < left + TS - 1 && col < width - 3; col++) { + pix = image + row * width + col; + rix = &rgb[d][row - top][col - left]; + lix = &lab[d][row - top][col - left]; + if ((c = 2 - FC(row, col)) == 1) { + c = FC(row + 1, col); + val = pix[0][1] + ((pix[-1][2 - c] + pix[1][2 - c] + - rix[-1][1] - rix[1][1]) >> 1); + rix[0][2 - c] = CLIP(val); + val = pix[0][1] + ((pix[-width][c] + pix[width][c] + - rix[-TS][1] - rix[TS][1]) >> 1); + } else + val = rix[0][1] + ((pix[-width - 1][c] + pix[-width + 1][c] + + pix[+width - 1][c] + pix[+width + 1][c] + - rix[-TS - 1][1] - rix[-TS + 1][1] + - rix[+TS - 1][1] - rix[+TS + 1][1] + 1) >> 2); + rix[0][c] = CLIP(val); + c = FC(row, col); + rix[0][c] = pix[0][c]; + cielab_INDI(rix[0], lix[0], colors, rgb_cam); + } + /* Build homogeneity maps from the CIELab images: */ + memset(homo, 0, 2 * TS * TS); + for (row = top + 2; row < top + TS - 2 && row < height - 4; row++) { + tr = row - top; + for (col = left + 2; col < left + TS - 2 && col < width - 4; col++) { + tc = col - left; + for (d = 0; d < 2; d++) { + lix = &lab[d][tr][tc]; + for (i = 0; i < 4; i++) { + ldiff[d][i] = ABS(lix[0][0] - lix[dir[i]][0]); + abdiff[d][i] = SQR(lix[0][1] - lix[dir[i]][1]) + + SQR(lix[0][2] - lix[dir[i]][2]); + } + } + leps = MIN(MAX(ldiff[0][0], ldiff[0][1]), + MAX(ldiff[1][2], ldiff[1][3])); + abeps = MIN(MAX(abdiff[0][0], abdiff[0][1]), + MAX(abdiff[1][2], abdiff[1][3])); + for (d = 0; d < 2; d++) + for (i = 0; i < 4; i++) + if (ldiff[d][i] <= leps && abdiff[d][i] <= abeps) + homo[d][tr][tc]++; + } + } + /* Combine the most homogenous pixels for the final result: */ + for (row = top + 3; row < top + TS - 3 && row < height - 5; row++) { + tr = row - top; + for (col = left + 3; col < left + TS - 3 && col < width - 5; col++) { + tc = col - left; + for (d = 0; d < 2; d++) + for (hm[d] = 0, i = tr - 1; i <= tr + 1; i++) + for (j = tc - 1; j <= tc + 1; j++) + hm[d] += homo[d][i][j]; + if (hm[0] != hm[1]) + FORC3 image[row * width + col][c] = rgb[hm[1] > hm[0]][tr][tc][c]; + else + FORC3 image[row * width + col][c] = + (rgb[0][tr][tc][c] + rgb[1][tr][tc][c]) >> 1; + } + } + } + } + free(buffer); + } /* _OPENMP */ +} +#undef TS + + +#define DTOP(x) ((x>65535) ? (unsigned short)65535 : (x<0) ? (unsigned short)0 : (unsigned short) x) + +/* + * MG - This comment applies to the 3x3 optimized median function + * + * The following routines have been built from knowledge gathered + * around the Web. I am not aware of any copyright problem with + * them, so use it as you want. + * N. Devillard - 1998 + */ + +#define PIX_SORT(a,b) { if ((a)>(b)) PIX_SWAP((a),(b)); } +#define PIX_SWAP(a,b) { int temp=(a);(a)=(b);(b)=temp; } + +static inline int median9(int *p) +{ + PIX_SORT(p[1], p[2]) ; + PIX_SORT(p[4], p[5]) ; + PIX_SORT(p[7], p[8]) ; + PIX_SORT(p[0], p[1]) ; + PIX_SORT(p[3], p[4]) ; + PIX_SORT(p[6], p[7]) ; + PIX_SORT(p[1], p[2]) ; + PIX_SORT(p[4], p[5]) ; + PIX_SORT(p[7], p[8]) ; + PIX_SORT(p[0], p[3]) ; + PIX_SORT(p[5], p[8]) ; + PIX_SORT(p[4], p[7]) ; + PIX_SORT(p[3], p[6]) ; + PIX_SORT(p[1], p[4]) ; + PIX_SORT(p[2], p[5]) ; + PIX_SORT(p[4], p[7]) ; + PIX_SORT(p[4], p[2]) ; + PIX_SORT(p[6], p[4]) ; + PIX_SORT(p[4], p[2]) ; + return (p[4]) ; +} + +#undef PIX_SWAP +#undef PIX_SORT + +// Just making this function inline speeds up ahd_interpolate_INDI() up to 15% +static inline ushort eahd_median(int row, int col, int color, + ushort(*image)[4], const int width) +{ + //declare the pixel array + int pArray[9]; + int result; + + //perform the median filter (this only works for red or blue) + // result = median(R-G)+G or median(B-G)+G + // + // to perform the filter on green, it needs to be the average + // results = (median(G-R)+median(G-B)+R+B)/2 + + //no checks are done here to speed up the inlining + pArray[0] = image[width * (row) + col + 1][color] - image[width * (row) + col + 1][1]; + pArray[1] = image[width * (row - 1) + col + 1][color] - image[width * (row - 1) + col + 1][1]; + pArray[2] = image[width * (row - 1) + col ][color] - image[width * (row - 1) + col ][1]; + pArray[3] = image[width * (row - 1) + col - 1][color] - image[width * (row - 1) + col - 1][1]; + pArray[4] = image[width * (row) + col - 1][color] - image[width * (row) + col - 1][1]; + pArray[5] = image[width * (row + 1) + col - 1][color] - image[width * (row + 1) + col - 1][1]; + pArray[6] = image[width * (row + 1) + col ][color] - image[width * (row + 1) + col ][1]; + pArray[7] = image[width * (row + 1) + col + 1][color] - image[width * (row + 1) + col + 1][1]; + pArray[8] = image[width * (row) + col ][color] - image[width * (row) + col ][1]; + + median9(pArray); + result = pArray[4] + image[width * (row) + col ][1]; + return DTOP(result); + +} + +// Add the color smoothing from Kimmel as suggested in the AHD paper +// Algorithm updated by Michael Goertz +void CLASS color_smooth(ushort(*image)[4], const int width, const int height, + const int passes) +{ + int row, col; + int row_start = 2; + int row_stop = height - 2; + int col_start = 2; + int col_stop = width - 2; + //interate through all the colors + int count; + + ushort *mpix; + + for (count = 0; count < passes; count++) { + //perform 3 iterations - seems to be a commonly settled upon number of iterations +#ifdef _OPENMP + #pragma omp parallel for default(shared) private(row,col,mpix) +#endif + for (row = row_start; row < row_stop; row++) { + for (col = col_start; col < col_stop; col++) { + //calculate the median only over the red and blue + //calculating over green seems to offer very little additional quality + mpix = image[row * width + col]; + mpix[0] = eahd_median(row, col, 0, image, width); + mpix[2] = eahd_median(row, col, 2, image, width); + } + } + } +} + +void CLASS fuji_rotate_INDI(ushort(**image_p)[4], int *height_p, + int *width_p, int *fuji_width_p, const int colors, + const double step, void *dcraw) +{ + int height = *height_p, width = *width_p, fuji_width = *fuji_width_p; /*UF*/ + ushort(*image)[4] = *image_p; /*UF*/ + int i, row, col; + float r, c, fr, fc; + int ur, uc; + ushort wide, high, (*img)[4], (*pix)[4]; + + if (!fuji_width) return; + dcraw_message(dcraw, DCRAW_VERBOSE, _("Rotating image 45 degrees...\n")); + fuji_width = (fuji_width - 1/* + shrink*/)/* >> shrink*/; + wide = fuji_width / step; + high = (height - fuji_width) / step; + img = (ushort(*)[4]) calloc(wide * high, sizeof * img); + merror(img, "fuji_rotate()"); + +#ifdef _OPENMP + #pragma omp parallel for default(shared) private(row,col,ur,uc,r,c,fr,fc,pix,i) +#endif + for (row = 0; row < high; row++) { + for (col = 0; col < wide; col++) { + ur = r = fuji_width + (row - col) * step; + uc = c = (row + col) * step; + if (ur > height - 2 || uc > width - 2) continue; + fr = r - ur; + fc = c - uc; + pix = image + ur * width + uc; + for (i = 0; i < colors; i++) + img[row * wide + col][i] = + (pix[ 0][i] * (1 - fc) + pix[ 1][i] * fc) * (1 - fr) + + (pix[width][i] * (1 - fc) + pix[width + 1][i] * fc) * fr; + } + } + free(image); + width = wide; + height = high; + image = img; + fuji_width = 0; + *height_p = height; /* INDI - UF*/ + *width_p = width; + *fuji_width_p = fuji_width; + *image_p = image; +} + +void CLASS flip_image_INDI(ushort(*image)[4], int *height_p, int *width_p, + /*const*/ int flip) /*UF*/ +{ + unsigned *flag; + int size, base, dest, next, row, col; + gint64 *img, hold; + int height = *height_p, width = *width_p;/* INDI - UF*/ + +// Message is suppressed because error handling is not enabled here. +// dcraw_message (dcraw, DCRAW_VERBOSE,_("Flipping image %c:%c:%c...\n"), +// flip & 1 ? 'H':'0', flip & 2 ? 'V':'0', flip & 4 ? 'T':'0'); /*UF*/ + + img = (gint64 *) image; + size = height * width; + flag = calloc((size + 31) >> 5, sizeof * flag); + merror(flag, "flip_image()"); + for (base = 0; base < size; base++) { + if (flag[base >> 5] & (1 << (base & 31))) + continue; + dest = base; + hold = img[base]; + while (1) { + if (flip & 4) { + row = dest % height; + col = dest / height; + } else { + row = dest / width; + col = dest % width; + } + if (flip & 2) + row = height - 1 - row; + if (flip & 1) + col = width - 1 - col; + next = row * width + col; + if (next == base) break; + flag[next >> 5] |= 1 << (next & 31); + img[dest] = img[next]; + dest = next; + } + img[dest] = hold; + } + free(flag); + if (flip & 4) SWAP(height, width); + *height_p = height; /* INDI - UF*/ + *width_p = width; +} diff --git a/plugins/load-dcraw/dcrawloader.c b/plugins/load-dcraw/dcrawloader.c new file mode 100644 index 00000000..48ceb0f9 --- /dev/null +++ b/plugins/load-dcraw/dcrawloader.c @@ -0,0 +1,231 @@ +/* + * * Copyright (C) 2006-2011 Anders Brander , + * * Anders Kvist and Klaus Post + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include "dcraw_api.h" + +/* + In order to inline this calculation, I make the risky + assumption that all filter patterns can be described + by a repeating pattern of eight rows and two columns + + Return values are either 0/1/2/3 = G/M/C/Y or 0/1/2/3 = R/G1/B/G2 + */ +#define FC(row,col) \ + (int)(filters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3) + +static int +fc_INDI (const unsigned int filters, const int row, const int col) +{ + static const char filter[16][16] = + { { 2,1,1,3,2,3,2,0,3,2,3,0,1,2,1,0 }, + { 0,3,0,2,0,1,3,1,0,1,1,2,0,3,3,2 }, + { 2,3,3,2,3,1,1,3,3,1,2,1,2,0,0,3 }, + { 0,1,0,1,0,2,0,2,2,0,3,0,1,3,2,1 }, + { 3,1,1,2,0,1,0,2,1,3,1,3,0,1,3,0 }, + { 2,0,0,3,3,2,3,1,2,0,2,0,3,2,2,1 }, + { 2,3,3,1,2,1,2,1,2,1,1,2,3,0,0,1 }, + { 1,0,0,2,3,0,0,3,0,3,0,3,2,1,2,3 }, + { 2,3,3,1,1,2,1,0,3,2,3,0,2,3,1,3 }, + { 1,0,2,0,3,0,3,2,0,1,1,2,0,1,0,2 }, + { 0,1,1,3,3,2,2,1,1,3,3,0,2,1,3,2 }, + { 2,3,2,0,0,1,3,0,2,0,1,2,3,0,1,0 }, + { 1,3,1,2,3,2,3,2,0,2,0,1,1,0,3,0 }, + { 0,2,0,3,1,0,0,1,1,3,3,2,3,2,2,1 }, + { 2,1,3,2,3,1,2,1,0,3,0,2,0,2,0,2 }, + { 0,3,1,0,0,2,0,3,2,1,3,1,1,3,1,3 } }; + + if (filters != 1) return FC(row,col); + /* Assume that we are handling the Leaf CatchLight with + * top_margin = 8; left_margin = 18; */ +// return filter[(row+top_margin) & 15][(col+left_margin) & 15]; + return filter[(row+8) & 15][(col+18) & 15]; +} + +static RS_IMAGE16 * +convert(dcraw_data *raw) +{ + RS_IMAGE16 *image = NULL; + gint row, col; + gushort *output; + gint shift; + gint temp; + + g_assert(raw != NULL); + + shift = (gint64) (16.0-log((gdouble) raw->rgbMax)/log(2.0)+0.5); + + /* Allocate a 1-channel RS_IMAGE16 */ + if (raw->filters != 0) + { + image = rs_image16_new(raw->raw.width*2, raw->raw.height*2, 1, 1); + + g_assert(raw->filters != 0); + g_assert(raw->fourColorFilters != 0); + g_assert(image->pixelsize == 1); + + image->filters = raw->filters; + + for(row=0 ; row < image->h ; row++) + { + output = GET_PIXEL(image, 0, row); + for(col=0 ; col < image->w ; col++) + { + /* Extract the correct color from the raw image */ + temp = raw->raw.image[(row>>1) * raw->raw.width + (col>>1)][fc_INDI(raw->fourColorFilters, row, col)]; + + /* Subtract black as calculated by dcraw */ + temp -= raw->black; + + /* Clamp */ + temp = MAX(0, temp); + + /* Shift our data to fit 16 bits */ + *output = temp<raw.colors == 3) + { + /* For foveon sensors, no demosaic is needed */ + gint i; + gint max = 0; + gint rawsize = raw->raw.width * raw->raw.height * 3; + dcraw_image_type *input; + + g_assert(raw->black == 0); /* raw->black is always zero for foveon - I think :) */ + + image = rs_image16_new(raw->raw.width, raw->raw.height, 3, 4); + + /* dcraw calculates 'wrong' rgbMax for Sigma's, let's calculate our own */ + for(i=0;iraw.image)[i], max); + + shift = (gint) (16.0-log((gdouble) max)/log(2.0)); + + for(row=0 ; row < image->h ; row++) + { + output = GET_PIXEL(image, 0, row); + input = raw->raw.image+row*raw->raw.width; + for(col=0 ; col < image->w ; col++) + { + /* Copy and shift our data to fill 16 bits */ + output[R] = (*input)[R] << shift; + output[G] = (*input)[G] << shift; + output[B] = (*input)[B] << shift; + + /* Advance input by one dcraw_image_type */ + input++; + + /* Advance output by one pixel */ + output += image->pixelsize; + } + } + } + else if (raw->raw.colors == 1) + { + dcraw_image_type *input; + + image = rs_image16_new(raw->raw.width, raw->raw.height, 3, 4); + + for(row=0 ; row < image->h ; row++) + { + output = GET_PIXEL(image, 0, row); + input = raw->raw.image+row*raw->raw.width; + for(col=0 ; col < image->w ; col++) + { + /* Copy and shift our data to fill 16 bits */ + output[R] = *(*input) << shift; + output[G] = *(*input) << shift; + output[B] = *(*input) << shift; + + /* Advance input by one dcraw_image_type */ + input++; + + /* Advance output by one pixel */ + output += image->pixelsize; + } + } + } + + return image; +} + +static RSFilterResponse * +open_dcraw(const gchar *filename) +{ + dcraw_data *raw = g_new0(dcraw_data, 1); + RS_IMAGE16 *image = NULL; + + RSFilterResponse* response = rs_filter_response_new(); + + rs_io_lock(); + if (!dcraw_open(raw, (char *) filename)) + { + dcraw_load_raw(raw); + rs_io_unlock(); + rs_filter_param_set_integer(RS_FILTER_PARAM(response), "fuji-width", raw->fuji_width); + image = convert(raw); + dcraw_close(raw); + } + else + rs_io_unlock(); + g_free(raw); + + if (image) + { + rs_filter_response_set_image(response, image); + rs_filter_response_set_width(response, image->w); + rs_filter_response_set_height(response, image->h); + g_object_unref(image); + } + return response; +} + +G_MODULE_EXPORT void +rs_plugin_load(RSPlugin *plugin) +{ + rs_filetype_register_loader(".cr2", "Canon CR2", open_dcraw, 10, RS_LOADER_FLAGS_RAW); + rs_filetype_register_loader(".crw", "Canon CIFF", open_dcraw, 10, RS_LOADER_FLAGS_RAW); + rs_filetype_register_loader(".nef", "Nikon NEF", open_dcraw, 10, RS_LOADER_FLAGS_RAW); + rs_filetype_register_loader(".nrw", "Nikon NEF 2", open_dcraw, 10, RS_LOADER_FLAGS_RAW); + rs_filetype_register_loader(".mrw", "Minolta raw", open_dcraw, 10, RS_LOADER_FLAGS_RAW); + rs_filetype_register_loader(".tif", "Canon TIFF", open_dcraw, 10, RS_LOADER_FLAGS_RAW); + rs_filetype_register_loader(".rwl", "Leica", open_dcraw, 10, RS_LOADER_FLAGS_RAW); + rs_filetype_register_loader(".arw", "Sony", open_dcraw, 10, RS_LOADER_FLAGS_RAW); + rs_filetype_register_loader(".sr2", "Sony", open_dcraw, 10, RS_LOADER_FLAGS_RAW); + rs_filetype_register_loader(".srf", "Sony", open_dcraw, 10, RS_LOADER_FLAGS_RAW); + rs_filetype_register_loader(".kdc", "Kodak", open_dcraw, 10, RS_LOADER_FLAGS_RAW); + rs_filetype_register_loader(".dcr", "Kodak", open_dcraw, 10, RS_LOADER_FLAGS_RAW); + rs_filetype_register_loader(".x3f", "Sigma", open_dcraw, 10, RS_LOADER_FLAGS_RAW); + rs_filetype_register_loader(".orf", "Olympus", open_dcraw, 10, RS_LOADER_FLAGS_RAW); + rs_filetype_register_loader(".raw", "Panasonic raw", open_dcraw, 10, RS_LOADER_FLAGS_RAW); + rs_filetype_register_loader(".rw2", "Panasonic raw v.2", open_dcraw, 10, RS_LOADER_FLAGS_RAW); + rs_filetype_register_loader(".pef", "Pentax raw", open_dcraw, 10, RS_LOADER_FLAGS_RAW); + rs_filetype_register_loader(".dng", "Adobe Digital negative", open_dcraw, 10, RS_LOADER_FLAGS_RAW); + rs_filetype_register_loader(".mef", "Mamiya", open_dcraw, 10, RS_LOADER_FLAGS_RAW); + rs_filetype_register_loader(".3fr", "Hasselblad", open_dcraw, 10, RS_LOADER_FLAGS_RAW); + rs_filetype_register_loader(".erf", "Epson", open_dcraw, 10, RS_LOADER_FLAGS_RAW); + rs_filetype_register_loader(".raf", "Fujifilm", open_dcraw, 10, RS_LOADER_FLAGS_RAW); + rs_filetype_register_loader(".srw", "Samsung", open_dcraw, 10, RS_LOADER_FLAGS_RAW); +} diff --git a/plugins/load-dcraw/mmap-hack.c b/plugins/load-dcraw/mmap-hack.c new file mode 100644 index 00000000..59f092a6 --- /dev/null +++ b/plugins/load-dcraw/mmap-hack.c @@ -0,0 +1,117 @@ +/* + * * Copyright (C) 2006-2011 Anders Brander , + * * Anders Kvist and Klaus Post + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifdef WITH_MMAP_HACK +#include +#include +#include +#include +#include +#include +#include +#include "mmap-hack.h" +#include + +RS_FILE * +rs_fopen(const char *path, const char *mode) +{ + RS_FILE *file; + int fd; + struct stat st; + + if(stat(path, &st)) + return(NULL); + + if ((fd = open(path, O_RDONLY)) == -1) + return(NULL); + + file = (RS_FILE *) malloc(sizeof(RS_FILE)); + file->fd = fd; + file->size = st.st_size; + file->map = (unsigned char *) mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, file->fd, 0); + file->offset = 0; + return file; +} + +int +rs_fclose(RS_FILE *RS_FILE) +{ + munmap(RS_FILE->map, RS_FILE->size); + close(RS_FILE->fd); + free(RS_FILE); + return 0; +} + +inline int +rs_fseek(RS_FILE *stream, long offset, int whence) +{ + switch(whence) + { + case SEEK_SET: + stream->offset = offset; + break; + case SEEK_CUR: + stream->offset += offset; + break; + case SEEK_END: + stream->offset = stream->size + offset; + } + + /* clamp */ + stream->offset = (stream->offset > stream->size) ? stream->size : stream->offset; + return(0); +} + +inline size_t +rs_fread(void *ptr, size_t size, size_t nmemb, RS_FILE *stream) +{ + if (stream->offset + size*nmemb <= stream->size) + { + memcpy(ptr, &stream->map[stream->offset], size*nmemb); + stream->offset+=size*nmemb; + return nmemb; + } + int bytes = stream->size - stream->offset; + memcpy(ptr, &stream->map[stream->offset], bytes); + stream->offset+=bytes; + return(bytes / size); +} + +char * +rs_fgets(char *s, int size, RS_FILE *stream) +{ + int destoff = 0; + while (destoff < size) + { + if (stream->offset >= stream->size) return 0; + s[destoff] = stream->map[stream->offset++]; + if (s[destoff] == 0 || s[destoff] == '\n') + return s; + destoff++; + } + return(NULL); +} + +int +rs_fscanf(RS_FILE *stream, const char *format, void* dst) +{ + int scanned = scanf(format, &stream->map[stream->offset], dst); + stream->offset+= scanned; + return(scanned); +} +#endif diff --git a/plugins/load-dcraw/mmap-hack.h b/plugins/load-dcraw/mmap-hack.h new file mode 100644 index 00000000..5fc5381c --- /dev/null +++ b/plugins/load-dcraw/mmap-hack.h @@ -0,0 +1,71 @@ +/* + * * Copyright (C) 2006-2011 Anders Brander , + * * Anders Kvist and Klaus Post + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef MMAP_HACK_H +#define MMAP_HACK_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct RS_FILE { + int fd; + unsigned char *map; + unsigned int offset; + unsigned int size; +} RS_FILE; + +#define RS_FILE(stream) ((RS_FILE *)(stream)) + +extern RS_FILE *rs_fopen(const char *path, const char *mode); +extern int rs_fclose(RS_FILE *fp); +extern int rs_fseek(RS_FILE *stream, long offset, int whence); +extern long rs_ftell(RS_FILE *stream); +extern void rs_rewind(RS_FILE *stream); +extern int rs_fscanf(RS_FILE *stream, const char *format, void* dst); +extern int rs_fgetc(RS_FILE *stream); +extern size_t rs_fread(void *ptr, size_t size, size_t nmemb, RS_FILE *stream); +extern char *rs_fgets(char *s, int size, RS_FILE *stream); + +#ifdef __cplusplus +} +#endif + +#define fopen(a,b) (FILE *) rs_fopen(a,b) +#define fclose(a) rs_fclose(RS_FILE(a)) +#define fseek(a, b, c) rs_fseek(RS_FILE(a),b,c) +#define fread(a,b,c,d) rs_fread(a,b,c,RS_FILE(d)) +#define fgets(a,b,c) rs_fgets(a,b,RS_FILE(c)) +#define fscanf(a,b,c) rs_fscanf(RS_FILE(a),b,c) + +#define fgetc(stream) (int) (RS_FILE(stream)->map[RS_FILE(stream)->offset++]) +#define ftell(stream) (long) (RS_FILE(stream)->offset) +#define rewind(stream) do {RS_FILE(stream)->offset = 0; } while(0) + +#ifdef feof +#undef feof +#endif +#define feof(stream) (RS_FILE(stream)->offset >= RS_FILE(stream)->size) + +#ifdef getc +#undef getc +#endif +#define getc(stream) fgetc(stream) + +#endif /* MMAP_HACK_H */ diff --git a/plugins/load-dcraw/nikon_curve.c b/plugins/load-dcraw/nikon_curve.c new file mode 100644 index 00000000..1a785b9f --- /dev/null +++ b/plugins/load-dcraw/nikon_curve.c @@ -0,0 +1,2322 @@ +/*************************************************** + nikon_curve.c - read Nikon NTC/NCV files + + Copyright 2004-2016 by Shawn Freeman, Udi Fuchs + + This program reads in a Nikon NTC/NCV file, + interperates it's tone curve, and writes out a + simple ASCII file containing a table of interpolation + values. See the header file for more information. + + 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. + +****************************************************/ + +////////////////////////////////////////// +//COMPILER CONTROLS +////////////////////////////////////////// +//Undef this if you don't want to use the stand-alone program +//This is mainly for debugging purposes +//#define _STAND_ALONE_ + +//Define this if you are using Microsoft Visual C++. This enables code to +//deal with the fact the MSVC does not support variable argument macros. +//#define __MSVC__ + +//the only remaining incompatibility between MSVC and gcc +#ifdef __MSVC__ +#define vsnprintf _vsnprintf +#endif + +//Define this if using with UFRaw +#define __WITH_UFRAW__ + + +#ifdef __WITH_UFRAW__ +#include "ufraw.h" +#else +#include "nikon_curve.h" +#include +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define g_fopen fopen +#endif +#include +#include +#include +#include +#include /* For variable argument lists */ + +/************************************************* + * Internal static functions + *************************************************/ + +/************************************************************ +nc_message: + The Nikon Curve message handler. + + code - Message code + format - The message to format + ... - variable arguments +**************************************************************/ +static void nc_message(int code, char *format, ...); + +static void DEBUG_PRINT(char *format, ...); + +/******************************************************************* + d3_np_fs: + Helper function for calculating and storing tridiagnol matrices. + Cubic spline calculations involve these types of matrices. +*********************************************************************/ +static double *d3_np_fs(int n, double a[], double b[]); + +/******************************************************************* + spline_cubic_set: + spline_cubic_set gets the second derivatives for the curve to be used in + spline construction + + n = number of control points + t[] = x array + y[] = y array + ibcbeg = initial point condition (see function notes). + ybcbeg = beginning value depending on above flag + ibcend = end point condition (see function notes). + ybcend = end value depending on above flag + + returns the y value at the given tval point +*********************************************************************/ +static double *spline_cubic_set(int n, double t[], double y[], int ibcbeg, + double ybcbeg, int ibcend, double ybcend); + +/******************************************************************* + spline_cubic_val: + spline_cubic_val gets a value from spline curve. + + n = number of control points + t[] = x array + tval = x value you're requesting the data for, can be anywhere on the interval. + y[] = y array + ypp[] = second derivative array calculated by spline_cubic_set + ypval = first derivative value of requested point + yppval = second derivative value of requested point + + returns the y value at the given tval point +*********************************************************************/ +static double spline_cubic_val(int n, double t[], double tval, double y[], + double ypp[], double *ypval, double *yppval); + +/************************************************************ +SaveNikonCurveFile: + Saves out curves to a Nikon ntc or ncv file. This function + takes a single curve and uses defaults for the other curves. + Typically, the curve used is the tone curve. + + curve - A NikonCurve structure. This is usually the tone curve + curve_type - The curve type (TONE_CURVE, RED_CURVE, etc.) + fileName - The filename. + filetype - Indicator for an NCV or NTC file. + +NOTE: The only version tested is Nikon 4.1 anything + other than this may result in unpredictable behavior. + For now, the version passed in is ignored and is forced + to 4.1. + + This function is just a helper function that allows the user + to just carry around a single curve. +**************************************************************/ +#ifdef _STAND_ALONE_ +static int SaveNikonCurveFile(CurveData *curve, int curve_type, char *outfile, + int filetype); +#endif + +/********************************************* +SaveSampledNikonCurve: + Saves a sampling from a curve to text file to + be processed by UFRaw. + + sample - Pointer to the sampled curve. + fileName - The filename. +**********************************************/ +#ifdef _STAND_ALONE_ +static int SaveSampledNikonCurve(CurveSample *sample, char *outfile); +#endif + +/***************************************************** +FindTIFFOffset: + Moves the file pointer to the location + indicated by the TAG-TYPE pairing. This is meant just + as a helper function for this code. Uses elsewhere + may be limited. + + file - Nikon File ptr + num_entries - Number of entries to search through + tiff_tag - The tiff tag to match. + tiff_type - The tiff type to match. +*******************************************************/ +#ifdef _STAND_ALONE_ +static int FindTIFFOffset(FILE *file, unsigned short num_entries, + unsigned short tiff_tag, unsigned short tiff_type); +#endif + +/**************************************************** +SampleToCameraCurve: + Transforms the curve generated by sampling the + spline interpolator into the curve that is used by + the camera. + + This is a special function. While the function places + no special restrictions on sampling resolution or + output resolution, it should be noted that Nikon D70 + camera curve is 4096 entries of 0-255. + + If you intend on using this function as such, you should + set the sampling resolution and output resolution + accordingly. + + curve - The Nikon curve to sample and transform. +*****************************************************/ +#ifdef _STAND_ALONE_ +static int SampleToCameraCurve(CurveData *curve, CurveSample *sample); +#endif + +/**************************************** +ConvertNikonCurveData: + The main driver. Takes a filename and + processes the curve, if possible. + + fileName - The file to process. +*****************************************/ +#ifdef _STAND_ALONE_ +static int ConvertNikonCurveData(char *inFileName, char *outFileName, + unsigned int samplingRes, unsigned int outputRes); +#endif + +/******************************************************* +RipNikonNEFData: + Gets Nikon NEF data. For now, this is just the tone + curve data. This is more of a helper function for running + in stand-alone. This function basically finds the correct + file offset, and then calls RipNikonNEFCurve. + + infile - The input file + curve - data structure to hold data in. + sample_p - pointer to the curve sample reference. + can be NULL if curve sample is not needed. +********************************************************/ +#ifdef _STAND_ALONE_ +static int RipNikonNEFData(char *infile, CurveData *data, + CurveSample **sample_p); +#endif + +/******************************************************************************* +Information regarding the file format. + +Section Headers: + +Order of Box Data: Left x, Right x, Midpoint x (gamma), Bottom y, Top y + +Order of Anchor Data: Start x, Start y, Anchor 1 x, Anchor 1 y, ... , End x, End y + +Anchor Point Data: This is aligned on 8 byte boundries. However, the section must + end on a 16 byte boundary, which means an 8 byte pad is added. +********************************************************************************/ + +//DEFINES FOR WRITING OUT DATA (for ntc/ncv files) +#define NCV_HEADER_SIZE 0x3E //Combined header length for an NCV file +#define NCV_SECOND_FILE_SIZE_OFFSET 0x3F //4 bytes (int). File size - NCV_header +#define NCV_UNKNOWN_HEADER_DATA 0x002 //2 bytes. (?) +#define NCV_SECOND_HEADER_LENGTH 23 +#define NCV_FILE_TERMINATOR_LENGTH 23 + +#define NTC_FILE_HEADER_LENGTH 0x10 //16 bytes. Doesn't change +//This seemed to change when Nikon released an updated capture program +//from 4.1 to 4.2. This may be an int but not sure. +#define NCV_PATCH_OFFSET 0x3D //2 bytes(?) +#define NTC_PATCH_OFFSET 0x10 //2 bytes(?) +#define FILE_SIZE_OFFSET 0x12 //4 bytes (int). File size - header. +#define NTC_VERSION_OFFSET 0x16 //4 bytes (int).(?) +//9 byte pad(?) +//16 bytes. Another section header goes here. + +//From here down repeats for every section +#define NTC_SECTION_TYPE_OFFSET 0x00 //4 bytes (int) (0,1,2,3) + +#define NTC_UNKNOWN 0x05 //2 bytes. Doesn't change but not sure what they do (0x03ff) +#define NTC_UNKNOWN_DATA 0x3FF // + +#define NTC_RED_COMPONENT_OFFSET 0x08 //4 bytes (int) (0-255) +#define NTC_GREEN_COMPONENT_OFFSET 0x0C //4 bytes (int) (0-255) +#define NTC_BLUE_COMPONENT_OFFSET 0x0F //4 bytes (int) (0-255) +//12 byte pad all zeros(align to 16?) + +#define NTC_RED_WEIGHT_OFFSET 0x1F //4 bytes (int) (0-255) +#define NTC_GREEN_WEIGHT_OFFSET 0x23 //4 bytes (int) (0-255) +#define NTC_BLUE_WEIGHT_OFFSET 0x27 //4 bytes (int) (0-255) + +#define END_ANCHOR_DATA_PAD_LENGTH 0x08 //Always all zeros +#define NTC_SECTION_HEADER_LENGTH 0x10 //Doesn't change + + +//DEFINES FOR READING IN DATA +#define HEADER_SIZE 0x10 //First characters may be unicode Japanese? + +#define NTC_BOX_DATA 0x5C //Start of box data +#define NTC_NUM_ANCHOR_POINTS 0x84 //Number of anchor points plus 2 for start and end points +#define NTC_ANCHOR_DATA_START 0x88 //Beginning of anchor point data + +#define NCV_BOX_DATA 0x89 //Start of box data +#define NCV_NUM_ANCHOR_POINTS 0xB2 //Number of anchor points plus 2 for start and end points +#define NCV_ANCHOR_DATA_START 0xB5 //Beginning of anchor point data + +//array indices to retrive data +#define PATCH_DATA 0 +#define BOX_DATA 1 +#define NUM_ANCHOR_POINTS 2 +#define ANCHOR_DATA 3 + +//Some data sections sizes for calculating offsets +#define NEXT_SECTION_BOX_DATA_OFFSET 0x43 //after the anchor data, this is the offset to +//the beginning of the next section's box data + +#define NUM_POINTS_TO_ANCHOR_OFFSET 0x03 //number of bytes from the number of anchor points +//byte to the start of anchor data. +//Nikon version defines +#define NIKON_VERSION_4_1 0x00000401 +#define NIKON_PATCH_4 0x04ff +#define NIKON_PATCH_5 0x05ff + +//Maximum resoltuion allowed due to space considerations. +#define MAX_RESOLUTION 65536 + +////////////////////////////// +//NEF/TIFF MACROS AND DEFINES +////////////////////////////// +#define TIFF_TAG_EXIF_OFFSET 34665 +#define TIFF_TAG_MAKER_NOTE_OFFSET 37500 +#define TIFF_TAG_CURVE_OFFSET 140 + +#define TIFF_TYPE_UNDEFINED 7 +#define TIFF_TYPE_LONG 4 + +//Flags used to determine what file we're trying to process. +//Should only be used in standalone mode. +#ifdef _STAND_ALONE_ +#define CURVE_MODE 0 +#define NEF_MODE 1 +#endif + +/************************************************* + * Internal static data + *************************************************/ + +//file offsets for the different data in different file types +static const int FileOffsets[2][4] = { + {NTC_PATCH_OFFSET, NTC_BOX_DATA, NTC_NUM_ANCHOR_POINTS, NTC_ANCHOR_DATA_START}, + {NCV_PATCH_OFFSET, NCV_BOX_DATA, NCV_NUM_ANCHOR_POINTS, NCV_ANCHOR_DATA_START}, +}; + +//file header indicating ntc file +static const unsigned char NTCFileHeader[] = {0x9d, 0xdc, 0x7d, 0x00, 0x65, 0xd4, + 0x11, 0xd1, 0x91, 0x94, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 + }; + +//file header indicating an ncv file +static const unsigned char NCVFileHeader[] = {0x40, 0xa9, 0x86, 0x7a, 0x1b, 0xe9, + 0xd2, 0x11, 0xa9, 0x0a, 0x00, 0xaa, 0x00, 0xb1, 0xc1, 0xb7 + }; + +//This is an additional header chunk at the beginning of the file +//There are some similarities between the headers, but not enough to fully crack. +//This does not appear to change. +static const unsigned char NCVSecondFileHeader[] = {0x01, 0x32, 0xa4, 0x76, 0xa2, + 0x17, 0xd4, 0x11, 0xa9, 0x0a, 0x00, 0xaa, 0x00, 0xb1, 0xc1, + 0xb7, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01 + }; + +//This is the terminator of an NCV file. Again there are some similarites +//to other sections, but not enough for to crack what it means. However, +//it does not appear to change. +static const unsigned char NCVFileTerminator[] = {0x45, 0xd3, 0x0d, 0x77, 0xa3, 0x6e, + 0x1e, 0x4e, 0xa4, 0xbe, 0xcf, 0xc1, 0x8e, 0xb5, 0xb7, 0x47, + 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01 + }; + +//File section header. Only a one byte difference between this and an NTC file header +static const unsigned char FileSectionHeader[] = {0x9d, 0xdc, 0x7d, 0x03, 0x65, 0xd4, + 0x11, 0xd1, 0x91, 0x94, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 + }; +//file type header array +static const unsigned char *FileTypeHeaders[NUM_FILE_TYPES] = { + NTCFileHeader, + NCVFileHeader, +}; + +/**STANDALONE**/ +#ifdef _STAND_ALONE_ + +//filenames +char exportFilename[1024]; +char nikonFilename[1024]; + +unsigned int standalone_samplingRes = 65536; +unsigned int standalone_outputRes = 256; +unsigned int program_mode = CURVE_MODE; + +/******************************************* +ProcessArgs: + Convenient function for processing the args + for the test runner. +********************************************/ +static int ProcessArgs(int num_args, char *args[]) +{ + exportFilename[0] = '\0'; + nikonFilename[0] = '\0'; + + int i; + for (i = 0; i < num_args; i++) { + if (strcmp(args[i], "-h") == 0 || strcmp(args[i], "-H") == 0 || num_args <= 1) { + printf("NikonCurveGenerator %s %s\n", NC_VERSION, NC_DATE); + printf("Written by Shawn Freeman\n"); + printf("Thanks go out to Udi Fuchs, UFRaw, and GIMP :)\n\n"); + printf("Usage:\n"); + printf("-o Specify output file.\n"); + printf("-sr Specify sampling resolution. Default is 65536.\n"); + printf("-or Specify output resolution. Default is 256.\n\n"); + printf("-nef Specify an NEF file to get tone curve data from.\n\n"); + printf(" The -or and -sr options are ignored for NEF files\n\n"); + printf("NOTE: If a resolution is not specified, a default one will be used.\n"); + printf(" If the -o option is not specified, default files will be used.\n\n"); + printf("Example:\n"); + printf("%s -sr 65536 -or 256 curveFile -o exportFile\n", args[0]); + + //signal that processing cannot occur + return NC_ERROR; + } else if (strcmp(args[i], "-o") == 0 || strcmp(args[i], "-O") == 0) { + i++; + strncpy(exportFilename, args[i], 1023); + exportFilename[1023] = '\0'; + } else if (strcmp(args[i], "-sr") == 0) { + i++; + standalone_samplingRes = atoi(args[i]); + + if (standalone_samplingRes < 1) { + nc_message(NC_WARNING, "WARNING: Sampling resolution must be" + ">= 1! Using default of 65535.\n"); + } + } else if (strcmp(args[i], "-or") == 0) { + i++; + standalone_outputRes = atoi(args[i]); + + if (standalone_outputRes < 1) { + nc_message(NC_WARNING, "WARNING: Output resolution must be" + ">= 1! Using default of 256.\n"); + } + } else if (strcmp(args[i], "-nef") == 0) { + i++; + program_mode = NEF_MODE; + strncpy(nikonFilename, args[i], 1023); + nikonFilename[1023] = '\0'; + } + //don't load argument 0 + else if (i != 0) { + //consider this the file name to load + strncpy(nikonFilename, args[i], 1023); + nikonFilename[1023] = '\0'; + } + } + + if (strlen(exportFilename) == 0) { + //set it to have a default output file name + strncpy(exportFilename, nikonFilename, 1023); + strncat(exportFilename, "_CURVE_OUTPUT.txt", 1023); + exportFilename[1023] = '\0'; + } + + return NC_SUCCESS; +} +#endif //End STAND_ALONE + +/************************************************************ +nc_message_handler: + The Nikon Curve message handler. Udi Fuchs created this +to make the error handling consistent acros the code. + + code - Message code + message - The message +**************************************************************/ +static void nc_message(int code, char *format, ...) +{ + char message[256]; + va_list ap; + va_start(ap, format); + + vsnprintf(message, 255, format, ap); + message[255] = '\0'; + va_end(ap); + +#ifdef _STAND_ALONE_ //if we're running standalone mode + + code = code; + fprintf(stderr, "%s", message); + fflush(stderr); + +#else + +#ifdef __WITH_UFRAW__ //and if compiling with UFRAW + + if (code == NC_SET_ERROR) { + ufraw_message(UFRAW_SET_ERROR, message); + } else { + ufraw_message(code, message); + } + +#else //else, just print out the errors normally + + code = code; + g_printerr("%s", message); + +#endif //End WITH_UFRAW + +#endif //End STAND_ALONE +} + +static void DEBUG_PRINT(char *format, ...) +{ +#ifdef _DEBUG + va_list ap; + va_start(ap, format); + vfprintf(stderr, format, ap); + fflush(stderr); + va_end(ap); +#else + format = format; +#endif +} + +/* nc_merror(): Handle memory allocaltion errors */ +static void nc_merror(void *ptr, char *where) +{ + if (ptr) return; +#ifdef __WITH_UFRAW__ + g_error("Out of memory in %s\n", where); +#else + fprintf(stderr, "Out of memory in %s\n", where); + exit(1); +#endif +} + +static size_t nc_fread(void *ptr, size_t size, size_t nmemb, FILE *stream) +{ + size_t num = fread(ptr, size, nmemb, stream); + if (num != nmemb) + nc_message(NC_WARNING, "WARNING: nc_fread %d != %d\n", num, nmemb); + return num; +} + +static size_t nc_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) +{ + size_t num = fwrite(ptr, size, nmemb, stream); + if (num != nmemb) + nc_message(NC_WARNING, "WARNING: nc_fwrite %d != %d\n", num, nmemb); + return num; +} + +// Assert something at compile time (must use this inside a function); +// works because compilers won't let us declare negative-length arrays. +#define STATIC_ASSERT(cond) \ + { (void)((int (*)(char failed_static_assertion[(cond)?1:-1]))0); } + +/*********************************************************************** +isBigEndian: + Determines if the machine we are running on is big endian or not. +************************************************************************/ +static int isBigEndian() +{ + STATIC_ASSERT(sizeof(short) == 2); + union { + unsigned char c[2]; + short x; + } EndianTest; + + EndianTest.c[0] = 1; + EndianTest.c[1] = 0; + + return (EndianTest.x != 1); +} + +/*********************************************************************** +ShortVal: + Convert short int (16 bit) from little endian to machine endianess. +************************************************************************/ +static short ShortVal(short s) +{ + STATIC_ASSERT(sizeof(short) == 2); + if (isBigEndian()) { + unsigned char b1, b2; + + b1 = s & 255; + b2 = (s >> 8) & 255; + + return (b1 << 8) + b2; + } else + return s; +} + +/*********************************************************************** +LongVal: + Convert long int (32 bit) from little endian to machine endianess. +************************************************************************/ +static int LongVal(int i) +{ + STATIC_ASSERT(sizeof(int) == 4); + if (isBigEndian()) { + unsigned char b1, b2, b3, b4; + + b1 = i & 255; + b2 = (i >> 8) & 255; + b3 = (i >> 16) & 255; + b4 = (i >> 24) & 255; + + return ((int)b1 << 24) + ((int)b2 << 16) + ((int)b3 << 8) + b4; + } else + return i; +} + +/*********************************************************************** +DoubleVal: + Convert double from little endian to machine endianess. +************************************************************************/ +static double DoubleVal(double d) +{ + STATIC_ASSERT(sizeof(double) == 8); + if (isBigEndian()) { + union { + double d; + unsigned char b[8]; + } dat1, dat2; + + dat1.d = d; + dat2.b[0] = dat1.b[7]; + dat2.b[1] = dat1.b[6]; + dat2.b[2] = dat1.b[5]; + dat2.b[3] = dat1.b[4]; + dat2.b[4] = dat1.b[3]; + dat2.b[5] = dat1.b[2]; + dat2.b[6] = dat1.b[1]; + dat2.b[7] = dat1.b[0]; + return dat2.d; + } else + return d; +} + +//********************************************************************** +// +// Purpose: +// +// D3_NP_FS factors and solves a D3 system. +// +// Discussion: +// +// The D3 storage format is used for a tridiagonal matrix. +// The superdiagonal is stored in entries (1,2:N), the diagonal in +// entries (2,1:N), and the subdiagonal in (3,1:N-1). Thus, the +// original matrix is "collapsed" vertically into the array. +// +// This algorithm requires that each diagonal entry be nonzero. +// It does not use pivoting, and so can fail on systems that +// are actually nonsingular. +// +// Example: +// +// Here is how a D3 matrix of order 5 would be stored: +// +// * A12 A23 A34 A45 +// A11 A22 A33 A44 A55 +// A21 A32 A43 A54 * +// +// Modified: +// +// 07 January 2005 Shawn Freeman (pure C modifications) +// 15 November 2003 John Burkardt +// +// Author: +// +// John Burkardt +// +// Parameters: +// +// Input, int N, the order of the linear system. +// +// Input/output, double A[3*N]. +// On input, the nonzero diagonals of the linear system. +// On output, the data in these vectors has been overwritten +// by factorization information. +// +// Input, double B[N], the right hand side. +// +// Output, double D3_NP_FS[N], the solution of the linear system. +// This is NULL if there was an error because one of the diagonal +// entries was zero. +// +static double *d3_np_fs(int n, double a[], double b[]) +{ + int i; + double *x; + double xmult; +// +// Check. +// + for (i = 0; i < n; i++) { + if (a[1 + i * 3] == 0.0E+00) { + return NULL; + } + } + x = (double *)calloc(n, sizeof(double)); + nc_merror(x, "d3_np_fs"); + + for (i = 0; i < n; i++) { + x[i] = b[i]; + } + + for (i = 1; i < n; i++) { + xmult = a[2 + (i - 1) * 3] / a[1 + (i - 1) * 3]; + a[1 + i * 3] = a[1 + i * 3] - xmult * a[0 + i * 3]; + x[i] = x[i] - xmult * x[i - 1]; + } + + x[n - 1] = x[n - 1] / a[1 + (n - 1) * 3]; + for (i = n - 2; 0 <= i; i--) { + x[i] = (x[i] - a[0 + (i + 1) * 3] * x[i + 1]) / a[1 + i * 3]; + } + + return x; +} + +//********************************************************************** +// +// Purpose: +// +// SPLINE_CUBIC_SET computes the second derivatives of a piecewise cubic spline. +// +// Discussion: +// +// For data interpolation, the user must call SPLINE_SET to determine +// the second derivative data, passing in the data to be interpolated, +// and the desired boundary conditions. +// +// The data to be interpolated, plus the SPLINE_SET output, defines +// the spline. The user may then call SPLINE_VAL to evaluate the +// spline at any point. +// +// The cubic spline is a piecewise cubic polynomial. The intervals +// are determined by the "knots" or abscissas of the data to be +// interpolated. The cubic spline has continous first and second +// derivatives over the entire interval of interpolation. +// +// For any point T in the interval T(IVAL), T(IVAL+1), the form of +// the spline is +// +// SPL(T) = A(IVAL) +// + B(IVAL) * ( T - T(IVAL) ) +// + C(IVAL) * ( T - T(IVAL) )**2 +// + D(IVAL) * ( T - T(IVAL) )**3 +// +// If we assume that we know the values Y(*) and YPP(*), which represent +// the values and second derivatives of the spline at each knot, then +// the coefficients can be computed as: +// +// A(IVAL) = Y(IVAL) +// B(IVAL) = ( Y(IVAL+1) - Y(IVAL) ) / ( T(IVAL+1) - T(IVAL) ) +// - ( YPP(IVAL+1) + 2 * YPP(IVAL) ) * ( T(IVAL+1) - T(IVAL) ) / 6 +// C(IVAL) = YPP(IVAL) / 2 +// D(IVAL) = ( YPP(IVAL+1) - YPP(IVAL) ) / ( 6 * ( T(IVAL+1) - T(IVAL) ) ) +// +// Since the first derivative of the spline is +// +// SPL'(T) = B(IVAL) +// + 2 * C(IVAL) * ( T - T(IVAL) ) +// + 3 * D(IVAL) * ( T - T(IVAL) )**2, +// +// the requirement that the first derivative be continuous at interior +// knot I results in a total of N-2 equations, of the form: +// +// B(IVAL-1) + 2 C(IVAL-1) * (T(IVAL)-T(IVAL-1)) +// + 3 * D(IVAL-1) * (T(IVAL) - T(IVAL-1))**2 = B(IVAL) +// +// or, setting H(IVAL) = T(IVAL+1) - T(IVAL) +// +// ( Y(IVAL) - Y(IVAL-1) ) / H(IVAL-1) +// - ( YPP(IVAL) + 2 * YPP(IVAL-1) ) * H(IVAL-1) / 6 +// + YPP(IVAL-1) * H(IVAL-1) +// + ( YPP(IVAL) - YPP(IVAL-1) ) * H(IVAL-1) / 2 +// = +// ( Y(IVAL+1) - Y(IVAL) ) / H(IVAL) +// - ( YPP(IVAL+1) + 2 * YPP(IVAL) ) * H(IVAL) / 6 +// +// or +// +// YPP(IVAL-1) * H(IVAL-1) + 2 * YPP(IVAL) * ( H(IVAL-1) + H(IVAL) ) +// + YPP(IVAL) * H(IVAL) +// = +// 6 * ( Y(IVAL+1) - Y(IVAL) ) / H(IVAL) +// - 6 * ( Y(IVAL) - Y(IVAL-1) ) / H(IVAL-1) +// +// Boundary conditions must be applied at the first and last knots. +// The resulting tridiagonal system can be solved for the YPP values. +// +// Modified: +// +// 07 January 2005 Shawn Freeman (pure C modifications) +// 06 February 2004 John Burkardt +// +// +// Author: +// +// John Burkardt +// +// Parameters: +// +// Input, int N, the number of data points. N must be at least 2. +// In the special case where N = 2 and IBCBEG = IBCEND = 0, the +// spline will actually be linear. +// +// Input, double T[N], the knot values, that is, the points were data is +// specified. The knot values should be distinct, and increasing. +// +// Input, double Y[N], the data values to be interpolated. +// +// Input, int IBCBEG, left boundary condition flag: +// 0: the cubic spline should be a quadratic over the first interval; +// 1: the first derivative at the left endpoint should be YBCBEG; +// 2: the second derivative at the left endpoint should be YBCBEG. +// +// Input, double YBCBEG, the values to be used in the boundary +// conditions if IBCBEG is equal to 1 or 2. +// +// Input, int IBCEND, right boundary condition flag: +// 0: the cubic spline should be a quadratic over the last interval; +// 1: the first derivative at the right endpoint should be YBCEND; +// 2: the second derivative at the right endpoint should be YBCEND. +// +// Input, double YBCEND, the values to be used in the boundary +// conditions if IBCEND is equal to 1 or 2. +// +// Output, double SPLINE_CUBIC_SET[N], the second derivatives of the cubic spline. +// +static double *spline_cubic_set(int n, double t[], double y[], int ibcbeg, + double ybcbeg, int ibcend, double ybcend) +{ + double *a; + double *b; + int i; + double *ypp; +// +// Check. +// + if (n <= 1) { + nc_message(NC_SET_ERROR, "spline_cubic_set() error: " + "The number of data points must be at least 2.\n"); + return NULL; + } + + for (i = 0; i < n - 1; i++) { + if (t[i + 1] <= t[i]) { + nc_message(NC_SET_ERROR, "spline_cubic_set() error: " + "The knots must be strictly increasing, but " + "T(%u) = %e, T(%u) = %e\n", i, t[i], i + 1, t[i + 1]); + return NULL; + } + } + a = (double *)calloc(3 * n, sizeof(double)); + nc_merror(a, "spline_cubic_set"); + b = (double *)calloc(n, sizeof(double)); + nc_merror(b, "spline_cubic_set"); +// +// Set up the first equation. +// + if (ibcbeg == 0) { + b[0] = 0.0E+00; + a[1 + 0 * 3] = 1.0E+00; + a[0 + 1 * 3] = -1.0E+00; + } else if (ibcbeg == 1) { + b[0] = (y[1] - y[0]) / (t[1] - t[0]) - ybcbeg; + a[1 + 0 * 3] = (t[1] - t[0]) / 3.0E+00; + a[0 + 1 * 3] = (t[1] - t[0]) / 6.0E+00; + } else if (ibcbeg == 2) { + b[0] = ybcbeg; + a[1 + 0 * 3] = 1.0E+00; + a[0 + 1 * 3] = 0.0E+00; + } else { + nc_message(NC_SET_ERROR, "spline_cubic_set() error: " + "IBCBEG must be 0, 1 or 2. The input value is %u.\n", ibcbeg); + free(a); + free(b); + return NULL; + } +// +// Set up the intermediate equations. +// + for (i = 1; i < n - 1; i++) { + b[i] = (y[i + 1] - y[i]) / (t[i + 1] - t[i]) + - (y[i] - y[i - 1]) / (t[i] - t[i - 1]); + a[2 + (i - 1) * 3] = (t[i] - t[i - 1]) / 6.0E+00; + a[1 + i * 3] = (t[i + 1] - t[i - 1]) / 3.0E+00; + a[0 + (i + 1) * 3] = (t[i + 1] - t[i]) / 6.0E+00; + } +// +// Set up the last equation. +// + if (ibcend == 0) { + b[n - 1] = 0.0E+00; + a[2 + (n - 2) * 3] = -1.0E+00; + a[1 + (n - 1) * 3] = 1.0E+00; + } else if (ibcend == 1) { + b[n - 1] = ybcend - (y[n - 1] - y[n - 2]) / (t[n - 1] - t[n - 2]); + a[2 + (n - 2) * 3] = (t[n - 1] - t[n - 2]) / 6.0E+00; + a[1 + (n - 1) * 3] = (t[n - 1] - t[n - 2]) / 3.0E+00; + } else if (ibcend == 2) { + b[n - 1] = ybcend; + a[2 + (n - 2) * 3] = 0.0E+00; + a[1 + (n - 1) * 3] = 1.0E+00; + } else { + nc_message(NC_SET_ERROR, "spline_cubic_set() error: " + "IBCEND must be 0, 1 or 2. The input value is %u", ibcend); + free(a); + free(b); + return NULL; + } +// +// Solve the linear system. +// + if (n == 2 && ibcbeg == 0 && ibcend == 0) { + ypp = (double *)calloc(2, sizeof(double)); + nc_merror(ypp, "spline_cubic_set"); + + ypp[0] = 0.0E+00; + ypp[1] = 0.0E+00; + } else { + ypp = d3_np_fs(n, a, b); + + if (!ypp) { + nc_message(NC_SET_ERROR, "spline_cubic_set() error: " + "The linear system could not be solved.\n"); + free(a); + free(b); + return NULL; + } + + } + + free(a); + free(b); + return ypp; +} + +//********************************************************************** +// +// Purpose: +// +// SPLINE_CUBIC_VAL evaluates a piecewise cubic spline at a point. +// +// Discussion: +// +// SPLINE_CUBIC_SET must have already been called to define the values of YPP. +// +// For any point T in the interval T(IVAL), T(IVAL+1), the form of +// the spline is +// +// SPL(T) = A +// + B * ( T - T(IVAL) ) +// + C * ( T - T(IVAL) )**2 +// + D * ( T - T(IVAL) )**3 +// +// Here: +// A = Y(IVAL) +// B = ( Y(IVAL+1) - Y(IVAL) ) / ( T(IVAL+1) - T(IVAL) ) +// - ( YPP(IVAL+1) + 2 * YPP(IVAL) ) * ( T(IVAL+1) - T(IVAL) ) / 6 +// C = YPP(IVAL) / 2 +// D = ( YPP(IVAL+1) - YPP(IVAL) ) / ( 6 * ( T(IVAL+1) - T(IVAL) ) ) +// +// Modified: +// +// 07 January 2005 Shawn Freeman (pure C modifications) +// 04 February 1999 John Burkardt +// +// Author: +// +// John Burkardt +// +// Parameters: +// +// Input, int n, the number of knots. +// +// Input, double Y[N], the data values at the knots. +// +// Input, double T[N], the knot values. +// +// Input, double TVAL, a point, typically between T[0] and T[N-1], at +// which the spline is to be evalulated. If TVAL lies outside +// this range, extrapolation is used. +// +// Input, double Y[N], the data values at the knots. +// +// Input, double YPP[N], the second derivatives of the spline at +// the knots. +// +// Output, double *YPVAL, the derivative of the spline at TVAL. +// +// Output, double *YPPVAL, the second derivative of the spline at TVAL. +// +// Output, double SPLINE_VAL, the value of the spline at TVAL. +// +static double spline_cubic_val(int n, double t[], double tval, double y[], + double ypp[], double *ypval, double *yppval) +{ + double dt; + double h; + int i; + int ival; + double yval; +// +// Determine the interval [ T(I), T(I+1) ] that contains TVAL. +// Values below T[0] or above T[N-1] use extrapolation. +// + ival = n - 2; + + for (i = 0; i < n - 1; i++) { + if (tval < t[i + 1]) { + ival = i; + break; + } + } +// +// In the interval I, the polynomial is in terms of a normalized +// coordinate between 0 and 1. +// + dt = tval - t[ival]; + h = t[ival + 1] - t[ival]; + + yval = y[ival] + + dt * ((y[ival + 1] - y[ival]) / h + - (ypp[ival + 1] / 6.0E+00 + ypp[ival] / 3.0E+00) * h + + dt * (0.5E+00 * ypp[ival] + + dt * ((ypp[ival + 1] - ypp[ival]) / (6.0E+00 * h)))); + + *ypval = (y[ival + 1] - y[ival]) / h + - (ypp[ival + 1] / 6.0E+00 + ypp[ival] / 3.0E+00) * h + + dt * (ypp[ival] + + dt * (0.5E+00 * (ypp[ival + 1] - ypp[ival]) / h)); + + *yppval = ypp[ival] + dt * (ypp[ival + 1] - ypp[ival]) / h; + + return yval; +} + +/********************************************* +GetNikonFileType: + Gets the nikon file type by comparing file + headers. + + file - The file to check. +**********************************************/ +static int GetNikonFileType(FILE *file) +{ + unsigned char buff[HEADER_SIZE]; + int i = 0, j = 0; + int found = 1; + + nc_fread(buff, HEADER_SIZE, 1, file); + + for (i = 0; i < NUM_FILE_TYPES; i++) { + found = 1; + for (j = 0; j < HEADER_SIZE; j++) { + if (buff[j] != FileTypeHeaders[i][j]) { + found = 0; + break; + } + } + + if (found) { + //return the file type + return i; + } + } + nc_message(NC_SET_ERROR, "Error, no compatible file types found!\n"); + return -1; +} + +/********************************************* +LoadNikonCurve: + Loads all curves from a Nikon ntc or ncv file. + + fileName - The filename. + curve - Pointer to curve struct to hold the data. + resolution - How many data points to sample from the curve. +**********************************************/ +int LoadNikonData(char *fileName, NikonData *data) +{ + FILE *input = NULL; + int offset = 0; + CurveData *curve = NULL; + + if (fileName == NULL || strlen(fileName) == 0) { + nc_message(NC_SET_ERROR, + "Error, input filename cannot be NULL or empty!\n"); + return NC_ERROR; + } + + DEBUG_PRINT("DEBUG: OPENING FILE: %s\n", fileName); + + //open file for reading only! + input = g_fopen(fileName, "rb"); + + //make sure we have a valid file + if (input == NULL) { + nc_message(NC_SET_ERROR, "Error opening '%s': %s\n", + fileName, strerror(errno)); + return NC_ERROR; + } + + //init the curve; + memset(data, 0, sizeof(NikonData)); + + //get the file type + data->m_fileType = GetNikonFileType(input); + // set file seek positions for curve tones depending of file type + // todo: is it possible to find one common rule? + long curveFilePos[4][4] = { + {FileOffsets[data->m_fileType][BOX_DATA], SEEK_SET, FileOffsets[data->m_fileType][ANCHOR_DATA], SEEK_SET}, + {NEXT_SECTION_BOX_DATA_OFFSET, SEEK_CUR, NUM_POINTS_TO_ANCHOR_OFFSET, SEEK_CUR}, + {NEXT_SECTION_BOX_DATA_OFFSET, SEEK_CUR, NUM_POINTS_TO_ANCHOR_OFFSET, SEEK_CUR}, + {NEXT_SECTION_BOX_DATA_OFFSET, SEEK_CUR, NUM_POINTS_TO_ANCHOR_OFFSET, SEEK_CUR} + }; + + //make sure we have a good file type + if (data->m_fileType == -1) + return NC_ERROR; + + //advance file pointer to necessary data section + fseek(input, offset, SEEK_SET); + + //Conevenience and opt if compiler doesn't already do it + curve = &data->curves[0]; + + //set curve type + curve->m_curveType = TONE_CURVE; + + //read patch version + fseek(input, FileOffsets[data->m_fileType][PATCH_DATA], SEEK_SET); + nc_fread(&data->m_patch_version, sizeof(unsigned short), 1, input); + data->m_patch_version = ShortVal(data->m_patch_version); + + // read all tone curves data follow from here + int i; + for (i = 0; i < NUM_CURVE_TYPES; i++) { + curve = &data->curves[i]; + + //set curve type + curve->m_curveType = i; + + //get box data + fseek(input, curveFilePos[i][0], curveFilePos[i][1]); + + if (!fread(&curve->m_min_x, sizeof(double), 1, input)) continue; + curve->m_min_x = DoubleVal(curve->m_min_x); + + if (!fread(&curve->m_max_x, sizeof(double), 1, input)) continue; + curve->m_max_x = DoubleVal(curve->m_max_x); + + if (!fread(&curve->m_gamma, sizeof(double), 1, input)) continue; + curve->m_gamma = DoubleVal(curve->m_gamma); + + if (!fread(&curve->m_min_y, sizeof(double), 1, input)) continue; + curve->m_min_y = DoubleVal(curve->m_min_y); + + if (!fread(&curve->m_max_y, sizeof(double), 1, input)) continue; + curve->m_max_y = DoubleVal(curve->m_max_y); + + //get number of anchors (always located after box data) + if (!fread(&curve->m_numAnchors, 1, 1, input)) continue; + + // It seems that if there is no curve then the 62 bytes in the buffer + // are either all 0x00 (D70) or 0xFF (D2H). + // We therefore switch these values with the default values. + if (curve->m_min_x == 1.0) { + curve->m_min_x = 0.0; + DEBUG_PRINT("DEBUG: NEF X MIN -> %e (changed)\n", curve->m_min_x); + } + if (curve->m_max_x == 0.0) { + curve->m_max_x = 1.0; + DEBUG_PRINT("DEBUG: NEF X MAX -> %e (changed)\n", curve->m_max_x); + } + if (curve->m_min_y == 1.0) { + curve->m_min_y = 0.0; + DEBUG_PRINT("DEBUG: NEF Y MIN -> %e (changed)\n", curve->m_min_y); + } + if (curve->m_max_y == 0.0) { + curve->m_max_y = 1.0; + DEBUG_PRINT("DEBUG: NEF Y MAX -> %e (changed)\n", curve->m_max_y); + } + if (curve->m_gamma == 0.0 || curve->m_gamma == 255.0 + 255.0 / 256.0) { + curve->m_gamma = 1.0; + DEBUG_PRINT("DEBUG: NEF GAMMA -> %e (changed)\n", curve->m_gamma); + } + if (curve->m_numAnchors == 255) { + curve->m_numAnchors = 0; + DEBUG_PRINT("DEBUG: NEF NUMBER OF ANCHORS -> %u (changed)\n", + curve->m_numAnchors); + } + if (curve->m_numAnchors > NIKON_MAX_ANCHORS) { + curve->m_numAnchors = NIKON_MAX_ANCHORS; + DEBUG_PRINT("DEBUG: NEF NUMBER OF ANCHORS -> %u (changed)\n", + curve->m_numAnchors); + } + //Move to start of the anchor data + fseek(input, curveFilePos[i][2], curveFilePos[i][3]); + + //read in the anchor points + int rs = nc_fread(curve->m_anchors, sizeof(CurveAnchorPoint), + curve->m_numAnchors, input); + if (curve->m_numAnchors != rs) { + nc_message(NC_SET_ERROR, "Error reading all anchor points\n"); + return NC_ERROR; + } + + int j; + for (j = 0; j < curve->m_numAnchors; j++) { + curve->m_anchors[j].x = DoubleVal(curve->m_anchors[j].x); + curve->m_anchors[j].y = DoubleVal(curve->m_anchors[j].y); + } + + DEBUG_PRINT("DEBUG: Loading Data:\n"); + DEBUG_PRINT("DEBUG: CURVE_TYPE: %u \n", curve->m_curveType); + DEBUG_PRINT("DEBUG: BOX->MIN_X: %f\n", curve->m_min_x); + DEBUG_PRINT("DEBUG: BOX->MAX_X: %f\n", curve->m_max_x); + DEBUG_PRINT("DEBUG: BOX->GAMMA: %f\n", curve->m_gamma); + DEBUG_PRINT("DEBUG: BOX->MIN_Y: %f\n", curve->m_min_y); + DEBUG_PRINT("DEBUG: BOX->MAX_Y: %f\n", curve->m_max_x); + +#ifdef _DEBUG + int i_dbg; + for (i_dbg = 0; i_dbg < curve->m_numAnchors; i_dbg++) { + DEBUG_PRINT("DEBUG: ANCHOR X,Y: %f,%f\n", + curve->m_anchors[i_dbg].x, curve->m_anchors[i_dbg].y); + } + DEBUG_PRINT("\n"); +#endif + } + fclose(input); + return NC_SUCCESS; +} + +/********************************************* +CurveDataSample: + Samples from a spline curve constructed from + the Nikon data. + + curve - Pointer to curve struct to hold the data. + sample - Pointer to sample struct to hold the data. +**********************************************/ +int CurveDataSample(CurveData *curve, CurveSample *sample) +{ + int i = 0, n; + + double x[20]; + double y[20]; + + //The box points (except the gamma) are what the anchor points are relative + //to so... + + double box_width = curve->m_max_x - curve->m_min_x; + double box_height = curve->m_max_y - curve->m_min_y; + double gamma = 1.0 / curve->m_gamma; + + //build arrays for processing + if (curve->m_numAnchors == 0) { + //just a straight line using box coordinates + x[0] = curve->m_min_x; + y[0] = curve->m_min_y; + x[1] = curve->m_max_x; + y[1] = curve->m_max_y; + n = 2; + } else { + for (i = 0; i < curve->m_numAnchors; i++) { + x[i] = curve->m_anchors[i].x * box_width + curve->m_min_x; + y[i] = curve->m_anchors[i].y * box_height + curve->m_min_y; + } + n = curve->m_numAnchors; + } + //returns an array of second derivatives used to calculate the spline curve. + //this is a malloc'd array that needs to be freed when done. + //The setings currently calculate the natural spline, which closely matches + //camera curve output in raw files. + double *ypp = spline_cubic_set(n, x, y, 2, 0.0, 2, 0.0); + if (ypp == NULL) return NC_ERROR; + + //first derivative at a point + double ypval = 0; + + //second derivate at a point + double yppval = 0; + + //Now build a table + int val; + double res = 1.0 / (double)(sample->m_samplingRes - 1); + + //allocate enough space for the samples + DEBUG_PRINT("DEBUG: SAMPLING ALLOCATION: %u bytes\n", + sample->m_samplingRes * sizeof(int)); + DEBUG_PRINT("DEBUG: SAMPLING OUTPUT RANGE: 0 -> %u\n", sample->m_outputRes); + + sample->m_Samples = (unsigned int *)realloc(sample->m_Samples, + sample->m_samplingRes * sizeof(int)); + nc_merror(sample->m_Samples, "CurveDataSample"); + + int firstPointX = x[0] * (sample->m_samplingRes - 1); + int firstPointY = pow(y[0], gamma) * (sample->m_outputRes - 1); + int lastPointX = x[n - 1] * (sample->m_samplingRes - 1); + int lastPointY = pow(y[n - 1], gamma) * (sample->m_outputRes - 1); + int maxY = curve->m_max_y * (sample->m_outputRes - 1); + int minY = curve->m_min_y * (sample->m_outputRes - 1); + + for (i = 0; i < (int)sample->m_samplingRes; i++) { + //get the value of the curve at a point + //take into account that curves may not necessarily begin at x = 0.0 + //nor end at x = 1.0 + + //Before the first point and after the last point, take a strait line + if (i < firstPointX) { + sample->m_Samples[i] = firstPointY; + } else if (i > lastPointX) { + sample->m_Samples[i] = lastPointY; + } else { + //within range, we can sample the curve + if (gamma == 1.0) + val = spline_cubic_val(n, x, i * res, y, + ypp, &ypval, &yppval) * (sample->m_outputRes - 1) + 0.5; + else + val = pow(spline_cubic_val(n, x, i * res, y, + ypp, &ypval, &yppval), gamma) * + (sample->m_outputRes - 1) + 0.5; + + sample->m_Samples[i] = MIN(MAX(val, minY), maxY); + } + } + + free(ypp); + return NC_SUCCESS; +} + +/********************************************* +CurveDataReset: + Reset curve to straight line but don't touch the curve name. +**********************************************/ +void CurveDataReset(CurveData *curve) +{ + curve->m_min_x = 0; + curve->m_max_x = 1; + curve->m_min_y = 0; + curve->m_max_y = 1; + curve->m_gamma = 1; + curve->m_numAnchors = 2; + curve->m_anchors[0].x = 0; + curve->m_anchors[0].y = 0; + curve->m_anchors[1].x = 1; + curve->m_anchors[1].y = 1; +} + +/********************************************* +CurveDataIsTrivial: + Check if the curve is a trivial linear curve. +**********************************************/ +int CurveDataIsTrivial(CurveData *curve) +{ + if (curve->m_min_x != 0) return FALSE; + if (curve->m_max_x != 1) return FALSE; + if (curve->m_min_y != 0) return FALSE; + if (curve->m_max_y != 1) return FALSE; + if (curve->m_numAnchors < 2) return TRUE; + if (curve->m_numAnchors != 2) return FALSE; + if (curve->m_anchors[0].x != 0) return FALSE; + if (curve->m_anchors[0].y != 0) return FALSE; + if (curve->m_anchors[1].x != 1) return FALSE; + if (curve->m_anchors[1].y != 1) return FALSE; + return TRUE; +} + +/********************************************* +CurveDataSetPoint: + Change the position of point to the new (x,y) coordinate. + The end-points get a special treatment. When these are moved all the + other points are moved together, keeping their relative position constant. +**********************************************/ +void CurveDataSetPoint(CurveData *curve, int point, double x, double y) +{ + int i; + double left = curve->m_anchors[0].x; + double right = curve->m_anchors[curve->m_numAnchors - 1].x; + if (point == 0) { + for (i = 0; i < curve->m_numAnchors; i++) + curve->m_anchors[i].x = x + (curve->m_anchors[i].x - left) * + (right - x) / (right - left); + } else if (point == curve->m_numAnchors - 1) { + for (i = 0; i < curve->m_numAnchors; i++) + curve->m_anchors[i].x = left + (curve->m_anchors[i].x - left) * + (x - left) / (right - left); + } else { + curve->m_anchors[point].x = x; + } + curve->m_anchors[point].y = y; +} + +/**************************************************** +SampleToCameraCurve: + + EXPERIMENTAL!!!!! + + Transforms the curve generated by sampling the + spline interpolator into the curve that is used by + the camera. + + This is a special function. While the function places + no special restrictions on sampling resolution or + output resolution, it should be noted that Nikon D70 + camera curve is 4096 entries of 0-255. + + If you intend on using this function as such, you should + set the sampling resolution and output resolution + accordingly. + + curve - The Nikon curve to sample and transform. +*****************************************************/ +#ifdef _STAND_ALONE_ +#define CAMERA_LINEAR_CURVE_SLOPE 0.26086956521739130434782608695652 +#define CAMERA_LINEAR_LIMIT ((276.0/4096.0)*65536.0) + +static int SampleToCameraCurve(CurveData *curve, CurveSample *sample) +{ + unsigned int i = 0; + + if (curve->m_numAnchors < 2) { + nc_message(NC_SET_ERROR, "Not enough anchor points(need at least two)!\n"); + return NC_ERROR; + } + + double x[20]; + double y[20]; + + //The box points (except the gamma) are what the anchor points are relative + //to so... + + double box_width = curve->m_max_x - curve->m_min_x; + double box_height = curve->m_max_y - curve->m_min_y; + double gamma = 1.0 / curve->m_gamma; + + //build arrays for processing + if (curve->m_numAnchors == 0) { + //just a straight line using box coordinates + x[0] = curve->m_min_x; + y[0] = curve->m_min_y; + x[1] = curve->m_max_x; + y[1] = curve->m_max_y; + } else { + for (i = 0; i < (unsigned int)curve->m_numAnchors; i++) { + x[i] = curve->m_anchors[i].x * box_width + curve->m_min_x; + y[i] = curve->m_anchors[i].y * box_height + curve->m_min_y; + } + } + + //returns an array of second derivatives used to calculate the spline curve. + //this is a malloc'd array that needs to be freed when done. + //The setings currently calculate the natural spline, which closely matches + //camera curve output in raw files. + double *ypp = spline_cubic_set(curve->m_numAnchors, x, y, 2, 0.0, 2, 0.0); + if (ypp == NULL) return NC_ERROR; + + //first derivative at a point + double ypval = 0; + + //second derivate at a point + double yppval = 0; + + //Now build a table + double val = 0; + double res = 1.0 / (double)sample->m_samplingRes; + + DEBUG_PRINT("DEBUG: SAMPLING RESOLUTION: %u bytes\n", + sample->m_samplingRes * sizeof(int)); + DEBUG_PRINT("DEBUG: SAMPLING OUTPUT RANGE: 0 -> %u\n", sample->m_outputRes); + + double outres = sample->m_outputRes; + + for (i = 0; i < sample->m_samplingRes; i++) { + //get the value of the curve at a point + //take into account that curves may not necessarily begin at x = 0.0 + //nor end at x = 1.0 + if (i * res < curve->m_min_x || i * res > curve->m_max_x) { + val = 0.0; + } else { + //within range, okay to sample the curve + val = spline_cubic_val(curve->m_numAnchors, x, i * res, + y, ypp, &ypval, &yppval); + + //Compensate for gamma. + val = pow(val, gamma); + + //cap at the high end of the range + if (val > curve->m_max_y) { + val = curve->m_max_y; + } + //cap at the low end of the range + else if (val < curve->m_min_y) { + val = curve->m_min_y; + } + + //transform "linear curve" to the camera curve + //outres = 4096; + //val *= outres; + + //this equation is used inside Nikon's program to transform + //the curves into the camera curves. + //FIX LINEAR SECTION + /*if (val < CAMERA_LINEAR_CURVE_SLOPE) + { + //do linear + val = val*4096*CAMERA_LINEAR_CURVE_SLOPE; + + } + else*/ + { + //do real curve?? + val = (log(7 * val + 1.0) / log(4 * val + 2.0)) * 142.0 + 104.0 * (val); + } + + //cap at the high end of the range + if (val > outres * curve->m_max_y) { + val = outres; + } + //cap at the low end of the range + else if (val < curve->m_min_y * outres) { + val = curve->m_min_y * outres; + } + + } + + //save the sample + sample->m_Samples[i] = (unsigned int)floor(val); + } + + free(ypp); + return NC_SUCCESS; +} +#endif + +/************************************************************ +SaveNikonDataFile: + Savess a curve to a Nikon ntc or ncv file. + + data - A NikonData structure containing info of all the curves. + fileName - The filename. + filetype - Indicator for an NCV or NTC file. +**************************************************************/ +int SaveNikonDataFile(NikonData *data, char *outfile, int filetype) +{ + FILE *output = NULL; + int i = 0, r = 0, g = 0, b = 0; + unsigned short_tmp = 0; + unsigned int long_tmp = 0; + double double_tmp = 0; + CurveData *curve = NULL; + + //used for file padding + unsigned char pad[32]; + memset(pad, 0, 32); + + output = g_fopen(outfile, "wb+"); + if (!output) { + nc_message(NC_SET_ERROR, "Error creating curve file '%s': %s\n", + outfile, strerror(errno)); + return NC_ERROR; + } + + //write out file header + nc_fwrite(FileTypeHeaders[filetype], HEADER_SIZE, 1, output); + + if (filetype == NCV_FILE) { + //write out unknown header bytes + short_tmp = ShortVal(NCV_UNKNOWN_HEADER_DATA); + nc_fwrite(&short_tmp, 2, 1, output); + + //write out file size - header + //Placeholder.The real filesize is written at the end. + //NCV files have two size location, one here and one in the + //NTC section of the file + long_tmp = 0; + nc_fwrite(&long_tmp, 4, 1, output); + + //write second header chunk + nc_fwrite(NCVSecondFileHeader, 1, NCV_SECOND_HEADER_LENGTH, output); + + //From here until almost the end, the file is an NTC file + nc_fwrite(NTCFileHeader, NTC_FILE_HEADER_LENGTH, 1, output); + } + + //patch version? (still unsure about this one) + if (data->m_patch_version < NIKON_PATCH_4) { + data->m_patch_version = NIKON_PATCH_5; + } + short_tmp = ShortVal(data->m_patch_version); + nc_fwrite(&short_tmp, 2, 1, output); + + //write out file size - header + //Placeholder.The real filesize is written at the end. + long_tmp = 0; + nc_fwrite(&long_tmp, 4, 1, output); + + //write out version + unsigned int forced_ver = ShortVal(NIKON_VERSION_4_1); + nc_fwrite(&forced_ver, 4, 1, output); + + //write out pad (this is a 7 byte pad) + nc_fwrite(&pad, 1, 7, output); + + //now wash and repeat for the four sections of data + for (i = 0; i < 4; i++) { + //write out section header (same as NTC file header) + nc_fwrite(FileSectionHeader, 1, NTC_FILE_HEADER_LENGTH, output); + + //write out section type + long_tmp = LongVal(i); + nc_fwrite(&long_tmp, 4, 1, output); + + //write out unknown data + short_tmp = ShortVal(NTC_UNKNOWN_DATA); + nc_fwrite(&short_tmp, 2, 1, output); + + //write out pad byte + nc_fwrite(pad, 1, 1, output); + + //write out components + switch (i) { + case 0: + r = g = b = 0; + break; + + case 1: + r = 255; + g = b = 0; + break; + + case 2: + g = 255; + r = b = 0; + break; + + case 3: + b = 255; + g = r = 0; + break; + } + + long_tmp = LongVal(r); + nc_fwrite(&long_tmp, 4, 1, output); + + long_tmp = LongVal(g); + nc_fwrite(&long_tmp, 4, 1, output); + + long_tmp = LongVal(b); + nc_fwrite(&long_tmp, 4, 1, output); + + //write out pad (12 byte pad) + nc_fwrite(pad, 12, 1, output); + + //write out rgb weights + switch (i) { + case 0: + r = g = b = 255; + break; + + case 1: + r = 255; + g = b = 0; + break; + + case 2: + g = 255; + r = b = 0; + break; + + case 3: + b = 255; + g = r = 0; + break; + } + + long_tmp = LongVal(r); + nc_fwrite(&long_tmp, 4, 1, output); + + long_tmp = LongVal(g); + nc_fwrite(&long_tmp, 4, 1, output); + + long_tmp = LongVal(b); + nc_fwrite(&long_tmp, 4, 1, output); + + curve = &data->curves[i]; + //write out curve data + if (curve->m_numAnchors >= 2) { + //we have a legit curve, use the data as is + double_tmp = DoubleVal(curve->m_min_x); + nc_fwrite(&double_tmp, sizeof(double), 1, output); + + double_tmp = DoubleVal(curve->m_max_x); + nc_fwrite(&double_tmp, sizeof(double), 1, output); + + double_tmp = DoubleVal(curve->m_gamma); + nc_fwrite(&double_tmp, sizeof(double), 1, output); + + double_tmp = DoubleVal(curve->m_min_y); + nc_fwrite(&double_tmp, sizeof(double), 1, output); + + double_tmp = DoubleVal(curve->m_max_y); + nc_fwrite(&double_tmp, sizeof(double), 1, output); + + //write out number of anchor points (minimum is two) + nc_fwrite(&curve->m_numAnchors, 1, 1, output); + + //write out pad + nc_fwrite(pad, NUM_POINTS_TO_ANCHOR_OFFSET, 1, output); + + //write out anchor point data + if (curve->m_anchors) { + int i; + for (i = 0; i < curve->m_numAnchors; i++) { + double_tmp = DoubleVal(curve->m_anchors[i].x); + nc_fwrite(&double_tmp, sizeof(double), 1, output); + double_tmp = DoubleVal(curve->m_anchors[i].y); + nc_fwrite(&double_tmp, sizeof(double), 1, output); + } + } else { + nc_message(NC_SET_ERROR, "Curve anchor data is NULL! Aborting file write!\n"); + return NC_ERROR; + } + } else { + DEBUG_PRINT("NOTE: There are < 2 anchor points for curve %u! Forcing curve defaults.\n", i); + DEBUG_PRINT("This should not be a concern unless it is happening for curve 0\n"); + //This curve either has not been correctly initialized or is empty. + //Force defaults. + double default_val = 0; + nc_fwrite(&default_val, sizeof(double), 1, output); //min x + default_val = DoubleVal(1.0); + nc_fwrite(&default_val, sizeof(double), 1, output); //max_x + //gamma has a default of 1 + default_val = DoubleVal(1.0); + nc_fwrite(&default_val, sizeof(double), 1, output); //gamma + default_val = 0; + nc_fwrite(&default_val, sizeof(double), 1, output); //min y + default_val = DoubleVal(1.0); + nc_fwrite(&default_val, sizeof(double), 1, output); //max y + + //force the number of anchors to be 2 + unsigned char num = 2; + nc_fwrite(&num, 1, 1, output); + + //write out pad + nc_fwrite(pad, NUM_POINTS_TO_ANCHOR_OFFSET, 1, output); + + //if the number of anchors was < 2, force default values. + default_val = 0; + nc_fwrite(&default_val, sizeof(double), 1, output); //min x + nc_fwrite(&default_val, sizeof(double), 1, output); //min y + default_val = DoubleVal(1.0); + nc_fwrite(&default_val, sizeof(double), 1, output); //max x + nc_fwrite(&default_val, sizeof(double), 1, output); //max y + + } + + //write out pad + nc_fwrite(pad, END_ANCHOR_DATA_PAD_LENGTH, 1, output); + } + + if (filetype == NCV_FILE) { + //write out the file terminator if this is an NCV file + nc_fwrite(NCVFileTerminator, NCV_FILE_TERMINATOR_LENGTH, 1, output); + } + + //calculate the file size + //size = filesize - size of header - 2 bytes (unknown data after the end of the header) + long size = ftell(output) - HEADER_SIZE - 2; + + //set the file write position to the size location + fseek(output, FILE_SIZE_OFFSET, SEEK_SET); + + //write out the file size + size = LongVal(size); + nc_fwrite(&size, 4, 1, output); + + if (filetype == NCV_FILE) { + //another size needs to placed in the NTC header inside the file + fseek(output, NCV_SECOND_FILE_SIZE_OFFSET, SEEK_SET); + + //The - 6 is interesting. The last 6 bytes of the terminator must have some special meaning because + //the calculated size in files from the Nikon progs always calculate size bytes short. + //I'm assuming it is more than coincedence that those bytes match the last 6 bytes + //of the NCV second file header. I've yet to determine their significance. + size = LongVal(size - NCV_HEADER_SIZE - 6); + nc_fwrite(&size, 4, 1, output); + + } + fclose(output); + + return NC_SUCCESS; +} + +/************************************************************ +SaveNikonCurveFile: + Saves out curves to a Nikon ntc or ncv file. This function + takes a single curve and uses defaults for the other curves. + Typically, the curve used is the tone curve. + + curve - A CurveData structure. This is usually the tone curve + curve_type - The curve type (TONE_CURVE, RED_CURVE, etc.) + fileName - The filename. + filetype - Indicator for an NCV or NTC file. + +NOTE: The only version tested is Nikon 4.1 anything + other than this may result in unpredictable behavior. + For now, the version passed in is ignored and is forced + to 4.1. + + This function is just a helper function that allows the user + to just carry around a single curve. +**************************************************************/ +#ifdef _STAND_ALONE_ +static int SaveNikonCurveFile(CurveData *curve, int curve_type, char *outfile, + int filetype) +{ + NikonData data; + //clear the structure + memset(&data, 0, sizeof(data)); + //assume that it's the tone curve + data.curves[curve_type] = *curve; + //call the work horse + return SaveNikonDataFile(&data, outfile, filetype); +} +#endif + +/********************************************* +SaveSampledNikonCurve: + Saves a sampling from a curve to text file to + be processed by UFRaw. + + sample - Pointer to sampled curve struct to hold the data. + fileName - The filename. +**********************************************/ +#ifdef _STAND_ALONE_ +static int SaveSampledNikonCurve(CurveSample *sample, char *outfile) +{ + unsigned int i = 0; + FILE *output = NULL; + + if (outfile == NULL || strlen(outfile) == 0) { + nc_message(NC_SET_ERROR, + "Output filename cannot be null or empty!\n"); + } + + output = g_fopen(outfile, "wb+"); + + if (!output) { + nc_message(NC_SET_ERROR, "Error creating curve file '%s': %s\n", + outfile, strerror(errno)); + return NC_ERROR; + } + + if (!sample->m_Samples) { + nc_message(NC_SET_ERROR, + "Sample array has not been allocated or is corrupt!\n"); + return NC_ERROR; + } + + DEBUG_PRINT("DEBUG: OUTPUT FILENAME: %s\n", outfile); + fprintf(output, "%u %u\n", 0, sample->m_Samples[0]); + for (i = 1; i < sample->m_samplingRes; i++) { + // Print sample point only if different than previous one + if (sample->m_Samples[i] != sample->m_Samples[i - 1]) { + fprintf(output, "%u %u\n", i, sample->m_Samples[i]); + } + } + // Make sure the last point is also printed + if (sample->m_Samples[i - 1] == sample->m_Samples[i - 2]) { + fprintf(output, "%u %u\n", i - 1, sample->m_Samples[i - 1]); + } + + fclose(output); + return NC_SUCCESS; +} +#endif + +/******************************************************* +CurveSampleInit: + Init and allocate curve sample. +********************************************************/ +CurveSample *CurveSampleInit(unsigned int samplingRes, unsigned int outputRes) +{ + CurveSample *sample = (CurveSample*)calloc(1, sizeof(CurveSample)); + nc_merror(sample, "CurveSampleInit"); + sample->m_samplingRes = samplingRes; + sample->m_outputRes = outputRes; + if (samplingRes > 0) { + sample->m_Samples = (unsigned int*)calloc(samplingRes, sizeof(int)); + nc_merror(sample->m_Samples, "CurveSampleInit"); + } else { + sample->m_Samples = NULL; + } + return sample; +} + +/******************************************************* +CurveSampleFree: + Frees memory allocated for this curve sample. +********************************************************/ +int CurveSampleFree(CurveSample *sample) +{ + //if these are null, they've already been deallocated + if (sample == NULL) return NC_SUCCESS; + + if (sample->m_Samples != NULL) { + free(sample->m_Samples); + sample->m_Samples = NULL; + } + + free(sample); + + return NC_SUCCESS; +} + +/**************************************** +ConvertNikonCurveData: + The main driver. Takes a filename and + processes the curve, if possible. + + fileName - The file to process. +*****************************************/ +#ifdef _STAND_ALONE_ +static int ConvertNikonCurveData(char *inFileName, char *outFileName, + unsigned int samplingRes, unsigned int outputRes) +{ + //Load the curve data from the ncv/ntc file + NikonData data; + char tmpstr[1024]; + + if (samplingRes <= 1 || outputRes <= 1 || samplingRes > MAX_RESOLUTION + || outputRes > MAX_RESOLUTION) { + nc_message(NC_SET_ERROR, "Error, sampling and output resolution" + "must be 1 <= res <= %u\n", MAX_RESOLUTION); + return NC_ERROR; + } + + //loads all the curve data. Does not allocate sample arrays. + if (LoadNikonData(inFileName, &data) != NC_SUCCESS) { + return NC_ERROR; + } + + CurveSample *sample = CurveSampleInit(samplingRes, outputRes); + + //Cycle through all curves + int i; + for (i = 0; i < NUM_CURVE_TYPES; i++) { + //Populates the samples array for the given curve + if (SampleToCameraCurve(&data.curves[i], sample) != NC_SUCCESS) { + CurveSampleFree(sample); + return NC_ERROR; + } + + //rename output files + strncpy(tmpstr, outFileName, 1023); + tmpstr[1023] = '\0'; + //if the name has an extension, attempt to remove it + if (tmpstr[strlen(tmpstr) - 4] == '.') { + tmpstr[strlen(tmpstr) - 4] = '\0'; + } + + switch (i) { + case TONE_CURVE: + strncat(tmpstr, "_TONE.txt", 1023); + break; + + case RED_CURVE: + strncat(tmpstr, "_RED.txt", 1023); + break; + + case GREEN_CURVE: + strncat(tmpstr, "_GREEN.txt", 1023); + break; + + case BLUE_CURVE: + strncat(tmpstr, "_BLUE.txt", 1023); + break; + + default: + //should never get here + break; + } + + //print out curve data + if (SaveSampledNikonCurve(sample, tmpstr) != NC_SUCCESS) { + CurveSampleFree(sample); + return NC_ERROR; + } + } + + //must be called when finished with a CurveSample structure + CurveSampleFree(sample); + + return NC_SUCCESS; +} +#endif + +/***************************************************** +FindTIFFOffset: + Moves the file pointer to the location + indicated by the TAG-TYPE pairing. This is meant just + as a helper function for this code. Uses elsewhere + may be limited. + + file - Nikon File ptr + num_entries - Number of entries to search through + tiff_tag - The tiff tag to match. + tiff_type - The tiff type to match. +*******************************************************/ +#ifdef _STAND_ALONE_ +static int FindTIFFOffset(FILE *file, unsigned short num_entries, + unsigned short tiff_tag, unsigned short tiff_type) +{ + unsigned short tag = 0; + unsigned short type = 0; + unsigned int offset = 0; + + int i; + for (i = 0; i < num_entries; i++) { + //get tag 2 bytes + tag = (fgetc(file) << 8) | fgetc(file); + if (tag == tiff_tag) { + //get type 2 bytes + type = (fgetc(file) << 8) | fgetc(file); + if (type == tiff_type) { //Type for length of field + //get length (4 bytes) + offset = (fgetc(file) << 24) | (fgetc(file) << 16) | (fgetc(file) << 8) | fgetc(file); + //get value\offset 4 bytes + offset = (fgetc(file) << 24) | (fgetc(file) << 16) | (fgetc(file) << 8) | fgetc(file); + fseek(file, offset, SEEK_SET); + return 1; //true; + } + } else { + //advance to next entry + fseek(file, 10, SEEK_CUR); + } + } + return 0; //false; +} +#endif + +/******************************************************* +RipNikonNEFData: + Gets Nikon NEF data. For now, this is just the tone + curve data. + + infile - The input file + curve - data structure to hold data in. + sample_p - pointer to the curve sample reference. + can be NULL if curve sample is not needed. +********************************************************/ +#ifdef _STAND_ALONE_ +static int RipNikonNEFData(char *infile, CurveData *data, + CurveSample **sample_p) +{ + unsigned short byte_order = 0; + unsigned short num_entries = 0; + unsigned short version = 0; + unsigned int offset = 0; + + //open the file + FILE *file = g_fopen(infile, "rb"); + + //make sure we have a valid file + if (file == NULL) { + nc_message(NC_SET_ERROR, "Error opening '%s': %s\n", + infile, strerror(errno)); + return NC_ERROR; + } + + //gets the byte order + nc_fread(&byte_order, 2, 1, file); + byte_order = ShortVal(byte_order); + if (byte_order != 0x4d4d) { + //Must be in motorola format if it came from a NIKON + nc_message(NC_SET_ERROR, + "NEF file data format is Intel. Data format should be Motorola.\n"); + return NC_ERROR; + } + + //get the version + //nc_fread(&version,2,1,file); + version = (fgetc(file) << 8) | fgetc(file); + if (version != 0x002a) { + //must be 42 or not a valid TIFF + nc_message(NC_SET_ERROR, + "NEF file version is %u. Version should be 42.\n", version); + return NC_ERROR; + } + + //get offset to first IFD + offset = (fgetc(file) << 24) | (fgetc(file) << 16) | (fgetc(file) << 8) | fgetc(file); + //go to the IFD + fseek(file, offset, SEEK_SET); + //get number of entries + num_entries = (fgetc(file) << 8) | fgetc(file); + + //move file pointer to exif offset + if (!FindTIFFOffset(file, num_entries, TIFF_TAG_EXIF_OFFSET, TIFF_TYPE_LONG)) { + nc_message(NC_SET_ERROR, + "NEF data entry could not be found with tag %u and type %u.\n", + TIFF_TAG_EXIF_OFFSET, TIFF_TYPE_LONG); + return NC_ERROR; + } + + //get number of entries + num_entries = (fgetc(file) << 8) | fgetc(file); + + //move file pointer to maker note offset + if (!FindTIFFOffset(file, num_entries, TIFF_TAG_MAKER_NOTE_OFFSET, TIFF_TYPE_UNDEFINED)) { + nc_message(NC_SET_ERROR, + "NEF data entry could not be found with tag %u and type %u.\n", + TIFF_TAG_MAKER_NOTE_OFFSET, TIFF_TYPE_UNDEFINED); + return NC_ERROR; + } + + ////////////////////////////////////////////////////////////////////////// + //NOTE: At this point, this section of the file acts almost like another + // file header. Skip the first bytes, (which just say nikon with a + // few bytes at the end. Offsets from here on in are from the start + // of this section, not the start of the file. + ////////////////////////////////////////////////////////////////////////// + + //Check the name. If it isn't Nikon then we can't do anything with this file. + char name[6]; + nc_fread(name, 6, 1, file); + if (strcmp(name, "Nikon") != 0) { + nc_message(NC_SET_ERROR, + "NEF string identifier is %s. Should be: Nikon.\n", name); + return NC_ERROR; + } + fseek(file, 4, SEEK_CUR); + + //save the current file location, as all other offsets for this section run off this. + unsigned long pos = ftell(file); + + //get byte order (use a regular fread) + nc_fread(&byte_order, 2, 1, file); + byte_order = ShortVal(byte_order); + if (byte_order != 0x4d4d) { + //Must be in motorola format or not from a Nikon + nc_message(NC_SET_ERROR, + "NEF secondary file data format is Intel. " + "Data format should be Motorola.\n"); + return NC_ERROR; + } + + //get version + version = (fgetc(file) << 8) | fgetc(file); + if (version != 0x002a) { + nc_message(NC_SET_ERROR, + "NEF secondary file version is %u. Version should be 42.\n", + version); + return NC_ERROR; + } + + //get offset to first IFD + offset = (fgetc(file) << 24) | (fgetc(file) << 16) | (fgetc(file) << 8) | fgetc(file); + //go to the IFD (these offsets are NOT from the start of the file, + //just the start of the section). + fseek(file, pos + offset, SEEK_SET); + //get number of entries + num_entries = (fgetc(file) << 8) | fgetc(file); + + //move file position to tone curve data + if (!FindTIFFOffset(file, num_entries, TIFF_TAG_CURVE_OFFSET, TIFF_TYPE_UNDEFINED)) { + nc_message(NC_SET_ERROR, + "NEF data entry could not be found with tag %u and type %u.\n", + TIFF_TAG_CURVE_OFFSET, TIFF_TYPE_UNDEFINED); + return NC_ERROR; + } + + offset = ftell(file); + return RipNikonNEFCurve(file, offset + pos, data, sample_p); +} +#endif + +/******************************************************* +RipNikonNEFCurve: + The actual retriever for the curve data from the NEF + file. + + file - The input file. + infile - Offset to retrieve the data + curve - data structure to hold curve in. + sample_p - pointer to the curve sample reference. + can be NULL if curve sample is not needed. +********************************************************/ +int RipNikonNEFCurve(void *file, int offset, CurveData *data, + CurveSample **sample_p) +{ + int i; + + //seek to the offset of the data. Skip first two bytes (section isn't needed). + fseek(file, offset + 2, SEEK_SET); + + memset(data, 0, sizeof(CurveData)); + ///////////////////////////////////////////////// + //GET CURVE DATA + ///////////////////////////////////////////////// + //get box data and gamma + data->m_min_x = (double)fgetc(file) / 255.0; + data->m_max_x = (double)fgetc(file) / 255.0; + data->m_min_y = (double)fgetc(file) / 255.0; + data->m_max_y = (double)fgetc(file) / 255.0; + //16-bit fixed point. + data->m_gamma = (double)fgetc(file) + ((double)fgetc(file) / 256.0); + + //DEBUG_PRINT("DEBUG: NEF SECTION SIZE -> %u\n",data->section_size); + DEBUG_PRINT("DEBUG: NEF X MIN -> %e\n", data->m_min_x); + DEBUG_PRINT("DEBUG: NEF X MAX -> %e\n", data->m_max_x); + DEBUG_PRINT("DEBUG: NEF Y MIN -> %e\n", data->m_min_y); + DEBUG_PRINT("DEBUG: NEF Y MAX -> %e\n", data->m_max_y); + //DEBUG_PRINT("DEBUG: NEF GAMMA (16-bit fixed point) -> %e\n",(data->m_gamma>>8)+(data->m_gamma&0x00ff)/256.0); + DEBUG_PRINT("DEBUG: NEF GAMMA -> %e\n", data->m_gamma); + // It seems that if there is no curve then the 62 bytes in the buffer + // are either all 0x00 (D70) or 0xFF (D2H). + // We therefore switch these values with the default values. + if (data->m_min_x == 1.0) { + data->m_min_x = 0.0; + DEBUG_PRINT("DEBUG: NEF X MIN -> %e (changed)\n", data->m_min_x); + } + if (data->m_max_x == 0.0) { + data->m_max_x = 1.0; + DEBUG_PRINT("DEBUG: NEF X MAX -> %e (changed)\n", data->m_max_x); + } + if (data->m_min_y == 1.0) { + data->m_min_y = 0.0; + DEBUG_PRINT("DEBUG: NEF Y MIN -> %e (changed)\n", data->m_min_y); + } + if (data->m_max_y == 0.0) { + data->m_max_y = 1.0; + DEBUG_PRINT("DEBUG: NEF Y MAX -> %e (changed)\n", data->m_max_y); + } + if (data->m_gamma == 0.0 || data->m_gamma == 255.0 + 255.0 / 256.0) { + data->m_gamma = 1.0; + DEBUG_PRINT("DEBUG: NEF GAMMA -> %e (changed)\n", data->m_gamma); + } + + //get number of anchor points (there should be at least 2 + nc_fread(&data->m_numAnchors, 1, 1, file); + DEBUG_PRINT("DEBUG: NEF NUMBER OF ANCHORS -> %u\n", data->m_numAnchors); + if (data->m_numAnchors == 255) { + data->m_numAnchors = 0; + DEBUG_PRINT("DEBUG: NEF NUMBER OF ANCHORS -> %u (changed)\n", + data->m_numAnchors); + } + if (data->m_numAnchors > NIKON_MAX_ANCHORS) { + data->m_numAnchors = NIKON_MAX_ANCHORS; + DEBUG_PRINT("DEBUG: NEF NUMBER OF ANCHORS -> %u (changed)\n", + data->m_numAnchors); + } + + //convert data to doubles + for (i = 0; i < data->m_numAnchors; i++) { + //get anchor points + data->m_anchors[i].x = (double)fgetc(file) / 255.0; + data->m_anchors[i].y = (double)fgetc(file) / 255.0; + } + + //The total number of points possible is 25 (50 bytes). + //At this point we subtract the number of bytes read for points from the max (50+1) + fseek(file, (51 - data->m_numAnchors * 2), SEEK_CUR); + + //get data (always 4096 entries, 1 byte apiece) + DEBUG_PRINT("DEBUG: NEF data OFFSET -> %ld\n", ftell(file)); + + if (sample_p != NULL) { + // Sampling res is always 4096, and output res is alway 256 + *sample_p = CurveSampleInit(4096, 256); + + //get the samples + for (i = 0; i < 4096; i++) { + (*sample_p)->m_Samples[i] = (unsigned int)fgetc(file); + } + } + + return NC_SUCCESS; +} + +/******************************* +main: + Uh....no comment. :) +********************************/ +#ifdef _STAND_ALONE_ + +int main(int argc, char* argv[]) +{ + //make sure we can continue processing + if (ProcessArgs(argc, argv) == NC_SUCCESS) { + + //if we are in NEF mode, rip the curve out of the RAW file + if (program_mode == NEF_MODE) { + NikonData data; + + //intiialze the structure to zero + memset(&data, 0, sizeof(NikonData)); + + if (RipNikonNEFData(nikonFilename, &data.curves[TONE_CURVE], NULL) + != NC_SUCCESS) { + return NC_ERROR; + } + + CurveSample *sample = CurveSampleInit(65536, 256); + + if (CurveDataSample(&data.curves[TONE_CURVE], sample) + != NC_SUCCESS) { + CurveSampleFree(sample); + return NC_ERROR; + } + + if (SaveSampledNikonCurve(sample, exportFilename) != NC_SUCCESS) { + CurveSampleFree(sample); + return NC_ERROR; + } + + if (SaveNikonCurveFile(&data.curves[TONE_CURVE], TONE_CURVE, + "outcurve.ncv", NCV_FILE)) { + CurveSampleFree(sample); + return NC_ERROR; + } + + //This can also be used + if (SaveNikonDataFile(&data, "outcurve2.ncv", NCV_FILE)) { + CurveSampleFree(sample); + return NC_ERROR; + } + + CurveSampleFree(sample); + } + //else, process a nikon curve file + else { + //do the deed + ConvertNikonCurveData(nikonFilename, exportFilename, + standalone_samplingRes, standalone_outputRes); + } + } + return NC_SUCCESS; +} +#endif diff --git a/plugins/load-dcraw/nikon_curve.h b/plugins/load-dcraw/nikon_curve.h new file mode 100644 index 00000000..65079c86 --- /dev/null +++ b/plugins/load-dcraw/nikon_curve.h @@ -0,0 +1,199 @@ +/*************************************************** + nikon_curve.h - read Nikon NTC/NCV files + + Copyright 2004-2016 by Shawn Freeman, Udi Fuchs + + 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 reads in a Nikon NTC/NCV file, + interperates it's tone curve, and writes out a + simple ascii file containing a table of interpolation + values. + + You'll note that this has been written in way that can be used in a + standalone program or incorporated into another program. You can use the + functions seperately or you can just call ConvertNikonCurveData with + an input and output file. + + I've tried to document the code as clearly as possible. Let me know if you + have any problems! + + Thanks goes out to Udi Fuchs for wanting to incorporate nikon curve loading + into his program. This will make GIMP just that much better. :) + + @author: Shawn Freeman 1/06/2005 + @liscense: GNU GPL +****************************************************/ +#ifndef _NIKON_CURVE_H +#define _NIKON_CURVE_H + +#define NC_VERSION "1.2" +#define NC_DATE "2005-08-06" + +#define NIKON_MAX_ANCHORS 20 + +//file types +#define NTC_FILE 0 +#define NCV_FILE 1 +#define NUM_FILE_TYPES 2 + +//Curve Types +#define TONE_CURVE 0 +#define RED_CURVE 1 +#define GREEN_CURVE 2 +#define BLUE_CURVE 3 +#define NUM_CURVE_TYPES 4 + +//////////////////////// +//ERROR HANDLING +//////////////////////// +#define NC_SUCCESS 0 +#define NC_ERROR 100 +#define NC_WARNING 104 +#define NC_SET_ERROR 200 + + +////////////////////////////////////////////////////////////////////////////// +//DATA STRUCTURES +////////////////////////////////////////////////////////////////////////////// + +/********************************************************** +CurveData: + Structure for the curve data inside a NTC/NCV file. +***********************************************************/ +typedef struct { + double x; + double y; +} CurveAnchorPoint; + +typedef struct { + char name[80]; + + //Type for this curve + unsigned int m_curveType; + + //Box data + double m_min_x; + double m_max_x; + double m_min_y; + double m_max_y; + double m_gamma; + + //Number of anchor points + unsigned char m_numAnchors; + + //contains a list of anchors, 2 doubles per each point, x-y format + //max is 20 points + CurveAnchorPoint m_anchors[NIKON_MAX_ANCHORS]; + +} CurveData; + +typedef struct { + //Number of samples to use for the curve. + unsigned int m_samplingRes; + unsigned int m_outputRes; + + //Sampling array + unsigned int *m_Samples; + +} CurveSample; + +/********************************************* +NikonData: + Overall data structure for Nikon file data +**********************************************/ +typedef struct { + //Number of output points + int m_fileType; + unsigned short m_patch_version; + CurveData curves[4]; +} NikonData; + +////////////////////////////////////////////////////////////////////////////// +//FUNCTIONS +////////////////////////////////////////////////////////////////////////////// + +/********************************************* +CurveDataSample: + Samples from a spline curve constructed from + the curve data. + + curve - Pointer to curve struct to hold the data. + sample - Pointer to sample struct to hold the data. +**********************************************/ +int CurveDataSample(CurveData *curve, CurveSample *sample); + +/********************************************* + * CurveDataReset: + * Reset curve to straight line but don't touch the curve name. + **********************************************/ +void CurveDataReset(CurveData *curve); + +/********************************************* + * CurveDataIsTrivial: + * Check if the curve is a trivial linear curve. + ***********************************************/ +int CurveDataIsTrivial(CurveData *curve); + +/********************************************* + CurveDataSetPoint: + Change the position of point to the new (x,y) coordinate. + The end-points get a special treatment. When these are moved all the + other points are moved together, keeping their relative position constant. +**********************************************/ +void CurveDataSetPoint(CurveData *curve, int point, double x, double y); + +/******************************************************* +CurveSampleInit: + Init and allocate curve sample. +********************************************************/ +CurveSample *CurveSampleInit(unsigned int samplingRes, unsigned int outputRes); + +/******************************************************* +CurveSampleFree: + Frees memory allocated for this curve sample. +********************************************************/ +int CurveSampleFree(CurveSample *sample); + +/********************************************* +LoadNikonData: + Loads a curve from a Nikon ntc or ncv file. + + fileName - The filename. + curve - Pointer to curve struct to hold the data. + resolution - How many data points to sample from the curve +**********************************************/ +int LoadNikonData(char *fileName, NikonData *data); + +/************************************************************ +SaveNikonDataFile: + Savess a curve to a Nikon ntc or ncv file. + + data - A NikonData structure containing info of all the curves. + fileName - The filename. + filetype - Indicator for an NCV or NTC file. +**************************************************************/ +int SaveNikonDataFile(NikonData *data, char *outfile, int filetype); + +/******************************************************* +RipNikonNEFCurve: + The actual retriever for the curve data from the NEF + file. + + file - The input file. + infile - Offset to retrieve the data + curve - data structure to hold curve in. + sample_p - pointer to the curve sample reference. + can be NULL if curve sample is not needed. +********************************************************/ +int RipNikonNEFCurve(void *file, int offset, CurveData *data, + CurveSample **sample_p); + +#endif diff --git a/plugins/load-dcraw/uf_glib.h b/plugins/load-dcraw/uf_glib.h new file mode 100644 index 00000000..56cd6971 --- /dev/null +++ b/plugins/load-dcraw/uf_glib.h @@ -0,0 +1,47 @@ +/* + * UFRaw - Unidentified Flying Raw converter for digital camera images + * + * uf_glib.h - glib compatibility header + * Copyright 2004-2016 by Udi Fuchs + * + * 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. + */ + +#ifndef _UF_GLIB_H +#define _UF_GLIB_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// g_win32_locale_filename_from_utf8 is needed only on win32 +#ifdef _WIN32 +#define uf_win32_locale_filename_from_utf8(__some_string__) \ + g_win32_locale_filename_from_utf8(__some_string__) +#define uf_win32_locale_filename_free(__some_string__) g_free(__some_string__) +#else +#define uf_win32_locale_filename_from_utf8(__some_string__) (__some_string__) +#define uf_win32_locale_filename_free(__some_string__) (void)(__some_string__) +#endif + +// On win32 command-line arguments need to be translated to UTF-8 +#ifdef _WIN32 +#define uf_win32_locale_to_utf8(__some_string__) \ + g_locale_to_utf8(__some_string__, -1, NULL, NULL, NULL) +#define uf_win32_locale_free(__some_string__) g_free(__some_string__) +#else +#define uf_win32_locale_to_utf8(__some_string__) (__some_string__) +#define uf_win32_locale_free(__some_string__) (void)(__some_string__) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /*_UF_GLIB_H*/ diff --git a/plugins/load-dcraw/uf_progress.h b/plugins/load-dcraw/uf_progress.h new file mode 100644 index 00000000..79f66bb8 --- /dev/null +++ b/plugins/load-dcraw/uf_progress.h @@ -0,0 +1,41 @@ +/* + * UFRaw - Unidentified Flying Raw converter for digital camera images + * + * uf_progress.h - progress bar header + * Copyright 2009-2016 by Frank van Maarseveen, Udi Fuchs + * + * 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. + */ + +#ifndef _UF_PROGRESS_H +#define _UF_PROGRESS_H + +#define PROGRESS_WAVELET_DENOISE 1 +#define PROGRESS_DESPECKLE 2 +#define PROGRESS_INTERPOLATE 3 +#define PROGRESS_RENDER 4 /* tiled work */ + +#define PROGRESS_LOAD 5 +#define PROGRESS_SAVE 6 + +extern void (*ufraw_progress)(int what, int ticks); + +/* + * The first call for a PROGRESS_* activity should specify a negative number + * of ticks. This call will prepare the corresponding progress bar segment. + * Subsequent calls for the same activity should specify a non-negative number + * of ticks corresponding to the amount of work just done. The total number + * of ticks including the initialization call should be approximately zero. + * + * This function is thread safe. See also preview_progress(). + */ +static inline void progress(int what, int ticks) +{ + if (ufraw_progress) + ufraw_progress(what, ticks); +} + +#endif /* _UF_PROGRESS_H */ diff --git a/plugins/load-dcraw/ufobject.cc b/plugins/load-dcraw/ufobject.cc new file mode 100644 index 00000000..bdcdc314 --- /dev/null +++ b/plugins/load-dcraw/ufobject.cc @@ -0,0 +1,1219 @@ +/* + * UFRaw - Unidentified Flying Raw converter for digital camera images + * + * ufobject.cc - UFObject C++ implementation and C interface. + * Copyright 2004-2016 by Udi Fuchs + * + * 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. + */ + +#include "ufobject.h" +#define G_LOG_DOMAIN "UFObject" +#include +#include +#include // for strcmp +#include // for sscanf +#include // for pow, log, floor +#include // for std::max +#include // for std::map +#include // for std::logic_error +#include // for std::bad_cast +#include // for std::numeric_limits::quiet_NaN() + +/***************************\ + * UFObject implementation * +\***************************/ + +class _UFObject +{ +public: + const UFName Name; + void *UserData; + char *String; + class _UFGroup *Parent; + UFEventHandle *EventHandle; + explicit _UFObject(UFName name) : Name(name), UserData(NULL), String(NULL), + Parent(NULL), EventHandle(NULL) { } + virtual ~_UFObject() { + g_free(String); + if (Parent != NULL) + g_warning("%s: Destroyed while having a parent.", Name); + } + virtual bool Changing() const; + virtual void SetChanging(bool state); + void CallValueChangedEvent(UFObject *that) { + bool saveChanging = Changing(); + if (!Changing()) { + SetChanging(true); + that->OriginalValueChangedEvent(); + } + that->Event(uf_value_changed); + SetChanging(saveChanging); + } +}; + +UFObject::UFObject(_UFObject *object) : ufobject(object) { } + +UFObject::~UFObject() +{ + Event(uf_destroyed); + delete ufobject; +} + +UFName UFObject::Name() const +{ + return ufobject->Name; +} + +void UFObject::SetUserData(void *userData) +{ + ufobject->UserData = userData; + Event(uf_user_data_set); +} + +void *UFObject::UserData() +{ + return ufobject->UserData; +} + +UFObject::operator class UFNumber&() +{ + return dynamic_cast(*this); +} + +UFObject::operator const class UFNumber&() const +{ + return dynamic_cast(*this); +} + +UFObject::operator class UFNumberArray&() +{ + return dynamic_cast(*this); +} + +UFObject::operator const class UFNumberArray&() const +{ + return dynamic_cast(*this); +} + +UFObject::operator class UFString&() +{ + return dynamic_cast(*this); +} + +UFObject::operator const class UFString&() const +{ + return dynamic_cast(*this); +} + +UFObject::operator class UFGroup&() +{ + return dynamic_cast(*this); +} + +UFObject::operator const class UFGroup&() const +{ + return dynamic_cast(*this); +} + +UFObject::operator class UFArray&() +{ + return dynamic_cast(*this); +} + +UFObject::operator const class UFArray&() const +{ + return dynamic_cast(*this); +} + +bool UFObject::HasParent() const +{ + return ufobject->Parent != NULL; +} + +const char *UFObject::StringValue() const +{ + return ufobject->String; +} + +std::string UFObject::XML(const char *indent) const +{ + if (IsDefault()) + return ""; + char *value = g_markup_escape_text(StringValue(), -1); + std::string str = (std::string)indent + + "<" + Name() + ">" + value + "\n"; + g_free(value); + return str; +} + +void UFObject::Message(const char *format, ...) const +{ + if (format == NULL) + return; + va_list ap; + va_start(ap, format); + char *message = g_strdup_vprintf(format, ap); + va_end(ap); + if (HasParent()) { + Parent().Message("%s: %s", Name(), message); + } else { + fprintf(stderr, "%s: %s\n", Name(), message); + } + g_free(message); +} + +void UFObject::Throw(const char *format, ...) const +{ + if (format == NULL) + return; + va_list ap; + va_start(ap, format); + char *message = g_strdup_vprintf(format, ap); + va_end(ap); + std::string mess(message); + g_free(message); + throw UFException(mess); +} + +void UFObject::SetEventHandle(UFEventHandle *handle) +{ + ufobject->EventHandle = handle; +} + +void UFObject::Event(UFEventType type) +{ + if (ufobject->EventHandle != NULL) + (*ufobject->EventHandle)(this, type); + if (type == uf_value_changed && HasParent()) + Parent().Event(type); +} + +void UFObject::OriginalValueChangedEvent() { } + +/***************************\ + * UFNumber implementation * +\***************************/ + +class _UFNumberCommon : public _UFObject +{ +public: + double Minimum; + double Maximum; + const int AccuracyDigits; + const double Accuracy; + const double Step; + const double Jump; + _UFNumberCommon(UFName name, double minimum, double maximum, + int accuracyDigits, double step, double jump) : + _UFObject(name), Minimum(minimum), Maximum(maximum), + AccuracyDigits(std::max(accuracyDigits < 0 ? + 3 - (int)floor(log(Maximum - Minimum) / log(10.0)) : + accuracyDigits, 0)), + Accuracy(pow(10.0, -AccuracyDigits)), + Step(step == 0.0 ? Accuracy * 10.0 : step), + Jump(jump == 0.0 ? Step * 10.0 : jump) { } +}; + +class _UFNumber : public _UFNumberCommon +{ +public: + double Number; + double Default; + _UFNumber(UFName name, double defaultValue, double minimum, double maximum, + int accuracyDigits, double step, double jump) : + _UFNumberCommon(name, minimum, maximum, accuracyDigits, step, jump), + Number(defaultValue), Default(defaultValue) { } +}; + +#define ufnumber (static_cast<_UFNumber *>(ufobject)) + +UFNumber::UFNumber(UFName name, double minimum, double maximum, + double defaultValue, int accuracyDigits, double step, double jump) : + UFObject(new _UFNumber(name, defaultValue, minimum, maximum, + accuracyDigits, step, jump)) { } + +const char *UFNumber::StringValue() const +{ + g_free(ufnumber->String); + ufnumber->String = g_strdup_printf("%.*f", ufnumber->AccuracyDigits, + ufnumber->Number); + return ufnumber->String; +} + +double UFNumber::DoubleValue() const +{ + return ufnumber->Number; +} + +void UFNumber::Set(const UFObject &object) +{ + if (this == &object) // Avoid self-assignment + return; + // We are comparing the strings ADDRESSes not values. + if (Name() != object.Name()) + Throw("Object name mismatch with '%s'", object.Name()); + const UFNumber &number = object; + Set(number.DoubleValue()); +} + +void UFNumber::Set(const char *string) +{ + double number; + int count = sscanf(string, "%lf", &number); + if (count != 1) + Throw("String '%s' is not a number", string); + Set(number); +} + +void UFNumber::Set(double number) +{ + if (number > Maximum()) { + Message(_("Value %.*f too large, truncated to %.*f."), + AccuracyDigits(), number, AccuracyDigits(), Maximum()); + number = Maximum(); + } else if (number < Minimum()) { + Message(_("Value %.*f too small, truncated to %.*f."), + AccuracyDigits(), number, AccuracyDigits(), Minimum()); + number = Minimum(); + } + if (!this->IsEqual(number)) { + ufnumber->Number = number; + ufnumber->CallValueChangedEvent(this); + } + // When numbers are equal up to Accuracy, we still want the new value + ufnumber->Number = number; +} + +bool UFNumber::IsDefault() const +{ + return this->IsEqual(ufnumber->Default); +} + +void UFNumber::SetDefault() +{ + ufnumber->Default = ufnumber->Number; + Event(uf_default_changed); +} + +void UFNumber::Reset() +{ + Set(ufnumber->Default); +} + +bool UFNumber::IsEqual(double number) const +{ + int oldValue = floor(ufnumber->Number / ufnumber->Accuracy + 0.5); + int newValue = floor(number / ufnumber->Accuracy + 0.5); + return oldValue == newValue; +} + +double UFNumber::Minimum() const +{ + return ufnumber->Minimum; +} + +double UFNumber::Maximum() const +{ + return ufnumber->Maximum; +} + +int UFNumber::AccuracyDigits() const +{ + return ufnumber->AccuracyDigits; +} +double UFNumber::Step() const +{ + return ufnumber->Step; +} + +double UFNumber::Jump() const +{ + return ufnumber->Jump; +} + +/********************************\ + * UFNumberArray implementation * +\********************************/ + +class _UFNumberArray : public _UFNumberCommon +{ +public: + const int Size; + double *const Array; + double *const Default; + _UFNumberArray(UFName name, int size, + double minimum, double maximum, double defaultValue, + int accuracyDigits, double step, double jump) : + _UFNumberCommon(name, minimum, maximum, accuracyDigits, step, jump), + Size(size), Array(new double[size]), Default(new double[size]) { + for (int i = 0; i < size; i++) + Array[i] = defaultValue; + for (int i = 0; i < size; i++) + Default[i] = defaultValue; + } + ~_UFNumberArray() { + delete [] Array; + delete [] Default; + } + bool SilentChange(UFNumberArray *that, int index, double number) { + if (index < 0 || index >= Size) + that->Throw("index (%d) out of range 0..%d", index, Size - 1); + if (number > Maximum) { + that->Message(_("Value %.*f too large, truncated to %.*f."), + AccuracyDigits, number, AccuracyDigits, Maximum); + number = Maximum; + } else if (number < Minimum) { + that->Message(_("Value %.*f too small, truncated to %.*f."), + AccuracyDigits, number, AccuracyDigits, Minimum); + number = Minimum; + } + if (!that->IsEqual(index, number)) { + Array[index] = number; + return true; + } + // When numbers are equal up to Accuracy, we still want the new value + Array[index] = number; + return false; + } +}; + +#define ufnumberarray (static_cast<_UFNumberArray *>(ufobject)) + +#define _uf_max_string 80 + +UFNumberArray::UFNumberArray(UFName name, int size, double minimum, + double maximum, double defaultValue, + int accuracyDigits, double step, double jump) : + UFObject(new _UFNumberArray(name, size, minimum, maximum, defaultValue, + accuracyDigits, step, jump)) { } + +const char *UFNumberArray::StringValue() const +{ + g_free(ufnumberarray->String); + std::string str = ""; + char num[_uf_max_string]; + for (int i = 0; i < Size(); i++) { + g_snprintf(num, _uf_max_string, "%.*f", + ufnumberarray->AccuracyDigits, ufnumberarray->Array[i]); + str += num; + if (i < Size() - 1) + str += " "; + } + ufnumberarray->String = g_strdup(str.c_str()); + return ufnumberarray->String; +} + +double UFNumberArray::DoubleValue(int index) const +{ + if (index < 0 || index >= Size()) + Throw("index (%d) out of range 0..%d", index, Size() - 1); + return ufnumberarray->Array[index]; +} + +void UFNumberArray::Set(const UFObject &object) +{ + if (this == &object) // Avoid self-assignment + return; + // We are comparing the strings ADDRESSes not values. + if (Name() != object.Name()) + Throw("Object name mismatch with '%s'", object.Name()); + const UFNumberArray &array = object; + if (Size() != array.Size()) + Throw("Object size mismatch %d != %d", Size(), array.Size()); + bool changed = false; + for (int i = 0; i < Size(); i++) + changed |= ufnumberarray->SilentChange(this, i, array.DoubleValue(i)); + if (changed) + ufnumberarray->CallValueChangedEvent(this); +} + +void UFNumberArray::Set(const char *string) +{ + char **token = g_strsplit(string, " ", Size()); + for (int i = 0; i < Size(); i++) { + if (token[i] == NULL) { + Set(i, ufnumberarray->Default[i]); + } else { + double number; + int count = sscanf(token[i], "%lf", &number); + if (count != 1) + Throw("String '%s' is not a number", string); + Set(i, number); + } + } + g_strfreev(token); +} + +void UFNumberArray::Set(int index, double number) +{ + bool changed = ufnumberarray->SilentChange(this, index, number); + if (changed) + ufnumberarray->CallValueChangedEvent(this); +} + +void UFNumberArray::Set(const double array[]) +{ + bool changed = false; + for (int i = 0; i < Size(); i++) + changed |= ufnumberarray->SilentChange(this, i, array[i]); + if (changed) + ufnumberarray->CallValueChangedEvent(this); +} + +bool UFNumberArray::IsDefault() const +{ + for (int i = 0; i < Size(); i++) + if (!IsEqual(i, ufnumberarray->Default[i])) + return false; + return true; +} + +void UFNumberArray::SetDefault() +{ + for (int i = 0; i < Size(); i++) + ufnumberarray->Default[i] = ufnumberarray->Array[i]; + Event(uf_default_changed); +} + +void UFNumberArray::Reset() +{ + bool changed = false; + for (int i = 0; i < Size(); i++) + changed |= ufnumberarray->SilentChange(this, i, ufnumberarray->Default[i]); + if (changed) + ufnumberarray->CallValueChangedEvent(this); +} + +bool UFNumberArray::IsEqual(int index, double number) const +{ + if (index < 0 || index >= Size()) + Throw("index (%d) out of range 0..%d", index, Size() - 1); + int newValue = floor(number / ufnumberarray->Accuracy + 0.5); + int oldValue = floor(ufnumberarray->Array[index] / ufnumberarray->Accuracy + 0.5); + return oldValue == newValue; +} + +int UFNumberArray::Size() const +{ + return ufnumberarray->Size; +} + +double UFNumberArray::Minimum() const +{ + return ufnumberarray->Minimum; +} + +double UFNumberArray::Maximum() const +{ + return ufnumberarray->Maximum; +} + +int UFNumberArray::AccuracyDigits() const +{ + return ufnumberarray->AccuracyDigits; +} +double UFNumberArray::Step() const +{ + return ufnumberarray->Step; +} + +double UFNumberArray::Jump() const +{ + return ufnumberarray->Jump; +} + +/***************************\ + * UFString implementation * +\***************************/ + +class _UFString : public _UFObject +{ +public: + char *Default; + _UFString(UFName name) : _UFObject(name) { } + ~_UFString() { + g_free(Default); + } +}; + +#define ufstring (static_cast<_UFString *>(ufobject)) + +UFString::UFString(UFName name, const char *defaultValue) : + UFObject(new _UFString(name)) +{ + ufstring->Default = g_strdup(defaultValue); + ufstring->String = g_strdup(defaultValue); +} + +void UFString::Set(const UFObject &object) +{ + if (this == &object) // Avoid self-assignment + return; + // We are comparing the strings ADDRESSes not values. + if (Name() != object.Name()) + Throw("Object name mismatch with '%s'", object.Name()); + Set(object.StringValue()); +} + +void UFString::Set(const char *string) +{ + if (this->IsEqual(string)) + return; + g_free(ufstring->String); + ufstring->String = g_strdup(string); + ufstring->CallValueChangedEvent(this); +} + +bool UFString::IsDefault() const +{ + return this->IsEqual(ufstring->Default); +} + +void UFString::SetDefault(const char *string) +{ + g_free(ufstring->Default); + ufstring->Default = g_strdup(string); + Event(uf_default_changed); +} + +void UFString::SetDefault() +{ + SetDefault(ufstring->String); +} + +void UFString::Reset() +{ + Set(ufstring->Default); +} + +bool UFString::IsEqual(const char *string) const +{ + // If the pointers are equal, the strings are equal + if (ufstring->String == string) + return true; + if (ufstring->String == NULL) + return false; + return strcmp(ufstring->String, string) == 0; +} + +/**************************\ + * UFGroup implementation * +\**************************/ + +class _UFNameCompare +{ +public: + bool operator()(char const *a, char const *b) const { + return strcmp(a, b) < 0; + } +}; +typedef std::map _UFGroupMap; +typedef std::pair _UFObjectPair; +class _UFGroup : public _UFObject +{ +public: + _UFGroupMap Map; + UFGroupList List; + UFGroup *const This; + bool GroupChanging; + // Index and Default Index are only used by UFArray + int Index; + char *DefaultIndex; + _UFGroup(UFGroup *that, UFName name, const char *label) : + _UFObject(name), This(that), GroupChanging(false), + Index(-1), DefaultIndex(NULL) { + String = g_strdup(label); + } + bool Changing() const { + if (Parent != NULL) + return Parent->Changing(); + return GroupChanging; + } + void SetChanging(bool state) { + if (Parent != NULL) + Parent->SetChanging(state); + else + GroupChanging = state; + } +}; + +// The following UFObject methods can only be implemented after _UFGroup +// is declared, since Parent is a _UFGroup object. +bool _UFObject::Changing() const +{ + if (Parent != NULL) + return Parent->Changing(); + return false; +} + +void _UFObject::SetChanging(bool state) +{ + if (Parent != NULL) + Parent->SetChanging(state); +} + +UFGroup &UFObject::Parent() const +{ + if (ufobject->Parent == NULL) + Throw("UFObject has not parent"); + return *static_cast<_UFGroup*>(ufobject->Parent)->This; +} + +#define ufgroup (static_cast<_UFGroup *>(ufobject)) + +// object is a and generally not a . +// The cast to is needed for accessing ufobject. +#define _UFGROUP_PARENT(object) static_cast(object)->ufobject->Parent + +UFGroup::UFGroup(UFName name, const char *label) : + UFObject(new _UFGroup(this, name, label)) { } + +UFGroup::~UFGroup() +{ + for (UFGroupList::iterator iter = ufgroup->List.begin(); + iter != ufgroup->List.end(); iter++) { + _UFGROUP_PARENT(*iter) = NULL; + delete *iter; + } + g_free(ufgroup->DefaultIndex); +} + +static std::string _UFGroup_XML(const UFGroup &group, UFGroupList &list, + const char *indent, const char *attribute) +{ + if (group.IsDefault()) + return ""; + if (strcmp(attribute, "Index") == 0 && // If object is a UFArray and + group.UFGroup::IsDefault()) { // all the array elements are default + // Just print the value in a simple format. + char *value = g_markup_escape_text(group.StringValue(), -1); + std::string xml = (std::string)indent + "<" + group.Name() + ">" + + value + "\n"; + return xml; + } + std::string xml = ""; + // For now, we don't want to surround the root XML with <[/]Image> tags. + if (strlen(indent) != 0) { + char *value = g_markup_escape_text(group.StringValue(), -1); + if (value[0] == '\0') { + xml += (std::string)indent + "<" + group.Name() + ">\n"; + } else { + xml += (std::string)indent + "<" + group.Name() + " " + + attribute + "='" + value + "'>\n"; + } + g_free(value); + } + char *newIndent = static_cast(g_alloca(strlen(indent) + 3)); + int i = 0; + while (indent[i] != 0) { + newIndent[i] = indent[i]; + i++; + } + newIndent[i + 0] = ' '; + newIndent[i + 1] = ' '; + newIndent[i + 2] = '\0'; + for (UFGroupList::iterator iter = list.begin(); iter != list.end(); iter++) + xml += (*iter)->XML(newIndent); + if (strlen(indent) != 0) + xml += (std::string)indent + "\n"; + return xml; +} + +std::string UFGroup::XML(const char *indent) const +{ + return _UFGroup_XML(*this, ufgroup->List, indent, "Label"); +} + +void UFGroup::Set(const UFObject &object) +{ + if (this == &object) // Avoid self-assignment + return; + // We are comparing the strings ADDRESSes not values. + if (Name() != object.Name()) + Throw("Object name mismatch with '%s'", object.Name()); + const UFGroup &group = object; + for (UFGroupList::iterator iter = ufgroup->List.begin(); + iter != ufgroup->List.end(); iter++) { + if (group.Has((*iter)->Name())) + (*iter)->Set(group[(*iter)->Name()]); + } +} + +void UFGroup::Set(const char * /*string*/) +{ + Throw("UFGroup does not support string values"); +} + +bool UFGroup::IsDefault() const +{ + for (UFGroupList::iterator iter = ufgroup->List.begin(); + iter != ufgroup->List.end(); iter++) { + if (!(*iter)->IsDefault()) + return false; + } + return true; +} + +void UFGroup::SetDefault() +{ + for (UFGroupList::iterator iter = ufgroup->List.begin(); + iter != ufgroup->List.end(); iter++) { + (*iter)->SetDefault(); + } + Event(uf_default_changed); +} + +void UFGroup::Reset() +{ + for (UFGroupList::iterator iter = ufgroup->List.begin(); + iter != ufgroup->List.end(); iter++) { + (*iter)->Reset(); + } +} + +bool UFGroup::Has(UFName name) const +{ + _UFGroupMap::iterator iter = ufgroup->Map.find(name); + return iter != ufgroup->Map.end(); +} + +UFObject &UFGroup::operator[](UFName name) +{ + _UFGroupMap::iterator iter = ufgroup->Map.find(name); + if (iter == ufgroup->Map.end()) + Throw("No object with name '%s'", name); // out-of-range + return *ufgroup->Map[name]; +} + +const UFObject &UFGroup::operator[](UFName name) const +{ + _UFGroupMap::iterator iter = ufgroup->Map.find(name); + if (iter == ufgroup->Map.end()) { + Throw("No object with name '%s'", name); // out-of-range + } + return *ufgroup->Map[name]; +} + +const UFGroupList UFGroup::List() const +{ + return ufgroup->List; +} + +UFGroup &UFGroup::operator<<(UFObject *object) +{ + _UFGroupMap::iterator iter = ufgroup->Map.find(object->Name()); + if (iter != ufgroup->Map.end()) + Throw("index '%s' already exists", object->Name()); + ufgroup->Map.insert(_UFObjectPair(object->Name(), object)); + ufgroup->List.push_back(object); + if (object->HasParent()) { + // Remove object from its original group + //_UFGroup *parent = static_cast<_UFGroup *>(object->ufobject->Parent); + _UFGroup *parent = static_cast<_UFGroup *>(object->Parent().ufobject); + parent->Map.erase(object->Name()); + for (UFGroupList::iterator iter = parent->List.begin(); + iter != parent->List.end(); iter++) { + if (*iter == object) { + parent->List.erase(iter); + break; + } + } + } + _UFGROUP_PARENT(object) = ufgroup; + Event(uf_element_added); + return *this; +} + +UFObject &UFGroup::Drop(UFName name) +{ + _UFGroupMap::iterator iter = ufgroup->Map.find(name); + if (iter == ufgroup->Map.end()) + Throw("index '%s' does not exists", name); + UFObject *dropObject = (*iter).second; + ufgroup->Map.erase(name); + for (UFGroupList::iterator iter = ufgroup->List.begin(); + iter != ufgroup->List.end(); iter++) { + if (*iter == dropObject) { + ufgroup->List.erase(iter); + break; + } + } + _UFGROUP_PARENT(dropObject) = NULL; + return *dropObject; +} + +void UFGroup::Clear() +{ + for (_UFGroupMap::iterator iter = ufgroup->Map.begin(); + iter != ufgroup->Map.end(); iter++) { + _UFGROUP_PARENT(iter->second) = NULL; + delete iter->second; + } + ufgroup->Map.clear(); + ufgroup->List.clear(); +} + +// object is a and generally not a . +// The cast to is needed for accessing ufobject. +#define _UFARRAY_PARENT(object) static_cast(object)->ufobject->Parent + +UFArray::UFArray(UFName name, const char *defaultIndex) : + UFGroup(name, defaultIndex) +{ + ufgroup->DefaultIndex = g_strdup(defaultIndex); +} + +std::string UFArray::XML(const char *indent) const +{ + return _UFGroup_XML(*this, ufgroup->List, indent, "Index"); +} + +void UFArray::Set(const UFObject &object) +{ + if (this == &object) // Avoid self-assignment + return; + // We are comparing the strings ADDRESSes not values. + if (Name() != object.Name()) + Throw("Object name mismatch with '%s'", object.Name()); + const UFArray &array = object; + for (UFGroupList::iterator iter = ufgroup->List.begin(); + iter != ufgroup->List.end(); iter++) { + if (array.Has((*iter)->StringValue())) + (*iter)->Set(array[(*iter)->StringValue()]); + } + Set(array.StringValue()); +} + +void UFArray::Set(const char *string) +{ + if (this->IsEqual(string)) + return; + g_free(ufgroup->String); + ufgroup->String = g_strdup(string); + + ufgroup->Index = -1; + int i = 0; + for (UFGroupList::iterator iter = ufgroup->List.begin(); + iter != ufgroup->List.end(); iter++, i++) { + if (IsEqual((*iter)->StringValue())) { + ufgroup->Index = i; + } + } + ufgroup->CallValueChangedEvent(this); +} + +const char *UFArray::StringValue() const +{ + return ufgroup->String; +} + +bool UFArray::IsDefault() const +{ + if (!IsEqual(ufgroup->DefaultIndex)) + return false; + return UFGroup::IsDefault(); +} + +void UFArray::SetDefault(const char *string) +{ + g_free(ufgroup->DefaultIndex); + ufgroup->DefaultIndex = g_strdup(string); + Event(uf_default_changed); +} + +void UFArray::SetDefault() +{ + g_free(ufgroup->DefaultIndex); + ufgroup->DefaultIndex = g_strdup(ufgroup->String); + Event(uf_default_changed); +} + +void UFArray::Reset() +{ + Set(ufgroup->DefaultIndex); + UFGroup::Reset(); +} + +bool UFArray::SetIndex(int index) +{ + UFGroupList::iterator iter = ufgroup->List.begin(); + std::advance(iter, index); + if (iter == ufgroup->List.end()) + return false; + ufgroup->Index = index; + Set((*iter)->StringValue()); + return true; +} + +int UFArray::Index() const +{ + return ufgroup->Index; +} + +bool UFArray::IsEqual(const char *string) const +{ + // If the pointers are equal, the strings are equal + if (ufgroup->String == string) + return true; + if (ufgroup->String == NULL || string == NULL) + return false; + return strcmp(ufstring->String, string) == 0; +} + +UFArray &UFArray::operator<<(UFObject *object) +{ + _UFGroupMap::iterator iter = ufgroup->Map.find(object->StringValue()); + if (iter != ufgroup->Map.end()) + Throw("index '%s' already exists", object->StringValue()); + ufgroup->Map.insert(_UFObjectPair(object->StringValue(), object)); + ufgroup->List.push_back(object); + if (IsEqual(object->StringValue())) + ufgroup->Index = ufgroup->List.size() - 1; + if (object->HasParent()) { + // Remove object from its original group. + _UFGroup *parent = static_cast(object)->ufobject->Parent; + // We assume that the previous parent was also a UFArray. + parent->Map.erase(object->StringValue()); + for (UFGroupList::iterator iter = parent->List.begin(); + iter != parent->List.end(); iter++) { + if (*iter == object) { + parent->List.erase(iter); + break; + } + } + } + _UFARRAY_PARENT(object) = ufgroup; + Event(uf_element_added); + return *this; +} + +UFException::UFException(std::string &Message) : + std::runtime_error(Message.c_str()) { } + +/******************************\ + * C interface implementation * +\******************************/ + +extern "C" { + + UFName ufobject_name(UFObject *object) + { + return object->Name(); + } + + UFObject *ufobject_delete(UFObject *object) + { + delete object; + return NULL; + } + + UFObject *ufobject_parent(UFObject *object) + { + try { + return &object->Parent(); + } catch (UFException &e) { + object->Message(e.what()); + return NULL; + } + } + + const char *ufobject_string_value(UFObject *object) + { + return object->StringValue(); + } + + UFBoolean ufobject_set_string(UFObject *object, const char *string) + { + try { + object->Set(string); + return true; + } catch (UFException &e) { + // Could be an string-is-not-a-number exception. + // Caller should handle the message. + return false; + } + } + + UFBoolean ufobject_copy(UFObject *destination, UFObject *source) + { + try { + destination->Set(*source); + return true; + } catch (UFException &e) { + destination->Message(e.what()); + return false; + } + } + + char *ufobject_xml(UFObject *object, const char *indent) + { + std::string xml = object->XML(indent); + return g_strdup(xml.c_str()); + } + + void *ufobject_user_data(UFObject *object) + { + return object->UserData(); + } + + void ufobject_set_user_data(UFObject *object, void *user_data) + { + object->SetUserData(user_data); + } + + void ufobject_set_changed_event_handle(UFObject *object, UFEventHandle *handle) + { + object->SetEventHandle(handle); + } + + UFBoolean ufobject_is_default(UFObject *object) + { + return object->IsDefault(); + } + + void ufobject_set_default(UFObject *object) + { + object->SetDefault(); + } + + double ufnumber_value(UFObject *object) + { + try { + return dynamic_cast(*object).DoubleValue(); + } catch (std::bad_cast &e) { + object->Message(e.what()); + return std::numeric_limits::quiet_NaN(); + } + } + + UFBoolean ufnumber_set(UFObject *object, double number) + { + try { + dynamic_cast(object)->Set(number); + return true; + } catch (std::bad_cast &e) { + object->Message(e.what()); + return false; + } + } + + double ufnumber_array_value(UFObject *object, int index) + { + try { + return dynamic_cast(*object).DoubleValue(index); + } catch (UFException &e) { + object->Message(e.what()); + return std::numeric_limits::quiet_NaN(); + } catch (std::bad_cast &e) { + object->Message(e.what()); + return std::numeric_limits::quiet_NaN(); + } + } + + UFBoolean ufnumber_array_set(UFObject *object, const double array[]) + { + try { + dynamic_cast(*object).Set(array); + return true; + } catch (std::bad_cast &e) { + object->Message(e.what()); + return false; + } + } + + UFBoolean ufstring_is_equal(UFObject *object, const char *string) + { + try { + return dynamic_cast(object)->IsEqual(string); + } catch (std::bad_cast &e) { + object->Message(e.what()); + return false; + } + } + + UFBoolean ufgroup_has(UFObject *object, UFName name) + { + try { + return dynamic_cast(object)->Has(name); + } catch (std::bad_cast &e) { + object->Message(e.what()); + return false; + } + } + + UFObject *ufgroup_element(UFObject *object, UFName name) + { + try { + UFObject &element = dynamic_cast(*object)[name]; + return &element; + } catch (UFException &e) { + object->Message(e.what()); + return NULL; + } catch (std::bad_cast &e) { + object->Message(e.what()); + return NULL; + } + } + + UFBoolean ufgroup_add(UFObject *group, UFObject *object) + { + try { + dynamic_cast(*group) << object; + return true; + } catch (UFException &e) { + group->Message(e.what()); + return false; + } catch (std::bad_cast &e) { + group->Message(e.what()); + return false; + } + } + + UFObject *ufgroup_drop(UFObject *group, UFName name) + { + try { + return &dynamic_cast(group)->Drop(name); + } catch (UFException &e) { + group->Message(e.what()); + return NULL; + } catch (std::bad_cast &e) { + group->Message(e.what()); + return NULL; + } + } + + UFBoolean ufarray_set_index(UFObject *object, int index) + { + try { + return dynamic_cast(object)->SetIndex(index); + } catch (std::bad_cast &e) { + object->Message(e.what()); + return false; + } + } + + int ufarray_index(UFObject *object) + { + try { + return dynamic_cast(object)->Index(); + } catch (std::bad_cast &e) { + object->Message(e.what()); + return -2; + } + } + + UFBoolean ufarray_is_equal(UFObject *object, const char *string) + { + try { + return dynamic_cast(object)->IsEqual(string); + } catch (std::bad_cast &e) { + object->Message(e.what()); + return false; + } + } + +} // extern "C" diff --git a/plugins/load-dcraw/ufobject.h b/plugins/load-dcraw/ufobject.h new file mode 100644 index 00000000..ae2887e0 --- /dev/null +++ b/plugins/load-dcraw/ufobject.h @@ -0,0 +1,497 @@ +/* + * UFRaw - Unidentified Flying Raw converter for digital camera images + * + * ufobject.h - UFObject definitions. + * Copyright 2004-2016 by Udi Fuchs + * + * 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. + */ + +#ifndef _UFOBJECT_H +#define _UFOBJECT_H + +/***********************************\ + * UFObject C/C++ common interface * +\***********************************/ + +/// Type definition for the name of a UFObject. +typedef const char *UFName; + +/// UFObject is base class for both the C and C++ interfaces. +typedef struct UFObject UFObject; + +/// Events that can be triggered and should be handled by the event handler. +typedef enum { + uf_value_changed, ///< Value changed. + uf_default_changed, ///< Default value changed. + uf_element_added, ///< An UFObject was added to a UFGroup or a UFArray. + uf_user_data_set, ///< User data was set. + uf_destroyed ///< UFObject is being destroyed. +} UFEventType; + +/// Function prototype for handling events. +typedef void (UFEventHandle)(UFObject *, UFEventType); + +/**************************\ + * UFObject C++ interface * +\**************************/ + +#ifdef __cplusplus + +#include +#include +#include // for std::runtime_error + +/** + * UFObjects are smart data containers, which are suppose to know everything + * that is needed to handle and manipulated their content. + * + * UFObject is an abstract class. There are four UFObject implementations: + * - UFNumber - holds a number with a defined range and accuracy. + * - UFNumberArray - holds a fixed length array of numbers. + * - UFString - holds a string and possibly a list of tokens for this string. + * - UFGroup - holds a group of UFObjects. + * - UFIndex - holds an indexed group of UFObjects. + * + * There are downcasting definitions from all these implementations down + * to UFObject. These are needed because each UFObject type has different + * methods. Downcasting eases the access to these methods. An + * std::bad_cast exception will be thrown if invalid downcasting is attempted. + * + * Each UFObject has a UFName. This name identifies the object and should be + * unique. It is also used to access UFGroup members. + * + * The C++ interface of UFObject throws an exception is case of failure. + * Therefore, there is no error indication in the return-value of any of + * the methods. Most exceptions indicated programming errors and can be avoided. + * Only in the case of UFObject::Set(const char *string), a UFException could + * result from a user input error. + * + * \anchor C-interface + * The C interface of UFObject is shielded from all exception. Failure will + * be indicated in the return-value of the calling function and result in a + * call to UFObject::Message() that sends an error to the console by default. + * In the case of ufobject_set_string(), UFObject::Message() is not called, + * since it is assumes that the exception resulted from user input error. + * + * \exception UFException is the common exception thrown in case of errors. + * \exception std::bad_cast is thrown when the downcasting operators fail. + */ +class UFObject +{ +public: + /// Trigger a #uf_destroyed event and destroy the object. An object that + /// has a Parent() should never be destroyed directly. It will be + /// destroyed when its parent is destroyed. + virtual ~UFObject(); + UFName Name() const; ///< Retrieve the name of the UFObject. + /// Set pointer to general user data. + /// A #uf_user_data_set event is triggered. + void SetUserData(void *userData); + void *UserData(); ///< Retrieve pointer to general user data. + /// Downcast UFObject to UFNumber. + operator class UFNumber&(); + /// Downcast const UFObject to const UFNumber. + operator const class UFNumber&() const; + /// Downcast UFObject to UFNumberArray. + operator class UFNumberArray&(); + /// Downcast const UFObject to const UFNumberArray. + operator const class UFNumberArray&() const; + /// Downcast UFObject to UFString. + operator class UFString&(); + /// Downcast const UFObject to const UFString. + operator const class UFString&() const; + /// Downcast UFObject to UFGroup. + operator class UFGroup&(); + /// Downcast const UFObject to const UFGroup. + operator const class UFGroup&() const; + /// Downcast UFObject to UFArray. + operator class UFArray&(); + /// Downcast const UFObject to const UFArray. + operator const class UFArray&() const; + bool HasParent() const; ///< Return true if object belongs to a UFGroup. + /// Return the UFGroup the object belongs too. + /// A std::logic_error will be thrown if the objects belongs to no group. + /// \exception UFException is thrown if the object has no parent. + /// This exception can be avoided with the use of HasParent(). + UFGroup &Parent() const; + /// Translate object to a string. UFObject takes care of the memory + /// allocation and freeing of the string. + virtual const char *StringValue() const; + /// Create an XML block for the object. + /// If the object value is its default, create and empty XML block. + /// \param indent - Controls the XML block indentations. + virtual std::string XML(const char *indent = "") const; + /// Send an informational message in case of an error or warning. + /// This method is used internally in the implementation of UFObject. + /// Override this method to implement your own message handling. + /// The default handling is to send the message to the parent object. + /// If no patent exists, send the message to stderr. + /// \param format - a printf-like string format. + virtual void Message(const char *format, ...) const; + /// Throw a UFException. Use this method to throw exceptions from + /// within customized Event() methods. + /// \param format - a printf-like string format. + void Throw(const char *format, ...) const; + /// Set the value of the object to the value of the object parameter. + /// Objects must be of same type and must have the same name. If the + /// value changes, a #uf_value_changed event is triggered. + /// \exception UFException is thrown if the two objects do not + /// have the same Name(). This is probably a programming error. + virtual void Set(const UFObject &object) = 0; + /// Set the value of the object from the string value. This is the + /// reverse of the StringValue() method. If the value changes, an + /// #uf_value_changed event is triggered. + /// \exception UFException is thrown if the the string can not be + /// converted to the object type. This could result from a user input + /// error. + virtual void Set(const char *string) = 0; + /// Return true if object has its default value. For numerical objects, + /// the values has to the same up to the prescribed accuracy. + virtual bool IsDefault() const = 0; + /// Set the current object value to its default value. + /// A #uf_default_changed event is triggered. + virtual void SetDefault() = 0; + /// Reset the object value to its default value. If the value changes, + /// a #uf_value_changed event is triggered. + virtual void Reset() = 0; + /// Set a C-style event handler. + /// C++ events can be set by overriding the Event() virtual member. + void SetEventHandle(UFEventHandle *handle); + /// Handle any #UFEventType event. Override this method to implement your + /// own event handling. The default handling is to call the event handle + /// set by SetEventHandle() and in the case of #uf_value_changed, to call + /// also the parent's Event(). If you override this method, you probably + /// want to call UFObject::Event() from your own implementation of Event(). + virtual void Event(UFEventType type); + /// Handle a #uf_value_changed event for the object that originated the + /// change. This method should be overridden if one wants to change + /// the values of other objects when the original object value has + /// changed. It is needed to prevent infinite loops where several + /// objects keep changing each other. The default method does not + /// do anything. + virtual void OriginalValueChangedEvent(); +protected: + /// UFObject 's internal implementation is hidden here. + class _UFObject *const ufobject; + /// UFObject is an abstract class, therefore it cannot be constructed + /// directly. + explicit UFObject(_UFObject *object); +private: + UFObject(const UFObject &); // Disable the copy constructor. + UFObject &operator=(const UFObject &); // Disable the assignment operator. +}; + +/** + * UFNumber is a UFObject that holds a number which has an allowed range of + * values, a specified accuracy and default value. + */ +class UFNumber : public UFObject +{ +public: + /// Construct a UFNumber whose initial value is set to its default value. + /// The number of accuracy digits effects the format of the StringValue() + /// of the number. The IsEqual() test is also controlled by + /// @a accuracyDigits. @a step and @a jump have no direct effect on the + /// object. They are useful for constructing a GtkAdjustment as in + /// ufnumber_hscale_new() and ufnumber_spin_button_new(). + /// + /// @a accuracyDigits, @a step and @a jump are + /// optional arguments, if they are not given they will be automatically + /// generated. @a accuracyDigits will be calculated from @a minimum, + /// @a maximum to given between 3 and 4 significant digits. @a step will + /// be set to 10 times the accuracy and @a jump to 10 times @a step. + UFNumber(UFName name, double minimum, double maximum, double defaultValue, + int accuracyDigits = -1, double step = 0.0, double jump = 0.0); + const char *StringValue() const; + /// Return the numerical value of the object. This @a double value can + /// have better accuracy than @a accuracyDigits. So, for example, after + /// an object.Set(1.0/3.0) command, the result of the condition + /// (obj.DoubleValue() == 1.0/3.0) should be true (but it is never + /// safe to rely on such behavior for floating-point numbers). + double DoubleValue() const; + void Set(const UFObject &object); + void Set(const char *string); + /// Set the value of the object to the given number. If the number is + /// outside of the allowed range, the number will be truncated and the + /// Message() method will be called to report this incident. + void Set(double number); + bool IsDefault() const; + void SetDefault(); + void Reset(); + /// Return true if object value is equal to @a number up to the prescribed + /// accuracy. + bool IsEqual(double number) const; + double Minimum() const; + double Maximum() const; + int AccuracyDigits() const; + double Step() const; + double Jump() const; +}; + +/** + * UFNumberArray is a UFObject that holds an fixed sized array of numbers. + */ +class UFNumberArray : public UFObject +{ +public: + /// Construct a UFNumberArray with the given @a size. The initial value of + /// the array elements is set to its default value. + /// The number of accuracy digits effects the format of the StringValue() + /// of the number. The IsEqual() test is also controlled by + /// @a accuracyDigits. @a step and @a jump have no direct effect on the + /// object. They are useful for constructing a GtkAdjustment as in + /// ufnumber_array_hscale_new() and ufnumber_array_spin_button_new(). + /// + /// The object is create with one default value for all elements. Once + /// SetDefault() is called, each element can have a different default. + /// \sa @a accuracyDigits, @a step and @a jump are optional arguments, + /// their default values are discussed in UFNumber::UFNumber(). + UFNumberArray(UFName name, int size, double minimum, double maximum, + double defaultValue, int accuracyDigits = 0xff, double step = 0.0, + double jump = 0.0); + const char *StringValue() const; + /// Return the numerical value of the @a index element of the object. + /// This @a double value can have better accuracy than @a accuracyDigits. + /// \sa UFNumber::StringValue() for more information. + /// \exception UFException is thrown if the index is negative or larger + /// than (Size()-1). This is probably a programming error. + double DoubleValue(int index) const; + void Set(const UFObject &object); + void Set(const char *string); + /// Set the value of the @a index element to the given number. If the + /// number is outside of the allowed range, the number will be truncated + /// and the Message() method will be called to report this incident. + /// \exception UFException is thrown if the index is negative or larger + /// than (Size()-1). This is probably a programming error. + void Set(int index, double number); + /// Set the values of all the array elements at once. This is useful if + /// one wants the #uf_value_changed event to be triggered only once. + /// @a array[] is assumed to be of the right Size(). + void Set(const double array[]); + bool IsDefault() const; + void SetDefault(); + void Reset(); + /// Return true if the @a index element value is equal to @a number + /// up to the prescribed accuracy. + /// \exception UFException is thrown if the index is negative or larger + /// than (Size()-1). This is probably a programming error. + bool IsEqual(int index, double number) const; + int Size() const; + double Minimum() const; + double Maximum() const; + int AccuracyDigits() const; + double Step() const; + double Jump() const; +}; + +/** + * UFString is a UFObject that holds a character string. + */ +class UFString : public UFObject +{ +public: + /// Construct a UFString whose initial value is set to its default value. + explicit UFString(UFName name, const char *defaultValue = ""); + void Set(const UFObject &object); + void Set(const char *string); + bool IsDefault() const; + void SetDefault(); + /// Set @a string as a default value. + /// A #uf_default_changed event is triggered. + void SetDefault(const char *string); + void Reset(); + /// Return true if object value is equal to @a string. + bool IsEqual(const char *string) const; +}; + +/// A list of UFObjects returned by UFGroup or UFArray. +typedef std::list UFGroupList; + +/** + * UFGroup is a UFObject that contain a group of UFObject elements. This + * object is considered the Patent() of these elements. + */ +class UFGroup : public UFObject +{ +public: + /// Construct an empty UFGroup, containing no objects. + /// The @a label is used to index the UFGroup inside a UFArray. + explicit UFGroup(UFName name, const char *label = ""); + /// Destroy a UFGroup after destroying all the objects it contains. + ~UFGroup(); + std::string XML(const char *indent = "") const; + void Set(const UFObject &object); + void Set(const char *string); + bool IsDefault() const; + void SetDefault(); + void Reset(); + /// Return true if the UFGroup contains an object called @a name. + bool Has(UFName name) const; + /// Access a UFObject element in a UFGroup. + /// \exception UFException is thrown if an element with the given name + /// does not exist. This can be avoided with the use of the Has() method. + UFObject &operator[](UFName name); + /// Access a constant UFObject element in a constant UFGroup. + /// \exception UFException is thrown if an element with the given name + /// does not exist. This can be avoided with the use of the Has() method. + const UFObject &operator[](UFName name) const; + /// Return a list of all UFObjects in the group. + const UFGroupList List() const; + /// Add (append) a UFObject to a UFGroup. If the object belonged to + /// another group before, it will be detached from the original group. + /// \exception UFException is thrown if UFGroup already contains + /// an object with the same name. This can be avoided with the use of the + /// Has() method. + virtual UFGroup &operator<<(UFObject *object); + /// Drop an object from the group. The dropped object is returned. + /// If it is not needed any more it should be deleted to free its memory. + /// \exception UFException is thrown if an element with the given name + /// does not exist. This can be avoided with the use of the Has() method. + /// For UFArray, the index does not get updated. + UFObject &Drop(UFName name); + /// Remove all elements from the group. + /// The removed elements are deleted from memory. + /// For UFArray, the index does not get updated. + void Clear(); +}; + +/** + * UFArray is a UFObject that contain an indexed group of UFObject elements. + * The array's elements are indexed by their StringValue(). In the current + * implementation, the StringValue() should not be changed after the + * UFObject was added to the UFArray. + */ +class UFArray : public UFGroup +{ +public: + /// Construct an empty UFArray, containing no objects. + explicit UFArray(UFName name, const char *defaultIndex = ""); + std::string XML(const char *indent = "") const; + void Set(const UFObject &object); + void Set(const char *string); + const char *StringValue() const; + bool IsDefault() const; + void SetDefault(); + /// Set @a string as a default string value for the UFArray. As opposed + /// to the SetDefault() method with no arguments, this method does not + /// changes the default of the array's elements. + /// A #uf_default_changed event is triggered. + void SetDefault(const char *string); + void Reset(); + /// Set the current index position in the array. + /// Return false if @a index is out of range. + bool SetIndex(int index); + /// Retriew the current index location in the array. -1 is returned + /// if the string index value corresponds to no element's label. + int Index() const; + /// Return true if the string index value is equal to @a string. + bool IsEqual(const char *string) const; + /// Add (append) a UFObject to a UFArray. If the object belonged to + /// another array before, it will be detached from the original array. + /// \exception UFException is thrown if UFArray already contains + /// an object with the same StringValue. This can be avoided with the + /// use of the Has() method. + UFArray &operator<<(UFObject *object); +}; + +/// This is the common exception thrown by the UFObject implementation. +/// Usually, it represents a programming error. But in the case of +/// UFObject::Set(const char *string), a UFException could result from +/// a user input error. +class UFException : public std::runtime_error +{ +public: + explicit UFException(std::string &Message); +}; + +#endif // __cplusplus + +/*************************\ + * UFObject C interface * +\*************************/ + +typedef int UFBoolean; +#define UF_FALSE (0) +#define UF_TRUE (!UF_FALSE) + +#ifdef __cplusplus +extern "C" { +#endif + +/// Delete a UFObject and free its resources. Never use free() on UFObject s. +UFObject *ufobject_delete(UFObject *object); +/// Retrieve the name of the UFObject. +UFName ufobject_name(UFObject *object); +UFObject *ufobject_parent(UFObject *object); +/// Translate object to a string. See UFObject::StringValue() for details. +const char *ufobject_string_value(UFObject *object); +/// Set the value of the object from the string value. +/// Returns false on failure. +/// See \ref C-interface and UFObject::Set(const char *string) for details. +UFBoolean ufobject_set_string(UFObject *object, const char *string); +/// Copy the value of the source object to the destination object. +/// Returns false on failure. +/// See \ref C-interface and UFObject::Set(const UFObject &object) for details. +UFBoolean ufobject_copy(UFObject *destination, UFObject *source); +/// Create an XML block for the object. The returned buffer should be +/// free()'d by the caller. See UFObject::XML() for details. +char *ufobject_xml(UFObject *object, const char *indent); +void *ufobject_user_data(UFObject *object); +void ufobject_set_user_data(UFObject *object, void *user_data); +void ufobject_set_changed_event_handle(UFObject *object, + UFEventHandle *handle); +/// Return TRUE if object is set to its default value. +UFBoolean ufobject_is_default(UFObject *object); +/// Set the current object value to its default value. +void ufobject_set_default(UFObject *object); +/// Return the numerical value of the object. Returns NaN if object is not a +/// UFNumber. See \ref C-interface and UFNumber::DoubleValue() for more details. +double ufnumber_value(UFObject *object); +/// Set the value of the object to the given number. Returns false if @a object +/// is not a UFNumber. See \ref C-interface and UFNumber::Set(double number) +/// for more details. +UFBoolean ufnumber_set(UFObject *object, double number); +/// Return the numerical value of the @a index element of the object. +/// Returns NaN if @a object is not a UFNumberArray or @a index is out of range. +/// See \ref C-interface and UFNumberArray::DoubleValue() for more details. +double ufnumber_array_value(UFObject *object, int index); +/// Set the value of all the array elements at once. +/// Returns false if @a object is not a UFNumberArray. See \ref C-interface +/// and UFNumberArray::Set(const double array[]) for more details. +UFBoolean ufnumber_array_set(UFObject *object, const double array[]); +/// Return true if string value is equal to @a string. +/// Return false if it is not equal or if object is not a UFString. +/// See \ref C-interface for more details. +UFBoolean ufstring_is_equal(UFObject *object, const char *string); +/// Return true if the UFGroup @a object contains an object called name. +/// Return false if it does not, or if object is not a UFGroup. +/// See \ref C-interface for more details. +UFBoolean ufgroup_has(UFObject *object, UFName name); +/// Return a UFObject element in a UFGroup. Return NULL if element is not found +/// or if @a object is not a UFGroup. See \ref C-interface for more details. +UFObject *ufgroup_element(UFObject *object, UFName name); +/// Add a UFObject to a UFGroup. Return false if UFGroup already contains +/// an object with the same name. See \ref C-interface for more details. +UFBoolean ufgroup_add(UFObject *group, UFObject *object); +/// Drop an object from the group. The dropped object is returned. +/// If it is not needed any more it should be deleted to free its memory. +UFObject *ufgroup_drop(UFObject *group, UFName name); +/// Set the current index position in the array. +UFBoolean ufarray_set_index(UFObject *object, int index); +/// Retriew the current index location in the array. -1 is returned +/// if the string index value corresponds to no element's label. +int ufarray_index(UFObject *object); +/// Return true if array's string value is equal to @a string. +/// Return false if it is not equal or if object is not a UFArray. +/// See \ref C-interface for more details. +UFBoolean ufarray_is_equal(UFObject *object, const char *string); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /*_UFOBJECT_H*/ diff --git a/plugins/load-dcraw/ufraw-batch.c b/plugins/load-dcraw/ufraw-batch.c new file mode 100644 index 00000000..a761d8c0 --- /dev/null +++ b/plugins/load-dcraw/ufraw-batch.c @@ -0,0 +1,166 @@ +/* + * UFRaw - Unidentified Flying Raw converter for digital camera images + * + * ufraw-batch.c - The standalone interface to UFRaw in batch mode. + * Copyright 2004-2016 by Udi Fuchs + * + * 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. + */ + +#include "ufraw.h" +#include /* for exit */ +#include /* for errno */ +#include +#include + +static gboolean silentMessenger; +char *ufraw_binary; + +int ufraw_batch_saver(ufraw_data *uf); + +int main(int argc, char **argv) +{ + ufraw_data *uf; + conf_data rc, cmd, conf; + int status; + int exitCode = 0; + +#if !GLIB_CHECK_VERSION(2,31,0) + g_thread_init(NULL); +#endif + char *argFile = uf_win32_locale_to_utf8(argv[0]); + ufraw_binary = g_path_get_basename(argFile); + uf_init_locale(argFile); + uf_win32_locale_free(argFile); + + /* Load $HOME/.ufrawrc */ + conf_load(&rc, NULL); + + /* Half interpolation is an option only for the GIMP plug-in. + * For the stand-alone tool it is disabled */ + if (rc.interpolation == half_interpolation) + rc.interpolation = ahd_interpolation; + + /* In batch the save options are always set to default */ + conf_copy_save(&rc, &conf_default); + g_strlcpy(rc.outputPath, "", max_path); + g_strlcpy(rc.inputFilename, "", max_path); + g_strlcpy(rc.outputFilename, "", max_path); + + /* Put the command-line options in cmd */ + int optInd = ufraw_process_args(&argc, &argv, &cmd, &rc); + if (optInd < 0) exit(1); + if (optInd == 0) exit(0); + silentMessenger = cmd.silent; + + conf_file_load(&conf, cmd.inputFilename); + + if (optInd == argc) { + ufraw_message(UFRAW_WARNING, _("No input file, nothing to do.")); + } + int fileCount = argc - optInd; + int fileIndex = 1; + for (; optInd < argc; optInd++, fileIndex++) { + argFile = uf_win32_locale_to_utf8(argv[optInd]); + uf = ufraw_open(argFile); + uf_win32_locale_free(argFile); + if (uf == NULL) { + exitCode = 1; + ufraw_message(UFRAW_REPORT, NULL); + continue; + } + status = ufraw_config(uf, &rc, &conf, &cmd); + if (uf->conf && uf->conf->createID == only_id && cmd.createID == -1) + uf->conf->createID = no_id; + if (status == UFRAW_ERROR) { + exitCode = 1; + ufraw_close_darkframe(uf->conf); + ufraw_close(uf); + g_free(uf); + exit(1); + } + if (ufraw_load_raw(uf) != UFRAW_SUCCESS) { + exitCode = 1; + ufraw_close_darkframe(uf->conf); + ufraw_close(uf); + g_free(uf); + continue; + } + char stat[max_name]; + if (fileCount > 1) + g_snprintf(stat, max_name, "[%d/%d]", fileIndex, fileCount); + else + stat[0] = '\0'; + ufraw_message(UFRAW_MESSAGE, _("Loaded %s %s"), uf->filename, stat); + status = ufraw_batch_saver(uf); + if (status == UFRAW_SUCCESS || status == UFRAW_WARNING) { + if (uf->conf->createID != only_id) + ufraw_message(UFRAW_MESSAGE, _("Saved %s %s"), + uf->conf->outputFilename, stat); + } else { + exitCode = 1; + } + ufraw_close_darkframe(uf->conf); + ufraw_close(uf); + g_free(uf); + } +// ufraw_close(cmd.darkframe); + ufobject_delete(cmd.ufobject); + ufobject_delete(rc.ufobject); + exit(exitCode); +} + +int ufraw_batch_saver(ufraw_data *uf) +{ + if (!uf->conf->overwrite && uf->conf->createID != only_id + && strcmp(uf->conf->outputFilename, "-") + && g_file_test(uf->conf->outputFilename, G_FILE_TEST_EXISTS)) { + char ans[max_name]; + /* First letter of the word 'yes' for the y/n question */ + gchar *yChar = g_utf8_strdown(_("y"), -1); + /* First letter of the word 'no' for the y/n question */ + gchar *nChar = g_utf8_strup(_("n"), -1); + if (!silentMessenger) { + g_printerr(_("%s: overwrite '%s'?"), ufraw_binary, + uf->conf->outputFilename); + g_printerr(" [%s/%s] ", yChar, nChar); + if (fgets(ans, max_name, stdin) == NULL) ans[0] = '\0'; + } + gchar *ans8 = g_utf8_strdown(ans, 1); + if (g_utf8_collate(ans8, yChar) != 0) { + g_free(yChar); + g_free(nChar); + g_free(ans8); + return UFRAW_CANCEL; + } + g_free(yChar); + g_free(nChar); + g_free(ans8); + } + if (strcmp(uf->conf->outputFilename, "-")) { + char *absname = uf_file_set_absolute(uf->conf->outputFilename); + g_strlcpy(uf->conf->outputFilename, absname, max_path); + g_free(absname); + } + if (uf->conf->embeddedImage) { + int status = ufraw_convert_embedded(uf); + if (status != UFRAW_SUCCESS) return status; + status = ufraw_write_embedded(uf); + return status; + } else { + + int status = ufraw_write_image(uf); + if (status != UFRAW_SUCCESS) + ufraw_message(status, ufraw_get_message(uf)); + return status; + } +} + +void ufraw_messenger(char *message, void *parentWindow) +{ + parentWindow = parentWindow; + if (!silentMessenger) ufraw_batch_messenger(message); +} diff --git a/plugins/load-dcraw/ufraw.h b/plugins/load-dcraw/ufraw.h new file mode 100644 index 00000000..0066ffb6 --- /dev/null +++ b/plugins/load-dcraw/ufraw.h @@ -0,0 +1,560 @@ + +/* + * UFRaw - Unidentified Flying Raw converter for digital camera images + * + * ufraw.h - Common definitions for UFRaw. + * Copyright 2004-2016 by Udi Fuchs + * + * 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. + */ + +#ifndef _UFRAW_H +#define _UFRAW_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "uf_glib.h" +#include "ufobject.h" + +#include "nikon_curve.h" +#include "uf_progress.h" + +#ifndef HAVE_STRCASECMP +#define strcasecmp stricmp +#endif + +/* macro to clamp a number between two values */ +#ifndef LIM +#define LIM(x,min,max) MAX(min,MIN(x,max)) +#endif + +#define MAXOUT 255 /* Max output sample */ + +#define max_curves 20 +#define max_anchors 20 +#define max_profiles 20 +#define max_path 200 +#define max_name 80 +#define max_adjustments 3 + +/* An impossible value for conf float values */ +#define NULLF -10000.0 + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/* Options, like auto-adjust buttons can be in 3 states. Enabled and disabled + * are obvious. Apply means that the option was selected and some function + * has to act accourdingly, before changing to one of the first two states */ +enum { + disabled_state, enabled_state, apply_state +}; + +extern const char uf_spot_wb[]; +extern const char uf_manual_wb[]; +extern const char uf_camera_wb[]; +extern const char uf_auto_wb[]; + +/* + * UFObject Definitions for ufraw_settings.cc + */ + +extern UFName ufWB; +extern UFName ufPreset; +extern UFName ufWBFineTuning; +extern UFName ufTemperature; +extern UFName ufGreen; +extern UFName ufChannelMultipliers; +extern UFName ufLensfunAuto; +extern UFName ufLensfun; +extern UFName ufCameraModel; +extern UFName ufLensModel; +extern UFName ufFocalLength; +extern UFName ufAperture; +extern UFName ufDistance; +extern UFName ufTCA; +extern UFName ufVignetting; +extern UFName ufDistortion; +extern UFName ufModel; +extern UFName ufLensGeometry; +extern UFName ufTargetLensGeometry; +extern UFName ufRawImage; +extern UFName ufRawResources; +extern UFName ufCommandLine; + +UFObject *ufraw_image_new(); +#ifdef HAVE_LENSFUN +UFObject *ufraw_lensfun_new(); +void ufraw_lensfun_init(UFObject *lensfun, UFBoolean reset); +struct lfDatabase *ufraw_lensfun_db(); /* mount/camera/lens database */ +const struct lfCamera *ufraw_lensfun_camera(const UFObject *lensfun); +void ufraw_lensfun_set_camera(UFObject *lensfun, const struct lfCamera *camera); +const struct lfLens *ufraw_lensfun_interpolation_lens(const UFObject *lensfun); +void ufraw_lensfun_set_lens(UFObject *lensfun, const struct lfLens *lens); +#endif +struct ufraw_struct *ufraw_image_get_data(UFObject *obj); +void ufraw_image_set_data(UFObject *obj, struct ufraw_struct *uf); +UFObject *ufraw_resources_new(); +UFObject *ufraw_command_line_new(); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +enum { rgb_histogram, r_g_b_histogram, luminosity_histogram, value_histogram, + saturation_histogram + }; +enum { linear_histogram, log_histogram }; +/* The following enum should match the dcraw_interpolation enum + * in dcraw_api.h. */ +enum { ahd_interpolation, vng_interpolation, four_color_interpolation, + ppg_interpolation, bilinear_interpolation, xtrans_interpolation, + none_interpolation, half_interpolation, obsolete_eahd_interpolation, + num_interpolations + }; +enum { no_id, also_id, only_id, send_id }; +enum { manual_curve, linear_curve, custom_curve, camera_curve }; +enum { in_profile, out_profile, display_profile, profile_types}; +enum { raw_expander, live_expander, expander_count }; +enum { ppm_type, ppm16_deprecated_type, tiff_type, tiff16_deprecated_type, + jpeg_type, png_type, png16_deprecated_type, + embedded_jpeg_type, embedded_png_type, fits_type, num_types + }; +enum { clip_details, restore_lch_details, restore_hsv_details, + restore_types + }; +enum { digital_highlights, film_highlights, highlights_types }; + +/* ufraw_standalone : Normal stand-alone + * ufraw_gimp_plugin : Gimp plug-in + * ufraw_standalone_output : Stand-alone with --output option + */ +enum { ufraw_standalone, ufraw_gimp_plugin, ufraw_standalone_output }; + +typedef enum { display_developer, file_developer, auto_developer } +DeveloperMode; +typedef enum { perceptual_intent, relative_intent, saturation_intent, + absolute_intent, disable_intent + } Intent; +typedef enum { ufraw_raw_phase, ufraw_first_phase, ufraw_transform_phase, + ufraw_develop_phase, ufraw_display_phase, ufraw_phases_num + } UFRawPhase; +typedef enum { grayscale_none, grayscale_lightness, + grayscale_luminance, grayscale_value, + grayscale_mixer, grayscale_invalid + } GrayscaleMode; + +typedef struct { + const char *make; + const char *model; + const char *name; + int tuning; + double channel[4]; +} wb_data; + +typedef struct { + double adjustment; + double hue; + double hueWidth; +} lightness_adjustment; + +typedef struct { + DeveloperMode mode; + unsigned rgbMax, max, exposure, colors, useMatrix; + int restoreDetails, clipHighlights; + int rgbWB[4], colorMatrix[3][4]; + double gamma, linear; + char profileFile[profile_types][max_path]; + void *profile[profile_types]; + Intent intent[profile_types]; + gboolean updateTransform; + void *colorTransform; + void *working2displayTransform; + void *rgbtolabTransform; + double saturation; +#ifdef UFRAW_CONTRAST + double contrast; +#endif + CurveData baseCurveData, luminosityCurveData; + guint16 gammaCurve[0x10000]; + void *luminosityProfile; + void *TransferFunction[3]; + void *saturationProfile; + void *adjustmentProfile; + GrayscaleMode grayscaleMode; + double grayscaleMixer[3]; + lightness_adjustment lightnessAdjustment[max_adjustments]; +} developer_data; + +typedef guint16 ufraw_image_type[4]; + +typedef struct { + char name[max_name]; + char file[max_path]; + char productName[max_name]; + double gamma, linear; + int BitDepth; +} profile_data; + +typedef struct { + gint x; + gint y; + gint width; + gint height; +} UFRectangle; + +/* conf_data holds the configuration data of UFRaw. + * The data can be split into three groups: + * IMAGE manipulation, SAVE options and GUI settings. + * The sources for this information are: + * DEF: UFRaw's defaults from conf_defaults. + * RC: users defaults from ~/.ufrawrc. These options are set from the last + * interactive session. + * If saveConfiguration==disabled_state, IMAGE options are not saved. + * ID: UFRaw ID files used on their original image. + * CONF: same ID files used as configuration for other raw images. + * CMD: command line options. + * UI: interactive input. + * The options are set in the above order, therefore the last sources will + * override the first ones with some subtelties: + * * ID|CONF contains only data which is different from DEF, still it is + * assumed that IMAGE and SAVE options are included. Therefore missing + * options are set to DEF overwriting RC. + * * if both CONF and ID are specified, only in/out filenames are taken from ID. + * * in batch mode SAVE options from RC are ignored. + * Some fields need special treatment: + * RC|CONF: auto[Exposure|Black]==enable_state it is switched to apply_state. + * RC|CONF: if !spot_wb reset chanMul[] to -1.0. + * CONF|ID: curve/profile are added to the list from RC. + * CONF: inputFilename, outputFilename are ignored. + * outputPath can only be specified in CMD or guessed in interactive mode. + * ID: createID==only_id is switched to no_id in case of ufraw-batch. + * ID: chanMul[] override wb, green, temperature. + */ +typedef struct { + /* Internal data */ + int version; + + // Eventually ufobject should replace conf_data. + UFObject *ufobject; + + /* IMAGE manipulation settings */ + double threshold; + double hotpixel; +#ifdef UFRAW_CONTRAST + double contrast; +#endif + double exposure, saturation, black; /* black is only used in CMD */ + int ExposureNorm; + int restoreDetails, clipHighlights; + int autoExposure, autoBlack, fullCrop, autoCrop; + int BaseCurveIndex, BaseCurveCount; + CurveData BaseCurve[max_curves]; + int curveIndex, curveCount; + CurveData curve[max_curves]; + int profileIndex[profile_types], profileCount[profile_types]; + profile_data profile[profile_types][max_profiles]; + Intent intent[profile_types]; + int interpolation; + int smoothing; + char darkframeFile[max_path]; + struct ufraw_struct *darkframe; + int CropX1, CropY1, CropX2, CropY2; + double aspectRatio; + int orientation; + double rotationAngle; + int lightnessAdjustmentCount; + lightness_adjustment lightnessAdjustment[max_adjustments]; + int grayscaleMode; + double grayscaleMixer[3]; + int grayscaleMixerDefined; + double despeckleWindow[4]; + double despeckleDecay[4]; + double despecklePasses[4]; + + /* SAVE options */ + char inputFilename[max_path], outputFilename[max_path], + outputPath[max_path]; + char inputURI[max_path], inputModTime[max_name]; + int type, compression, createID, embedExif, progressiveJPEG; + int shrink, size; + gboolean overwrite, losslessCompress, embeddedImage, noExit; + gboolean rotate; + + /* GUI settings */ + double Zoom; + gboolean LockAspect; /* True if aspect ratio is locked */ + int saveConfiguration; + int histogram, liveHistogramScale; + int rawHistogramScale; + int expander[expander_count]; + gboolean overExp, underExp, blinkOverUnder; + gboolean RememberOutputPath; + gboolean WindowMaximized; + int drawLines; + char curvePath[max_path]; + char profilePath[max_path]; + gboolean silent; + char remoteGimpCommand[max_path]; + + /* EXIF data */ + int CameraOrientation; + float iso_speed, shutter, aperture, focal_len, subject_distance; + char exifSource[max_name], isoText[max_name], shutterText[max_name], + apertureText[max_name], focalLenText[max_name], + focalLen35Text[max_name], lensText[max_name], + flashText[max_name], whiteBalanceText[max_name]; + char timestampText[max_name], make[max_name], model[max_name]; + time_t timestamp; + /* Unfortunately dcraw strips make and model, but we need originals too */ + char real_make[max_name], real_model[max_name]; +} conf_data; + +typedef struct { + guint8 *buffer; + int height, width, depth, rowstride; + /* This bit field marks valid pieces of the image with 1's. + The variable contains a fixed 4x8 matrix of bits, every bit containing + the validity of the respective subarea of the whole image. The subarea + sizes are determined by dividing the width by 4 and height by 8. + This field must always contain at least 32 bits. */ + guint32 valid; + gboolean rgbg; + gboolean invalidate_event; +} ufraw_image_data; + +typedef struct ufraw_struct { + int status; + char *message; + char filename[max_path]; + int initialHeight, initialWidth, rgbMax, colors, raw_color, useMatrix; + int rotatedHeight, rotatedWidth; + int autoCropHeight, autoCropWidth; + gboolean LoadingID; /* Indication that we are loading an ID file */ + gboolean WBDirty; + float rgb_cam[3][4]; + ufraw_image_data Images[ufraw_phases_num]; + ufraw_image_data thumb; + void *raw; + gboolean HaveFilters; + gboolean IsXTrans; + void *unzippedBuf; + gsize unzippedBufLen; + developer_data *developer; + developer_data *AutoDeveloper; + guint8 *displayProfile; + gint displayProfileSize; + conf_data *conf; + guchar *inputExifBuf; + guint inputExifBufLen; + guchar *outputExifBuf; + guint outputExifBufLen; + int gimpImage; + int *RawHistogram; + int RawChanMul[4]; + int RawCount; +#ifdef HAVE_LENSFUN + int modFlags; /* postprocessing operations (LF_MODIFY_XXX) */ + struct lfModifier *TCAmodifier; + struct lfModifier *modifier; +#endif /* HAVE_LENSFUN */ + int hotpixels; + gboolean mark_hotpixels; + unsigned raw_multiplier; + gboolean wb_presets_make_model_match; +} ufraw_data; + +extern const conf_data conf_default; +extern const wb_data wb_preset[]; +extern const int wb_preset_count; +extern const char raw_ext[]; +extern const char *file_type[]; + +/* ufraw_binary contains the name of the binary file for error messages. + * It should be set in every UFRaw main() */ +extern char *ufraw_binary; + +#ifdef __cplusplus +extern "C" { +#endif + +/* prototypes for functions in ufraw_ufraw.c */ +ufraw_data *ufraw_open(char *filename); +int ufraw_config(ufraw_data *uf, conf_data *rc, conf_data *conf, conf_data *cmd); +int ufraw_load_raw(ufraw_data *uf); +int ufraw_load_darkframe(ufraw_data *uf); +void ufraw_developer_prepare(ufraw_data *uf, DeveloperMode mode); +int ufraw_convert_image(ufraw_data *uf); +ufraw_image_data *ufraw_get_image(ufraw_data *uf, UFRawPhase phase, + gboolean bufferok); +ufraw_image_data *ufraw_convert_image_area(ufraw_data *uf, unsigned saidx, + UFRawPhase phase); +void ufraw_close_darkframe(conf_data *uf); +void ufraw_close(ufraw_data *uf); +void ufraw_flip_orientation(ufraw_data *uf, int flip); +void ufraw_flip_image(ufraw_data *uf, int flip); +void ufraw_invalidate_layer(ufraw_data *uf, UFRawPhase phase); +void ufraw_invalidate_tca_layer(ufraw_data *uf); +void ufraw_invalidate_hotpixel_layer(ufraw_data *uf); +void ufraw_invalidate_denoise_layer(ufraw_data *uf); +void ufraw_invalidate_darkframe_layer(ufraw_data *uf); +void ufraw_invalidate_despeckle_layer(ufraw_data *uf); +void ufraw_invalidate_whitebalance_layer(ufraw_data *uf); +void ufraw_invalidate_smoothing_layer(ufraw_data *uf); +int ufraw_set_wb(ufraw_data *uf, gboolean interactive); +void ufraw_auto_expose(ufraw_data *uf); +void ufraw_auto_black(ufraw_data *uf); +void ufraw_auto_curve(ufraw_data *uf); +void ufraw_normalize_rotation(ufraw_data *uf); +void ufraw_unnormalize_rotation(ufraw_data *uf); +void ufraw_get_image_dimensions(ufraw_data *uf); +/* Get scaled crop coordinates in final image coordinates */ +void ufraw_get_scaled_crop(ufraw_data *uf, UFRectangle *crop); + +UFRectangle ufraw_image_get_subarea_rectangle(ufraw_image_data *img, + unsigned saidx); +unsigned ufraw_img_get_subarea_idx(ufraw_image_data *img, int x, int y); + +/* prototypes for functions in ufraw_message.c */ +char *ufraw_get_message(ufraw_data *uf); +/* The following functions should only be used internally */ +void ufraw_message_init(ufraw_data *uf); +void ufraw_message_reset(ufraw_data *uf); +void ufraw_set_error(ufraw_data *uf, const char *format, ...); +void ufraw_set_warning(ufraw_data *uf, const char *format, ...); +void ufraw_set_info(ufraw_data *uf, const char *format, ...); +int ufraw_get_status(ufraw_data *uf); +int ufraw_is_error(ufraw_data *uf); +// Old error handling, should be removed after being fully implemented. +char *ufraw_message(int code, const char *format, ...); +void ufraw_batch_messenger(char *message); + +/* prototypes for functions in ufraw_preview.c */ +int ufraw_preview(ufraw_data *uf, conf_data *rc, int plugin, + long(*save_func)()); +void ufraw_focus(void *window, gboolean focus); +void ufraw_messenger(char *message, void *parentWindow); + +/* prototypes for functions in ufraw_routines.c */ +const char *uf_get_home_dir(); +void uf_init_locale(const char *exename); +char *uf_file_set_type(const char *filename, const char *type); +char *uf_file_set_absolute(const char *filename); +/* Set locale of LC_NUMERIC to "C" to make sure that printf behaves correctly.*/ +char *uf_set_locale_C(); +void uf_reset_locale(char *locale); +char *uf_markup_buf(char *buffer, const char *format, ...); +double profile_default_linear(profile_data *p); +double profile_default_gamma(profile_data *p); +void Temperature_to_RGB(double T, double RGB[3]); +void RGB_to_Temperature(double RGB[3], double *T, double *Green); +int curve_load(CurveData *cp, char *filename); +int curve_save(CurveData *cp, char *filename); +char *curve_buffer(CurveData *cp); +/* Useful functions for handling the underappreciated Glib ptr arrays */ +int ptr_array_insert_sorted(GPtrArray *array, const void *item, GCompareFunc compare); +int ptr_array_find_sorted(const GPtrArray *array, const void *item, GCompareFunc compare); +void ptr_array_insert_index(GPtrArray *array, const void *item, int index); + +/* prototypes for functions in ufraw_conf.c */ +int conf_load(conf_data *c, const char *confFilename); +void conf_file_load(conf_data *conf, char *confFilename); +int conf_save(conf_data *c, char *confFilename, char **confBuffer); +/* copy default config to given instance and initialize non-const fields */ +void conf_init(conf_data *c); +/* Copy the image manipulation options from *src to *dst */ +void conf_copy_image(conf_data *dst, const conf_data *src); +/* Copy the transformation options from *src to *dst */ +void conf_copy_transform(conf_data *dst, const conf_data *src); +/* Copy the 'save options' from *src to *dst */ +void conf_copy_save(conf_data *dst, const conf_data *src); +int conf_set_cmd(conf_data *conf, const conf_data *cmd); +int ufraw_process_args(int *argc, char ***argv, conf_data *cmd, conf_data *rc); + +/* prototype for functions in ufraw_developer.c */ +// Convert linear RGB to CIE-LCh +void uf_rgb_to_cielch(gint64 rgb[3], float lch[3]); +// Convert CIE-LCh to linear RGB +void uf_cielch_to_rgb(float lch[3], gint64 rgb[3]); +void uf_raw_to_cielch(const developer_data *d, + const guint16 raw[4], float lch[3]); +developer_data *developer_init(); +void developer_destroy(developer_data *d); +void developer_profile(developer_data *d, int type, profile_data *p); +void developer_display_profile(developer_data *d, + unsigned char *profile, int size, char productName[]); +void developer_prepare(developer_data *d, conf_data *conf, + int rgbMax, float rgb_cam[3][4], int colors, int useMatrix, + DeveloperMode mode); +void develop(void *po, guint16 pix[4], developer_data *d, int mode, int count); +void develop_display(void *pout, void *pin, developer_data *d, int count); +void develop_linear(guint16 in[4], guint16 out[3], developer_data *d); + +/* prototype for functions in ufraw_saver.c */ +long ufraw_save_now(ufraw_data *uf, void *widget); +long ufraw_send_to_gimp(ufraw_data *uf); + +/* prototype for functions in ufraw_writer.c */ +int ufraw_write_image(ufraw_data *uf); +void ufraw_write_image_data( + ufraw_data *uf, void * volatile out, + const UFRectangle *Crop, int bitDepth, int grayscaleMode, + int (*row_writer)(ufraw_data *, void * volatile, void *, int, int, int, int, int)); + +/* prototype for functions in ufraw_delete.c */ +long ufraw_delete(void *widget, ufraw_data *uf); + +/* prototype for functions in ufraw_embedded.c */ +int ufraw_read_embedded(ufraw_data *uf); +int ufraw_convert_embedded(ufraw_data *uf); +int ufraw_write_embedded(ufraw_data *uf); + +/* prototype for functions in ufraw_chooser.c */ +void ufraw_chooser(conf_data *conf, conf_data *rc, conf_data *cmd, + const char *defPath); + +/* prototype for functions in ufraw_icons.c */ +void ufraw_icons_init(); + +/* prototype for functions in ufraw_exiv2.cc */ +int ufraw_exif_read_input(ufraw_data *uf); +int ufraw_exif_prepare_output(ufraw_data *uf); +int ufraw_exif_write(ufraw_data *uf); + +#ifdef __cplusplus +} // extern "C" +#endif + +/* status numbers from DCRaw and UFRaw */ +#define UFRAW_SUCCESS 0 +//#define UFRAW_DCRAW_ERROR 1 /* General dcraw unrecoverable error */ +//#define UFRAW_DCRAW_UNSUPPORTED 2 +//#define UFRAW_DCRAW_NO_CAMERA_WB 3 +//#define UFRAW_DCRAW_VERBOSE 4 +//#define UFRAW_DCRAW_OPEN_ERROR 5 +#define UFRAW_DCRAW_SET_LOG 4 /* DCRAW_VERBOSE */ +#define UFRAW_ERROR 100 +#define UFRAW_CANCEL 101 +#define UFRAW_RC_VERSION 103 /* Mismatch in version from .ufrawrc */ +#define UFRAW_WARNING 104 +#define UFRAW_MESSAGE 105 +#define UFRAW_SET_ERROR 200 +#define UFRAW_SET_WARNING 201 +#define UFRAW_SET_LOG 202 +#define UFRAW_GET_ERROR 203 /* Return the warning buffer if an error occured */ +#define UFRAW_GET_WARNING 204 /* Return the warning buffer */ +#define UFRAW_GET_LOG 205 /* Return the log buffer */ +#define UFRAW_BATCH_MESSAGE 206 +#define UFRAW_INTERACTIVE_MESSAGE 207 +#define UFRAW_REPORT 208 /* Report previous messages */ +#define UFRAW_CLEAN 209 /* Clean all buffers */ +#define UFRAW_RESET 210 /* Reset warnings and errors */ +#define UFRAW_SET_PARENT 211 /* Set parent window for message dialog */ + +#endif /*_UFRAW_H*/ diff --git a/plugins/load-dcraw/ufraw_colorspaces.c b/plugins/load-dcraw/ufraw_colorspaces.c new file mode 100644 index 00000000..19b29899 --- /dev/null +++ b/plugins/load-dcraw/ufraw_colorspaces.c @@ -0,0 +1,147 @@ +/* + * UFRaw - Unidentified Flying Raw converter for digital camera images + * + * ufraw_colorspaces.c - Functions and data to create built-in color profiles. + * Copyright 2004-2016 by Udi Fuchs + * + * 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. + */ + +#include +#include +#include + +static const uint16_t uf_srgb_tone_curve_values[] = { + 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 59, 64, 69, + 74, 79, 84, 89, 94, 99, 104, 109, 114, 119, 124, 129, 134, 139, 144, + 149, 154, 159, 164, 169, 174, 178, 183, 188, 193, 198, 203, 208, 213, 219, + 224, 229, 235, 240, 246, 251, 257, 263, 269, 275, 281, 287, 293, 299, 306, + 312, 318, 325, 332, 338, 345, 352, 359, 366, 373, 380, 387, 395, 402, 410, + 417, 425, 433, 441, 449, 457, 465, 473, 481, 489, 498, 506, 515, 524, 532, + 541, 550, 559, 568, 577, 587, 596, 605, 615, 625, 634, 644, 654, 664, 674, + 684, 694, 705, 715, 725, 736, 747, 757, 768, 779, 790, 801, 813, 824, 835, + 847, 858, 870, 882, 894, 906, 918, 930, 942, 954, 967, 979, 992, 1004, 1017, + 1030, 1043, 1056, 1069, 1083, 1096, 1109, 1123, 1137, 1150, 1164, 1178, 1192, 1206, 1220, + 1235, 1249, 1264, 1278, 1293, 1308, 1323, 1338, 1353, 1368, 1383, 1399, 1414, 1430, 1446, + 1461, 1477, 1493, 1509, 1526, 1542, 1558, 1575, 1591, 1608, 1625, 1642, 1659, 1676, 1693, + 1711, 1728, 1745, 1763, 1781, 1799, 1817, 1835, 1853, 1871, 1889, 1908, 1926, 1945, 1964, + 1983, 2002, 2021, 2040, 2059, 2079, 2098, 2118, 2138, 2158, 2178, 2198, 2218, 2238, 2258, + 2279, 2299, 2320, 2341, 2362, 2383, 2404, 2425, 2447, 2468, 2490, 2511, 2533, 2555, 2577, + 2599, 2621, 2644, 2666, 2689, 2712, 2734, 2757, 2780, 2803, 2827, 2850, 2873, 2897, 2921, + 2944, 2968, 2992, 3016, 3041, 3065, 3090, 3114, 3139, 3164, 3189, 3214, 3239, 3264, 3289, + 3315, 3341, 3366, 3392, 3418, 3444, 3470, 3497, 3523, 3550, 3576, 3603, 3630, 3657, 3684, + 3711, 3739, 3766, 3794, 3822, 3849, 3877, 3905, 3934, 3962, 3990, 4019, 4047, 4076, 4105, + 4134, 4163, 4193, 4222, 4251, 4281, 4311, 4341, 4371, 4401, 4431, 4461, 4492, 4522, 4553, + 4584, 4615, 4646, 4677, 4708, 4740, 4771, 4803, 4835, 4867, 4899, 4931, 4963, 4995, 5028, + 5061, 5093, 5126, 5159, 5193, 5226, 5259, 5293, 5326, 5360, 5394, 5428, 5462, 5496, 5531, + 5565, 5600, 5635, 5670, 5705, 5740, 5775, 5810, 5846, 5882, 5917, 5953, 5989, 6025, 6062, + 6098, 6135, 6171, 6208, 6245, 6282, 6319, 6357, 6394, 6432, 6469, 6507, 6545, 6583, 6621, + 6660, 6698, 6737, 6775, 6814, 6853, 6892, 6932, 6971, 7011, 7050, 7090, 7130, 7170, 7210, + 7250, 7291, 7331, 7372, 7413, 7454, 7495, 7536, 7577, 7619, 7660, 7702, 7744, 7786, 7828, + 7870, 7913, 7955, 7998, 8041, 8084, 8127, 8170, 8213, 8257, 8300, 8344, 8388, 8432, 8476, + 8520, 8565, 8609, 8654, 8699, 8743, 8789, 8834, 8879, 8925, 8970, 9016, 9062, 9108, 9154, + 9200, 9247, 9293, 9340, 9387, 9434, 9481, 9528, 9576, 9623, 9671, 9719, 9767, 9815, 9863, + 9911, 9960, 10008, 10057, 10106, 10155, 10204, 10253, 10303, 10353, 10402, 10452, 10502, 10552, 10603, + 10653, 10704, 10754, 10805, 10856, 10907, 10959, 11010, 11062, 11113, 11165, 11217, 11269, 11321, 11374, + 11426, 11479, 11532, 11585, 11638, 11691, 11745, 11798, 11852, 11906, 11959, 12014, 12068, 12122, 12177, + 12231, 12286, 12341, 12396, 12452, 12507, 12562, 12618, 12674, 12730, 12786, 12842, 12899, 12955, 13012, + 13069, 13126, 13183, 13240, 13297, 13355, 13413, 13470, 13528, 13587, 13645, 13703, 13762, 13821, 13879, + 13938, 13998, 14057, 14116, 14176, 14236, 14295, 14356, 14416, 14476, 14536, 14597, 14658, 14719, 14780, + 14841, 14902, 14964, 15026, 15087, 15149, 15211, 15274, 15336, 15399, 15461, 15524, 15587, 15650, 15713, + 15777, 15840, 15904, 15968, 16032, 16096, 16161, 16225, 16290, 16354, 16419, 16484, 16550, 16615, 16681, + 16746, 16812, 16878, 16944, 17010, 17077, 17143, 17210, 17277, 17344, 17411, 17479, 17546, 17614, 17682, + 17749, 17818, 17886, 17954, 18023, 18091, 18160, 18229, 18299, 18368, 18437, 18507, 18577, 18647, 18717, + 18787, 18857, 18928, 18999, 19069, 19140, 19212, 19283, 19354, 19426, 19498, 19570, 19642, 19714, 19786, + 19859, 19932, 20005, 20078, 20151, 20224, 20297, 20371, 20445, 20519, 20593, 20667, 20742, 20816, 20891, + 20966, 21041, 21116, 21191, 21267, 21343, 21418, 21494, 21570, 21647, 21723, 21800, 21877, 21954, 22031, + 22108, 22185, 22263, 22340, 22418, 22496, 22575, 22653, 22731, 22810, 22889, 22968, 23047, 23126, 23206, + 23285, 23365, 23445, 23525, 23605, 23686, 23766, 23847, 23928, 24009, 24090, 24172, 24253, 24335, 24417, + 24499, 24581, 24663, 24746, 24828, 24911, 24994, 25077, 25161, 25244, 25328, 25411, 25495, 25579, 25664, + 25748, 25833, 25917, 26002, 26087, 26173, 26258, 26344, 26429, 26515, 26601, 26687, 26774, 26860, 26947, + 27034, 27121, 27208, 27295, 27383, 27471, 27559, 27647, 27735, 27823, 27912, 28000, 28089, 28178, 28267, + 28356, 28446, 28536, 28625, 28715, 28806, 28896, 28986, 29077, 29168, 29259, 29350, 29441, 29533, 29624, + 29716, 29808, 29900, 29992, 30085, 30177, 30270, 30363, 30456, 30550, 30643, 30737, 30830, 30924, 31018, + 31113, 31207, 31302, 31397, 31492, 31587, 31682, 31777, 31873, 31969, 32065, 32161, 32257, 32354, 32450, + 32547, 32644, 32741, 32839, 32936, 33034, 33131, 33229, 33328, 33426, 33524, 33623, 33722, 33821, 33920, + 34019, 34119, 34219, 34318, 34418, 34519, 34619, 34719, 34820, 34921, 35022, 35123, 35225, 35326, 35428, + 35530, 35632, 35734, 35836, 35939, 36042, 36145, 36248, 36351, 36454, 36558, 36662, 36766, 36870, 36974, + 37078, 37183, 37288, 37393, 37498, 37603, 37709, 37814, 37920, 38026, 38132, 38239, 38345, 38452, 38559, + 38666, 38773, 38880, 38988, 39096, 39204, 39312, 39420, 39528, 39637, 39746, 39855, 39964, 40073, 40183, + 40292, 40402, 40512, 40622, 40733, 40843, 40954, 41065, 41176, 41287, 41398, 41510, 41622, 41734, 41846, + 41958, 42070, 42183, 42296, 42409, 42522, 42635, 42749, 42862, 42976, 43090, 43204, 43319, 43433, 43548, + 43663, 43778, 43893, 44009, 44124, 44240, 44356, 44472, 44589, 44705, 44822, 44939, 45056, 45173, 45290, + 45408, 45526, 45643, 45762, 45880, 45998, 46117, 46236, 46355, 46474, 46593, 46713, 46832, 46952, 47072, + 47193, 47313, 47434, 47554, 47675, 47797, 47918, 48039, 48161, 48283, 48405, 48527, 48650, 48772, 48895, + 49018, 49141, 49264, 49388, 49511, 49635, 49759, 49883, 50008, 50132, 50257, 50382, 50507, 50632, 50758, + 50883, 51009, 51135, 51261, 51388, 51514, 51641, 51768, 51895, 52022, 52150, 52277, 52405, 52533, 52661, + 52790, 52918, 53047, 53176, 53305, 53434, 53564, 53694, 53823, 53953, 54084, 54214, 54345, 54475, 54606, + 54737, 54869, 55000, 55132, 55264, 55396, 55528, 55660, 55793, 55926, 56059, 56192, 56325, 56458, 56592, + 56726, 56860, 56994, 57129, 57263, 57398, 57533, 57668, 57804, 57939, 58075, 58211, 58347, 58483, 58620, + 58756, 58893, 59030, 59167, 59305, 59442, 59580, 59718, 59856, 59995, 60133, 60272, 60411, 60550, 60689, + 60828, 60968, 61108, 61248, 61388, 61528, 61669, 61810, 61951, 62092, 62233, 62375, 62516, 62658, 62800, + 62942, 63085, 63227, 63370, 63513, 63656, 63800, 63943, 64087, 64231, 64375, 64519, 64664, 64809, 64954, + 65099, 65244, 65389, 65535 +}; + +static const guint uf_srgb_tone_curve_values_n = G_N_ELEMENTS(uf_srgb_tone_curve_values); + +cmsHPROFILE uf_colorspaces_create_srgb_profile() +{ + cmsHPROFILE hsRGB; + + cmsCIEXYZTRIPLE Colorants = { { 0.436066, 0.222488, 0.013916 }, + { 0.385147, 0.716873, 0.097076 }, + { 0.143066, 0.060608, 0.714096 } + }; + + cmsCIEXYZ black = { 0, 0, 0 }; + cmsCIEXYZ D65 = { 0.95045, 1, 1.08905 }; + cmsToneCurve *transferFunction; + + transferFunction + = cmsBuildTabulatedToneCurve16(NULL, uf_srgb_tone_curve_values_n, uf_srgb_tone_curve_values); + + hsRGB = cmsCreateProfilePlaceholder(0); + + cmsSetProfileVersion(hsRGB, 2.1); + + cmsMLU *mlu0 = cmsMLUalloc(NULL, 1); + cmsMLUsetASCII(mlu0, "en", "US", "Public Domain"); + cmsMLU *mlu1 = cmsMLUalloc(NULL, 1); + cmsMLUsetASCII(mlu1, "en", "US", "sRGB"); + cmsMLU *mlu2 = cmsMLUalloc(NULL, 1); + cmsMLUsetASCII(mlu2, "en", "US", "UFRaw"); + cmsMLU *mlu3 = cmsMLUalloc(NULL, 1); + cmsMLUsetASCII(mlu3, "en", "US", "sRGB"); + // this will only be displayed when the embedded profile is read by for example GIMP + cmsWriteTag(hsRGB, cmsSigCopyrightTag, mlu0); + cmsWriteTag(hsRGB, cmsSigProfileDescriptionTag, mlu1); + cmsWriteTag(hsRGB, cmsSigDeviceMfgDescTag, mlu2); + cmsWriteTag(hsRGB, cmsSigDeviceModelDescTag, mlu3); + cmsMLUfree(mlu0); + cmsMLUfree(mlu1); + cmsMLUfree(mlu2); + cmsMLUfree(mlu3); + + cmsSetDeviceClass(hsRGB, cmsSigDisplayClass); + cmsSetColorSpace(hsRGB, cmsSigRgbData); + cmsSetPCS(hsRGB, cmsSigXYZData); + + cmsWriteTag(hsRGB, cmsSigMediaWhitePointTag, &D65); + cmsWriteTag(hsRGB, cmsSigMediaBlackPointTag, &black); + + cmsWriteTag(hsRGB, cmsSigRedColorantTag, (void *)&Colorants.Red); + cmsWriteTag(hsRGB, cmsSigGreenColorantTag, (void *)&Colorants.Green); + cmsWriteTag(hsRGB, cmsSigBlueColorantTag, (void *)&Colorants.Blue); + + cmsWriteTag(hsRGB, cmsSigRedTRCTag, (void *)transferFunction); + cmsLinkTag(hsRGB, cmsSigGreenTRCTag, cmsSigRedTRCTag); + cmsLinkTag(hsRGB, cmsSigBlueTRCTag, cmsSigRedTRCTag); + + cmsFreeToneCurve(transferFunction); + + return hsRGB; +} diff --git a/plugins/load-dcraw/ufraw_colorspaces.h b/plugins/load-dcraw/ufraw_colorspaces.h new file mode 100644 index 00000000..bd830e0d --- /dev/null +++ b/plugins/load-dcraw/ufraw_colorspaces.h @@ -0,0 +1,14 @@ +/* + * UFRaw - Unidentified Flying Raw converter for digital camera images + * + * ufraw_colorspaces.h - Built-in color profile declarations. + * Copyright 2004-2016 by Udi Fuchs + * + * 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. + */ + +/** create the ICC virtual profile for srgb space. */ +cmsHPROFILE uf_colorspaces_create_srgb_profile(void); diff --git a/plugins/load-dcraw/ufraw_conf.c b/plugins/load-dcraw/ufraw_conf.c new file mode 100644 index 00000000..e66d2226 --- /dev/null +++ b/plugins/load-dcraw/ufraw_conf.c @@ -0,0 +1,2461 @@ +/* + * UFRaw - Unidentified Flying Raw converter for digital camera images + * + * ufraw_conf.c - handle configuration issues + * Copyright 2004-2016 by Udi Fuchs + * + * 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. + */ + +#include "ufraw.h" +#include +#include +#include +#include /* needed for fstat() */ +#include +#include + +#ifdef HAVE_EXIV2 +#include +#endif + +const conf_data conf_default = { + /* Internal data */ + 7, /* configuration version */ + + NULL, /* ufobject */ + /* Image manipulation settings */ + 0.0, /* wavelet denoising threshold */ + 0.0, /* hotpixel sensitivity */ +#ifdef UFRAW_CONTRAST + 1.0, /* global contrast */ +#endif + 0.0, 1.0, 0.0, /* exposure, saturation, black */ + 0, /* ExposureNorm */ + restore_lch_details, /* restoreDetails */ + digital_highlights, /* clipHighlights */ + disabled_state, /* autoExposure */ + disabled_state, /* autoBlack */ + enabled_state, /* fullCrop */ + disabled_state, /* autoCrop */ + camera_curve, camera_curve + 1, /* BaseCurveIndex, BaseCurveCount */ + /* BaseCurve data defaults */ + { { + N_("Manual curve"), TONE_CURVE, 0.0, 1.0, 0.0, 1.0, 1.0, + 2 , { { 0.0, 0.0 }, { 1.0, 1.0 } } + }, + { + N_("Linear curve"), TONE_CURVE, 0.0, 1.0, 0.0, 1.0, 1.0, + 2 , { { 0.0, 0.0 }, { 1.0, 1.0 } } + }, + { + N_("Custom curve"), TONE_CURVE, 0.0, 1.0, 0.0, 1.0, 1.0, + 2 , { { 0.0, 0.0 }, { 1.0, 1.0 } } + }, + { + N_("Camera curve"), TONE_CURVE, 0.0, 1.0, 0.0, 1.0, 1.0, + 2 , { { 0.0, 0.0 }, { 1.0, 1.0 } } + } + }, + linear_curve, linear_curve + 1, /* curveIndex, curveCount */ + /* Curve data defaults */ + { { + N_("Manual curve"), TONE_CURVE, 0.0, 1.0, 0.0, 1.0, 1.0, + 2 , { { 0.0, 0.0 }, { 1.0, 1.0 } } + }, + { + N_("Linear curve"), TONE_CURVE, 0.0, 1.0, 0.0, 1.0, 1.0, + 2 , { { 0.0, 0.0 }, { 1.0, 1.0 } } + } + }, + { 1, 0, 0 } , { 2, 2, 2 }, /* profileIndex[], profileCount[] */ + /* Profile data defaults */ + { { { N_("No profile"), "", "", 0.45, 0.1, 0 }, + { N_("Color matrix"), "", "", 0.45, 0.1, 0 }, + { "Some ICC Profile", "", "", 0.45, 0.0, 0 } + }, + { { N_("sRGB"), "", "", 0.0, 0.0, 8 }, + { N_("sRGB (embedded)"), "", "", 0.0, 0.0, 8 }, + { "Some ICC Profile", "", "", 0.0, 0.0, 8 } + }, + { { N_("System default"), "", "", 0.0, 0.0, 0 }, + { N_("sRGB"), "", "", 0.0, 0.0, 0 }, + { "Some ICC Profile", "", "", 0.0, 0.0, 0 } + } + }, + { 0, 0, 0 }, /* intent */ + ahd_interpolation, 0, /* interpolation, smoothing */ + "", NULL, /* darkframeFile, darkframe */ + -1, -1, -1, -1, /* Crop X1,Y1,X2,Y2 */ + 0.0, /* aspectRatio */ + -1, /* orientation */ + 0, /* rotationAngle */ + 0, /* lightness adjustment count */ + { + { 1, 0, 0 }, + { 1, 0, 0 }, + { 1, 0, 0 }, + }, /* lightness adjustments */ + grayscale_none, /* grayscale mode */ + { 1.0, 1.0, 1.0 }, /* grayscale mixer */ + 1, /* grayscale mixer defined */ + { 0.0, 0.0, 0.0, 0.0 }, /* despeckle window */ + { 0.0, 0.0, 0.0, 0.0 }, /* despeckle color decay */ + { 1.0, 1.0, 1.0, 1.0 }, /* despeckle passes */ + /* Save options */ + "", "", "", /* inputFilename, outputFilename, outputPath */ + "", "", /* inputURI, inputModTime */ + ppm_type, 85, no_id, /* type, compression, createID */ + TRUE, /* embedExif */ + FALSE, /* progressiveJPEG */ + 1, 0, /* shrink, size */ + FALSE, /* overwrite existing files without asking */ + FALSE, /* losslessCompress */ + FALSE, /* load embedded preview image */ + FALSE, /* noExit */ + TRUE, /* rotate to camera's setting */ + + /* GUI settings */ + 25.0, TRUE, /* Zoom, LockAspect */ + enabled_state, /* saveConfiguration */ + rgb_histogram, /* histogram */ + linear_histogram, /* liveHistogramScale */ + linear_histogram, /* rawHistogramScale */ + { TRUE, TRUE }, /* expander[] */ + FALSE, /* overExp indicator */ + FALSE, /* underExp indicator */ + TRUE, /* blinkOverUnder indicators */ + FALSE, /* RememberOutputPath */ + FALSE, /* WindowMaximized */ + 0, /* number of helper lines to draw */ + "", "", /* curvePath, profilePath */ + FALSE, /* silent */ +#ifdef _WIN32 + "gimp-win-remote gimp-2.8.exe", /* remoteGimpCommand */ +#elif HAVE_GIMP_2_4 + "gimp", /* remoteGimpCommand */ +#else + "gimp", /* remoteGimpCommand */ +#endif + + /* EXIF data */ + 0, /* CameraOrientation */ + 0.0, 0.0, 0.0, 0.0, 1.0, /* iso_speed, shutter, aperture, focal_len, subject_dist */ + "", "", "", "", /* exifSource, isoText, shutterText, apertureText */ + "", "", "", "", /* focalLenText, focalLen35Text, lensText, flashText */ + "", /* whiteBalanceText */ + "", "", "", /* timestamp, make, model */ + 0, /* timestamp */ + "", "", /* real_make, real_model */ +}; + +static const char *interpolationNames[] = { + "ahd", "vng", "four-color", "ppg", "bilinear", "xtrans", "none", "half", + "eahd", NULL +}; +static const char *restoreDetailsNames[] = +{ "clip", "lch", "hsv", NULL }; +static const char *clipHighlightsNames[] = +{ "digital", "film", NULL }; +static const char *intentNames[] = +{ "perceptual", "relative", "saturation", "absolute", "disable", NULL }; +static const char *grayscaleModeNames[] = +{ "none", "lightness", "luminance", "value", "mixer", NULL }; + +void conf_init(conf_data *c) +{ + *c = conf_default; +} + +static int conf_find_name(const char name[], const char *namesList[], int notFound) +{ + int i; + for (i = 0; namesList[i] != NULL; i++) { + if (!strcmp(name, namesList[i])) return i; + } + return notFound; +} + +static const char *conf_get_name(const char *namesList[], int index) +{ + int i; + for (i = 0; namesList[i] != NULL; i++) + if (i == index) return namesList[i]; + return "Error"; +} + +typedef struct { + conf_data *conf; + UFObject *group; + GQuark ufrawQuark; +} parse_data; + +static void conf_parse_start(GMarkupParseContext *context, + const gchar *element, const gchar **names, const gchar **values, + gpointer user, GError **error) +{ + parse_data *data = (parse_data *)user; + conf_data *c = data->conf; + int int_value; + (void)context; + + int i; + for (i = 0; names[i] != NULL; i++) { + if (strcmp(names[i], "Index") == 0) { + if (!ufgroup_has(data->group, element)) { + ufraw_message(UFRAW_WARNING, + "UFGroup '%s' does not contain UFArray '%s'", + ufobject_name(data->group), element); + return; + } + data->group = ufgroup_element(data->group, element); + if (!ufobject_set_string(data->group, values[i])) { + ufraw_message(UFRAW_WARNING, + "UFArray set '%s' to string value '%s' failed", + ufobject_name(data->group), values[i]); + } + return; + } else if (strcmp(names[i], "Label") == 0) { + // We assume that only UFArray elements have a label. + if (!ufgroup_has(data->group, values[i])) { + ufraw_message(UFRAW_WARNING, + "UFArray '%s' does not contain UFObject '%s'", + ufobject_name(data->group), element); + return; + } + data->group = ufgroup_element(data->group, values[i]); + if (strcmp(ufobject_name(data->group), element) != 0) + g_set_error(error, data->ufrawQuark, UFRAW_ERROR, + "Expecting '%s' XML element and not '%s' XML element", + ufobject_name(data->group), element); + return; + } + } + if (ufgroup_has(data->group, element)) { + data->group = ufgroup_element(data->group, element); + return; + } + while (*names != NULL) { + if (!strcasecmp(*values, "yes")) + int_value = 1; + if (!strcasecmp(*values, "no")) + int_value = 0; + else + sscanf(*values, "%d", &int_value); + if (!strcmp(element, "UFRaw") && !strcmp(*names, "Version")) { + if (int_value == 3) { + ufraw_message(UFRAW_WARNING, + _("Trying to convert .ufrawrc from UFRaw-0.4 or earlier")); + c->version = int_value; + } + /* In version 7 temperature calculation has changed */ + if (int_value == 5) { + ufraw_message(UFRAW_WARNING, + _("Trying to convert .ufrawrc from UFRaw-0.6 or earlier")); + c->version = int_value; + } + if (int_value != c->version) + g_set_error(error, data->ufrawQuark, UFRAW_RC_VERSION, + _("UFRaw version in .ufrawrc is not supported")); + } + if (!strcmp(*names, "Current") && int_value != 0) { + if (!strcmp("BaseManualCurve", element)) + c->BaseCurveIndex = manual_curve; + if (!strcmp("BaseLinearCurve", element)) + c->BaseCurveIndex = linear_curve; + if (!strcmp("BaseCustomCurve", element)) + c->BaseCurveIndex = custom_curve; + if (!strcmp("BaseCameraCurve", element)) + c->BaseCurveIndex = camera_curve; + if (!strcmp("BaseCurve", element)) + c->BaseCurveIndex = c->BaseCurveCount; + if (!strcmp("ManualCurve", element)) + c->curveIndex = manual_curve; + if (!strcmp("LinearCurve", element)) + c->curveIndex = linear_curve; + if (!strcmp("Curve", element)) + c->curveIndex = c->curveCount; + // For compatibility with ufraw-0.13 or older + if (!strcmp("sRGBInputProfile", element)) + c->profileIndex[in_profile] = 0; + if (!strcmp("NoInputProfile", element)) + c->profileIndex[in_profile] = 0; + if (!strcmp("MatrixInputProfile", element)) + c->profileIndex[in_profile] = 1; + if (!strcmp("sRGBOutputProfile", element)) + c->profileIndex[out_profile] = 0; + if (!strcmp("sRGBEmbeddedOutputProfile", element)) + c->profileIndex[out_profile] = 1; + if (!strcmp("SystemDisplayProfile", element)) + c->profileIndex[display_profile] = 0; + if (!strcmp("sRGBDisplayProfile", element)) + c->profileIndex[display_profile] = 1; + if (!strcmp("InputProfile", element)) + c->profileIndex[in_profile] = c->profileCount[in_profile]; + if (!strcmp("OutputProfile", element)) + c->profileIndex[out_profile] = c->profileCount[out_profile]; + if (!strcmp("DisplayProfile", element)) + c->profileIndex[display_profile] = + c->profileCount[display_profile]; + } + names++; + values++; + } + /* The default curve/profile count is always larger than 0, + * threfore we can treat 0 as a negative number. + * m_numAnchors==0 marks that no anchors where read from the XML. */ + if (!strcmp("BaseManualCurve", element)) { + c->BaseCurveCount = - manual_curve; + c->BaseCurve[-c->BaseCurveCount].m_numAnchors = 0; + } + if (!strcmp("BaseLinearCurve", element)) { + c->BaseCurveCount = - linear_curve; + c->BaseCurve[-c->BaseCurveCount].m_numAnchors = 0; + } + if (!strcmp("BaseCustomCurve", element)) { + c->BaseCurveCount = - custom_curve; + c->BaseCurve[-c->BaseCurveCount].m_numAnchors = 0; + } + if (!strcmp("BaseCameraCurve", element)) { + c->BaseCurveCount = - camera_curve; + c->BaseCurve[-c->BaseCurveCount].m_numAnchors = 0; + } + if (!strcmp("ManualCurve", element)) { + c->curveCount = - manual_curve; + c->curve[-c->curveCount].m_numAnchors = 0; + } + if (!strcmp("LinearCurve", element)) { + c->curveCount = - linear_curve; + c->curve[-c->curveCount].m_numAnchors = 0; + } + if (!strcmp("NoInputProfile", element)) + c->profileCount[in_profile] = 0; + if (!strcmp("MatrixInputProfile", element)) + c->profileCount[in_profile] = -1; + // For compatibility with ufraw-0.13 or older + if (!strcmp("sRGBInputProfile", element)) + c->profileCount[in_profile] = -1; + if (!strcmp("sRGBOutputProfile", element)) + c->profileCount[out_profile] = 0; + if (!strcmp("sRGBEmbeddedOutputProfile", element)) + c->profileCount[out_profile] = -1; + if (!strcmp("SystemDisplayProfile", element)) + c->profileCount[display_profile] = 0; + if (!strcmp("sRGBDisplayProfile", element)) + c->profileCount[display_profile] = -1; +} + +static void conf_parse_end(GMarkupParseContext *context, const gchar *element, + gpointer user, GError **error) +{ + parse_data *data = (parse_data *)user; + conf_data *c = data->conf; + + (void)context; + (void)error; + + if (strcmp(ufobject_name(data->group), element) == 0) { + data->group = ufobject_parent(data->group); + return; + } + if (c->BaseCurveCount <= 0 && + (!strcmp("BaseManualCurve", element) || + !strcmp("BaseLinearCurve", element) || + !strcmp("BaseCustomCurve", element) || + !strcmp("BaseCameraCurve", element))) { + if (c->BaseCurve[-c->BaseCurveCount].m_numAnchors == 0) + c->BaseCurve[-c->BaseCurveCount].m_numAnchors = 2; + c->BaseCurveCount = camera_curve + 1; + } + if (c->BaseCurveCount <= 0 && !strcmp("BaseCurve", element)) { + if (c->BaseCurve[-c->BaseCurveCount].m_numAnchors == 0) + c->BaseCurve[-c->BaseCurveCount].m_numAnchors = 2; + c->BaseCurveCount = - c->BaseCurveCount + 1; + } + if (c->curveCount <= 0 && + (!strcmp("ManualCurve", element) || + !strcmp("LinearCurve", element))) { + if (c->curve[-c->curveCount].m_numAnchors == 0) + c->curve[-c->curveCount].m_numAnchors = 2; + c->curveCount = linear_curve + 1; + } + if (c->curveCount <= 0 && !strcmp("Curve", element)) { + if (c->curve[-c->curveCount].m_numAnchors == 0) + c->curve[-c->curveCount].m_numAnchors = 2; + c->curveCount = - c->curveCount + 1; + } + // For compatibility with ufraw-0.13 or older + if (!strcmp("sRGBInputProfile", element)) + c->profileCount[in_profile] = + conf_default.profileCount[in_profile]; + if (!strcmp("NoInputProfile", element)) + c->profileCount[in_profile] = + conf_default.profileCount[in_profile]; + if (!strcmp("MatrixInputProfile", element)) + c->profileCount[in_profile] = + conf_default.profileCount[in_profile]; + if (!strcmp("sRGBOutputProfile", element)) + c->profileCount[out_profile] = + conf_default.profileCount[out_profile]; + if (!strcmp("sRGBEmbeddedOutputProfile", element)) + c->profileCount[out_profile] = + conf_default.profileCount[out_profile]; + if (!strcmp("SystemDisplayProfile", element)) + c->profileCount[display_profile] = + conf_default.profileCount[display_profile]; + if (!strcmp("sRGBDisplayProfile", element)) + c->profileCount[display_profile] = + conf_default.profileCount[display_profile]; + if (c->profileCount[in_profile] <= 0 && strcmp("InputProfile", element) == 0) + c->profileCount[in_profile] = -c->profileCount[in_profile] + 1; + if (c->profileCount[out_profile] <= 0 && + strcmp("OutputProfile", element) == 0) + c->profileCount[out_profile] = - c->profileCount[out_profile] + 1; + if (c->profileCount[display_profile] <= 0 && + strcmp("DisplayProfile", element) == 0) + c->profileCount[display_profile] = -c->profileCount[display_profile] + 1; +} + +static void conf_parse_text(GMarkupParseContext *context, const gchar *text, + gsize len, gpointer user, GError **error) +{ + parse_data *data = (parse_data *)user; + conf_data *c = data->conf; + + const gchar *element = g_markup_parse_context_get_element(context); + char temp[max_path]; + int i; + error = error; + for (; len > 0 && g_ascii_isspace(*text); len--, text++); + for (; len > 0 && g_ascii_isspace(text[len - 1]); len--); + if (len == 0) return; + if (len > max_path - 1) len = max_path - 1; + strncpy(temp, text, len); + temp[len] = '\0'; + + if (strcmp(ufobject_name(data->group), element) == 0) { + if (!ufobject_set_string(data->group, text)) + ufraw_message(UFRAW_WARNING, + "UFObject set '%s' to string value '%s' failed", + ufobject_name(data->group), text); + return; + } + if (c->curveCount <= 0) { + i = - c->curveCount; + /* for backward compatibility with ufraw-0.4 */ + if (!strcmp("File", element)) { + /* Ignore this curve if curve_load() fails */ + if (curve_load(&c->curve[i], temp) != UFRAW_SUCCESS) + c->curveCount = - c->curveCount; + } + if (!strcmp("MinXY", element)) { + sscanf(temp, "%lf %lf", &c->curve[i].m_min_x, &c->curve[i].m_min_y); + c->curve[i].m_min_x = LIM(c->curve[i].m_min_x, 0, 1); + c->curve[i].m_min_y = LIM(c->curve[i].m_min_y, 0, 1); + } + if (!strcmp("MaxXY", element)) { + sscanf(temp, "%lf %lf", &c->curve[i].m_max_x, &c->curve[i].m_max_y); + c->curve[i].m_max_x = LIM(c->curve[i].m_max_x, 0, 1); + c->curve[i].m_max_y = LIM(c->curve[i].m_max_y, 0, 1); + } + if (!strcmp("AnchorXY", element)) { + if (c->curve[i].m_numAnchors == max_anchors) { + ufraw_message(UFRAW_WARNING, + _("Too many anchors for curve '%s'"), c->curve[i].name); + /* We try to keep the last anchor point */ + c->curve[i].m_numAnchors--; + } + /* If one anchor is supplied then all anchors should be supplied */ + sscanf(temp, "%lf %lf", + &c->curve[i].m_anchors[c->curve[i].m_numAnchors].x, + &c->curve[i].m_anchors[c->curve[i].m_numAnchors].y); + c->curve[i].m_anchors[c->curve[i].m_numAnchors].x = + LIM(c->curve[i].m_anchors[c->curve[i].m_numAnchors].x, 0, 1); + c->curve[i].m_anchors[c->curve[i].m_numAnchors].y = + LIM(c->curve[i].m_anchors[c->curve[i].m_numAnchors].y, 0, 1); + c->curve[i].m_numAnchors++; + } + return; + } + + if (c->BaseCurveCount <= 0) { + i = - c->BaseCurveCount; + if (!strcmp("MinXY", element)) { + sscanf(temp, "%lf %lf", &c->BaseCurve[i].m_min_x, &c->BaseCurve[i].m_min_y); + c->BaseCurve[i].m_min_x = LIM(c->BaseCurve[i].m_min_x, 0, 1); + c->BaseCurve[i].m_min_y = LIM(c->BaseCurve[i].m_min_y, 0, 1); + } + if (!strcmp("MaxXY", element)) { + sscanf(temp, "%lf %lf", &c->BaseCurve[i].m_max_x, &c->BaseCurve[i].m_max_y); + c->BaseCurve[i].m_max_x = LIM(c->BaseCurve[i].m_max_x, 0, 1); + c->BaseCurve[i].m_max_y = LIM(c->BaseCurve[i].m_max_y, 0, 1); + } + if (!strcmp("AnchorXY", element)) { + /* If one anchor is supplied then all anchors should be supplied */ + sscanf(temp, "%lf %lf", + &c->BaseCurve[i].m_anchors[c->BaseCurve[i].m_numAnchors].x, + &c->BaseCurve[i].m_anchors[c->BaseCurve[i].m_numAnchors].y); + c->BaseCurve[i].m_anchors[c->BaseCurve[i].m_numAnchors].x = + LIM(c->BaseCurve[i].m_anchors[c->BaseCurve[i].m_numAnchors].x, 0, 1); + c->BaseCurve[i].m_anchors[c->BaseCurve[i].m_numAnchors].y = + LIM(c->BaseCurve[i].m_anchors[c->BaseCurve[i].m_numAnchors].y, 0, 1); + c->BaseCurve[i].m_numAnchors++; + } + return; + } + + if (c->profileCount[in_profile] <= 0) { + i = - c->profileCount[in_profile]; + if (!strcmp("File", element)) + g_strlcpy(c->profile[in_profile][i].file, temp, max_path); + if (!strcmp("ProductName", element)) + g_strlcpy(c->profile[in_profile][i].productName, temp, max_name); + if (!strcmp("Gamma", element)) + sscanf(temp, "%lf", &c->profile[in_profile][i].gamma); + if (!strcmp("Linearity", element)) + sscanf(temp, "%lf", &c->profile[in_profile][i].linear); + if (!strcmp("UseColorMatrix", element)) { + gboolean useMatrix; + sscanf(temp, "%d", &useMatrix); + // TODO: choose between 'No profile' and 'Color matrix' + } + return; + } + if (c->profileCount[out_profile] <= 0) { + i = - c->profileCount[out_profile]; + if (!strcmp("File", element)) { + char *utf8 = g_filename_display_name(temp); + g_strlcpy(c->profile[out_profile][i].file, utf8, max_path); + g_free(utf8); + } + if (!strcmp("ProductName", element)) + g_strlcpy(c->profile[out_profile][i].productName, temp, max_name); + if (!strcmp("BitDepth", element)) + sscanf(temp, "%d", &c->profile[out_profile][i].BitDepth); + return; + } + if (c->profileCount[display_profile] <= 0) { + i = - c->profileCount[display_profile]; + if (!strcmp("File", element)) { + char *utf8 = g_filename_display_name(temp); + g_strlcpy(c->profile[display_profile][i].file, utf8, max_path); + g_free(utf8); + } + if (!strcmp("ProductName", element)) + g_strlcpy(c->profile[display_profile][i].productName, temp, + max_name); + return; + } + if (!strcmp("BaseCurve", element)) { + c->BaseCurveCount = - c->BaseCurveCount; + i = - c->BaseCurveCount; + c->BaseCurve[i] = conf_default.BaseCurve[0]; + g_strlcpy(c->BaseCurve[i].name, temp, max_name); + /* m_numAnchors==0 marks that no anchors where read from the XML */ + c->BaseCurve[-c->BaseCurveCount].m_numAnchors = 0; + } + if (!strcmp("Curve", element)) { + c->curveCount = - c->curveCount; + i = - c->curveCount; + c->curve[i] = conf_default.curve[0]; + g_strlcpy(c->curve[i].name, temp, max_name); + /* m_numAnchors==0 marks that no anchors where read from the XML */ + c->curve[-c->curveCount].m_numAnchors = 0; + } + if (!strcmp("InputProfile", element)) { + c->profileCount[in_profile] = - c->profileCount[in_profile]; + i = - c->profileCount[in_profile]; + c->profile[in_profile][i] = conf_default.profile[in_profile][1]; + g_strlcpy(c->profile[in_profile][i].name, temp, max_name); + } + if (!strcmp("OutputProfile", element)) { + c->profileCount[out_profile] = - c->profileCount[out_profile]; + i = - c->profileCount[out_profile]; + c->profile[out_profile][i] = conf_default.profile[out_profile][0]; + g_strlcpy(c->profile[out_profile][i].name, temp, max_name); + } + if (!strcmp("DisplayProfile", element)) { + c->profileCount[display_profile] = - c->profileCount[display_profile]; + i = - c->profileCount[display_profile]; + c->profile[display_profile][i] = + conf_default.profile[display_profile][0]; + g_strlcpy(c->profile[display_profile][i].name, temp, max_name); + } + if (!strcmp("InputFilename", element)) { + char *utf8 = g_filename_from_utf8(temp, -1, NULL, NULL, NULL); + if (utf8 != NULL) + g_strlcpy(c->inputFilename, utf8, max_path); + g_free(utf8); + } + if (!strcmp("OutputFilename", element)) { + char *utf8 = g_filename_from_utf8(temp, -1, NULL, NULL, NULL); + if (utf8 != NULL) + g_strlcpy(c->outputFilename, utf8, max_path); + g_free(utf8); + } + if (!strcmp("OutputPath", element)) { + char *utf8 = g_filename_from_utf8(temp, -1, NULL, NULL, NULL); + if (utf8 != NULL) + g_strlcpy(c->outputPath, utf8, max_path); + g_free(utf8); + } + if (!strcmp("SaveConfiguration", element)) + sscanf(temp, "%d", &c->saveConfiguration); + if (!strcmp("Interpolation", element)) { + /* Keep compatibility with old numbers from ufraw-0.5 */ + if (sscanf(temp, "%d", &c->interpolation) == 1) { + switch (c->interpolation) { + case 0: + c->interpolation = vng_interpolation; + break; + case 1: + c->interpolation = four_color_interpolation; + break; + case 2: + c->interpolation = bilinear_interpolation; + break; + case 3: + c->interpolation = half_interpolation; + break; + default: + c->interpolation = ahd_interpolation; + } + } else { + c->interpolation = conf_find_name(temp, interpolationNames, + conf_default.interpolation); + if (c->interpolation == obsolete_eahd_interpolation) { + c->interpolation = ahd_interpolation; + c->smoothing = 3; + } + } + } + if (!strcmp("ColorSmoothing", element)) + sscanf(temp, "%d", &c->smoothing); + if (!strcmp("RawExpander", element)) + sscanf(temp, "%d", &c->expander[raw_expander]); + if (!strcmp("LiveExpander", element)) + sscanf(temp, "%d", &c->expander[live_expander]); + if (!strcmp("Histogram", element)) sscanf(temp, "%d", &c->histogram); + if (!strcmp("LiveHistogramScale", element)) + sscanf(temp, "%d", &c->liveHistogramScale); + if (!strcmp("RawHistogramScale", element)) + sscanf(temp, "%d", &c->rawHistogramScale); + if (!strcmp("RemoteGimpCommand", element)) + g_strlcpy(c->remoteGimpCommand, temp, max_path); + if (!strcmp("LockAspectRatio", element)) sscanf(temp, "%d", &c->LockAspect); + if (!strcmp("OverExposure", element)) sscanf(temp, "%d", &c->overExp); + if (!strcmp("UnderExposure", element)) sscanf(temp, "%d", &c->underExp); + if (!strcmp("BlinkOverUnder", element)) + sscanf(temp, "%d", &c->blinkOverUnder); + if (!strcmp("DrawLines", element)) + sscanf(temp, "%d", &c->drawLines); + if (!strcmp("RememberOutputPath", element)) + sscanf(temp, "%d", &c->RememberOutputPath); + if (!strcmp("WindowMaximized", element)) + sscanf(temp, "%d", &c->WindowMaximized); + if (!strcmp("WaveletDenoisingThreshold", element)) + sscanf(temp, "%lf", &c->threshold); + if (!strcmp("HotpixelSensitivity", element)) + sscanf(temp, "%lf", &c->hotpixel); +#ifdef UFRAW_CONTRAST + if (!strcmp("Contrast", element)) + sscanf(temp, "%lf", &c->contrast); +#endif + if (!strcmp("Exposure", element)) sscanf(temp, "%lf", &c->exposure); + if (!strcmp("ExposureNorm", element)) sscanf(temp, "%d", &c->ExposureNorm); + if (!strcmp("Saturation", element)) sscanf(temp, "%lf", &c->saturation); + if (!strcmp("RestoreDetails", element)) + c->restoreDetails = conf_find_name(temp, restoreDetailsNames, + conf_default.restoreDetails); + if (!strcmp("ClipHighlights", element)) + c->clipHighlights = conf_find_name(temp, clipHighlightsNames, + conf_default.clipHighlights); + /* For compatibility with UFRaw-0.10 and earlier. */ + if (!strcmp("Unclip", element)) { + int unclip; + sscanf(temp, "%d", &unclip); + if (unclip) c->restoreDetails = restore_lch_details; + else c->restoreDetails = clip_details; + } + if (!strcmp("AutoExposure", element)) sscanf(temp, "%d", &c->autoExposure); + if (!strcmp("AutoBlack", element)) sscanf(temp, "%d", &c->autoBlack); + if (!strcmp("AutoCrop", element)) sscanf(temp, "%d", &c->autoCrop); + if (!strcmp("CurvePath", element)) { + char *utf8 = g_filename_from_utf8(temp, -1, NULL, NULL, NULL); + if (utf8 != NULL) + g_strlcpy(c->curvePath, utf8, max_path); + g_free(utf8); + } + if (strcmp("Intent", element) == 0) { + /* Keep compatibility with numbers from ufraw-0.11 */ + if (sscanf(temp, "%d", &i) == 1) c->intent[out_profile] = i; + else c->intent[out_profile] = conf_find_name(temp, intentNames, + conf_default.intent[out_profile]); + } + if (strcmp("LightnessAdjustment", element) == 0) { + if (c->lightnessAdjustmentCount < max_adjustments) { + lightness_adjustment *a = &c->lightnessAdjustment[c->lightnessAdjustmentCount]; + sscanf(temp, "%lf %lf %lf", + &a->adjustment, &a->hue, &a->hueWidth); + c->lightnessAdjustmentCount++; + } else { + ufraw_message(UFRAW_SET_ERROR, + _("Too many lightness adjustments in the ID file, ignored\n")); + } + } + if (strcmp("GrayscaleMode", element) == 0) { + c->grayscaleMode = (sscanf(temp, "%d", &i) == 1) + ? i + : conf_find_name(temp, grayscaleModeNames, + conf_default.grayscaleMode); + } + c->grayscaleMixerDefined = 0; + if (strcmp("GrayscaleMixer", element) == 0) { + sscanf(temp, "%lf %lf %lf", &c->grayscaleMixer[0], + &c->grayscaleMixer[1], &c->grayscaleMixer[2]); + c->grayscaleMixerDefined = 1; + } + if (strcmp("DespeckleWindow", element) == 0) { + sscanf(temp, "%lf %lf %lf", &c->despeckleWindow[0], + &c->despeckleWindow[1], &c->despeckleWindow[2]); + } + if (strcmp("DespeckleDecay", element) == 0) { + sscanf(temp, "%lf %lf %lf", &c->despeckleDecay[0], + &c->despeckleDecay[1], &c->despeckleDecay[2]); + } + if (strcmp("DespecklePasses", element) == 0) { + sscanf(temp, "%lf %lf %lf", &c->despecklePasses[0], + &c->despecklePasses[1], &c->despecklePasses[2]); + } + /* OutputIntent replaces Intent starting from ufraw-0.12. */ + if (strcmp("OutputIntent", element) == 0) + c->intent[out_profile] = conf_find_name(temp, intentNames, + conf_default.intent[out_profile]); + if (strcmp("DisplayIntent", element) == 0) + c->intent[display_profile] = conf_find_name(temp, intentNames, + conf_default.intent[display_profile]); + if (!strcmp("Make", element)) g_strlcpy(c->make, temp, max_name); + if (!strcmp("Model", element)) g_strlcpy(c->model, temp, max_name); + if (!strcmp("Lens", element)) g_strlcpy(c->lensText, temp, max_name); + if (!strcmp("DarkframeFile", element)) + g_strlcpy(c->darkframeFile, temp, max_path); + if (!strcmp("ProfilePath", element)) { + char *utf8 = g_filename_from_utf8(temp, -1, NULL, NULL, NULL); + if (utf8 != NULL) + g_strlcpy(c->profilePath, utf8, max_path); + g_free(utf8); + } + if (!strcmp("Orientation", element)) sscanf(temp, "%d", &c->orientation); + if (!strcmp("Crop", element)) sscanf(temp, "%d %d %d %d", + &c->CropX1, &c->CropY1, &c->CropX2, &c->CropY2); + if (!strcmp("AspectRatio", element)) sscanf(temp, "%lf", &c->aspectRatio); + if (!strcmp("Rotation", element)) sscanf(temp, "%lf", &c->rotationAngle); + if (!strcmp("Shrink", element)) sscanf(temp, "%d", &c->shrink); + if (!strcmp("Size", element)) sscanf(temp, "%d", &c->size); + if (!strcmp("OutputType", element)) sscanf(temp, "%d", &c->type); + if (!strcmp("CreateID", element)) sscanf(temp, "%d", &c->createID); + if (!strcmp("EmbedExif", element)) sscanf(temp, "%d", &c->embedExif); + if (!strcmp("ProgressiveJPEG", element)) sscanf(temp, "%d", &c->progressiveJPEG); + if (!strcmp("Compression", element)) sscanf(temp, "%d", &c->compression); + if (!strcmp("Overwrite", element)) sscanf(temp, "%d", &c->overwrite); + if (!strcmp("LosslessCompression", element)) + sscanf(temp, "%d", &c->losslessCompress); + if (!strcmp("NoExit", element)) sscanf(temp, "%d", &c->noExit); +} + +int conf_load(conf_data *c, const char *IDFilename) +{ + char *confFilename, line[max_path], *locale; + const char *xdgconf; + FILE *in; + GMarkupParser parser = { + &conf_parse_start, &conf_parse_end, + &conf_parse_text, NULL, NULL + }; + GMarkupParseContext *context; + GError *err = NULL; + int i; + + conf_init(c); + if (IDFilename == NULL) + c->ufobject = ufraw_resources_new(); + else + c->ufobject = ufraw_image_new(); + if (IDFilename == NULL) { + confFilename = g_build_filename(uf_get_home_dir(), ".ufrawrc", NULL); + if (!g_file_test(confFilename, G_FILE_TEST_IS_REGULAR)) + if ((xdgconf = g_get_user_config_dir())) + confFilename = g_build_filename(xdgconf, "ufrawrc", NULL); + + in = g_fopen(confFilename, "r"); + /* We don't mind if confFilename does not exist. */ + if (in == NULL) { + g_free(confFilename); + return UFRAW_SUCCESS; + } + } else { + if (!g_file_test(IDFilename, G_FILE_TEST_IS_REGULAR)) { + ufraw_message(UFRAW_SET_ERROR, + _("ID file %s does not appear to be a regular file\n%s\n"), + IDFilename, strerror(errno)); + return UFRAW_ERROR; + } + if ((in = g_fopen(IDFilename, "r")) == NULL) { + ufraw_message(UFRAW_SET_ERROR, + _("Can't open ID file %s for reading\n%s\n"), + IDFilename, strerror(errno)); + return UFRAW_ERROR; + } + confFilename = g_strdup(IDFilename); + } + g_snprintf(c->inputURI, max_path, "file://%s", confFilename); + struct stat s; + fstat(fileno(in), &s); + g_snprintf(c->inputModTime, max_name, "%d", (int)s.st_mtime); + + locale = uf_set_locale_C(); + parse_data user_data; + user_data.conf = c; + if (ufobject_name(c->ufobject) == ufRawImage) + user_data.group = c->ufobject; + else + user_data.group = ufgroup_element(c->ufobject, ufRawImage); + user_data.ufrawQuark = g_quark_from_static_string("UFRaw"); + context = g_markup_parse_context_new(&parser, 0, &user_data, NULL); + line[max_path - 1] = '\0'; + if (fgets(line, max_path - 1, in) == NULL && !feof(in)) { + ufraw_message(UFRAW_ERROR, _("Error reading from file '%s'."), + confFilename); + uf_reset_locale(locale); + g_free(confFilename); + fclose(in); + return UFRAW_ERROR; + } + while (!feof(in)) { + if (!g_markup_parse_context_parse(context, line, strlen(line), &err)) { + ufraw_message(UFRAW_ERROR, _("Error parsing '%s'\n%s"), + confFilename, err->message); + g_markup_parse_context_free(context); + uf_reset_locale(locale); + g_free(confFilename); + fclose(in); + // We could if needed check explicitly for a version mismatch error + //GQuark ufrawQuark = g_quark_from_static_string("UFRaw"); + //if (g_error_matches(err, data->ufrawQuark, UFRAW_RC_VERSION)) + g_error_free(err); + return UFRAW_ERROR; + } + if (fgets(line, max_path, in) == NULL && !feof(in)) { + ufraw_message(UFRAW_ERROR, _("Error reading from file '%s'."), + confFilename); + uf_reset_locale(locale); + g_free(confFilename); + fclose(in); + return UFRAW_ERROR; + } + } + g_markup_parse_context_end_parse(context, NULL); + g_markup_parse_context_free(context); + uf_reset_locale(locale); + g_free(confFilename); + fclose(in); + + if (c->version == 3) { + c->version = conf_default.version; + /* Don't add linear part to existing profile curves (except sRGB) */ + for (i = 2; i < c->profileCount[in_profile]; i++) + c->profile[in_profile][i].linear = 0.0; + } + if (c->version == 5) { + c->version = conf_default.version; + } + // Display profile should not be read from ID files. + if (IDFilename != NULL) + c->profileIndex[display_profile] = + conf_default.profileIndex[display_profile]; + + // Support OutputType's deprecated in UFRaw-0.14 + if (c->type == ppm16_deprecated_type) { + c->type = ppm_type; + c->profile[out_profile][c->profileIndex[out_profile]].BitDepth = 16; + } + if (c->type == tiff16_deprecated_type) { + c->type = tiff_type; + c->profile[out_profile][c->profileIndex[out_profile]].BitDepth = 16; + } + if (c->type == png16_deprecated_type) { + c->type = png_type; + c->profile[out_profile][c->profileIndex[out_profile]].BitDepth = 16; + } + /* a few consistency settings */ + if (c->curveIndex >= c->curveCount) c->curveIndex = conf_default.curveIndex; + return UFRAW_SUCCESS; +} + +void conf_file_load(conf_data *conf, char *confFilename) +{ + /* Load the --conf file. version==0 means ignore conf. */ + conf->version = 0; + if (strlen(confFilename) > 0) { + int status = conf_load(conf, confFilename); + if (status == UFRAW_SUCCESS) { + strcpy(conf->inputFilename, ""); + strcpy(conf->outputFilename, ""); + strcpy(conf->outputPath, ""); + } else { + ufraw_message(UFRAW_REPORT, NULL); + conf->version = 0; + } + } +} + +int conf_save(conf_data *c, char *IDFilename, char **confBuffer) +{ + char *buf = NULL; + int i, j; + + char *locale = uf_set_locale_C(); + + buf = uf_markup_buf(buf, "\n"); + buf = uf_markup_buf(buf, "\n", c->version); + if (strlen(c->inputFilename) > 0 && IDFilename != NULL) { + char *utf8 = g_filename_display_name(c->inputFilename); + buf = uf_markup_buf(buf, "%s\n", utf8); + g_free(utf8); + } + if (strlen(c->outputFilename) > 0 && IDFilename != NULL) { + char *utf8 = g_filename_display_name(c->outputFilename); + buf = uf_markup_buf(buf, "%s\n", utf8); + g_free(utf8); + } + if (strlen(c->outputPath) > 0) { + char *utf8 = g_filename_display_name(c->outputPath); + buf = uf_markup_buf(buf, "%s\n", utf8); + g_free(utf8); + } + + /* GUI settings are only saved to .ufrawrc */ + if (IDFilename == NULL) { + if (c->saveConfiguration != conf_default.saveConfiguration) + buf = uf_markup_buf(buf, + "%d\n", + c->saveConfiguration); + if (c->expander[raw_expander] != conf_default.expander[raw_expander]) + buf = uf_markup_buf(buf, "%d\n", + c->expander[raw_expander]); + if (c->expander[live_expander] != conf_default.expander[live_expander]) + buf = uf_markup_buf(buf, "%d\n", + c->expander[live_expander]); + if (c->histogram != conf_default.histogram) + buf = uf_markup_buf(buf, + "%d\n", c->histogram); + if (c->liveHistogramScale != conf_default.liveHistogramScale) + buf = uf_markup_buf(buf, + "%d\n", + c->liveHistogramScale); + if (c->rawHistogramScale != conf_default.rawHistogramScale) + buf = uf_markup_buf(buf, + "%d\n", + c->rawHistogramScale); + if (c->LockAspect != conf_default.LockAspect) + buf = uf_markup_buf(buf, + "%d\n", c->LockAspect); + if (c->overExp != conf_default.overExp) + buf = uf_markup_buf(buf, + "%d\n", c->overExp); + if (c->underExp != conf_default.underExp) + buf = uf_markup_buf(buf, + "%d\n", c->underExp); + if (c->blinkOverUnder != conf_default.blinkOverUnder) + buf = uf_markup_buf(buf, + "%d\n", c->blinkOverUnder); + if (c->drawLines != conf_default.drawLines) + buf = uf_markup_buf(buf, + "%d\n", c->drawLines); + if (c->RememberOutputPath != conf_default.RememberOutputPath) + buf = uf_markup_buf(buf, + "%d\n", + c->RememberOutputPath); + if (c->WindowMaximized != conf_default.WindowMaximized) + buf = uf_markup_buf(buf, + "%d\n", + c->WindowMaximized); + if (strcmp(c->remoteGimpCommand, conf_default.remoteGimpCommand) != 0) + buf = uf_markup_buf(buf, + "%s\n", + c->remoteGimpCommand); + if (strlen(c->curvePath) > 0) { + char *utf8 = g_filename_display_name(c->curvePath); + buf = uf_markup_buf(buf, "%s\n", utf8); + g_free(utf8); + } + if (strlen(c->profilePath) > 0) { + char *utf8 = g_filename_display_name(c->profilePath); + buf = uf_markup_buf(buf, "%s\n", utf8); + g_free(utf8); + } + } + if (c->interpolation != conf_default.interpolation) + buf = uf_markup_buf(buf, "%s\n", + conf_get_name(interpolationNames, c->interpolation)); + // 'smoothing' is boolean at the moment, but we keep the option + // to upgrade it to the number of color smoothing passes. + if (c->smoothing != 0) { + if (c->interpolation == ahd_interpolation) + c->smoothing = 3; + else + c->smoothing = 1; + } + if (c->smoothing != conf_default.smoothing) + buf = uf_markup_buf(buf, "%d\n", + c->smoothing); + UFObject *image; + if (ufobject_name(c->ufobject) == ufRawImage) + image = c->ufobject; + else + image = ufgroup_element(c->ufobject, ufRawImage); + { + char *xml = ufobject_xml(image, ""); + char *newbuf = g_strconcat(buf, xml, NULL); + g_free(xml); + g_free(buf); + buf = newbuf; + } + if (c->threshold != conf_default.threshold) + buf = uf_markup_buf(buf, + "%d\n", + (int)floor(c->threshold)); + if (c->hotpixel != conf_default.hotpixel) + buf = uf_markup_buf(buf, + "%f\n", + c->hotpixel); +#ifdef UFRAW_CONTRAST + if (c->contrast != conf_default.contrast) + buf = uf_markup_buf(buf, + "%f\n", c->contrast); +#endif + if (c->exposure != conf_default.exposure) + buf = uf_markup_buf(buf, "%lf\n", c->exposure); + if (c->ExposureNorm != conf_default.ExposureNorm) + buf = uf_markup_buf(buf, "%d\n", + c->ExposureNorm); + if (c->restoreDetails != conf_default.restoreDetails) + buf = uf_markup_buf(buf, "%s\n", + conf_get_name(restoreDetailsNames, c->restoreDetails)); + if (c->clipHighlights != conf_default.clipHighlights) + buf = uf_markup_buf(buf, "%s\n", + conf_get_name(clipHighlightsNames, c->clipHighlights)); + if (c->autoExposure != conf_default.autoExposure) + buf = uf_markup_buf(buf, + "%d\n", c->autoExposure); + if (c->autoBlack != conf_default.autoBlack) + buf = uf_markup_buf(buf, "%d\n", c->autoBlack); + if (c->autoCrop != conf_default.autoCrop) + buf = uf_markup_buf(buf, "%d\n", c->autoCrop); + if (c->saturation != conf_default.saturation) + buf = uf_markup_buf(buf, + "%lf\n", c->saturation); + for (i = 0; i < max_adjustments; ++i) { + lightness_adjustment *a = &c->lightnessAdjustment[i]; + if (fabs(a->adjustment - conf_default.lightnessAdjustment[i].adjustment) > 0.01) { + buf = uf_markup_buf(buf, "%f %f %f\n", + a->adjustment, a->hue, a->hueWidth); + } + } + if (c->grayscaleMode != grayscale_invalid && + c->grayscaleMode != conf_default.grayscaleMode) + buf = uf_markup_buf(buf, + "%s\n", + grayscaleModeNames[c->grayscaleMode]); + if (c->grayscaleMode == grayscale_mixer) { + buf = uf_markup_buf(buf, + "%f %f %f\n", + c->grayscaleMixer[0], + c->grayscaleMixer[1], + c->grayscaleMixer[2]); + } + if (c->despeckleWindow[0] != conf_default.despeckleWindow[0] || + c->despeckleWindow[1] != conf_default.despeckleWindow[1] || + c->despeckleWindow[2] != conf_default.despeckleWindow[2]) { + buf = uf_markup_buf(buf, "%f %f %f\n", + c->despeckleWindow[0], c->despeckleWindow[1], c->despeckleWindow[2]); + } + if (c->despeckleDecay[0] != conf_default.despeckleDecay[0] || + c->despeckleDecay[1] != conf_default.despeckleDecay[1] || + c->despeckleDecay[2] != conf_default.despeckleDecay[2]) { + buf = uf_markup_buf(buf, "%f %f %f\n", + c->despeckleDecay[0], c->despeckleDecay[1], c->despeckleDecay[2]); + } + if (c->despecklePasses[0] != conf_default.despecklePasses[0] || + c->despecklePasses[1] != conf_default.despecklePasses[1] || + c->despecklePasses[2] != conf_default.despecklePasses[2]) { + buf = uf_markup_buf(buf, "%f %f %f\n", + c->despecklePasses[0], c->despecklePasses[1], c->despecklePasses[2]); + } + if (c->size != conf_default.size) + buf = uf_markup_buf(buf, "%d\n", c->size); + if (c->shrink != conf_default.shrink) + buf = uf_markup_buf(buf, "%d\n", c->shrink); + if (c->type != conf_default.type) + buf = uf_markup_buf(buf, "%d\n", c->type); + if (c->createID != conf_default.createID) + buf = uf_markup_buf(buf, "%d\n", c->createID); + if (c->embedExif != conf_default.embedExif) + buf = uf_markup_buf(buf, "%d\n", c->embedExif); + if (c->progressiveJPEG != conf_default.progressiveJPEG) + buf = uf_markup_buf(buf, "%d\n", c->progressiveJPEG); + if (c->compression != conf_default.compression) + buf = uf_markup_buf(buf, + "%d\n", c->compression); + if (c->overwrite != conf_default.overwrite) + buf = uf_markup_buf(buf, "%d\n", c->overwrite); + if (c->losslessCompress != conf_default.losslessCompress) + buf = uf_markup_buf(buf, + "%d\n", + c->losslessCompress); + if (c->noExit != conf_default.noExit) + buf = uf_markup_buf(buf, "%d\n", c->noExit); + for (i = 0; i < c->BaseCurveCount; i++) { + char *curveBuf = curve_buffer(&c->BaseCurve[i]); + /* Write curve if it is non-default and we are not writing to .ufraw */ + /* But ALWAYS write the current curve */ + if (c->BaseCurveIndex == i || (curveBuf != NULL && IDFilename == NULL)) { + if (curveBuf == NULL) curveBuf = g_strdup(""); + char *current = i == c->BaseCurveIndex ? "yes" : "no"; + switch (i) { + case manual_curve: + buf = uf_markup_buf(buf, + "\n", current); + buf = uf_markup_buf(buf, curveBuf); + buf = uf_markup_buf(buf, "\n"); + break; + case linear_curve: + buf = uf_markup_buf(buf, + "\n", current); + buf = uf_markup_buf(buf, curveBuf); + buf = uf_markup_buf(buf, "\n"); + break; + case custom_curve: + buf = uf_markup_buf(buf, + "\n", current); + buf = uf_markup_buf(buf, curveBuf); + buf = uf_markup_buf(buf, "\n"); + break; + case camera_curve: + buf = uf_markup_buf(buf, + "\n", current); + buf = uf_markup_buf(buf, curveBuf); + buf = uf_markup_buf(buf, "\n"); + break; + default: + buf = uf_markup_buf(buf, + "%s\n", current, + c->BaseCurve[i].name); + buf = uf_markup_buf(buf, curveBuf); + buf = uf_markup_buf(buf, "\n"); + } + } + g_free(curveBuf); + } + for (i = 0; i < c->curveCount; i++) { + char *curveBuf = curve_buffer(&c->curve[i]); + /* Write curve if it is non-default and we are not writing to .ufraw */ + /* But ALWAYS write the current curve */ + if (c->curveIndex == i || (curveBuf != NULL && IDFilename == NULL)) { + if (curveBuf == NULL) curveBuf = g_strdup(""); + char *current = i == c->curveIndex ? "yes" : "no"; + switch (i) { + case manual_curve: + buf = uf_markup_buf(buf, + "\n", current); + buf = uf_markup_buf(buf, curveBuf); + buf = uf_markup_buf(buf, "\n"); + break; + case linear_curve: + buf = uf_markup_buf(buf, + "\n", current); + buf = uf_markup_buf(buf, curveBuf); + buf = uf_markup_buf(buf, "\n"); + break; + default: + buf = uf_markup_buf(buf, + "%s\n", current, + c->curve[i].name); + buf = uf_markup_buf(buf, curveBuf); + buf = uf_markup_buf(buf, "\n"); + } + } + g_free(curveBuf); + } + for (j = 0; j < profile_types; j++) { + // Display profile does not belong in ID files. + if (IDFilename != NULL && j == display_profile) + continue; + char *type = j == in_profile ? "InputProfile" : + j == out_profile ? "OutputProfile" : + j == display_profile ? "DisplayProfile" : "Error"; + + for (i = 0; i < c->profileCount[j]; i++) { + + gboolean current = i == c->profileIndex[j]; + /* In ID files we only save the current profiles */ + if (IDFilename != NULL && !current) + continue; + /* For the default profiles, if it is not the current profile + * and nothing change, do not write it. */ + if (i < conf_default.profileCount[j] && !current && + (c->profile[j][i].gamma == conf_default.profile[j][i].gamma && + c->profile[j][i].linear == conf_default.profile[j][i].linear && + c->profile[j][i].BitDepth == + conf_default.profile[j][i].BitDepth)) + continue; + char *profile = ""; + if (j == in_profile && i == 0) profile = "No"; + if (j == in_profile && i == 1) profile = "Matrix"; + if (j == out_profile && i == 0) profile = "sRGB"; + if (j == out_profile && i == 1) profile = "sRGBEmbedded"; + if (j == display_profile && i == 0) profile = "System"; + if (j == display_profile && i == 1) profile = "sRGB"; + buf = uf_markup_buf(buf, "<%s%s Current='%s'>%s\n", + profile, type, current ? "yes" : "no", c->profile[j][i].name); + if (i >= conf_default.profileCount[j]) { + char *utf8 = g_filename_display_name(c->profile[j][i].file); + buf = uf_markup_buf(buf, "\t%s\n", utf8); + g_free(utf8); + buf = uf_markup_buf(buf, "\t%s\n", + c->profile[j][i].productName); + } + if (c->profile[j][i].gamma != conf_default.profile[j][1].gamma) + buf = uf_markup_buf(buf, + "\t%lf\n", c->profile[j][i].gamma); + if (c->profile[j][i].linear != conf_default.profile[j][1].linear) + buf = uf_markup_buf(buf, "\t%lf\n", + c->profile[j][i].linear); + if (c->profile[j][i].BitDepth != conf_default.profile[j][1].BitDepth) + buf = uf_markup_buf(buf, "\t%d\n", + c->profile[j][i].BitDepth); + buf = uf_markup_buf(buf, "\n", profile, type); + } + } + if (c->intent[out_profile] != conf_default.intent[out_profile]) + buf = uf_markup_buf(buf, "%s\n", + conf_get_name(intentNames, c->intent[out_profile])); + if (c->intent[display_profile] != conf_default.intent[display_profile]) + buf = uf_markup_buf(buf, "%s\n", + conf_get_name(intentNames, c->intent[display_profile])); + /* We always write the Make and Mode information + * to know if the WB setting is relevant */ + buf = uf_markup_buf(buf, "%s\n", c->make); + buf = uf_markup_buf(buf, "%s\n", c->model); + if (IDFilename != NULL) { + if (strcmp(c->darkframeFile, conf_default.darkframeFile) != 0) + buf = uf_markup_buf(buf, + "%s\n", c->darkframeFile); + buf = uf_markup_buf(buf, "%s\n", + c->timestampText); + buf = uf_markup_buf(buf, "%d\n", + c->orientation); + buf = uf_markup_buf(buf, "%s\n", c->isoText); + buf = uf_markup_buf(buf, "%s\n", c->shutterText); + buf = uf_markup_buf(buf, "%s\n", c->apertureText); + buf = uf_markup_buf(buf, "%s\n", + c->focalLenText); + buf = uf_markup_buf(buf, "%s\n", + c->focalLen35Text); + if (strlen(c->lensText) > 0) + buf = uf_markup_buf(buf, "%s\n", c->lensText); + buf = uf_markup_buf(buf, "%s\n", + c->exifSource); + buf = uf_markup_buf(buf, "%d %d %d %d\n", + c->CropX1, c->CropY1, c->CropX2, c->CropY2); + if (c->aspectRatio != 0.0) + buf = uf_markup_buf(buf, "%lf\n", c->aspectRatio); + buf = uf_markup_buf(buf, "%lf\n", c->rotationAngle); + char *log = ufraw_message(UFRAW_GET_LOG, NULL); + if (log != NULL) { + char *utf8 = g_filename_display_name(log); + buf = uf_markup_buf(buf, "\n%s\n", utf8); + g_free(utf8); + } + /* As long as darkframe is not in the GUI we save it only to ID files.*/ + } + buf = uf_markup_buf(buf, "\n"); + uf_reset_locale(locale); + if (confBuffer == NULL) { + char *confFilename; + const char *xdgconf; + FILE *out; + if (IDFilename == NULL) { + confFilename = g_build_filename(uf_get_home_dir(), ".ufrawrc", NULL); + if (!g_file_test(confFilename, G_FILE_TEST_IS_REGULAR)) + if ((xdgconf = g_get_user_config_dir())) + confFilename = g_build_filename(xdgconf, "ufrawrc", NULL); + } else + confFilename = g_strdup(IDFilename); + if ((out = g_fopen(confFilename, "w")) == NULL) { + ufraw_message(UFRAW_ERROR, + _("Can't open file %s for writing\n%s\n"), + confFilename, strerror(errno)); + g_free(confFilename); + g_free(buf); + return UFRAW_ERROR; + } + fputs(buf, out); + fclose(out); + g_free(confFilename); + g_free(buf); + } else { + *confBuffer = buf; + } + return UFRAW_SUCCESS; +} + +/* Copy the image manipulation options from *src to *dst */ +void conf_copy_image(conf_data *dst, const conf_data *src) +{ + int i, j; + + UFObject *dstImage; + if (ufobject_name(dst->ufobject) == ufRawImage) + dstImage = dst->ufobject; + else + dstImage = ufgroup_element(dst->ufobject, ufRawImage); + ufobject_copy(dstImage, src->ufobject); + + dst->interpolation = src->interpolation; + dst->smoothing = src->smoothing; + /* make and model are 'part of' ChanMul, + * since on different make and model ChanMul are meaningless */ + g_strlcpy(dst->make, src->make, max_name); + g_strlcpy(dst->model, src->model, max_name); + dst->threshold = src->threshold; + dst->exposure = src->exposure; + dst->hotpixel = src->hotpixel; +#ifdef UFRAW_CONTRAST + dst->contrast = src->contrast; +#endif + dst->ExposureNorm = src->ExposureNorm; + dst->saturation = src->saturation; + dst->black = src->black; + dst->autoExposure = src->autoExposure; + dst->autoBlack = src->autoBlack; + dst->autoCrop = src->autoCrop; + if (src->autoCrop == enabled_state) + dst->fullCrop = disabled_state; + dst->restoreDetails = src->restoreDetails; + dst->clipHighlights = src->clipHighlights; + memcpy(dst->lightnessAdjustment, src->lightnessAdjustment, + sizeof dst->lightnessAdjustment); + dst->lightnessAdjustmentCount = src->lightnessAdjustmentCount; + dst->grayscaleMode = src->grayscaleMode; + dst->grayscaleMixerDefined = src->grayscaleMixerDefined; + memcpy(dst->grayscaleMixer, src->grayscaleMixer, + sizeof dst->grayscaleMixer); + memcpy(dst->despeckleWindow, src->despeckleWindow, sizeof(dst->despeckleWindow)); + memcpy(dst->despeckleDecay, src->despeckleDecay, sizeof(dst->despeckleDecay)); + memcpy(dst->despecklePasses, src->despecklePasses, sizeof(dst->despecklePasses)); + g_strlcpy(dst->darkframeFile, src->darkframeFile, max_path); + /* We only copy the current BaseCurve */ + if (src->BaseCurveIndex <= camera_curve) { + dst->BaseCurveIndex = src->BaseCurveIndex; + if (src->BaseCurveIndex == manual_curve) + dst->BaseCurve[manual_curve] = src->BaseCurve[manual_curve]; + } else { + /* For non-standard curves we look for a curve with the same name + * and override it, assuming it is the same curve. */ + for (i = camera_curve + 1; i < dst->BaseCurveCount; i++) { + if (!strcmp(dst->BaseCurve[i].name, + src->BaseCurve[src->BaseCurveIndex].name)) { + dst->BaseCurve[i] = src->BaseCurve[src->BaseCurveIndex]; + dst->BaseCurveIndex = i; + break; + } + } + /* If the curve was not found we add it. */ + if (i == dst->BaseCurveCount) { + /* If there is no more room we throw away the last curve. */ + if (dst->BaseCurveCount == max_curves) dst->BaseCurveCount--; + dst->BaseCurve[dst->BaseCurveCount] = + src->BaseCurve[src->BaseCurveIndex]; + dst->BaseCurveIndex = dst->BaseCurveCount; + dst->BaseCurveCount++; + } + } + /* We only copy the current curve */ + if (src->curveIndex <= linear_curve) { + dst->curveIndex = src->curveIndex; + if (src->curveIndex == manual_curve) + dst->curve[manual_curve] = src->curve[manual_curve]; + } else { + /* For non-standard curves we look for a curve with the same name + * and override it, assuming it is the same curve. */ + for (i = camera_curve + 1; i < dst->curveCount; i++) { + if (!strcmp(dst->curve[i].name, src->curve[src->curveIndex].name)) { + dst->curve[i] = src->curve[src->curveIndex]; + dst->curveIndex = i; + break; + } + } + /* If the curve was not found we add it. */ + if (i == dst->curveCount) { + /* If there is no more room we throw away the last curve. */ + if (dst->curveCount == max_curves) dst->curveCount--; + dst->curve[dst->curveCount] = src->curve[src->curveIndex]; + dst->curveIndex = dst->curveCount; + dst->curveCount++; + } + } + /* We only copy the current input/output profile */ + for (j = 0; j < profile_types; j++) { + // Ignore the display profile + if (j == display_profile) + continue; + if (src->profileIndex[j] == 0) { + dst->profileIndex[j] = src->profileIndex[j]; + dst->profile[j][0] = src->profile[j][0]; + } else { + /* For non-standard profiles we look for a profile with the same + * name and override it, assuming it is the same profile. */ + for (i = 1; i < dst->profileCount[j]; i++) { + if (!strcmp(dst->profile[j][i].name, + src->profile[j][src->profileIndex[j]].name)) { + dst->profile[j][i] = src->profile[j][src->profileIndex[j]]; + dst->profileIndex[j] = i; + break; + } + } + /* If the profile was not found we add it. */ + if (i == dst->profileCount[j]) { + /* If there is no more room we throw away the last profile. */ + if (dst->profileCount[j] == max_profiles) dst->profileCount[j]--; + dst->profile[j][dst->profileCount[j]] = + src->profile[j][src->profileIndex[j]]; + dst->profileIndex[j] = dst->profileCount[j]; + dst->profileCount[j]++; + } + } + } + dst->intent[out_profile] = src->intent[out_profile]; + dst->intent[display_profile] = src->intent[display_profile]; +} + +/* Copy the transformation information from *src to *dst. */ +void conf_copy_transform(conf_data *dst, const conf_data *src) +{ + dst->orientation = src->orientation; + dst->CropX1 = src->CropX1; + dst->CropY1 = src->CropY1; + dst->CropX2 = src->CropX2; + dst->CropY2 = src->CropY2; + dst->aspectRatio = src->aspectRatio; + dst->rotationAngle = src->rotationAngle; + + if (src->CropX1 != -1 || src->CropX2 != -1 || + src->CropY1 != -1 || src->CropY2 != -1) { + dst->fullCrop = disabled_state; + dst->autoCrop = disabled_state; + } +} + +/* Copy the 'save options' from *src to *dst */ +void conf_copy_save(conf_data *dst, const conf_data *src) +{ + /* Filenames get special treatment and are not simply copied + g_strlcpy(dst->inputFilename, src->inputFilename, max_path); + g_strlcpy(dst->outputFilename, src->outputFilename, max_path); + g_strlcpy(dst->outputPath, src->outputPath, max_path); + */ + g_strlcpy(dst->inputURI, src->inputURI, max_path); + g_strlcpy(dst->inputModTime, src->inputModTime, max_name); + dst->type = src->type; + dst->compression = src->compression; + dst->createID = src->createID; + dst->embedExif = src->embedExif; + dst->shrink = src->shrink; + dst->size = src->size; + dst->overwrite = src->overwrite; + dst->RememberOutputPath = src->RememberOutputPath; + dst->progressiveJPEG = src->progressiveJPEG; + dst->losslessCompress = src->losslessCompress; + dst->embeddedImage = src->embeddedImage; + dst->noExit = src->noExit; +} + +int conf_set_cmd(conf_data *conf, const conf_data *cmd) +{ + UFObject *cmdImage = ufgroup_element(cmd->ufobject, ufRawImage); + ufobject_copy(conf->ufobject, cmdImage); + + if (cmd->overwrite != -1) conf->overwrite = cmd->overwrite; + if (cmd->WindowMaximized != -1) conf->WindowMaximized = cmd->WindowMaximized; + if (cmd->restoreDetails != -1) + conf->restoreDetails = cmd->restoreDetails; + if (cmd->clipHighlights != -1) + conf->clipHighlights = cmd->clipHighlights; + if (cmd->losslessCompress != -1) + conf->losslessCompress = cmd->losslessCompress; + if (cmd->embedExif != -1) conf->embedExif = cmd->embedExif; + if (cmd->embeddedImage != -1) conf->embeddedImage = cmd->embeddedImage; + if (cmd->noExit != -1) conf->noExit = cmd->noExit; + if (cmd->rotate != -1) conf->rotate = cmd->rotate; + if (cmd->rotationAngle != NULLF) conf->rotationAngle = cmd->rotationAngle; + if (cmd->autoCrop != -1) + if ((conf->autoCrop = cmd->autoCrop) == enabled_state) + conf->fullCrop = disabled_state; + if (cmd->CropX1 != -1 || cmd->CropX2 != -1 || + cmd->CropY1 != -1 || cmd->CropY2 != -1) { + conf->fullCrop = disabled_state; + conf->autoCrop = disabled_state; + } + if (cmd->CropX1 != -1) conf->CropX1 = cmd->CropX1; + if (cmd->CropY1 != -1) conf->CropY1 = cmd->CropY1; + if (cmd->CropX2 != -1) conf->CropX2 = cmd->CropX2; + if (cmd->CropY2 != -1) conf->CropY2 = cmd->CropY2; + if (cmd->aspectRatio != 0.0) conf->aspectRatio = cmd->aspectRatio; + if (cmd->silent != -1) conf->silent = cmd->silent; + if (cmd->compression != NULLF) conf->compression = cmd->compression; + if (cmd->autoExposure) { + conf->autoExposure = cmd->autoExposure; + } + if (cmd->threshold != NULLF) conf->threshold = cmd->threshold; + if (cmd->hotpixel != NULLF) conf->hotpixel = cmd->hotpixel; +#ifdef UFRAW_CONTRAST + if (cmd->contrast != NULLF) conf->contrast = cmd->contrast; +#endif + if (cmd->exposure != NULLF) { + conf->exposure = cmd->exposure; + conf->autoExposure = disabled_state; + } + if (cmd->profile[0][0].gamma != NULLF) + conf->profile[0][conf->profileIndex[0]].gamma = + cmd->profile[0][0].gamma; + if (cmd->profile[0][0].linear != NULLF) + conf->profile[0][conf->profileIndex[0]].linear = + cmd->profile[0][0].linear; + if (cmd->profile[1][0].BitDepth != -1) + conf->profile[1][conf->profileIndex[1]].BitDepth = + cmd->profile[1][0].BitDepth; + if (cmd->saturation != NULLF) + conf->saturation = cmd->saturation; + if (cmd->grayscaleMode != -1) { + conf->grayscaleMode = cmd->grayscaleMode; + if (cmd->grayscaleMode == grayscale_mixer && + cmd->grayscaleMixerDefined == 1) { + conf->grayscaleMixerDefined = 1; + conf->grayscaleMixer[0] = cmd->grayscaleMixer[0]; + conf->grayscaleMixer[1] = cmd->grayscaleMixer[1]; + conf->grayscaleMixer[2] = cmd->grayscaleMixer[2]; + } + } + if (cmd->BaseCurveIndex >= 0) conf->BaseCurveIndex = cmd->BaseCurveIndex; + if (cmd->curveIndex >= 0) conf->curveIndex = cmd->curveIndex; + if (cmd->autoBlack) { + conf->autoBlack = cmd->autoBlack; + } + if (cmd->black != NULLF) { + CurveDataSetPoint(&conf->curve[conf->curveIndex], + 0, cmd->black, 0); + conf->autoBlack = disabled_state; + } + if (cmd->smoothing != -1) conf->smoothing = cmd->smoothing; + if (cmd->interpolation >= 0) conf->interpolation = cmd->interpolation; + if (cmd->interpolation == obsolete_eahd_interpolation) { + conf->interpolation = ahd_interpolation; + conf->smoothing = 3; + } + if (cmd->shrink != NULLF) { + conf->shrink = cmd->shrink; + conf->size = 0; + if (conf->interpolation == half_interpolation) + conf->interpolation = ahd_interpolation; + } + if (cmd->size != NULLF) { + conf->size = cmd->size; + conf->shrink = 1; + if (conf->interpolation == half_interpolation) + conf->interpolation = ahd_interpolation; + } + if (cmd->type >= 0) conf->type = cmd->type; + if (cmd->createID >= 0) conf->createID = cmd->createID; + if (strlen(cmd->darkframeFile) > 0) + g_strlcpy(conf->darkframeFile, cmd->darkframeFile, max_path); + if (cmd->darkframe != NULL) + conf->darkframe = cmd->darkframe; + if (strlen(cmd->outputPath) > 0) + g_strlcpy(conf->outputPath, cmd->outputPath, max_path); + if (strlen(cmd->outputFilename) > 0) { + if (conf->createID != no_id && !strcmp(cmd->outputFilename, "-") && + !cmd->embeddedImage) { + ufraw_message(UFRAW_ERROR, _("cannot --create-id with stdout")); + return UFRAW_ERROR; + } + g_strlcpy(conf->outputFilename, cmd->outputFilename, max_path); + } + return UFRAW_SUCCESS; +} + +/* Following are global strings and functions used by both 'ufraw' and + * 'ufraw-batch'. ufraw_conf.c is a good home for them since they are + * closely related to the other configuration functions. */ +char *helpText[] = { + N_("UFRaw "), VERSION, N_(" - Unidentified Flying Raw converter for digital camera images.\n"), + "\n", + N_("Usage: ufraw [ options ... ] [ raw-image-files ... ]\n"), + N_(" ufraw-batch [ options ... ] [ raw-image-files ... ]\n"), + N_(" ufraw [ options ... ] [ default-directory ]\n"), + "\n", + N_("By default 'ufraw' displays a preview window for each raw image allowing\n" + "the user to tweak the image parameters before saving. If no raw images\n" + "are given at the command line, UFRaw will display a file chooser dialog.\n" + "To process the images with no questions asked (and no preview) use\n" + "'ufraw-batch'.\n"), + "\n", + N_("The input files can be either raw images or ufraw's ID files. ID files\n" + "contain a raw image filename and the parameters for handling the image.\n" + "One can also use an ID file with the option:\n"), + "\n", + N_("--conf=ID-file Apply the parameters in ID-file to other raw images.\n"), + "\n", + N_("The rest of the options are separated into two groups.\n"), + N_("The options which are related to the image manipulation are:\n"), + "\n", + N_("--wb=camera|auto White balance setting.\n"), + N_("--temperature=TEMP Color temperature in Kelvin.\n"), + N_("--green=GREEN Green color normalization.\n"), + N_("--base-curve=manual|linear|camera|custom|CURVE\n" + " Type of base tone curve to use. CURVE can be any\n" + " curve that was previously loaded in the GUI.\n" + " (default camera if such exists, linear otherwise).\n"), + N_("--base-curve-file=file\n" + " Use base tone curve included in specified file.\n" + " Overrides --base-curve option.\n"), + N_("--curve=manual|linear|CURVE\n" + " Type of luminosity curve to use. CURVE can be any\n" + " curve that was previously loaded in the GUI.\n" + " (default linear).\n"), + N_("--curve-file=file Use luminosity curve included in specified file.\n" + " Overrides --curve option.\n"), + N_("--restore=clip|lch|hsv\n" + " Restore details for negative EV.\n" + " 'clip' restores nothing - safe from artifacts.\n" + " 'lch' restores in LCH space - giving soft details.\n" + " 'hsv' restores in HSV space - giving sharp details.\n" + " (default lch).\n"), + N_("--clip=digital|film Clip highlights for positive EV.\n" + " 'digital' linear digital sensor response.\n" + " 'film' emulate soft film response. (default digital).\n"), + N_("--gamma=GAMMA Gamma adjustment of the base curve (default 0.45).\n"), + N_("--linearity=LINEARITY Linearity of the base curve (default 0.10).\n"), +#ifdef UFRAW_CONTRAST + N_("--contrast=CONT Contrast adjustment (default 1.0).\n"), +#endif + N_("--saturation=SAT Saturation adjustment (default 1.0, 0 for B&W output).\n"), + N_("--wavelet-denoising-threshold=THRESHOLD\n" + " Wavelet denoising threshold (default 0.0).\n"), + N_("--hotpixel-sensitivity=VALUE\n" + " Sensitivity for detecting and shaving hot pixels (default 0.0).\n"), + N_("--exposure=auto|EXPOSURE\n" + " Auto exposure or exposure correction in EV (default 0).\n"), + N_("--black-point=auto|BLACK\n" + " Auto black-point or black-point value (default 0).\n"), + N_("--interpolation=ahd|vng|four-color|ppg|bilinear\n" + " Interpolation algorithm to use (default ahd).\n"), + N_("--color-smoothing Apply color smoothing.\n"), + N_("--grayscale=none|lightness|luminance|value|mixer\n" + " Grayscale conversion algorithm to use (default none).\n"), + N_("--grayscale-mixer=RED,GREEN,BLUE\n" + " Grayscale mixer values to use (default 1,1,1).\n"), + "\n", + N_("The options which are related to the final output are:\n"), + "\n", + N_("--shrink=FACTOR Shrink the image by FACTOR (default 1).\n"), + N_("--size=SIZE Downsize max(height,width) to SIZE.\n"), + N_("--out-type=ppm|tiff|tif|png|jpeg|jpg|fits\n" + " Output file format (default ppm).\n"), + N_("--out-depth=8|16 Output bit depth per channel (default 8).\n"), + N_("--create-id=no|also|only\n" + " Create no|also|only ID file (default no).\n"), + N_("--compression=VALUE JPEG compression (0-100, default 85).\n"), + N_("--[no]exif Embed EXIF in output (default embed EXIF).\n"), + N_("--[no]zip Enable [disable] TIFF zip compression (default nozip).\n"), + N_("--embedded-image Extract the preview image embedded in the raw file\n" + " instead of converting the raw image. This option\n" + " is only valid with 'ufraw-batch'.\n"), + N_("--rotate=camera|ANGLE|no\n" + " Rotate image to camera's setting, by ANGLE degrees\n" + " clockwise, or do not rotate the image (default camera).\n"), + N_("--crop-(left|right|top|bottom)=PIXELS\n" + " Crop the output to the given pixel range, relative to the\n" + " raw image after rotation but before any scaling.\n"), + N_("--auto-crop Crop the output automatically.\n"), + N_("--aspect-ratio X:Y Set crop area aspect ratio.\n"), +#ifdef HAVE_LENSFUN + N_("--lensfun=none|auto Do not apply lens correction or try to apply\n" + " correction by auto-detecting the lens (default auto).\n"), +#endif + N_("--out-path=PATH PATH for output file (default use input file's path).\n"), + N_("--output=FILE Output file name, use '-' to output to stdout.\n"), + N_("--darkframe=FILE Use FILE for raw darkframe subtraction.\n"), + N_("--overwrite Overwrite existing files without asking (default no).\n"), + N_("--maximize-window Force window to be maximized.\n"), + N_("--silent Do not display any messages during conversion. This\n" + " option is only valid with 'ufraw-batch'.\n"), + "\n", + N_("UFRaw first reads the setting from the resource file $HOME/.ufrawrc.\n" + "Then, if an ID file is specified, its setting are read. Next, the setting from\n" + "the --conf option are taken, ignoring input/output filenames in the ID file.\n" + "Lastly, the options from the command line are set. In batch mode, the second\n" + "group of options is NOT read from the resource file.\n"), + "\n", + N_("Last, but not least, --version displays the version number and compilation\n" + "options for ufraw and --help displays this help message and exits.\n"), + "END" +}; + +char versionText[] = + "%s " VERSION "\n" + + "EXIV2 " +#ifdef HAVE_EXIV2 + "enabled.\n" +#else + "disabled.\n" +#endif + + "JPEG " +#ifdef HAVE_LIBJPEG + "enabled.\n" +#else + "disabled.\n" +#endif + + "JPEG2000 (libjasper) " +#ifdef HAVE_LIBJASPER + "enabled.\n" +#else + "disabled.\n" +#endif + + "TIFF " +#ifdef HAVE_LIBTIFF + "enabled.\n" +#else + "disabled.\n" +#endif + + "PNG " +#ifdef HAVE_LIBPNG + "enabled.\n" +#else + "disabled.\n" +#endif + + "FITS " +#ifdef HAVE_LIBCFITSIO + "enabled.\n" +#else + "disabled.\n" +#endif + + "ZIP " +#ifdef HAVE_LIBZ + "enabled.\n" +#else + "disabled.\n" +#endif + + "BZIP2 " +#ifdef HAVE_LIBBZ2 + "enabled.\n" +#else + "disabled.\n" +#endif + + "LENSFUN " +#ifdef HAVE_LENSFUN + "enabled.\n" +#else + "disabled.\n" +#endif + ""; + +/* ufraw_process_args returns values: + * -1 : an error occurred. + * 0 : --help or --version text were printed. + * optint : the index in argv of the first argv-element that is not an option. + */ +int ufraw_process_args(int *argc, char ***argv, conf_data *cmd, conf_data *rc) +{ + cmd->ufobject = ufraw_command_line_new(); + UFObject *cmdImage = ufgroup_element(cmd->ufobject, ufRawImage); + int index = 0, c, i; + char *base, *locale; + char *baseCurveName = NULL, *baseCurveFile = NULL, + *curveName = NULL, *curveFile = NULL, *outTypeName = NULL, *rotateName = NULL, + *createIDName = NULL, *outPath = NULL, *output = NULL, *conf = NULL, + *interpolationName = NULL, *darkframeFile = NULL, + *restoreName = NULL, *clipName = NULL, *grayscaleName = NULL, + *grayscaleMixer = NULL; + static const struct option options[] = { + { "wb", 1, 0, 'w'}, + { "temperature", 1, 0, 't'}, + { "green", 1, 0, 'g'}, +#ifdef HAVE_LENSFUN + { "lensfun", 1, 0, 'A'}, +#endif + { "base-curve", 1, 0, 'B'}, + { "base-curve-file", 1, 0, 'S'}, + { "curve", 1, 0, 'c'}, + { "curve-file", 1, 0, 'f'}, + { "gamma", 1, 0, 'G'}, + { "linearity", 1, 0, 'L'}, + { "saturation", 1, 0, 's'}, + { "hotpixel-sensitivity", 1, 0, 'H'}, +#ifdef UFRAW_CONTRAST + { "contrast", 1, 0, 'y'}, +#endif + { "wavelet-denoising-threshold", 1, 0, 'n'}, + { "exposure", 1, 0, 'e'}, + { "black-point", 1, 0, 'k'}, + { "interpolation", 1, 0, 'i'}, + { "grayscale", 1, 0, 'Y'}, + { "grayscale-mixer", 1, 0, 'a'}, + { "shrink", 1, 0, 'x'}, + { "size", 1, 0, 'X'}, + { "compression", 1, 0, 'j'}, + { "out-type", 1, 0, 'T'}, + { "out-depth", 1, 0, 'd'}, + { "rotate", 1, 0, 'R'}, + { "create-id", 1, 0, 'I'}, + { "out-path", 1, 0, 'p'}, + { "output", 1, 0, 'o'}, + { "darkframe", 1, 0, 'D'}, + { "restore", 1, 0, 'r'}, + { "clip", 1, 0, 'u'}, + { "conf", 1, 0, 'C'}, + { "crop-left", 1, 0, '1'}, + { "crop-top", 1, 0, '2'}, + { "crop-right", 1, 0, '3'}, + { "crop-bottom", 1, 0, '4'}, + { "aspect-ratio", 1, 0, 'P'}, + /* Binary flags that don't have a value are here at the end */ + { "zip", 0, 0, 'z'}, + { "nozip", 0, 0, 'Z'}, + { "overwrite", 0, 0, 'O'}, + { "color-smoothing", 0, 0, 'M' }, + { "maximize-window", 0, 0, 'W'}, + { "exif", 0, 0, 'E'}, + { "noexif", 0, 0, 'F'}, + { "embedded-image", 0, 0, 'm'}, + { "silent", 0, 0, 'q'}, + { "help", 0, 0, 'h'}, + { "version", 0, 0, 'v'}, + { "batch", 0, 0, 'b'}, + { "auto-crop", 0, 0, '0'}, + { 0, 0, 0, 0} + }; + UFObject *tmpImage = ufraw_image_new(); + void *optPointer[] = { + ufgroup_element(tmpImage, ufWB), + ufgroup_element(tmpImage, ufTemperature), + ufgroup_element(tmpImage, ufGreen), +#ifdef HAVE_LENSFUN + ufgroup_element(tmpImage, ufLensfunAuto), +#endif + &baseCurveName, &baseCurveFile, &curveName, &curveFile, + &cmd->profile[0][0].gamma, &cmd->profile[0][0].linear, + &cmd->saturation, + &cmd->hotpixel, +#ifdef UFRAW_CONTRAST + &cmd->contrast, +#endif + &cmd->threshold, + &cmd->exposure, &cmd->black, &interpolationName, &grayscaleName, + &grayscaleMixer, + &cmd->shrink, &cmd->size, &cmd->compression, + &outTypeName, &cmd->profile[1][0].BitDepth, &rotateName, + &createIDName, &outPath, &output, &darkframeFile, + &restoreName, &clipName, &conf, + &cmd->CropX1, &cmd->CropY1, &cmd->CropX2, &cmd->CropY2, + &cmd->aspectRatio + }; + cmd->autoExposure = disabled_state; + cmd->autoBlack = disabled_state; + cmd->losslessCompress = -1; + cmd->overwrite = -1; + cmd->noExit = -1; + cmd->WindowMaximized = -1; + cmd->embedExif = -1; + cmd->profile[1][0].BitDepth = -1; + cmd->embeddedImage = FALSE; + cmd->silent = FALSE; + cmd->profile[0][0].gamma = NULLF; + cmd->profile[0][0].linear = NULLF; + cmd->hotpixel = NULLF; +#ifdef UFRAW_CONTRAST + cmd->contrast = NULLF; +#endif + cmd->saturation = NULLF; + cmd->black = NULLF; + cmd->threshold = NULLF; + cmd->exposure = NULLF; + cmd->shrink = NULLF; + cmd->size = NULLF; + cmd->compression = NULLF; + cmd->rotationAngle = NULLF; + cmd->CropX1 = -1; + cmd->CropY1 = -1; + cmd->CropX2 = -1; + cmd->CropY2 = -1; + cmd->fullCrop = -1; + cmd->autoCrop = -1; + cmd->aspectRatio = 0.0; + cmd->rotate = -1; + cmd->smoothing = -1; + + while (1) { + c = getopt_long(*argc, *argv, "h", options, &index); + if (c == -1) break; + switch (c) { + case 'w': // --wb + case 't': // --temperature + case 'g': // --green + case 'A': // --lensfun + locale = uf_set_locale_C(); + if (!ufobject_set_string(optPointer[index], optarg)) { + ufraw_message(UFRAW_ERROR, + _("'%s' is not a valid value for the --%s option."), + optarg, options[index].name); + uf_reset_locale(locale); + return -1; + } + uf_reset_locale(locale); + if (!ufgroup_add(cmdImage, optPointer[index])) + return -1; + break; + case 'e': + if (!strcmp(optarg, "auto")) { + cmd->autoExposure = apply_state; + break; + } + // fall through + case 'k': + if (!strcmp(optarg, "auto")) { + cmd->autoBlack = apply_state; + break; + } + // fall through + case 'G': + case 'L': + case 's': + case 'H': +#ifdef UFRAW_CONTRAST + case 'y': +#endif + case 'n': + locale = uf_set_locale_C(); + if (sscanf(optarg, "%lf", (double *)optPointer[index]) == 0) { + ufraw_message(UFRAW_ERROR, + _("'%s' is not a valid value for the --%s option."), + optarg, options[index].name); + uf_reset_locale(locale); + return -1; + } + uf_reset_locale(locale); + break; + case 'x': + case 'X': + case 'j': + case 'd': + case '1': + case '2': + case '3': + case '4': + locale = uf_set_locale_C(); + if (sscanf(optarg, "%d", (int *)optPointer[index]) == 0) { + ufraw_message(UFRAW_ERROR, + _("'%s' is not a valid value for the --%s option."), + optarg, options[index].name); + uf_reset_locale(locale); + return -1; + } + uf_reset_locale(locale); + break; + case 'B': + case 'S': + case 'c': + case 'f': + case 'i': + case 'T': + case 'R': + case 'I': + case 'p': + case 'o': + case 'D': + case 'C': + case 'r': + case 'u': + case 'Y': + case 'a': + *(char **)optPointer[index] = optarg; + break; + case 'O': + cmd->overwrite = TRUE; + break; + case 'W': + cmd->WindowMaximized = TRUE; + break; + case 'm': + cmd->embeddedImage = TRUE; + break; + case 'M': + cmd->smoothing = TRUE; + break; + case 'q': + cmd->silent = TRUE; + break; + case 'z': +#ifdef HAVE_LIBZ + cmd->losslessCompress = TRUE; + break; +#else + ufraw_message(UFRAW_ERROR, + _("ufraw was build without ZIP support.")); + return -1; +#endif + case 'Z': + cmd->losslessCompress = FALSE; + break; + case 'E': + cmd->embedExif = TRUE; + break; + case 'F': + cmd->embedExif = FALSE; + break; + case 'h': + for (i = 0; strcmp(helpText[i], "END") != 0; i++) + ufraw_message(UFRAW_SET_WARNING, _(helpText[i])); + ufraw_message(UFRAW_WARNING, + ufraw_message(UFRAW_GET_WARNING, NULL)); + return 0; + case 'v': + base = g_path_get_basename(*argv[0]); + ufraw_message(UFRAW_WARNING, versionText, base); + g_free(base); + return 0; + case 'b': + ufraw_message(UFRAW_ERROR, + _("--batch is obsolete. Use 'ufraw-batch' instead.")); + return -1; + case '0': + cmd->autoCrop = enabled_state; + break; + case 'P': { + double num = 0.0, denom = 1.0; + locale = uf_set_locale_C(); + if (sscanf(optarg, "%lf:%lf", &num, &denom) < 2 && + sscanf(optarg, "%lf/%lf", &num, &denom) < 2 && + sscanf(optarg, "%lf", &num) == 0) { + ufraw_message(UFRAW_ERROR, + _("'%s' is not a valid value for the --%s option."), + optarg, options[index].name); + uf_reset_locale(locale); + return -1; + } + *(double *)optPointer[index] = num / denom; + uf_reset_locale(locale); + } + break; + case '?': /* invalid option. Warning printed by getopt() */ + return -1; + default: + ufraw_message(UFRAW_ERROR, _("getopt returned " + "character code 0%o ??"), c); + return -1; + } + } + cmd->BaseCurveIndex = -1; + if (baseCurveFile != NULL) { + baseCurveFile = uf_win32_locale_to_utf8(baseCurveFile); + if (cmd->BaseCurveCount == max_curves) { + ufraw_message(UFRAW_ERROR, _("failed to load curve from %s, " + "too many configured base curves"), baseCurveFile); + uf_win32_locale_free(baseCurveFile); + return -1; + } + cmd->BaseCurveIndex = cmd->BaseCurveCount; + if (curve_load(&(rc->BaseCurve[cmd->BaseCurveIndex]), baseCurveFile) + == UFRAW_ERROR) { + ufraw_message(UFRAW_ERROR, + _("failed to load curve from %s"), baseCurveFile); + uf_win32_locale_free(baseCurveFile); + return -1; + } + uf_win32_locale_free(baseCurveFile); + cmd->BaseCurveCount++; + } else if (baseCurveName != NULL) { + if (!strcmp(baseCurveName, "manual")) + cmd->BaseCurveIndex = manual_curve; + else if (!strcmp(baseCurveName, "linear")) + cmd->BaseCurveIndex = linear_curve; + else if (!strcmp(baseCurveName, "custom")) + cmd->BaseCurveIndex = custom_curve; + else if (!strcmp(baseCurveName, "camera")) + cmd->BaseCurveIndex = camera_curve; + else { + cmd->BaseCurveIndex = -1; + for (i = camera_curve + 1; i < rc->BaseCurveCount; i++) { + if (!strcmp(baseCurveName, rc->BaseCurve[i].name)) { + cmd->BaseCurveIndex = i; + break; + } + } + if (cmd->BaseCurveIndex == -1) { + ufraw_message(UFRAW_ERROR, + _("'%s' is not a valid base curve name."), baseCurveName); + return -1; + } + } + } + cmd->curveIndex = -1; + if (curveFile != NULL) { + curveFile = uf_win32_locale_to_utf8(curveFile); + if (cmd->curveCount == max_curves) { + ufraw_message(UFRAW_ERROR, _("failed to load curve from %s, " + "too many configured curves"), curveFile); + uf_win32_locale_free(curveFile); + return -1; + } + cmd->curveIndex = cmd->curveCount; + if (curve_load(&(rc->curve[cmd->curveIndex]), curveFile) == UFRAW_ERROR) { + ufraw_message(UFRAW_ERROR, + _("failed to load curve from %s"), curveFile); + uf_win32_locale_free(curveFile); + return -1; + } + uf_win32_locale_free(curveFile); + cmd->curveCount++; + } else if (curveName != NULL) { + if (!strcmp(curveName, "manual")) cmd->curveIndex = manual_curve; + else if (!strcmp(curveName, "linear")) cmd->curveIndex = linear_curve; + else { + cmd->curveIndex = -1; + for (i = linear_curve + 1; i < rc->curveCount; i++) { + if (!strcmp(curveName, rc->curve[i].name)) { + cmd->curveIndex = i; + break; + } + } + if (cmd->curveIndex == -1) { + ufraw_message(UFRAW_ERROR, + _("'%s' is not a valid curve name."), curveName); + return -1; + } + } + } + cmd->interpolation = -1; + if (interpolationName != NULL) { + /* Keep compatebility with old numbers from ufraw-0.5 */ + /*if (!strcmp(interpolationName, "full")) + cmd->interpolation = vng_interpolation; + else if (!strcmp(interpolationName, "quick")) + cmd->interpolation = bilinear_interpolation; + else */ + cmd->interpolation = conf_find_name(interpolationName, + interpolationNames, -1); + // "eahd" is being silently supported since ufraw-0.13. + if (cmd->interpolation < 0 || cmd->interpolation == half_interpolation) { + ufraw_message(UFRAW_ERROR, + _("'%s' is not a valid interpolation option."), + interpolationName); + return -1; + } + } + if (cmd->smoothing != -1) { + if (cmd->interpolation == ahd_interpolation) + cmd->smoothing = 3; + else + cmd->smoothing = 1; + } + cmd->grayscaleMode = -1; + cmd->grayscaleMixerDefined = 0; + if (grayscaleName != NULL) { + cmd->grayscaleMode = conf_find_name(grayscaleName, grayscaleModeNames, + grayscale_invalid); + if (cmd->grayscaleMode == grayscale_invalid) { + ufraw_message(UFRAW_ERROR, + _("'%s' is not a valid grayscale option."), + grayscaleName); + return -1; + } + if (cmd->grayscaleMode == grayscale_mixer) { + if (grayscaleMixer != NULL) { + double red, green, blue; + char *locale = uf_set_locale_C(); + if (sscanf(grayscaleMixer, "%lf,%lf,%lf", &red, &green, &blue) != 3) { + ufraw_message(UFRAW_ERROR, + _("'%s' is not a valid grayscale-mixer option."), + grayscaleMixer); + uf_reset_locale(locale); + return -1; + } + cmd->grayscaleMixerDefined = 1; + cmd->grayscaleMixer[0] = red; + cmd->grayscaleMixer[1] = green; + cmd->grayscaleMixer[2] = blue; + uf_reset_locale(locale); + } + } + } + cmd->restoreDetails = -1; + if (restoreName != NULL) { + cmd->restoreDetails = conf_find_name(restoreName, + restoreDetailsNames, -1); + if (cmd->restoreDetails < 0) { + ufraw_message(UFRAW_ERROR, _("'%s' is not a valid restore option."), + restoreName); + return -1; + } + } + cmd->clipHighlights = -1; + if (clipName != NULL) { + cmd->clipHighlights = conf_find_name(clipName, + clipHighlightsNames, -1); + if (cmd->clipHighlights < 0) { + ufraw_message(UFRAW_ERROR, _("'%s' is not a valid clip option."), + clipName); + return -1; + } + } + if (cmd->shrink != NULLF && cmd->size != NULLF) { + ufraw_message(UFRAW_ERROR, + _("you can not specify both --shrink and --size")); + return -1; + } + if (cmd->profile[1][0].BitDepth != -1) { + if (cmd->profile[1][0].BitDepth != 8 && + cmd->profile[1][0].BitDepth != 16) { + ufraw_message(UFRAW_ERROR, + _("'%d' is not a valid bit depth."), + cmd->profile[1][0].BitDepth); + return -1; + } + } + cmd->type = -1; + if (outTypeName != NULL && !cmd->embeddedImage) { + if (strcmp(outTypeName, "ppm") == 0) { + cmd->type = ppm_type; + } else if (strcmp(outTypeName, "ppm8") == 0) { + cmd->type = ppm_type; + cmd->profile[1][0].BitDepth = 8; + ufraw_message(UFRAW_WARNING, + _("Output type '%s' is deprecated"), outTypeName); + } else if (strcmp(outTypeName, "ppm16") == 0) { + cmd->type = ppm_type; + cmd->profile[1][0].BitDepth = 16; + ufraw_message(UFRAW_WARNING, + _("Output type '%s' is deprecated"), outTypeName); + } +#ifdef HAVE_LIBCFITSIO + else if (strcmp(outTypeName, "fits") == 0) { + cmd->type = fits_type; + } +#endif + + else if (!strcmp(outTypeName, "tiff") || !strcmp(outTypeName, "tif")) +#ifdef HAVE_LIBTIFF + { + cmd->type = tiff_type; + } +#else + { + ufraw_message(UFRAW_ERROR, + _("ufraw was build without TIFF support.")); + return -1; + } +#endif + else if (!strcmp(outTypeName, "tiff8")) +#ifdef HAVE_LIBTIFF + { + cmd->type = tiff_type; + cmd->profile[1][0].BitDepth = 8; + ufraw_message(UFRAW_WARNING, + _("Output type '%s' is deprecated"), outTypeName); + } +#else + { + ufraw_message(UFRAW_ERROR, + _("ufraw was build without TIFF support.")); + return -1; + } +#endif + else if (!strcmp(outTypeName, "tiff16")) +#ifdef HAVE_LIBTIFF + { + cmd->type = tiff_type; + cmd->profile[1][0].BitDepth = 16; + ufraw_message(UFRAW_WARNING, + _("Output type '%s' is deprecated"), outTypeName); + } +#else + { + ufraw_message(UFRAW_ERROR, + _("ufraw was build without TIFF support.")); + return -1; + } +#endif + else if (!strcmp(outTypeName, "jpeg") || !strcmp(outTypeName, "jpg")) +#ifdef HAVE_LIBJPEG + cmd->type = jpeg_type; +#else + { + ufraw_message(UFRAW_ERROR, + _("ufraw was build without JPEG support.")); + return -1; + } +#endif + else if (!strcmp(outTypeName, "png")) +#ifdef HAVE_LIBPNG + { + cmd->type = png_type; + } +#else + { + ufraw_message(UFRAW_ERROR, + _("ufraw was build without PNG support.")); + return -1; + } +#endif + else if (!strcmp(outTypeName, "png8")) +#ifdef HAVE_LIBPNG + { + cmd->type = png_type; + cmd->profile[1][0].BitDepth = 8; + ufraw_message(UFRAW_WARNING, + _("Output type '%s' is deprecated"), outTypeName); + } +#else + { + ufraw_message(UFRAW_ERROR, + _("ufraw was build without PNG support.")); + return -1; + } +#endif + else if (!strcmp(outTypeName, "png16")) +#ifdef HAVE_LIBPNG + { + cmd->type = png_type; + cmd->profile[1][0].BitDepth = 16; + ufraw_message(UFRAW_WARNING, + _("Output type '%s' is deprecated"), outTypeName); + } +#else + { + ufraw_message(UFRAW_ERROR, + _("ufraw was build without PNG support.")); + return -1; + } +#endif + else { + ufraw_message(UFRAW_ERROR, + _("'%s' is not a valid output type."), outTypeName); + return -1; + } + } + if (cmd->embeddedImage) { +#ifndef HAVE_LIBJPEG + ufraw_message(UFRAW_ERROR, _("ufraw was build without JPEG support.")); + return -1; +#endif + if (outTypeName == NULL || !strcmp(outTypeName, "jpeg") || + !strcmp(outTypeName, "jpg")) + cmd->type = embedded_jpeg_type; +#ifdef HAVE_LIBPNG + else if (strcmp(outTypeName, "png") == 0) + cmd->type = embedded_png_type; +#endif + + else { + ufraw_message(UFRAW_ERROR, + _("'%s' is not a valid output type for embedded image."), + outTypeName); + return -1; + } + if (cmd->profile[1][0].BitDepth != -1 && + cmd->profile[1][0].BitDepth != 8) { + ufraw_message(UFRAW_ERROR, + _("'%d' is not a valid bit depth for embedded image."), + cmd->profile[1][0].BitDepth); + return -1; + } + } + if (rotateName != NULL) { + if (strcmp(rotateName, "camera") == 0) + cmd->rotate = TRUE; + else if (strcmp(rotateName, "no") == 0) + cmd->rotate = FALSE; + else if (sscanf(rotateName, "%lf", &cmd->rotationAngle) == 1) { + cmd->rotate = TRUE; + } else { + ufraw_message(UFRAW_ERROR, + _("'%s' is not a valid rotate option."), rotateName); + return -1; + } + } + cmd->createID = -1; + if (createIDName != NULL) { + if (!strcmp(createIDName, "no")) + cmd->createID = no_id; + else if (!strcmp(createIDName, "also")) + cmd->createID = also_id; + else if (!strcmp(createIDName, "only")) + cmd->createID = only_id; + else { + ufraw_message(UFRAW_ERROR, + _("'%s' is not a valid create-id option."), createIDName); + return -1; + } + } + g_strlcpy(cmd->outputPath, "", max_path); + if (outPath != NULL) { + outPath = uf_win32_locale_to_utf8(outPath); + if (g_file_test(outPath, G_FILE_TEST_IS_DIR)) { + g_strlcpy(cmd->outputPath, outPath, max_path); + uf_win32_locale_free(outPath); + } else { + ufraw_message(UFRAW_ERROR, _("'%s' is not a valid path."), outPath); + uf_win32_locale_free(outPath); + return -1; + } + } + g_strlcpy(cmd->outputFilename, "", max_path); + if (output != NULL) { + if (*argc - optind > 1) { + ufraw_message(UFRAW_ERROR, + _("cannot output more than one file to the same output")); + return -1; + } + output = uf_win32_locale_to_utf8(output); + g_strlcpy(cmd->outputFilename, output, max_path); + uf_win32_locale_free(output); + } + g_strlcpy(cmd->darkframeFile, "", max_path); + cmd->darkframe = NULL; + if (darkframeFile != NULL) { + darkframeFile = uf_win32_locale_to_utf8(darkframeFile); + char *df = uf_file_set_absolute(darkframeFile); + uf_win32_locale_free(darkframeFile); + g_strlcpy(cmd->darkframeFile, df, max_path); + g_free(df); + } + /* cmd->inputFilename is used to store the conf file */ + g_strlcpy(cmd->inputFilename, "", max_path); + if (conf != NULL) + g_strlcpy(cmd->inputFilename, conf, max_path); + + ufobject_delete(tmpImage); + return optind; +} diff --git a/plugins/load-dcraw/ufraw_developer.c b/plugins/load-dcraw/ufraw_developer.c new file mode 100644 index 00000000..ff9be030 --- /dev/null +++ b/plugins/load-dcraw/ufraw_developer.c @@ -0,0 +1,1043 @@ +/* + * UFRaw - Unidentified Flying Raw converter for digital camera images + * + * ufraw_developer.c - functions for developing images or more exactly pixels. + * Copyright 2004-2016 by Udi Fuchs + * + * 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. + */ + +#include "ufraw.h" +#ifdef _OPENMP +#include +#endif +#include +#include +#include +#include +#include "ufraw_colorspaces.h" + +static void lcms_message(cmsContext ContextID, + cmsUInt32Number ErrorCode, + const char *ErrorText) +{ + (void) ContextID; + /* Possible ErrorCode: see cmsERROR_* in . */ + (void) ErrorCode; + ufraw_message(UFRAW_ERROR, "%s", ErrorText); +} + +developer_data *developer_init() +{ + int i; + developer_data *d = g_new(developer_data, 1); + d->mode = -1; + d->gamma = -1; + d->linear = -1; + d->saturation = -1; +#ifdef UFRAW_CONTRAST + d->contrast = -1; +#endif + for (i = 0; i < profile_types; i++) { + d->profile[i] = NULL; + strcpy(d->profileFile[i], "no such file"); + } + memset(&d->baseCurveData, 0, sizeof(d->baseCurveData)); + d->baseCurveData.m_gamma = -1.0; + memset(&d->luminosityCurveData, 0, sizeof(d->luminosityCurveData)); + d->luminosityCurveData.m_gamma = -1.0; + d->luminosityProfile = NULL; + cmsToneCurve **TransferFunction = (cmsToneCurve **)d->TransferFunction; + TransferFunction[0] = cmsBuildGamma(NULL, 1.0); + TransferFunction[1] = TransferFunction[2] = cmsBuildGamma(NULL, 1.0); + d->saturationProfile = NULL; + d->adjustmentProfile = NULL; + d->intent[out_profile] = -1; + d->intent[display_profile] = -1; + d->updateTransform = TRUE; + d->colorTransform = NULL; + d->working2displayTransform = NULL; + d->rgbtolabTransform = NULL; + d->grayscaleMode = -1; + d->grayscaleMixer[0] = d->grayscaleMixer[1] = d->grayscaleMixer[2] = -1; + for (i = 0; i < max_adjustments; i++) { /* Suppress valgrind error. */ + d->lightnessAdjustment[i].adjustment = 0.0; + d->lightnessAdjustment[i].hue = 0.0; + d->lightnessAdjustment[i].hueWidth = 0.0; + } + cmsSetLogErrorHandler(lcms_message); + return d; +} + +void developer_destroy(developer_data *d) +{ + int i; + if (d == NULL) return; + for (i = 0; i < profile_types; i++) + if (d->profile[i] != NULL) cmsCloseProfile(d->profile[i]); + cmsCloseProfile(d->luminosityProfile); + cmsFreeToneCurve(d->TransferFunction[0]); + cmsFreeToneCurve(d->TransferFunction[1]); + cmsCloseProfile(d->saturationProfile); + cmsCloseProfile(d->adjustmentProfile); + if (d->colorTransform != NULL) + cmsDeleteTransform(d->colorTransform); + if (d->working2displayTransform != NULL) + cmsDeleteTransform(d->working2displayTransform); + if (d->rgbtolabTransform != NULL) + cmsDeleteTransform(d->rgbtolabTransform); + g_free(d); +} + +static const char *embedded_display_profile = "embedded display profile"; + +/* + * Emulates cmsTakeProductName() from lcms 1.x. + * + * This is tailored for use with statically allocated strings and not + * thread-safe. + */ +const char *cmsTakeProductName(cmsHPROFILE profile) +{ + static char name[max_name * 2 + 4]; + char manufacturer[max_name], model[max_name]; + + name[0] = manufacturer[0] = model[0] = '\0'; + + cmsGetProfileInfoASCII(profile, cmsInfoManufacturer, + "en", "US", manufacturer, max_name); + cmsGetProfileInfoASCII(profile, cmsInfoModel, + "en", "US", model, max_name); + + if (!manufacturer[0] && !model[0]) { + cmsGetProfileInfoASCII(profile, cmsInfoDescription, + "en", "US", name, max_name * 2 + 4); + } else { + if (!manufacturer[0] || (strncmp(model, manufacturer, 8) == 0) || + strlen(model) > 30) + strcpy(name, model); + else + sprintf(name, "%s - %s", model, manufacturer); + } + + return name; +} + +/* Update the profile in the developer + * and init values in the profile if needed */ +void developer_profile(developer_data *d, int type, profile_data *p) +{ + // embedded_display_profile were handled by developer_display_profile() + if (strcmp(d->profileFile[type], embedded_display_profile) == 0) + return; + if (strcmp(p->file, d->profileFile[type])) { + g_strlcpy(d->profileFile[type], p->file, max_path); + if (d->profile[type] != NULL) cmsCloseProfile(d->profile[type]); + if (!strcmp(d->profileFile[type], "")) + d->profile[type] = uf_colorspaces_create_srgb_profile(); + else { + char *filename = + uf_win32_locale_filename_from_utf8(d->profileFile[type]); + d->profile[type] = cmsOpenProfileFromFile(filename, "r"); + uf_win32_locale_filename_free(filename); + if (d->profile[type] == NULL) + d->profile[type] = uf_colorspaces_create_srgb_profile(); + } + d->updateTransform = TRUE; + } + if (d->updateTransform) { + if (d->profile[type] != NULL) + g_strlcpy(p->productName, cmsTakeProductName(d->profile[type]), + max_name); + else + strcpy(p->productName, ""); + } +} + +void developer_display_profile(developer_data *d, + unsigned char *profile, int size, char productName[]) +{ + int type = display_profile; + if (profile != NULL) { + if (d->profile[type] != NULL) cmsCloseProfile(d->profile[type]); + d->profile[type] = cmsOpenProfileFromMem(profile, size); + // If embedded profile is invalid fall-back to sRGB + if (d->profile[type] == NULL) + d->profile[type] = uf_colorspaces_create_srgb_profile(); + if (strcmp(d->profileFile[type], embedded_display_profile) != 0) { + // start using embedded profile + g_strlcpy(d->profileFile[type], embedded_display_profile, max_path); + d->updateTransform = TRUE; + } + } else { + if (strcmp(d->profileFile[type], embedded_display_profile) == 0) { + // embedded profile is no longer used + if (d->profile[type] != NULL) cmsCloseProfile(d->profile[type]); + d->profile[type] = uf_colorspaces_create_srgb_profile(); + strcpy(d->profileFile[type], ""); + d->updateTransform = TRUE; + } + } + if (d->updateTransform) { + if (d->profile[type] != NULL) + g_strlcpy(productName, cmsTakeProductName(d->profile[type]), + max_name); + else + strcpy(productName, ""); + } +} + +static double clamp(double in, double min, double max) +{ + return (in < min) ? min : (in > max) ? max : in; +} + +struct contrast_saturation { + double contrast; + double saturation; +}; + +/* Scale in along a curve from min to max by scale */ +static double scale_curve(double in, double min, double max, double scale) +{ + double halfrange = (max - min) / 2.0; + /* Normalize in to [ -1, 1 ] */ + double value = clamp((in - min) / halfrange - 1.0, -1.0, 1.0); + /* Linear scaling makes more visual sense for low contrast values. */ + if (scale > 1.0) { + double n = fabs(value); + if (n > 1.0) + n = 1.0; + scale = n <= 0.0 ? 0.0 : (1.0 - pow(1.0 - n, scale)) / n; + } + return clamp((value * scale + 1.0) * halfrange + min, min, max); +} + +static const double max_luminance = 100.0; +static const double max_colorfulness = 181.019336; /* sqrt(128*128+128*128) */ + +static cmsInt32Number contrast_saturation_sampler(const cmsUInt16Number In[], + cmsUInt16Number Out[], + void *Cargo) +{ + cmsCIELab Lab; + cmsCIELCh LCh; + const struct contrast_saturation* cs = Cargo; + + cmsLabEncoded2Float(&Lab, In); + cmsLab2LCh(&LCh, &Lab); + LCh.L = scale_curve(LCh.L, 0.0, max_luminance, cs->contrast); + LCh.C = scale_curve(LCh.C, -max_colorfulness, max_colorfulness, + cs->saturation); + cmsLCh2Lab(&Lab, &LCh); + cmsFloat2LabEncoded(Out, &Lab); + + return TRUE; +} + +/* Based on lcms' cmsCreateBCHSWabstractProfile() */ +static cmsHPROFILE create_contrast_saturation_profile(double contrast, + double saturation) +{ + cmsHPROFILE hICC; + struct contrast_saturation cs = { contrast, saturation }; + + cmsPipeline* Pipeline = NULL; + cmsStage* CLUT = NULL; + + hICC = cmsCreateProfilePlaceholder(NULL); + if (hICC == NULL) return NULL; // can't allocate + + cmsSetDeviceClass(hICC, cmsSigAbstractClass); + cmsSetColorSpace(hICC, cmsSigLabData); + cmsSetPCS(hICC, cmsSigLabData); + cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); + + // Creates a pipeline with 3D grid only + Pipeline = cmsPipelineAlloc(NULL, 3, 3); + if (!Pipeline) goto error_out; + + if (!(CLUT = cmsStageAllocCLut16bit(NULL, 11, 3, 3, NULL))) + goto error_out; + if (!cmsStageSampleCLut16bit(CLUT, contrast_saturation_sampler, &cs, 0)) + goto error_out; + +#if LCMS_VERSION >= 2050 + if (!cmsPipelineInsertStage(Pipeline, cmsAT_END, CLUT)) + goto error_out; +#else + cmsPipelineInsertStage(Pipeline, cmsAT_END, CLUT); +#endif + + // Create tags + cmsWriteTag(hICC, cmsSigMediaWhitePointTag, cmsD50_XYZ()); + cmsWriteTag(hICC, cmsSigAToB0Tag, Pipeline); + + // Pipeline is already on virtual profile + cmsPipelineFree(Pipeline); + + return hICC; + +error_out: + if (CLUT) cmsStageFree(CLUT); + if (Pipeline) cmsPipelineFree(Pipeline); + if (hICC) cmsCloseProfile(hICC); + return NULL; +} + +static cmsInt32Number luminance_adjustment_sampler(const cmsUInt16Number In[], + cmsUInt16Number Out[], + void *Cargo) +{ + cmsCIELab Lab; + cmsCIELCh LCh; + const developer_data *d = Cargo; + const lightness_adjustment *a; + + cmsLabEncoded2Float(&Lab, In); + cmsLab2LCh(&LCh, &Lab); + + double adj = 0.0; + int i; + for (i = 0, a = d->lightnessAdjustment; i < max_adjustments; i++, a++) { + double deltaHue = fabs(LCh.h - a->hue); + double hueWidth = MAX(a->hueWidth, 360.0 / 33.0); + if (deltaHue > 180.0) + deltaHue = 360.0 - deltaHue; + if (deltaHue > hueWidth) + continue; + /* This assigns the scales on a nice curve. */ + double scale = cos(deltaHue / hueWidth * (M_PI / 2)); + adj += (a->adjustment - 1) * (scale * scale); + } + /* The adjustment is scaled based on the colorfulness of the point, + * since uncolored pixels should not be adjusted. However, few + * (s)RGB colors have a colorfulness value larger than 1/2 of + * max_colorfulness, so use that as an actual maximum colorfulness. */ + adj = adj * MIN(LCh.C / (max_colorfulness / 2), 1.0) + 1; + LCh.L *= adj; + + cmsLCh2Lab(&Lab, &LCh); + cmsFloat2LabEncoded(Out, &Lab); + + return TRUE; +} + +/* Based on lcms' cmsCreateBCHSWabstractProfile() */ +static cmsHPROFILE create_adjustment_profile(const developer_data *d) +{ + cmsHPROFILE hICC; + + cmsPipeline* Pipeline = NULL; + cmsStage* CLUT = NULL; + + hICC = cmsCreateProfilePlaceholder(NULL); + if (hICC == NULL) return NULL; // can't allocate + + cmsSetDeviceClass(hICC, cmsSigAbstractClass); + cmsSetColorSpace(hICC, cmsSigLabData); + cmsSetPCS(hICC, cmsSigLabData); + cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); + + // Creates a pipeline with 3D grid only + Pipeline = cmsPipelineAlloc(NULL, 3, 3); + if (!Pipeline) goto error_out; + + if (!(CLUT = cmsStageAllocCLut16bit(NULL, 11, 3, 3, NULL))) + goto error_out; + + if (!cmsStageSampleCLut16bit(CLUT, luminance_adjustment_sampler, + (void*)d, 0)) + goto error_out; + +#if LCMS_VERSION >= 2050 + if (!cmsPipelineInsertStage(Pipeline, cmsAT_END, CLUT)) + goto error_out; +#else + cmsPipelineInsertStage(Pipeline, cmsAT_END, CLUT); +#endif + + // Create tags + cmsWriteTag(hICC, cmsSigMediaWhitePointTag, cmsD50_XYZ()); + cmsWriteTag(hICC, cmsSigAToB0Tag, Pipeline); + + // Pipeline is already on virtual profile + cmsPipelineFree(Pipeline); + + return hICC; + +error_out: + if (CLUT) cmsStageFree(CLUT); + if (Pipeline) cmsPipelineFree(Pipeline); + if (hICC) cmsCloseProfile(hICC); + return NULL; +} + +/* Find a for which (1-exp(-a x)/(1-exp(-a)) has derivative b at x=0 */ +/* In other words, solve a/(1-exp(-a))==b */ +static double findExpCoeff(double b) +{ + double a, bg; + int try; + if (b <= 1) return 0; + if (b < 2) a = (b - 1) / 2; + else a = b; + bg = a / (1 - exp(-a)); + /* The limit on try is just to be sure there is no infinite loop. */ + for (try = 0; fabs(bg - b) > 0.001 || try < 100; try++) { + a = a + (b - bg); + bg = a / (1 - exp(-a)); + } + return a; +} + +static void developer_create_transform(developer_data *d, DeveloperMode mode) +{ + if (!d->updateTransform) + return; + d->updateTransform = FALSE; + /* Create transformations according to mode: + * auto_developer|output_developer: + * colorTransformation from in to out + * working2displayTransform is null + * display_developer: + * with softproofing: + * colorTransformation from in to out + * working2displayTransform from out to display + * without softproofing: + * colorTransformation from in to display + * working2displayTransform is null + */ + int targetProfile; + if (mode == display_developer + && d->intent[display_profile] == disable_intent) { + targetProfile = display_profile; + } else { + targetProfile = out_profile; + } + if (d->colorTransform != NULL) + cmsDeleteTransform(d->colorTransform); + if (strcmp(d->profileFile[in_profile], "") == 0 && + strcmp(d->profileFile[targetProfile], "") == 0 && + d->luminosityProfile == NULL && + d->adjustmentProfile == NULL && + d->saturationProfile == NULL) { + /* No transformation at all. */ + d->colorTransform = NULL; + } else { + cmsHPROFILE prof[5]; + int i = 0; + prof[i++] = d->profile[in_profile]; + if (d->luminosityProfile != NULL) + prof[i++] = d->luminosityProfile; + if (d->adjustmentProfile != NULL) + prof[i++] = d->adjustmentProfile; + if (d->saturationProfile != NULL) + prof[i++] = d->saturationProfile; + prof[i++] = d->profile[targetProfile]; + d->colorTransform = cmsCreateMultiprofileTransform(prof, i, + TYPE_RGB_16, TYPE_RGB_16, d->intent[out_profile], 0); + } + + if (d->working2displayTransform != NULL) + cmsDeleteTransform(d->working2displayTransform); + if (mode == display_developer + && d->intent[display_profile] != disable_intent + && strcmp(d->profileFile[out_profile], + d->profileFile[display_profile]) != 0) { + // TODO: We should use TYPE_RGB_'bit_depth' for working profile. + d->working2displayTransform = cmsCreateTransform( + d->profile[out_profile], TYPE_RGB_8, + d->profile[display_profile], TYPE_RGB_8, + d->intent[display_profile], 0); + } else { + d->working2displayTransform = NULL; + } + + if (d->rgbtolabTransform == NULL) { + cmsHPROFILE labProfile = cmsCreateLab2Profile(cmsD50_xyY()); + d->rgbtolabTransform = cmsCreateTransform(d->profile[in_profile], + TYPE_RGB_16, labProfile, + TYPE_Lab_16, INTENT_ABSOLUTE_COLORIMETRIC, 0); + cmsCloseProfile(labProfile); + } +} + +static gboolean test_adjustments(const lightness_adjustment values[max_adjustments], + gdouble reference, gdouble threshold) +{ + int i; + for (i = 0; i < max_adjustments; ++i) + if (fabs(values[i].adjustment - reference) >= threshold) + return TRUE; + return FALSE; +} + +void developer_prepare(developer_data *d, conf_data *conf, + int rgbMax, float rgb_cam[3][4], int colors, int useMatrix, + DeveloperMode mode) +{ + unsigned c, i; + profile_data *in, *out, *display; + CurveData *baseCurve, *curve; + double total; + + if (mode != d->mode) { + d->mode = mode; + d->updateTransform = TRUE; + } + in = &conf->profile[in_profile][conf->profileIndex[in_profile]]; + /* For auto-tools we create an sRGB output. */ + if (mode == auto_developer) + out = &conf->profile[out_profile][0]; + else + out = &conf->profile[out_profile][conf->profileIndex[out_profile]]; + display = &conf->profile[display_profile] + [conf->profileIndex[display_profile]]; + baseCurve = &conf->BaseCurve[conf->BaseCurveIndex]; + curve = &conf->curve[conf->curveIndex]; + + d->rgbMax = rgbMax; + d->colors = colors; + d->useMatrix = useMatrix; + + double max = 0; + UFObject *chanMul = ufgroup_element(conf->ufobject, ufChannelMultipliers); + /* We assume that min(chanMul)==1.0 */ + for (c = 0; c < d->colors; c++) + max = MAX(max, ufnumber_array_value(chanMul, c)); + d->max = 0x10000 / max; + /* rgbWB is used in dcraw_finalized_interpolation() before the color filter + * array interpolation. It is normalized to guarantee that values do not + * exceed 0xFFFF */ + for (c = 0; c < d->colors; c++) + d->rgbWB[c] = ufnumber_array_value(chanMul, c) * d->max * + 0xFFFF / d->rgbMax; + + if (d->useMatrix) { + if (d->colors == 1) + for (i = 0; i < 3; i++) + d->colorMatrix[i][0] = rgb_cam[0][0] * 0x10000; + else + for (i = 0; i < 3; i++) + for (c = 0; c < d->colors; c++) + d->colorMatrix[i][c] = rgb_cam[i][c] * 0x10000; + } + + switch (conf->grayscaleMode) { + + case grayscale_mixer: + d->grayscaleMode = grayscale_mixer; + for (c = 0, total = 0.0; c < 3; ++c) + total += fabs(conf->grayscaleMixer[c]); + total = total == 0.0 ? 1.0 : total; + for (c = 0; c < 3; ++c) + d->grayscaleMixer[c] = conf->grayscaleMixer[c] / total; + break; + + case grayscale_lightness: + case grayscale_value: + d->grayscaleMode = conf->grayscaleMode; + break; + + default: + d->grayscaleMode = grayscale_none; + } + + d->restoreDetails = conf->restoreDetails; + int clipHighlights = conf->clipHighlights; + unsigned exposure = pow(2, conf->exposure) * 0x10000; + /* Handle the exposure normalization for Canon EOS cameras. */ + if (conf->ExposureNorm > 0) + exposure = (guint64)exposure * d->rgbMax / conf->ExposureNorm; + if (exposure >= 0x10000) d->restoreDetails = clip_details; + if (exposure <= 0x10000) clipHighlights = digital_highlights; + /* Check if gamma curve data has changed. */ + if (in->gamma != d->gamma || in->linear != d->linear || + exposure != d->exposure || clipHighlights != d->clipHighlights || + memcmp(baseCurve, &d->baseCurveData, sizeof(CurveData)) != 0) { + d->baseCurveData = *baseCurve; + guint16 BaseCurve[0x10000]; + CurveSample *cs = CurveSampleInit(0x10000, 0x10000); + ufraw_message(UFRAW_RESET, NULL); + if (CurveDataSample(baseCurve, cs) != UFRAW_SUCCESS) { + ufraw_message(UFRAW_REPORT, NULL); + for (i = 0; i < 0x10000; i++) cs->m_Samples[i] = i; + } + for (i = 0; i < 0x10000; i++) BaseCurve[i] = cs->m_Samples[i]; + CurveSampleFree(cs); + + d->gamma = in->gamma; + d->linear = in->linear; + d->exposure = exposure; + d->clipHighlights = clipHighlights; + guint16 FilmCurve[0x10000]; + if (d->clipHighlights == film_highlights) { + /* Exposure is set by FilmCurve[]. + * Set initial slope to d->exposuse/0x10000 */ + double a = findExpCoeff((double)d->exposure / 0x10000); + for (i = 0; i < 0x10000; i++) FilmCurve[i] = + (1 - exp(-a * i / 0x10000)) / (1 - exp(-a)) * 0xFFFF; + } else { /* digital highlights */ + for (i = 0; i < 0x10000; i++) FilmCurve[i] = i; + } + double a, b, c, g; + /* The parameters of the linearized gamma curve are set in a way that + * keeps the curve continuous and smooth at the connecting point. + * d->linear also changes the real gamma used for the curve (g) in + * a way that keeps the derivative at i=0x10000 constant. + * This way changing the linearity changes the curve behaviour in + * the shadows, but has a minimal effect on the rest of the range. */ + if (d->linear < 1.0) { + g = d->gamma * (1.0 - d->linear) / (1.0 - d->gamma * d->linear); + a = 1.0 / (1.0 + d->linear * (g - 1)); + b = d->linear * (g - 1) * a; + c = pow(a * d->linear + b, g) / d->linear; + } else { + a = b = g = 0.0; + c = 1.0; + } + for (i = 0; i < 0x10000; i++) + if (BaseCurve[FilmCurve[i]] < 0x10000 * d->linear) + d->gammaCurve[i] = MIN(c * BaseCurve[FilmCurve[i]], 0xFFFF); + else + d->gammaCurve[i] = MIN(pow(a * BaseCurve[FilmCurve[i]] / 0x10000 + b, + g) * 0x10000, 0xFFFF); + } + developer_profile(d, in_profile, in); + developer_profile(d, out_profile, out); + if (conf->intent[out_profile] != d->intent[out_profile]) { + d->intent[out_profile] = conf->intent[out_profile]; + d->updateTransform = TRUE; + } + /* For auto-tools we ignore all the output settings: + * luminosity, saturation, output profile and proofing. */ + if (mode == auto_developer) { + developer_create_transform(d, mode); + return; + } + developer_profile(d, display_profile, display); + if (conf->intent[display_profile] != d->intent[display_profile]) { + d->intent[display_profile] = conf->intent[display_profile]; + d->updateTransform = TRUE; + } + /* Check if curve data has changed. */ + if (memcmp(curve, &d->luminosityCurveData, sizeof(CurveData))) { + d->luminosityCurveData = *curve; + /* Trivial curve does not require a profile */ + if (CurveDataIsTrivial(curve)) { + d->luminosityProfile = NULL; + } else { + cmsCloseProfile(d->luminosityProfile); + CurveSample *cs = CurveSampleInit(0x100, 0x10000); + ufraw_message(UFRAW_RESET, NULL); + if (CurveDataSample(curve, cs) != UFRAW_SUCCESS) { + ufraw_message(UFRAW_REPORT, NULL); + d->luminosityProfile = NULL; + } else { + cmsToneCurve **TransferFunction = + (cmsToneCurve **)d->TransferFunction; + cmsFloat32Number values[0x100]; + cmsFreeToneCurve(TransferFunction[0]); + for (i = 0; i < 0x100; i++) + values[i] = (cmsFloat32Number) cs->m_Samples[i] / 0x10000; + TransferFunction[0] = + cmsBuildTabulatedToneCurveFloat(NULL, 0x100, values); + d->luminosityProfile = cmsCreateLinearizationDeviceLink( + cmsSigLabData, TransferFunction); + cmsSetDeviceClass(d->luminosityProfile, cmsSigAbstractClass); + } + CurveSampleFree(cs); + } + d->updateTransform = TRUE; + } + if (memcmp(d->lightnessAdjustment, conf->lightnessAdjustment, + sizeof d->lightnessAdjustment) != 0) { + /* Adjustments have changed, need to update them. */ + d->updateTransform = TRUE; + memcpy(d->lightnessAdjustment, conf->lightnessAdjustment, + sizeof d->lightnessAdjustment); + cmsCloseProfile(d->adjustmentProfile); + d->adjustmentProfile = test_adjustments(d->lightnessAdjustment, 1.0, 0.01) + ? create_adjustment_profile(d) + : NULL; + } + + if (conf->saturation != d->saturation +#ifdef UFRAW_CONTRAST + || conf->contrast != d->contrast +#endif + || conf->grayscaleMode == grayscale_luminance) { +#ifdef UFRAW_CONTRAST + d->contrast = conf->contrast; +#endif + d->saturation = (conf->grayscaleMode == grayscale_luminance) + ? 0 : conf->saturation; + cmsCloseProfile(d->saturationProfile); + if (d->saturation == 1.0 +#ifdef UFRAW_CONTRAST + && d->contrast == 1.0 +#endif + ) + d->saturationProfile = NULL; + else + d->saturationProfile = create_contrast_saturation_profile( +#ifdef UFRAW_CONTRAST + d->contrast, +#else + 1.0, +#endif + d->saturation); + d->updateTransform = TRUE; + } + developer_create_transform(d, mode); +} + +static void apply_matrix(const developer_data *d, + const gint64 in[4], + gint64 out[3]) +{ + gint64 tmp[3]; + unsigned c, cc; + for (cc = 0; cc < 3; cc++) { + tmp[cc] = 0; + for (c = 0; c < d->colors; c++) + tmp[cc] += in[c] * d->colorMatrix[cc][c]; + } + for (cc = 0; cc < 3; cc++) + out[cc] = MAX(tmp[cc] / 0x10000, 0); +} + +static void cond_apply_matrix(const developer_data *d, + const gint64 in[4], + gint64 out[3]) +{ + if (d->useMatrix) + apply_matrix(d, in, out); + else + memcpy(out, in, 3 * sizeof out[0]); +} + +extern const double xyz_rgb[3][3]; +static const double rgb_xyz[3][3] = { /* RGB from XYZ */ + { 3.24048, -1.53715, -0.498536 }, + { -0.969255, 1.87599, 0.0415559 }, + { 0.0556466, -0.204041, 1.05731 } +}; + +// Convert linear RGB to CIE-LCh +void uf_rgb_to_cielch(gint64 rgb[3], float lch[3]) +{ + int c, cc, i; + float r, xyz[3], lab[3]; + // The use of static varibles here should be thread safe. + // In the worst case cbrt[] will be calculated more than once. + static gboolean firstRun = TRUE; + static float cbrt[0x10000]; + + if (firstRun) { + for (i = 0; i < 0x10000; i++) { + r = i / 65535.0; + cbrt[i] = r > 0.008856 ? pow(r, 1 / 3.0) : 7.787 * r + 16 / 116.0; + } + firstRun = FALSE; + } + xyz[0] = xyz[1] = xyz[2] = 0.5; + for (c = 0; c < 3; c++) + for (cc = 0; cc < 3; cc++) + xyz[cc] += xyz_rgb[cc][c] * rgb[c]; + for (c = 0; c < 3; c++) + xyz[c] = cbrt[MAX(MIN((int)xyz[c], 0xFFFF), 0)]; + lab[0] = 116 * xyz[1] - 16; + lab[1] = 500 * (xyz[0] - xyz[1]); + lab[2] = 200 * (xyz[1] - xyz[2]); + + lch[0] = lab[0]; + lch[1] = sqrt(lab[1] * lab[1] + lab[2] * lab[2]); + lch[2] = atan2(lab[2], lab[1]); +} + +// Convert CIE-LCh to linear RGB +void uf_cielch_to_rgb(float lch[3], gint64 rgb[3]) +{ + int c, cc; + float xyz[3], fx, fy, fz, xr, yr, zr, kappa, epsilon, tmpf, lab[3]; + epsilon = 0.008856; + kappa = 903.3; + lab[0] = lch[0]; + lab[1] = lch[1] * cos(lch[2]); + lab[2] = lch[1] * sin(lch[2]); + yr = (lab[0] <= kappa * epsilon) ? + (lab[0] / kappa) : (pow((lab[0] + 16.0) / 116.0, 3.0)); + fy = (yr <= epsilon) ? ((kappa * yr + 16.0) / 116.0) : ((lab[0] + 16.0) / 116.0); + fz = fy - lab[2] / 200.0; + fx = lab[1] / 500.0 + fy; + zr = (pow(fz, 3.0) <= epsilon) ? ((116.0 * fz - 16.0) / kappa) : (pow(fz, 3.0)); + xr = (pow(fx, 3.0) <= epsilon) ? ((116.0 * fx - 16.0) / kappa) : (pow(fx, 3.0)); + + xyz[0] = xr * 65535.0 - 0.5; + xyz[1] = yr * 65535.0 - 0.5; + xyz[2] = zr * 65535.0 - 0.5; + + for (c = 0; c < 3; c++) { + tmpf = 0; + for (cc = 0; cc < 3; cc++) + tmpf += rgb_xyz[c][cc] * xyz[cc]; + rgb[c] = MAX(tmpf, 0); + } +} + +void uf_raw_to_cielch(const developer_data *d, + const guint16 raw[4], + float lch[3]) +{ + gint64 tmp[4]; + guint16 rgbpixel[3]; + guint16 labpixel[3]; + cmsCIELab Lab; + cmsCIELCh LCh; + unsigned int c; + + for (c = 0; c < d->colors; ++c) { + tmp[c] = raw[c]; + tmp[c] *= d->rgbWB[c]; + tmp[c] /= 0x10000; + } + cond_apply_matrix(d, tmp, tmp); + for (c = 0; c < 3; ++c) + rgbpixel[c] = tmp[c]; + + cmsDoTransform(d->rgbtolabTransform, rgbpixel, labpixel, 1); + + cmsLabEncoded2Float(&Lab, labpixel); + cmsLab2LCh(&LCh, &Lab); + lch[0] = LCh.L; + lch[1] = LCh.C; + lch[2] = LCh.h; +} + +static void MaxMidMin(const gint64 p[3], int *maxc, int *midc, int *minc) +{ + gint64 a = p[0]; + gint64 b = p[1]; + gint64 c = p[2]; + int max = 0; + int mid = 1; + int min = 2; + + if (a < b) { + gint64 tmp = b; + b = a; + a = tmp; + max = 1; + mid = 0; + } + if (b < c) { + b = c; + min = mid; + mid = 2; + if (a < b) { + int tmp = max; + max = mid; + mid = tmp; + } + } + + *maxc = max; + *midc = mid; + *minc = min; +} + +void develop(void *po, guint16 pix[4], developer_data *d, int mode, int count) +{ + guint16 c, tmppix[3], *buf; + int i; + if (mode == 16) buf = po; + else buf = g_alloca(count * 6); + +#ifdef _OPENMP + #pragma omp parallel \ + if (count > 16) \ + default(none) \ + shared(d, buf, count, pix) \ + private(i, tmppix, c) + { + int chunk = count / omp_get_num_threads() + 1; + int offset = chunk * omp_get_thread_num(); + int width = (chunk > count - offset) ? count - offset : chunk; + for (i = offset; i < offset + width; i++) { + develop_linear(pix + i * 4, tmppix, d); + for (c = 0; c < 3; c++) + buf[i * 3 + c] = d->gammaCurve[tmppix[c]]; + } + if (d->colorTransform != NULL) + cmsDoTransform(d->colorTransform, + buf + offset * 3, buf + offset * 3, width); + } +#else + for (i = 0; i < count; i++) { + develop_linear(pix + i * 4, tmppix, d); + for (c = 0; c < 3; c++) + buf[i * 3 + c] = d->gammaCurve[tmppix[c]]; + } + if (d->colorTransform != NULL) + cmsDoTransform(d->colorTransform, buf, buf, count); +#endif + + if (mode != 16) { + guint8 *p8 = po; + for (i = 0; i < 3 * count; i++) p8[i] = buf[i] >> 8; + } +} + +void develop_display(void *pout, void *pin, developer_data *d, int count) +{ + if (d->working2displayTransform == NULL) + g_error("develop_display: working2displayTransform == NULL"); + + cmsDoTransform(d->working2displayTransform, pin, pout, count); +} + +static void develop_grayscale(guint16 *pixel, const developer_data *d) +{ + gint32 spot; + guint16 min; + guint16 max; + + switch (d->grayscaleMode) { + + case grayscale_mixer: + spot = pixel[0] * d->grayscaleMixer[0] + + pixel[1] * d->grayscaleMixer[1] + + pixel[2] * d->grayscaleMixer[2]; + if (spot > 65535) spot = 65535; + else if (spot < 0) spot = 0; + break; + + case grayscale_lightness: + min = max = pixel[0]; + if (pixel[1] > max) max = pixel[1]; + if (pixel[2] > max) max = pixel[2]; + if (pixel[1] < min) min = pixel[1]; + if (pixel[2] < min) min = pixel[2]; + spot = ((int)min + (int)max) / 2; + break; + + case grayscale_value: + max = pixel[0]; + if (pixel[1] > max) max = pixel[1]; + if (pixel[2] > max) max = pixel[2]; + spot = max; + break; + + default: + return; + } + pixel[0] = pixel[1] = pixel[2] = spot; +} + +void develop_linear(guint16 in[4], guint16 out[3], developer_data *d) +{ + unsigned c; + gint64 tmppix[4]; + gboolean clipped = FALSE; + for (c = 0; c < d->colors; c++) { + /* Set WB, normalizing tmppix[c]<0x10000 */ + tmppix[c] = in[c]; + tmppix[c] *= d->rgbWB[c]; + tmppix[c] /= 0x10000; + if (d->restoreDetails != clip_details && + tmppix[c] > d->max) { + clipped = TRUE; + } else { + tmppix[c] = MIN(tmppix[c], d->max); + } + /* We are counting on the fact that film_highlights + * and !clip_highlights cannot be set simultaneously. */ + if (d->clipHighlights == film_highlights) + tmppix[c] = tmppix[c] * 0x10000 / d->max; + else + tmppix[c] = tmppix[c] * d->exposure / d->max; + } + if (d->colors == 1) + tmppix[1] = tmppix[2] = tmppix[0]; + if (clipped) { + /* At this point a value of d->exposure in tmppix[c] corresponds + * to "1.0" (full exposure). Still the maximal value can be + * d->exposure * 0x10000 / d->max */ + gint64 unclippedPix[3], clippedPix[3]; + cond_apply_matrix(d, tmppix, unclippedPix); + for (c = 0; c < 3; c++) tmppix[c] = MIN(tmppix[c], d->exposure); + cond_apply_matrix(d, tmppix, clippedPix); + if (d->restoreDetails == restore_lch_details) { + float lch[3], clippedLch[3], unclippedLch[3]; + uf_rgb_to_cielch(unclippedPix, unclippedLch); + uf_rgb_to_cielch(clippedPix, clippedLch); + //lch[0] = clippedLch[0] + (unclippedLch[0]-clippedLch[0]) * x; + lch[0] = unclippedLch[0]; + lch[1] = clippedLch[1]; + lch[2] = clippedLch[2]; + uf_cielch_to_rgb(lch, tmppix); + } else { /* restore_hsv_details */ + int maxc, midc, minc; + MaxMidMin(unclippedPix, &maxc, &midc, &minc); + gint64 unclippedLum = unclippedPix[maxc]; + gint64 clippedLum = clippedPix[maxc]; + /*gint64 unclippedSat; + if ( unclippedPix[maxc]==0 ) + unclippedSat = 0; + else + unclippedSat = 0x10000 - + unclippedPix[minc] * 0x10000 / unclippedPix[maxc];*/ + gint64 clippedSat; + if (clippedPix[maxc] < clippedPix[minc] || clippedPix[maxc] == 0) + clippedSat = 0; + else + clippedSat = 0x10000 - + clippedPix[minc] * 0x10000 / clippedPix[maxc]; + gint64 clippedHue; + if (clippedPix[maxc] == clippedPix[minc]) clippedHue = 0; + else clippedHue = + (clippedPix[midc] - clippedPix[minc]) * 0x10000 / + (clippedPix[maxc] - clippedPix[minc]); + gint64 unclippedHue; + if (unclippedPix[maxc] == unclippedPix[minc]) + unclippedHue = clippedHue; + else + unclippedHue = + (unclippedPix[midc] - unclippedPix[minc]) * 0x10000 / + (unclippedPix[maxc] - unclippedPix[minc]); + /* Here we decide how to mix the clipped and unclipped values. + * The general equation is clipped + (unclipped - clipped) * x, + * where x is between 0 and 1. */ + /* For lum we set x=1/2. Thus hightlights are not too bright. */ + gint64 lum = clippedLum + (unclippedLum - clippedLum) * 1 / 2; + /* For sat we should set x=0 to prevent color artifacts. */ + //gint64 sat = clippedSat + (unclippedSat - clippedSat) * 0/1 ; + gint64 sat = clippedSat; + /* For hue we set x=1. This doesn't seem to have much effect. */ + gint64 hue = unclippedHue; + + tmppix[maxc] = lum; + tmppix[minc] = lum * (0x10000 - sat) / 0x10000; + tmppix[midc] = lum * (0x10000 - sat + sat * hue / 0x10000) / 0x10000; + } + } else { /* !clipped */ + if (d->useMatrix) + apply_matrix(d, tmppix, tmppix); + gint64 max = tmppix[0]; + for (c = 1; c < 3; c++) max = MAX(tmppix[c], max); + if (max > 0xFFFF) { + gint64 unclippedLum = max; + gint64 clippedLum = 0xFFFF; + gint64 lum = clippedLum + (unclippedLum - clippedLum) * 1 / 4; + for (c = 0; c < 3; c++) tmppix[c] = tmppix[c] * lum / max; + } + } + for (c = 0; c < 3; c++) + out[c] = MIN(MAX(tmppix[c], 0), 0xFFFF); + develop_grayscale(out, d); +} diff --git a/plugins/load-dcraw/ufraw_embedded.c b/plugins/load-dcraw/ufraw_embedded.c new file mode 100644 index 00000000..a010a63f --- /dev/null +++ b/plugins/load-dcraw/ufraw_embedded.c @@ -0,0 +1,380 @@ +/* + * UFRaw - Unidentified Flying Raw converter for digital camera images + * + * ufraw_embedded.c - functions to output embedded preview image. + * Copyright 2004-2016 by Udi Fuchs + * + * 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. + */ + +#include "ufraw.h" +#include "dcraw_api.h" +#include /* for errno */ +#include +#include +#ifdef HAVE_LIBJPEG +#include +#include +#endif +#ifdef HAVE_LIBPNG +#include +#endif + +#ifdef HAVE_LIBJPEG +static void ufraw_jpeg_warning(j_common_ptr cinfo) +{ + ufraw_message(UFRAW_SET_WARNING, + cinfo->err->jpeg_message_table[cinfo->err->msg_code], + cinfo->err->msg_parm.i[0], + cinfo->err->msg_parm.i[1], + cinfo->err->msg_parm.i[2], + cinfo->err->msg_parm.i[3]); +} + +static void ufraw_jpeg_error(j_common_ptr cinfo) +{ + /* We ignore the SOI error if second byte is 0xd8 since Minolta's + * SOI is known to be wrong */ + if (cinfo->err->msg_code == JERR_NO_SOI && + cinfo->err->msg_parm.i[1] == 0xd8) { + ufraw_message(UFRAW_SET_LOG, + cinfo->err->jpeg_message_table[cinfo->err->msg_code], + cinfo->err->msg_parm.i[0], + cinfo->err->msg_parm.i[1], + cinfo->err->msg_parm.i[2], + cinfo->err->msg_parm.i[3]); + return; + } + ufraw_message(UFRAW_SET_ERROR, + cinfo->err->jpeg_message_table[cinfo->err->msg_code], + cinfo->err->msg_parm.i[0], + cinfo->err->msg_parm.i[1], + cinfo->err->msg_parm.i[2], + cinfo->err->msg_parm.i[3]); +} +#endif /*HAVE_LIBJPEG*/ + +int ufraw_read_embedded(ufraw_data *uf) +{ + int status = UFRAW_SUCCESS; + dcraw_data *raw = uf->raw; + ufraw_message(UFRAW_RESET, NULL); + +#ifndef HAVE_LIBJPEG + ufraw_message(UFRAW_ERROR, _("Reading embedded image requires libjpeg.")); + return UFRAW_ERROR; +#endif + if (raw->thumbType == unknown_thumb_type) { + ufraw_message(UFRAW_ERROR, _("No embedded image found")); + return UFRAW_ERROR; + } + fseek(raw->ifp, raw->thumbOffset, SEEK_SET); + + if (uf->conf->shrink < 2 && uf->conf->size == 0 && uf->conf->orientation == 0 && + uf->conf->type == embedded_jpeg_type && + raw->thumbType == jpeg_thumb_type) { + uf->thumb.buffer = g_new(unsigned char, raw->thumbBufferLength); + size_t num = fread(uf->thumb.buffer, 1, raw->thumbBufferLength, + raw->ifp); + if (num != raw->thumbBufferLength) + ufraw_message(UFRAW_WARNING, "Corrupt thumbnail (fread %d != %d)", + num, raw->thumbBufferLength); + uf->thumb.buffer[0] = 0xff; + } else { + unsigned srcHeight = uf->thumb.height, srcWidth = uf->thumb.width; + int scaleNum = 1, scaleDenom = 1; + + if (uf->conf->size > 0) { + int srcSize = MAX(srcHeight, srcWidth); + if (srcSize < uf->conf->size) { + ufraw_message(UFRAW_WARNING, _("Original size (%d) " + "is smaller than the requested size (%d)"), + srcSize, uf->conf->size); + } else { + scaleNum = uf->conf->size; + scaleDenom = srcSize; + } + } else if (uf->conf->shrink > 1) { + scaleNum = 1; + scaleDenom = uf->conf->shrink; + } + if (raw->thumbType == ppm_thumb_type) { + if (srcHeight * srcWidth * 3 != (unsigned)raw->thumbBufferLength) { + ufraw_message(UFRAW_ERROR, _("ppm thumb mismatch, " + "height %d, width %d, while buffer %d."), + srcHeight, srcWidth, raw->thumbBufferLength); + return UFRAW_ERROR; + } + uf->thumb.buffer = g_new(guint8, raw->thumbBufferLength); + size_t num = fread(uf->thumb.buffer, 1, raw->thumbBufferLength, + raw->ifp); + if (num != raw->thumbBufferLength) + ufraw_message(UFRAW_WARNING, + "Corrupt thumbnail (fread %d != %d)", + num, raw->thumbBufferLength); + } else { +#ifdef HAVE_LIBJPEG + struct jpeg_decompress_struct srcinfo; + struct jpeg_error_mgr jsrcerr; + srcinfo.err = jpeg_std_error(&jsrcerr); + /* possible BUG: two messages in case of error? */ + srcinfo.err->output_message = ufraw_jpeg_warning; + srcinfo.err->error_exit = ufraw_jpeg_error; + + jpeg_create_decompress(&srcinfo); + jpeg_stdio_src(&srcinfo, raw->ifp); + + jpeg_read_header(&srcinfo, TRUE); + if (srcinfo.image_height != srcHeight) { + ufraw_message(UFRAW_WARNING, _("JPEG thumb height %d " + "different than expected %d."), + srcinfo.image_height, srcHeight); + srcHeight = srcinfo.image_height; + } + if (srcinfo.image_width != srcWidth) { + ufraw_message(UFRAW_WARNING, _("JPEG thumb width %d " + "different than expected %d."), + srcinfo.image_width, srcWidth); + srcWidth = srcinfo.image_width; + } + srcinfo.scale_num = scaleNum; + srcinfo.scale_denom = scaleDenom; + jpeg_start_decompress(&srcinfo); + uf->thumb.buffer = g_new(JSAMPLE, + srcinfo.output_width * srcinfo.output_height * + srcinfo.output_components); + JSAMPROW buf; + while (srcinfo.output_scanline < srcinfo.output_height) { + buf = uf->thumb.buffer + srcinfo.output_scanline * + srcinfo.output_width * srcinfo.output_components; + jpeg_read_scanlines(&srcinfo, &buf, srcinfo.rec_outbuf_height); + } + uf->thumb.width = srcinfo.output_width; + uf->thumb.height = srcinfo.output_height; + jpeg_finish_decompress(&srcinfo); + jpeg_destroy_decompress(&srcinfo); + char *message = ufraw_message(UFRAW_GET_ERROR, NULL); + if (message != NULL) { + ufraw_message(UFRAW_ERROR, _("Error creating file '%s'.\n%s"), + uf->conf->outputFilename, message); + status = UFRAW_ERROR; + } else if (ufraw_message(UFRAW_GET_WARNING, NULL) != NULL) { + ufraw_message(UFRAW_REPORT, NULL); + } +#endif /* HAVE_LIBJPEG */ + } + } + return status; +} + +int ufraw_convert_embedded(ufraw_data *uf) +{ + if (uf->thumb.buffer == NULL) { + ufraw_message(UFRAW_ERROR, _("No embedded image read")); + return UFRAW_ERROR; + } + unsigned srcHeight = uf->thumb.height, srcWidth = uf->thumb.width; + int scaleNum = 1, scaleDenom = 1; + + if (uf->conf->size > 0) { + int srcSize = MAX(srcHeight, srcWidth); + if (srcSize > uf->conf->size) { + scaleNum = uf->conf->size; + scaleDenom = srcSize; + } + } else if (uf->conf->shrink > 1) { + scaleNum = 1; + scaleDenom = uf->conf->shrink; + } + unsigned dstWidth = srcWidth * scaleNum / scaleDenom; + unsigned dstHeight = srcHeight * scaleNum / scaleDenom; + if (dstWidth != srcWidth || dstHeight != srcHeight) { + /* libjpeg only shrink by 1,2,4 or 8. Here we finish the work */ + unsigned r, nr, c, nc; + int m; + for (r = 0; r < srcHeight; r++) { + nr = r * dstHeight / srcHeight; + for (c = 0; c < srcWidth; c++) { + nc = c * dstWidth / srcWidth; + for (m = 0; m < 3; m++) + uf->thumb.buffer[(nr * dstWidth + nc) * 3 + m] = + uf->thumb.buffer[(r * srcWidth + c) * 3 + m]; + } + } + } + if (uf->conf->orientation != 0) { + unsigned r, nr, c, nc, tmp; + int m; + unsigned height = dstHeight; + unsigned width = dstWidth; + if (uf->conf->orientation & 4) { + tmp = height; + height = width; + width = tmp; + } + unsigned char *newBuffer = g_new(unsigned char, width * height * 3); + for (r = 0; r < dstHeight; r++) { + if (uf->conf->orientation & 2) nr = dstHeight - r - 1; + else nr = r; + for (c = 0; c < dstWidth; c++) { + if (uf->conf->orientation & 1) nc = dstWidth - c - 1; + else nc = c; + if (uf->conf->orientation & 4) tmp = nc * width + nr; + else tmp = nr * width + nc; + for (m = 0; m < 3; m++) { + newBuffer[tmp * 3 + m] = + uf->thumb.buffer[(r * dstWidth + c) * 3 + m]; + } + } + } + g_free(uf->thumb.buffer); + uf->thumb.buffer = newBuffer; + if (uf->conf->orientation & 4) { + dstHeight = height; + dstWidth = width; + } + } + uf->thumb.height = dstHeight; + uf->thumb.width = dstWidth; + return UFRAW_SUCCESS; +} + +int ufraw_write_embedded(ufraw_data *uf) +{ + volatile int status = UFRAW_SUCCESS; + dcraw_data *raw = uf->raw; + FILE * volatile out = NULL; /* 'volatile' supresses clobbering warning */ + ufraw_message(UFRAW_RESET, NULL); + + if (uf->conf->type != embedded_jpeg_type && + uf->conf->type != embedded_png_type) { + ufraw_message(UFRAW_ERROR, + _("Error creating file '%s'. Unknown file type %d."), + uf->conf->outputFilename, uf->conf->type); + return UFRAW_ERROR; + } + if (uf->thumb.buffer == NULL) { + ufraw_message(UFRAW_ERROR, _("No embedded image read")); + return UFRAW_ERROR; + } + if (!strcmp(uf->conf->outputFilename, "-")) { + out = stdout; + } else { + if ((out = g_fopen(uf->conf->outputFilename, "wb")) == NULL) { + ufraw_message(UFRAW_ERROR, _("Error creating file '%s': %s"), + uf->conf->outputFilename, g_strerror(errno)); + return UFRAW_ERROR; + } + } + if (uf->conf->shrink < 2 && uf->conf->size == 0 && uf->conf->orientation == 0 && + uf->conf->type == embedded_jpeg_type && + raw->thumbType == jpeg_thumb_type) { + size_t num = fwrite(uf->thumb.buffer, 1, raw->thumbBufferLength, out); + if (num != raw->thumbBufferLength) { + ufraw_message(UFRAW_ERROR, _("Error writing '%s'"), + uf->conf->outputFilename); + fclose(out); + return UFRAW_ERROR; + } + } else if (uf->conf->type == embedded_jpeg_type) { +#ifdef HAVE_LIBJPEG + struct jpeg_compress_struct dstinfo; + struct jpeg_error_mgr jdsterr; + dstinfo.err = jpeg_std_error(&jdsterr); + /* possible BUG: two messages in case of error? */ + dstinfo.err->output_message = ufraw_jpeg_warning; + dstinfo.err->error_exit = ufraw_jpeg_error; + + jpeg_create_compress(&dstinfo); + dstinfo.in_color_space = JCS_RGB; + jpeg_set_defaults(&dstinfo); + jpeg_set_quality(&dstinfo, uf->conf->compression, TRUE); + dstinfo.input_components = 3; + jpeg_default_colorspace(&dstinfo); + dstinfo.image_width = uf->thumb.width; + dstinfo.image_height = uf->thumb.height; + + jpeg_stdio_dest(&dstinfo, out); + jpeg_start_compress(&dstinfo, TRUE); + JSAMPROW buf; + while (dstinfo.next_scanline < dstinfo.image_height) { + buf = uf->thumb.buffer + dstinfo.next_scanline * + dstinfo.image_width * dstinfo.input_components; + jpeg_write_scanlines(&dstinfo, &buf, 1); + } + jpeg_finish_compress(&dstinfo); + jpeg_destroy_compress(&dstinfo); + char *message = ufraw_message(UFRAW_GET_ERROR, NULL); + if (message != NULL) { + ufraw_message(UFRAW_ERROR, _("Error creating file '%s'.\n%s"), + uf->conf->outputFilename, message); + status = UFRAW_ERROR; + } else if (ufraw_message(UFRAW_GET_WARNING, NULL) != NULL) { + ufraw_message(UFRAW_REPORT, NULL); + } +#endif /*HAVE_LIBJPEG*/ + } else if (uf->conf->type == embedded_png_type) { +#ifdef HAVE_LIBPNG + /* It is assumed that PNG output will be used to create thumbnails. + * Therefore the PNG image is created according to the + * thumbmail standards in: + * http://jens.triq.net/thumbnail-spec/index.html + */ + png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL); + png_infop info = png_create_info_struct(png); + if (setjmp(png_jmpbuf(png))) { + ufraw_message(UFRAW_ERROR, _("Error writing '%s'"), + uf->conf->outputFilename); + png_destroy_write_struct(&png, &info); + fclose(out); + return UFRAW_ERROR; + } + png_init_io(png, out); + png_set_IHDR(png, info, uf->thumb.width, uf->thumb.height, + 8 /*bit_depth*/, PNG_COLOR_TYPE_RGB, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, + PNG_FILTER_TYPE_BASE); + png_text text[5]; +// char height[max_name], width[max_name]; + text[0].compression = PNG_TEXT_COMPRESSION_NONE; + text[0].key = "Thumb::URI"; + text[0].text = uf->conf->inputURI; + text[1].compression = PNG_TEXT_COMPRESSION_NONE; + text[1].key = "Thumb::MTime"; + text[1].text = uf->conf->inputModTime; +// text[2].compression = PNG_TEXT_COMPRESSION_NONE; +// text[2].key = "Thumb::Image::Height"; +// g_snprintf(height, max_name, "%d", uf->predictedHeight); +// text[2].text = height; +// text[3].compression = PNG_TEXT_COMPRESSION_NONE; +// text[3].key = "Thumb::Image::Width"; +// g_snprintf(width, max_name, "%d", uf->predictedWidth); +// text[3].text = width; +// text[4].compression = PNG_TEXT_COMPRESSION_NONE; +// text[4].key = "Software"; +// text[4].text = "UFRaw"; + png_set_text(png, info, text, 2); + png_write_info(png, info); + + int r; + for (r = 0; r < uf->thumb.height; r++) + png_write_row(png, uf->thumb.buffer + r * uf->thumb.width * 3); + png_write_end(png, NULL); + png_destroy_write_struct(&png, &info); +#endif /*HAVE_LIBPNG*/ + } else { + ufraw_message(UFRAW_ERROR, + _("Unsupported output type (%d) for embedded image"), + uf->conf->type); + status = UFRAW_ERROR; + } + // TODO: Before fclose() we should fflush() and check for errors. + if (strcmp(uf->conf->outputFilename, "-")) + fclose(out); + + return status; +} diff --git a/plugins/load-dcraw/ufraw_exiv2.cc b/plugins/load-dcraw/ufraw_exiv2.cc new file mode 100644 index 00000000..873bacc2 --- /dev/null +++ b/plugins/load-dcraw/ufraw_exiv2.cc @@ -0,0 +1,397 @@ +/* + * UFRaw - Unidentified Flying Raw converter for digital camera images + * + * ufraw_exiv2.cc - read the EXIF data from the RAW file using exiv2. + * Copyright 2004-2016 by Udi Fuchs + * + * Based on a sample program from exiv2 and neftags2jpg. + * + * 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. + */ + +#include "ufraw.h" + +#ifdef HAVE_EXIV2 +#include +#include +#include +#include + +/* + * Helper function to copy a string to a buffer, converting it from + * current locale (in which exiv2 often returns strings) to UTF-8. + */ +static void uf_strlcpy_to_utf8(char *dest, size_t dest_max, + Exiv2::ExifData::const_iterator pos, Exiv2::ExifData& exifData) +{ + std::string str = pos->print(&exifData); + + char *s = g_locale_to_utf8(str.c_str(), str.length(), + NULL, NULL, NULL); + if (s != NULL) { + g_strlcpy(dest, s, dest_max); + g_free(s); + } else { + g_strlcpy(dest, str.c_str(), dest_max); + } +} + +extern "C" int ufraw_exif_read_input(ufraw_data *uf) +{ + /* Redirect exiv2 errors to a string buffer */ + std::ostringstream stderror; + std::streambuf *savecerr = std::cerr.rdbuf(); + std::cerr.rdbuf(stderror.rdbuf()); + + try { + uf->inputExifBuf = NULL; + uf->inputExifBufLen = 0; + + Exiv2::Image::AutoPtr image; + if (uf->unzippedBuf != NULL) { + image = Exiv2::ImageFactory::open( + (const Exiv2::byte*)uf->unzippedBuf, uf->unzippedBufLen); + } else { + char *filename = uf_win32_locale_filename_from_utf8(uf->filename); + image = Exiv2::ImageFactory::open(filename); + uf_win32_locale_filename_free(filename); + } + assert(image.get() != 0); + image->readMetadata(); + + Exiv2::ExifData &exifData = image->exifData(); + if (exifData.empty()) { + std::string error(uf->filename); + error += ": No Exif data found in the file"; +#if EXIV2_TEST_VERSION(0,27,0) + throw Exiv2::Error(Exiv2::kerErrorMessage, error); +#else + throw Exiv2::Error(1, error); +#endif + } + + /* List of tag names taken from exiv2's printSummary() in actions.cpp */ + Exiv2::ExifData::const_iterator pos; + /* Read shutter time */ + if ((pos = Exiv2::exposureTime(exifData)) != exifData.end()) { + uf_strlcpy_to_utf8(uf->conf->shutterText, max_name, pos, exifData); + uf->conf->shutter = pos->toFloat(); + } + /* Read aperture */ + if ((pos = Exiv2::fNumber(exifData)) != exifData.end()) { + uf_strlcpy_to_utf8(uf->conf->apertureText, max_name, pos, exifData); + uf->conf->aperture = pos->toFloat(); + } + /* Read ISO speed */ + if ((pos = Exiv2::isoSpeed(exifData)) != exifData.end()) { + uf_strlcpy_to_utf8(uf->conf->isoText, max_name, pos, exifData); + } + /* Read focal length */ + if ((pos = Exiv2::focalLength(exifData)) != exifData.end()) { + uf_strlcpy_to_utf8(uf->conf->focalLenText, max_name, pos, exifData); + uf->conf->focal_len = pos->toFloat(); + } + /* Read focal length in 35mm equivalent */ + if ((pos = exifData.findKey(Exiv2::ExifKey( + "Exif.Photo.FocalLengthIn35mmFilm"))) + != exifData.end()) { + uf_strlcpy_to_utf8(uf->conf->focalLen35Text, max_name, pos, exifData); + } + /* Read full lens name */ + if ((pos = Exiv2::lensName(exifData)) != exifData.end()) { + uf_strlcpy_to_utf8(uf->conf->lensText, max_name, pos, exifData); + } + /* Read flash mode */ + if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Photo.Flash"))) + != exifData.end()) { + uf_strlcpy_to_utf8(uf->conf->flashText, max_name, pos, exifData); + } + /* Read White Balance Setting */ + if ((pos = Exiv2::whiteBalance(exifData)) != exifData.end()) { + uf_strlcpy_to_utf8(uf->conf->whiteBalanceText, max_name, pos, exifData); + } + + if ((pos = Exiv2::make(exifData)) != exifData.end()) { + uf_strlcpy_to_utf8(uf->conf->real_make, max_name, pos, exifData); + } + if ((pos = Exiv2::model(exifData)) != exifData.end()) { + uf_strlcpy_to_utf8(uf->conf->real_model, max_name, pos, exifData); + } + + /* Store all EXIF data read in. */ + Exiv2::Blob blob; + Exiv2::ExifParser::encode(blob, Exiv2::bigEndian, exifData); + uf->inputExifBufLen = blob.size(); + uf->inputExifBuf = g_new(unsigned char, uf->inputExifBufLen); + memcpy(uf->inputExifBuf, &blob[0], blob.size()); + ufraw_message(UFRAW_SET_LOG, "EXIF data read using exiv2, buflen %d\n", + uf->inputExifBufLen); + g_strlcpy(uf->conf->exifSource, EXV_PACKAGE_STRING, max_name); + + std::cerr.rdbuf(savecerr); + ufraw_message(UFRAW_SET_LOG, "%s\n", stderror.str().c_str()); + + return UFRAW_SUCCESS; + } catch (Exiv2::AnyError& e) { + std::cerr.rdbuf(savecerr); + std::string s(e.what()); + ufraw_message(UFRAW_SET_WARNING, "%s\n", s.c_str()); + return UFRAW_ERROR; + } + +} + +static Exiv2::ExifData ufraw_prepare_exifdata(ufraw_data *uf) +{ + Exiv2::ExifData exifData = Exiv2::ExifData(); + + /* Start from the input EXIF data */ + Exiv2::ExifParser::decode(exifData, uf->inputExifBuf, uf->inputExifBufLen); + Exiv2::ExifData::iterator pos; + if (uf->conf->rotate) { + /* Reset orientation tag since UFRaw already rotates the image */ + if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.Orientation"))) + != exifData.end()) { + ufraw_message(UFRAW_SET_LOG, "Resetting %s from '%d' to '1'\n", + pos->key().c_str(), pos->value().toLong()); + pos->setValue("1"); /* 1 = Normal orientation */ + } + } + + /* Delete original TIFF data, which is irrelevant*/ + if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.ImageWidth"))) + != exifData.end()) + exifData.erase(pos); + if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.ImageLength"))) + != exifData.end()) + exifData.erase(pos); + if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.BitsPerSample"))) + != exifData.end()) + exifData.erase(pos); + if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.Compression"))) + != exifData.end()) + exifData.erase(pos); + if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.PhotometricInterpretation"))) + != exifData.end()) + exifData.erase(pos); + if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.FillOrder"))) + != exifData.end()) + exifData.erase(pos); + if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.SamplesPerPixel"))) + != exifData.end()) + exifData.erase(pos); + if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.StripOffsets"))) + != exifData.end()) + exifData.erase(pos); + if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.RowsPerStrip"))) + != exifData.end()) + exifData.erase(pos); + if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.StripByteCounts"))) + != exifData.end()) + exifData.erase(pos); + if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.XResolution"))) + != exifData.end()) + exifData.erase(pos); + if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.YResolution"))) + != exifData.end()) + exifData.erase(pos); + if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.PlanarConfiguration"))) + != exifData.end()) + exifData.erase(pos); + if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.ResolutionUnit"))) + != exifData.end()) + exifData.erase(pos); + + /* Delete various MakerNote fields only applicable to the raw file */ + + // Nikon thumbnail data + if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Nikon3.Preview"))) + != exifData.end()) + exifData.erase(pos); + if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.NikonPreview.JPEGInterchangeFormat"))) + != exifData.end()) + exifData.erase(pos); + + // DCRaw handles TIFF files as raw if DNGVersion is found. + if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.DNGVersion"))) + != exifData.end()) + exifData.erase(pos); + + // DNG private data + if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.DNGPrivateData"))) + != exifData.end()) + exifData.erase(pos); + + // Pentax thumbnail data + if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Pentax.PreviewResolution"))) + != exifData.end()) + exifData.erase(pos); + if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Pentax.PreviewLength"))) + != exifData.end()) + exifData.erase(pos); + if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Pentax.PreviewOffset"))) + != exifData.end()) + exifData.erase(pos); + + // Minolta thumbnail data + if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Minolta.Thumbnail"))) + != exifData.end()) + exifData.erase(pos); + if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Minolta.ThumbnailOffset"))) + != exifData.end()) + exifData.erase(pos); + if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Minolta.ThumbnailLength"))) + != exifData.end()) + exifData.erase(pos); + + // Olympus thumbnail data + if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Olympus.Thumbnail"))) + != exifData.end()) + exifData.erase(pos); + if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Olympus.ThumbnailOffset"))) + != exifData.end()) + exifData.erase(pos); + if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Olympus.ThumbnailLength"))) + != exifData.end()) + exifData.erase(pos); + + /* Write appropriate color space tag if using sRGB output */ + if (!strcmp(uf->developer->profileFile[out_profile], "")) + exifData["Exif.Photo.ColorSpace"] = uint16_t(1); /* sRGB */ + + /* Add "UFRaw" and version used to output file as processing software. */ + exifData["Exif.Image.ProcessingSoftware"] = "UFRaw " VERSION; + + return exifData; +} + +extern "C" int ufraw_exif_prepare_output(ufraw_data *uf) +{ + /* Redirect exiv2 errors to a string buffer */ + std::ostringstream stderror; + std::streambuf *savecerr = std::cerr.rdbuf(); + std::cerr.rdbuf(stderror.rdbuf()); + try { + uf->outputExifBuf = NULL; + uf->outputExifBufLen = 0; + + Exiv2::ExifData exifData = ufraw_prepare_exifdata(uf); + + int size; + Exiv2::Blob blob; + Exiv2::ExifParser::encode(blob, Exiv2::bigEndian, exifData); + size = blob.size(); + const unsigned char ExifHeader[] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00}; + /* If buffer too big for JPEG, try deleting some stuff. */ + if (size + sizeof(ExifHeader) > 65533) { + Exiv2::ExifData::iterator pos; + if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Photo.MakerNote"))) + != exifData.end()) { + exifData.erase(pos); + ufraw_message(UFRAW_SET_LOG, + "buflen %d too big, erasing Exif.Photo.MakerNote " + "and related decoded metadata\n", + size + sizeof(ExifHeader)); + /* Delete decoded metadata associated with + * Exif.Photo.MakerNote, otherwise erasing it isn't + * effective. */ + for (pos = exifData.begin(); pos != exifData.end();) { + if (!strcmp(pos->ifdName(), "Makernote")) + pos = exifData.erase(pos); + else + pos++; + } + blob.clear(); + Exiv2::ExifParser::encode(blob, Exiv2::bigEndian, exifData); + size = blob.size(); + } + } + if (size + sizeof(ExifHeader) > 65533) { + Exiv2::ExifThumb thumb(exifData); + thumb.erase(); + ufraw_message(UFRAW_SET_LOG, + "buflen %d too big, erasing Thumbnail\n", + size + sizeof(ExifHeader)); + blob.clear(); + Exiv2::ExifParser::encode(blob, Exiv2::bigEndian, exifData); + size = blob.size(); + } + uf->outputExifBufLen = size + sizeof(ExifHeader); + uf->outputExifBuf = g_new(unsigned char, uf->outputExifBufLen); + memcpy(uf->outputExifBuf, ExifHeader, sizeof(ExifHeader)); + memcpy(uf->outputExifBuf + sizeof(ExifHeader), &blob[0], blob.size()); + std::cerr.rdbuf(savecerr); + ufraw_message(UFRAW_SET_LOG, "%s\n", stderror.str().c_str()); + + return UFRAW_SUCCESS; + } catch (Exiv2::AnyError& e) { + std::cerr.rdbuf(savecerr); + std::string s(e.what()); + ufraw_message(UFRAW_SET_WARNING, "%s\n", s.c_str()); + return UFRAW_ERROR; + } + +} + +extern "C" int ufraw_exif_write(ufraw_data *uf) +{ + /* Redirect exiv2 errors to a string buffer */ + std::ostringstream stderror; + std::streambuf *savecerr = std::cerr.rdbuf(); + std::cerr.rdbuf(stderror.rdbuf()); + try { + Exiv2::ExifData rawExifData = ufraw_prepare_exifdata(uf); + + char *filename = + uf_win32_locale_filename_from_utf8(uf->conf->outputFilename); + Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(filename); + uf_win32_locale_filename_free(filename); + assert(image.get() != 0); + + image->readMetadata(); + Exiv2::ExifData &outExifData = image->exifData(); + + Exiv2::ExifData::iterator pos = rawExifData.begin(); + while (!rawExifData.empty()) { + outExifData.add(*pos); + pos = rawExifData.erase(pos); + } + outExifData.sortByTag(); + image->setExifData(outExifData); + image->writeMetadata(); + + std::cerr.rdbuf(savecerr); + ufraw_message(UFRAW_SET_LOG, "%s\n", stderror.str().c_str()); + + return UFRAW_SUCCESS; + } catch (Exiv2::AnyError& e) { + std::cerr.rdbuf(savecerr); + std::string s(e.what()); + ufraw_message(UFRAW_SET_WARNING, "%s\n", s.c_str()); + return UFRAW_ERROR; + } +} + +#else +extern "C" int ufraw_exif_read_input(ufraw_data *uf) +{ + (void)uf; + ufraw_message(UFRAW_SET_LOG, "ufraw built without EXIF support\n"); + return UFRAW_ERROR; +} + +extern "C" int ufraw_exif_prepare_output(ufraw_data *uf) +{ + (void)uf; + return UFRAW_ERROR; +} + +extern "C" int ufraw_exif_write(ufraw_data *uf) +{ + (void)uf; + return UFRAW_ERROR; +} +#endif /* HAVE_EXIV2 */ diff --git a/plugins/load-dcraw/ufraw_message.c b/plugins/load-dcraw/ufraw_message.c new file mode 100644 index 00000000..f5039663 --- /dev/null +++ b/plugins/load-dcraw/ufraw_message.c @@ -0,0 +1,198 @@ +/* + * UFRaw - Unidentified Flying Raw converter for digital camera images + * + * ufraw_message.c - Error message handling functions + * Copyright 2004-2016 by Udi Fuchs + * + * 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. + */ + +#include "ufraw.h" +#include + +/* + * Every ufraw internal function that might fail should return a status + * with one of these values: + * UFRAW_SUCCESS + * UFRAW_WARNING + * UFRAW_ERROR + * The relevant message can be retrived using ufraw_get_message(). + * Even when UFRAW_SUCCESS is returned there could be an information message. + */ +char *ufraw_get_message(ufraw_data *uf) +{ + return uf->message; +} + +static void message_append(ufraw_data *uf, char *message) +{ + if (message == NULL) return; + if (uf->message == NULL) { + uf->message = g_strdup(message); + return; + } + if (uf->message[strlen(uf->message) - 1] == '\n') + uf->message = g_strconcat(uf->message, message, NULL); + else + uf->message = g_strconcat(uf->message, "\n", message, NULL); +} + + +/* The following function should be used by ufraw's internal functions. */ +void ufraw_message_init(ufraw_data *uf) +{ + uf->status = UFRAW_SUCCESS; + uf->message = NULL; +} + +void ufraw_message_reset(ufraw_data *uf) +{ + uf->status = UFRAW_SUCCESS; + g_free(uf->message); + uf->message = NULL; +} + +void ufraw_set_error(ufraw_data *uf, const char *format, ...) +{ + uf->status = UFRAW_ERROR; + if (format != NULL) { + va_list ap; + va_start(ap, format); + char *message = g_strdup_vprintf(format, ap); + va_end(ap); + message_append(uf, message); + g_free(message); + } +} + +void ufraw_set_warning(ufraw_data *uf, const char *format, ...) +{ + // Set warning only if no error was set before + if (uf->status != UFRAW_ERROR) uf->status = UFRAW_WARNING; + if (format != NULL) { + va_list ap; + va_start(ap, format); + char *message = g_strdup_vprintf(format, ap); + va_end(ap); + message_append(uf, message); + g_free(message); + } +} + +void ufraw_set_info(ufraw_data *uf, const char *format, ...) +{ + if (format != NULL) { + va_list ap; + va_start(ap, format); + char *message = g_strdup_vprintf(format, ap); + va_end(ap); + message_append(uf, message); + g_free(message); + } +} + +int ufraw_get_status(ufraw_data *uf) +{ + return uf->status; +} + +int ufraw_is_error(ufraw_data *uf) +{ + return uf->status == UFRAW_ERROR; +} + +// Old error handling, should be removed after being fully implemented. + +static char *ufraw_message_buffer(char *buffer, char *message) +{ +#ifdef UFRAW_DEBUG + ufraw_batch_messenger(message); +#endif + char *buf; + if (buffer == NULL) return g_strdup(message); + buf = g_strconcat(buffer, message, NULL); + g_free(buffer); + return buf; +} + +void ufraw_batch_messenger(char *message) +{ + /* Print the 'ufraw:' header only if there are no newlines in the message + * (not including possibly one at the end). + * Otherwise, the header will be printed only for the first line. */ + if (g_strstr_len(message, strlen(message) - 1, "\n") == NULL) + g_printerr("%s: ", ufraw_binary); + g_printerr("%s%c", message, message[strlen(message) - 1] != '\n' ? '\n' : 0); +} + +char *ufraw_message(int code, const char *format, ...) +{ + // TODO: The following static variables are not thread-safe + static char *logBuffer = NULL; + static char *errorBuffer = NULL; + static gboolean errorFlag = FALSE; + static void *parentWindow = NULL; + char *message = NULL; + void *saveParentWindow; + + if (code == UFRAW_SET_PARENT) { + saveParentWindow = parentWindow; + parentWindow = (void *)format; + return saveParentWindow; + } + if (format != NULL) { + va_list ap; + va_start(ap, format); + message = g_strdup_vprintf(format, ap); + va_end(ap); + } + switch (code) { + case UFRAW_SET_ERROR: + errorFlag = TRUE; + // fall through + case UFRAW_SET_WARNING: + errorBuffer = ufraw_message_buffer(errorBuffer, message); + // fall through + case UFRAW_SET_LOG: + case UFRAW_DCRAW_SET_LOG: + logBuffer = ufraw_message_buffer(logBuffer, message); + g_free(message); + return NULL; + case UFRAW_GET_ERROR: + if (!errorFlag) return NULL; + // fall through + case UFRAW_GET_WARNING: + return errorBuffer; + case UFRAW_GET_LOG: + return logBuffer; + case UFRAW_CLEAN: + g_free(logBuffer); + logBuffer = NULL; + // fall through + case UFRAW_RESET: + g_free(errorBuffer); + errorBuffer = NULL; + errorFlag = FALSE; + return NULL; + case UFRAW_BATCH_MESSAGE: + if (parentWindow == NULL) + ufraw_messenger(message, parentWindow); + g_free(message); + return NULL; + case UFRAW_INTERACTIVE_MESSAGE: + if (parentWindow != NULL) + ufraw_messenger(message, parentWindow); + g_free(message); + return NULL; + case UFRAW_REPORT: + ufraw_messenger(errorBuffer, parentWindow); + return NULL; + default: + ufraw_messenger(message, parentWindow); + g_free(message); + return NULL; + } +} diff --git a/plugins/load-dcraw/ufraw_routines.c b/plugins/load-dcraw/ufraw_routines.c new file mode 100644 index 00000000..4fcbe100 --- /dev/null +++ b/plugins/load-dcraw/ufraw_routines.c @@ -0,0 +1,607 @@ +/* + * UFRaw - Unidentified Flying Raw converter for digital camera images + * + * ufraw_routines.c - general routines + * Copyright 2004-2016 by Udi Fuchs + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if defined(HAVE_CANONICALIZE_FILE_NAME) && !defined(_GNU_SOURCE) +#define _GNU_SOURCE /* needed for canonicalize_file_name() */ +#endif + +#include "ufraw.h" +#include +#include +#include +#include /* needed for canonicalize_file_name() */ +#include + +/* we start by some general purpose functions that mostly take care of + * making the rest of the code platform independ */ + +const char *uf_get_home_dir() +{ + const char *hd = g_get_home_dir(); + if (hd == NULL) +#ifdef _WIN32 + hd = "C:\\"; +#else + hd = "/"; +#endif + return hd; +} + +void uf_init_locale(const char *exename) +{ + const char *locale = setlocale(LC_ALL, ""); + /* Disable the Hebrew and Arabic locale, since the right-to-left setting + * does not go well with the preview window. */ + if (locale != NULL && + (!strncmp(locale, "he", 2) || !strncmp(locale, "iw", 2) || + !strncmp(locale, "ar", 2) || + !strncmp(locale, "Hebrew", 6) || !strncmp(locale, "Arabic", 6))) { + /* I'm not sure why the following doesn't work (on Windows at least) */ + /* locale = setlocale(LC_ALL, "C"); + * gtk_disable_setlocale(); */ + /* so I'm using setenv */ + g_setenv("LC_ALL", "C", TRUE); + } + /* Try getting the localedir from the environment */ + char *localedir = g_strconcat(g_getenv("UFRAW_LOCALEDIR"), NULL); + if (localedir == NULL) { + /* If that fails, there are two defaults: */ +#ifdef _WIN32 + /* In Windows the localedir is found relative to the exe file. + * The exact location here should match ufraw-setup.iss.in */ + char *basename = g_path_get_basename(exename); + if (strcasecmp(basename, "ufraw-gimp.exe") == 0) { + localedir = g_strconcat(g_path_get_dirname(exename), + "/../../../locale", NULL); + } else { + localedir = g_strconcat(g_path_get_dirname(exename), + "/../lib/locale", NULL); + } + g_free(basename); +#else + exename = exename; /* suppress warning */ + /* In other environments localedir is set at compile time */ + localedir = g_strconcat(UFRAW_LOCALEDIR, NULL); +#endif + } + bindtextdomain("ufraw", localedir); + g_free(localedir); + bind_textdomain_codeset("ufraw", "UTF-8"); + textdomain("ufraw"); +} + +char *uf_file_set_type(const char *filename, const char *type) +{ + char *infile = (char *)filename, *outfile, *tmpfile = NULL, *dotPosition; + if ((dotPosition = strrchr(infile, '.')) == NULL) { + outfile = g_strconcat(infile, type, NULL); + return outfile; + } + if (strcasecmp(dotPosition, ".gz") == 0 || + strcasecmp(dotPosition, ".bz2") == 0) { + char *tmpfile = g_strndup(infile, dotPosition - infile); + if ((dotPosition = strrchr(tmpfile, '.')) == NULL) { + outfile = g_strconcat(tmpfile, type, NULL); + g_free(tmpfile); + return outfile; + } + infile = tmpfile; + } + outfile = g_new(char, dotPosition - infile + strlen(type) + 1); + g_strlcpy(outfile, infile, dotPosition - infile + 1); + g_strlcpy(outfile + (dotPosition - infile), type, strlen(type) + 1); + g_free(tmpfile); + return outfile; +} + +/* Make sure filename has asolute path */ +char *uf_file_set_absolute(const char *filename) +{ + if (g_path_is_absolute(filename)) { + return g_strdup(filename); + } else { +#ifdef HAVE_CANONICALIZE_FILE_NAME + // canonicalize_file_name() requires the file to exist. + // This is why we need to split 'filename' to dirname and basename. + char *path = g_path_get_dirname(filename); + char *canon = canonicalize_file_name(path); + if (canon == NULL) { + // We should never reach this code + g_message("Error in canonicalize_file_name(""%s""): %s", + path, strerror(errno)); + g_free(path); + return g_strdup(filename); + } + // If filename ends with a separator there is no basename + if (strlen(path) == strlen(filename) - 1) { + g_free(path); + return canon; + } + g_free(path); + char *base = g_path_get_basename(filename); + char *abs = g_build_filename(canon, base, NULL); + g_free(base); + g_free(canon); + return abs; +#else + // We could use realpath(filename, NULL) + // if we add a check that it is not buggy + // This code does not remove '/./' or '/../' + char *cd = g_get_current_dir(); + char *fn = g_build_filename(cd, filename, NULL); + g_free(cd); + return fn; +#endif + } +} + +char *uf_markup_buf(char *buffer, const char *format, ...) +{ + va_list ap; + va_start(ap, format); + char *line = g_markup_vprintf_escaped(format, ap); + va_end(ap); + if (buffer == NULL) { + return line; + } else { + char *buf; + buf = g_strconcat(buffer, line, NULL); + g_free(line); + g_free(buffer); + return buf; + } +} + +const char raw_ext[] = "3fr,ari,arw,cap,cine,cr2,crw,cs1,dc2,dcr,dng,erf,fff," + "hdr,ia,iiq,jpeg,jpg,k25,kc2,kdc,mdc,mef,mos,mrw,nef," + "nrw,orf,ori,pef,pxn,qtk,r3d,raf,raw,rdc,rw2,rwl,sr2," + "srf,srw,sti,tif,tiff,ufraw,x3f"; + +const char *file_type[] = { ".ppm", ".ppm", ".tif", ".tif", ".jpg", + ".png", ".png", ".embedded.jpg", ".embedded.png", + ".fits" + }; + +/* Set locale of LC_NUMERIC to "C" to make sure that printf behaves correctly.*/ +char *uf_set_locale_C() +{ + char *locale = NULL; + char *test = g_markup_printf_escaped("%.1f", 1234.5); + if (strcmp(test, "1234.5") != 0) { + locale = setlocale(LC_NUMERIC, NULL); + if (locale != NULL) { + locale = g_strdup(locale); + } else { + ufraw_message(UFRAW_ERROR, _("Fatal error setting C locale")); + } + setlocale(LC_NUMERIC, "C"); + g_free(test); + test = g_markup_printf_escaped("%.1f", 1234.5); + if (strcmp(test, "1234.5") != 0) { + ufraw_message(UFRAW_ERROR, _("Fatal error setting C locale")); + if (locale != NULL) { + setlocale(LC_NUMERIC, locale); + g_free(locale); + locale = NULL; + } + } + } + g_free(test); + return locale; +} + +void uf_reset_locale(char *locale) +{ + if (locale == NULL) + return; + setlocale(LC_NUMERIC, locale); + g_free(locale); +} + +double profile_default_linear(profile_data *p) +{ + if (!strcmp(p->name, "No profile") + || !strcmp(p->name, "Color matrix")) + return 0.1; + else + return 0.0; +} + +double profile_default_gamma(profile_data *p) +{ + if (!strcmp(p->name, "No profile") + || !strcmp(p->name, "Color matrix") + || !strncmp(p->productName, "Nikon D", 7) + || !strncmp(p->productName, "Adobe RGB (1998)", 16)) + return 0.45; + else + return 1.0; +} + +/* Convert between Temperature and RGB. + * Base on information from http://www.brucelindbloom.com/ + * The fit for D-illuminant between 4000K and 23000K are from CIE + * The generalization to 2000K < T < 4000K and the blackbody fits + * are my own and should be taken with a grain of salt. + */ +static const double XYZ_to_RGB[3][3] = { + { 3.24071, -0.969258, 0.0556352 }, + { -1.53726, 1.87599, -0.203996 }, + { -0.498571, 0.0415557, 1.05707 } +}; + +void Temperature_to_RGB(double T, double RGB[3]) +{ + int c; + double xD, yD, X, Y, Z, max; + // Fit for CIE Daylight illuminant + if (T <= 4000) { + xD = 0.27475e9 / (T * T * T) - 0.98598e6 / (T * T) + 1.17444e3 / T + 0.145986; + } else if (T <= 7000) { + xD = -4.6070e9 / (T * T * T) + 2.9678e6 / (T * T) + 0.09911e3 / T + 0.244063; + } else { + xD = -2.0064e9 / (T * T * T) + 1.9018e6 / (T * T) + 0.24748e3 / T + 0.237040; + } + yD = -3 * xD * xD + 2.87 * xD - 0.275; + + // Fit for Blackbody using CIE standard observer function at 2 degrees + //xD = -1.8596e9/(T*T*T) + 1.37686e6/(T*T) + 0.360496e3/T + 0.232632; + //yD = -2.6046*xD*xD + 2.6106*xD - 0.239156; + + // Fit for Blackbody using CIE standard observer function at 10 degrees + //xD = -1.98883e9/(T*T*T) + 1.45155e6/(T*T) + 0.364774e3/T + 0.231136; + //yD = -2.35563*xD*xD + 2.39688*xD - 0.196035; + + X = xD / yD; + Y = 1; + Z = (1 - xD - yD) / yD; + max = 0; + for (c = 0; c < 3; c++) { + RGB[c] = X * XYZ_to_RGB[0][c] + Y * XYZ_to_RGB[1][c] + Z * XYZ_to_RGB[2][c]; + if (RGB[c] > max) max = RGB[c]; + } + for (c = 0; c < 3; c++) RGB[c] = RGB[c] / max; +} + +void RGB_to_Temperature(double RGB[3], double *T, double *Green) +{ + double Tmax, Tmin, testRGB[3]; + Tmin = 2000; + Tmax = 23000; + for (*T = (Tmax + Tmin) / 2; Tmax - Tmin > 0.1; *T = (Tmax + Tmin) / 2) { + Temperature_to_RGB(*T, testRGB); + if (testRGB[2] / testRGB[0] > RGB[2] / RGB[0]) + Tmax = *T; + else + Tmin = *T; + } + *Green = (testRGB[1] / testRGB[0]) / (RGB[1] / RGB[0]); + if (*Green < 0.2) *Green = 0.2; + if (*Green > 2.5) *Green = 2.5; +} + +static void curve_parse_start(GMarkupParseContext *context, + const gchar *element, const gchar **names, const gchar **values, + gpointer user, GError **error) +{ + CurveData *c = user; + int int_value; + GQuark ufrawQuark = g_quark_from_static_string("UFRaw"); + + context = context; + while (*names != NULL) { + sscanf(*values, "%d", &int_value); + if (!strcmp(element, "Curve") && !strcmp(*names, "Version")) { + /* We never changed the curve format so we support all + * previous versions */ + if (int_value > conf_default.version) + g_set_error(error, ufrawQuark, UFRAW_RC_VERSION, + _("Curve version is not supported")); + } + names++; + values++; + } + if (!strcmp("Curve", element)) { + /* m_gamma==-1 marks that we are inside a XML Curve block. + * This is ok since we never set m_gamma. */ + c->m_gamma = -1.0; + /* m_numAnchors==0 marks that no anchors where read from the XML */ + c->m_numAnchors = 0; + } +} + +static void curve_parse_end(GMarkupParseContext *context, const gchar *element, + gpointer user, GError **error) +{ + CurveData *c = user; + context = context; + error = error; + if (!strcmp("Curve", element)) { + c->m_gamma = conf_default.curve[0].m_gamma; + if (c->m_numAnchors == 0) + c->m_numAnchors = conf_default.curve[0].m_numAnchors; + } +} + +static void curve_parse_text(GMarkupParseContext *context, const gchar *text, + gsize len, gpointer user, GError **error) +{ + CurveData *c = user; + const gchar *element = g_markup_parse_context_get_element(context); + char temp[max_path]; + error = error; + for (; len > 0 && g_ascii_isspace(*text); len--, text++); + for (; len > 0 && g_ascii_isspace(text[len - 1]); len--); + if (len == 0) return; + if (len > max_path - 1) len = max_path - 1; + strncpy(temp, text, len); + temp[len] = '\0'; + if (!strcmp("Curve", element)) { + g_strlcpy(c->name, temp, max_name); + } + /* A negative gamma marks that we are in a Curve XML block */ + if (c->m_gamma < 0) { + if (!strcmp("MinXY", element)) { + sscanf(temp, "%lf %lf", &c->m_min_x, &c->m_min_y); + c->m_min_x = LIM(c->m_min_x, 0, 1); + c->m_min_y = LIM(c->m_min_y, 0, 1); + } + if (!strcmp("MaxXY", element)) { + sscanf(temp, "%lf %lf", &c->m_max_x, &c->m_max_y); + c->m_max_x = LIM(c->m_max_x, 0, 1); + c->m_max_y = LIM(c->m_max_y, 0, 1); + } + if (!strcmp("AnchorXY", element)) { + /* If one anchor is supplied then all anchors should be supplied */ + sscanf(temp, "%lf %lf", + &c->m_anchors[c->m_numAnchors].x, + &c->m_anchors[c->m_numAnchors].y); + c->m_anchors[c->m_numAnchors].x = + LIM(c->m_anchors[c->m_numAnchors].x, 0, 1); + c->m_anchors[c->m_numAnchors].y = + LIM(c->m_anchors[c->m_numAnchors].y, 0, 1); + c->m_numAnchors++; + } + } +} + +int curve_load(CurveData *cp, char *filename) +{ + NikonData data; + + if (!strcasecmp(filename + strlen(filename) - 4, ".ntc") || + !strcasecmp(filename + strlen(filename) - 4, ".ncv")) { + /* Try loading ntc/ncv files */ + if (LoadNikonData(filename, &data) != UFRAW_SUCCESS) { + ufraw_message(UFRAW_ERROR, _("Invalid Nikon curve file '%s'"), + filename); + return UFRAW_ERROR; + } + *cp = data.curves[TONE_CURVE]; + } else { + /* Load UFRaw's curve file format */ + char line[max_path], *locale; + FILE *in; + GMarkupParser parser = {&curve_parse_start, &curve_parse_end, + &curve_parse_text, NULL, NULL + }; + GMarkupParseContext *context; + GError *err = NULL; + + *cp = conf_default.curve[0]; + if ((in = g_fopen(filename, "r")) == NULL) { + ufraw_message(UFRAW_ERROR, _("Error opening Curve file '%s': %s"), + filename, strerror(errno)); + return UFRAW_ERROR; + } + locale = uf_set_locale_C(); + context = g_markup_parse_context_new(&parser, 0, cp, NULL); + line[max_path - 1] = '\0'; + if (fgets(line, max_path - 1, in) == NULL && !feof(in)) { + ufraw_message(UFRAW_ERROR, _("Error reading from file '%s'."), + filename); + uf_reset_locale(locale); + fclose(in); + return UFRAW_ERROR; + } + while (!feof(in)) { + if (!g_markup_parse_context_parse(context, line, + strlen(line), &err)) { + ufraw_message(UFRAW_ERROR, _("Error parsing '%s'\n%s"), + filename, err->message); + g_markup_parse_context_free(context); + uf_reset_locale(locale); + fclose(in); + g_error_free(err); + return UFRAW_ERROR; + } + if (fgets(line, max_path, in) == NULL && !feof(in)) { + ufraw_message(UFRAW_ERROR, _("Error reading from file '%s'."), + filename); + uf_reset_locale(locale); + fclose(in); + return UFRAW_ERROR; + } + } + g_markup_parse_context_end_parse(context, NULL); + g_markup_parse_context_free(context); + uf_reset_locale(locale); + fclose(in); + } + char *base = g_path_get_basename(filename); + char *name = uf_file_set_type(base, ""); + char *utf8 = g_filename_display_name(name); + g_strlcpy(cp->name, utf8, max_name); + g_free(utf8); + g_free(name); + g_free(base); + return UFRAW_SUCCESS; +} + +int curve_save(CurveData *cp, char *filename) +{ + int nikon_file_type = -1; + + /* Try saving ntc/ncv format */ + if (!strcasecmp(filename + strlen(filename) - 4, ".ntc")) + nikon_file_type = NTC_FILE; + else if (!strcasecmp(filename + strlen(filename) - 4, ".ncv")) + nikon_file_type = NCV_FILE; + + //if it's ntc or ncv + if (nikon_file_type != -1) { + NikonData data; + + //clear it out + memset(&data, 0, sizeof(NikonData)); + + data.curves[TONE_CURVE] = *cp; + + if (SaveNikonDataFile(&data, filename, nikon_file_type) + != UFRAW_SUCCESS) { + ufraw_message(UFRAW_ERROR, _("Invalid Nikon curve file '%s'"), + filename); + return UFRAW_ERROR; + } + } else { + /* Save UFRaw's curve format */ + FILE *out; + + if ((out = g_fopen(filename, "w")) == NULL) { + ufraw_message(UFRAW_ERROR, _("Error opening file '%s': %s"), + filename, g_strerror(errno)); + return UFRAW_ERROR; + } + char *locale = uf_set_locale_C(); + fprintf(out, "\n"); + char *base = g_path_get_basename(filename); + char *name = uf_file_set_type(base, ""); + char *utf8 = g_filename_display_name(name); + fprintf(out, "%s\n", conf_default.version, utf8); + g_free(utf8); + g_free(name); + g_free(base); + char *buf = curve_buffer(cp); + if (buf != NULL) fprintf(out, "%s", buf); + g_free(buf); + fprintf(out, "\n"); + uf_reset_locale(locale); + fclose(out); + } + return UFRAW_SUCCESS; +} + +char *curve_buffer(CurveData *c) +{ + char *buf = NULL; + int i; + if (c->m_min_x != conf_default.curve[0].m_min_x || + c->m_min_y != conf_default.curve[0].m_min_y || + c->m_max_x != conf_default.curve[0].m_max_x || + c->m_max_y != conf_default.curve[0].m_max_y) { + buf = uf_markup_buf(buf, + "\t%lf %lf\n", c->m_min_x, c->m_min_y); + buf = uf_markup_buf(buf, + "\t%lf %lf\n", c->m_max_x, c->m_max_y); + } + if (c->m_numAnchors != conf_default.curve[0].m_numAnchors || + c->m_anchors[0].x != conf_default.curve[0].m_anchors[0].x || + c->m_anchors[0].y != conf_default.curve[0].m_anchors[0].y || + c->m_anchors[1].x != conf_default.curve[0].m_anchors[1].x || + c->m_anchors[1].y != conf_default.curve[0].m_anchors[1].y) { + for (i = 0; i < c->m_numAnchors; i++) + buf = uf_markup_buf(buf, + "\t%lf %lf\n", + c->m_anchors[i].x, c->m_anchors[i].y); + } + return buf; +} + +int ptr_array_insert_sorted( + GPtrArray *array, const void *item, GCompareFunc compare) +{ + int length = array->len; + g_ptr_array_set_size(array, length + 1); + const void **root = (const void **)array->pdata; + + int m = 0, l = 0, r = length - 1; + + // Skip trailing NULL, if any + if (l <= r && !root [r]) + r--; + + while (l <= r) { + m = (l + r) / 2; + int cmp = compare(root [m], item); + + if (cmp == 0) { + ++m; + goto done; + } else if (cmp < 0) + l = m + 1; + else + r = m - 1; + } + if (r == m) + m++; + +done: + memmove(root + m + 1, root + m, (length - m) * sizeof(void *)); + root [m] = item; + return m; +} + +int ptr_array_find_sorted( + const GPtrArray *array, const void *item, GCompareFunc compare) +{ + int length = array->len; + void **root = array->pdata; + + int l = 0, r = length - 1; + int m = 0, cmp = 0; + + if (!length) + return -1; + + // Skip trailing NULL, if any + if (!root [r]) + r--; + + while (l <= r) { + m = (l + r) / 2; + cmp = compare(root [m], item); + + if (cmp == 0) + return m; + else if (cmp < 0) + l = m + 1; + else + r = m - 1; + } + + return -1; +} + +void ptr_array_insert_index( + GPtrArray *array, const void *item, int index) +{ + const void **root; + int length = array->len; + g_ptr_array_set_size(array, length + 1); + root = (const void **)array->pdata; + memmove(root + index + 1, root + index, (length - index) * sizeof(void *)); + root [index] = item; +} diff --git a/plugins/load-dcraw/ufraw_settings.cc b/plugins/load-dcraw/ufraw_settings.cc new file mode 100644 index 00000000..5076ec91 --- /dev/null +++ b/plugins/load-dcraw/ufraw_settings.cc @@ -0,0 +1,510 @@ +/* + * UFRaw - Unidentified Flying Raw converter for digital camera images + * + * ufraw_settings.cc - define all UFObject settings. + * Copyright 2004-2016 by Udi Fuchs + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ufraw.h" +#include "dcraw_api.h" +#include +#include +#include + +namespace UFRaw +{ + +// Shortcut for UFString definitions +#define UF_STRING(Class, Name, String, ...) \ + extern "C" { UFName Name = String; } \ + class Class : public UFString { \ + public: \ + Class() : UFString(Name, __VA_ARGS__) { } \ + } +// We could have also used a template: +/* +template + class UF_STRING : public UFString { + public: + UF_STRING() : UFString(name) { } + }; + +typedef UF_STRING UFCameraMake; +*/ + +// Shortcut for UFNumber definitions +#define UF_NUMBER(Class, Name, String, ...) \ + extern "C" { UFName Name = String; } \ + class Class : public UFNumber { \ + public: \ + Class() : UFNumber(Name, __VA_ARGS__) { } \ + } + +// ufRawImage is short for 'raw image processing parameters'. +extern "C" { + UFName ufRawImage = "Image"; +} +// Common class for Image and CommandLineImage +class ImageCommon : public UFGroup +{ +private: +public: + // uf should be private + ufraw_data *uf; + ImageCommon() : UFGroup(ufRawImage), uf(NULL) { } +}; + +class Image : public ImageCommon +{ +private: +public: + explicit Image(UFObject *root = NULL); + void SetUFRawData(ufraw_data *data); + static ufraw_data *UFRawData(UFObject *object) { + if (object->Name() == ufRawImage) + return dynamic_cast(object)->uf; + if (!object->HasParent()) + return NULL; + return Image::UFRawData(&object->Parent()); + } + void SetWB(const char *mode = NULL); + void Message(const char *Format, ...) const { + if (Format == NULL) + return; + va_list ap; + va_start(ap, Format); + char *message = g_strdup_vprintf(Format, ap); + va_end(ap); + ufraw_message(UFRAW_ERROR, "%s: %s\n", Name(), message); + g_free(message); + } +}; + +static Image &ParentImage(UFObject *obj) +{ + return static_cast(obj->Parent()); +} + +//UF_STRING(CameraMake, ufCameraMake, "Make", ""); + +extern "C" { + UFName ufWB = "WB"; +} +extern "C" { + UFName ufPreset = "Preset"; +} +class WB : public UFArray +{ +public: + WB() : UFArray(ufWB, uf_camera_wb) { } + void Event(UFEventType type) { + // spot_wb is a temporary value, that would be changed in SetWB() + if (!this->IsEqual(uf_spot_wb)) + UFObject::Event(type); + } + void OriginalValueChangedEvent() { + /* Keep compatibility with old numbers from ufraw-0.6 */ + int i; + if (strlen(StringValue()) <= 2 && + sscanf(StringValue(), "%d", &i) == 1) { + switch (i) { + case -1: + Set(uf_spot_wb); + break; + case 0: + Set(uf_manual_wb); + break; + case 1: + Set(uf_camera_wb); + break; + case 2: + Set(uf_auto_wb); + break; + case 3: + Set("Incandescent"); + break; + case 4: + Set("Fluorescent"); + break; + case 5: + Set("Direct sunlight"); + break; + case 6: + Set("Flash"); + break; + case 7: + Set("Cloudy"); + break; + case 8: + Set("Shade"); + break; + default: + Set(""); + } + } + if (HasParent()) + ParentImage(this).SetWB(); + } + // Use the original XML format instead of UFArray's format. + // Output XML block even if IsDefault(). + std::string XML(const char *indent) const { + char *value = g_markup_escape_text(StringValue(), -1); + std::string str = (std::string)indent + + "<" + Name() + ">" + value + "\n"; + g_free(value); + return str; + } +}; + +extern "C" { + UFName ufWBFineTuning = "WBFineTuning"; +} +class WBFineTuning : public UFNumber +{ +public: + WBFineTuning() : UFNumber(ufWBFineTuning, -9, 9, 0, 0, 1, 1) { } + void OriginalValueChangedEvent() { + if (!HasParent()) + return; + UFArray &wb = ParentImage(this)[ufWB]; + if (wb.IsEqual(uf_auto_wb) || wb.IsEqual(uf_camera_wb)) + /* Prevent recalculation of Camera/Auto WB on WBTuning events */ + Set(0.0); + else + ParentImage(this).SetWB(); + } + // Output XML block even if IsDefault(). + std::string XML(const char *indent) const { + char *value = g_markup_escape_text(StringValue(), -1); + std::string str = (std::string)indent + + "<" + Name() + ">" + value + "\n"; + g_free(value); + return str; + } +}; + +extern "C" { + UFName ufTemperature = "Temperature"; +} +class Temperature : public UFNumber +{ +public: + Temperature() : UFNumber(ufTemperature, 2000, 23000, 6500, 0, 50, 200) { } + void OriginalValueChangedEvent() { + if (HasParent()) + ParentImage(this).SetWB(uf_manual_wb); + } +}; + +extern "C" { + UFName ufGreen = "Green"; +} +class Green : public UFNumber +{ +public: + Green() : UFNumber(ufGreen, 0.2, 2.5, 1.0, 3, 0.01, 0.05) { }; + void OriginalValueChangedEvent() { + if (HasParent()) + ParentImage(this).SetWB(uf_manual_wb); + } +}; + +extern "C" { + UFName ufChannelMultipliers = "ChannelMultipliers"; +} +class ChannelMultipliers : public UFNumberArray +{ +public: + ChannelMultipliers() : UFNumberArray(ufChannelMultipliers, 4, + 0.010, 99.000, 1.0, 3, 0.001, + 0.001) { }; + void Event(UFEventType type) { + if (type != uf_value_changed) + return UFObject::Event(type); + if (!HasParent()) + return UFObject::Event(type); + ufraw_data *uf = Image::UFRawData(this); + if (uf == NULL) + return UFObject::Event(type); + /* Normalize chanMul so that min(chanMul) will be 1.0 */ + double min = Maximum(); + for (int c = 0; c < uf->colors; c++) + if (DoubleValue(c) < min) + min = DoubleValue(c); + assert(min > 0.0); + double chanMulArray[4] = { 1.0, 1.0, 1.0, 1.0 }; + for (int c = 0; c < uf->colors; c++) + chanMulArray[c] = DoubleValue(c) / min; + Set(chanMulArray); + + if (uf->conf->autoExposure == enabled_state) + uf->conf->autoExposure = apply_state; + if (uf->conf->autoBlack == enabled_state) + uf->conf->autoBlack = apply_state; + + UFObject::Event(type); + } + void OriginalValueChangedEvent() { + if (HasParent()) + ParentImage(this).SetWB(uf_spot_wb); + } + // Output XML block even if IsDefault(). + std::string XML(const char *indent) const { + std::string str = ""; + char num[10]; + for (int i = 0; i < Size(); i++) { + g_snprintf(num, 10, "%.6lf", DoubleValue(i)); + str += num; + if (i < Size() - 1) + str += " "; + } + char *value = g_markup_escape_text(str.c_str(), -1); + str = (std::string)indent + + "<" + Name() + ">" + value + "\n"; + g_free(value); + return str; + } +}; + +extern "C" { + UFName ufLensfunAuto = "LensfunAuto"; +} +class LensfunAuto : public UFString +{ +public: + LensfunAuto() : UFString(ufLensfunAuto, "yes") { } + void OriginalValueChangedEvent() { + if (!HasParent()) + return; + if (IsEqual("auto")) { + Set("yes"); + return; + } + if (IsEqual("none")) { + Set("no"); + return; + } + if (!IsEqual("yes") && !IsEqual("no")) + Throw("Invalid value '%s'", StringValue()); +#ifdef HAVE_LENSFUN + if (!Parent().Has(ufLensfun)) + return; + if (IsEqual("yes")) + ufraw_lensfun_init(&Parent()[ufLensfun], TRUE); +#endif + } +}; + +Image::Image(UFObject *root) : ImageCommon() +{ + *this + << new WB + << new WBFineTuning + << new Temperature + << new Green + << new ChannelMultipliers + ; +#ifdef HAVE_LENSFUN + *this << new LensfunAuto; + if (root == NULL || root->Name() != ufRawResources) + *this << ufraw_lensfun_new(); // Lensfun data is not saved to .ufrawrc +#else + (void)root; +#endif +} + +void Image::SetWB(const char *mode) +{ + UFArray &wb = (*this)[ufWB]; + if (wb.IsEqual(uf_manual_wb) || wb.IsEqual(uf_camera_wb) || + wb.IsEqual(uf_auto_wb) || wb.IsEqual(uf_spot_wb)) { + if (!Has(ufWBFineTuning)) + *this << new WBFineTuning; + UFNumber &wbTuning = (*this)[ufWBFineTuning]; + wbTuning.Set(0.0); + } + // While loading rc/cmd/conf data we do not want to alter the raw data. + if (uf == NULL) + return; + if (uf->rgbMax == 0) { // Raw file was not loaded yet. + if (!wb.IsEqual(uf_manual_wb)) + uf->WBDirty = true; // ChannelMultipliers should be calculated later + return; + } + if (mode != NULL) + wb.Set(mode); + ufraw_set_wb(uf, TRUE); + if (wb.IsEqual(uf_spot_wb)) + wb.Set(uf_manual_wb); +} + +void Image::SetUFRawData(ufraw_data *data) +{ + uf = data; + if (uf == NULL) + return; + + dcraw_data *raw = static_cast(uf->raw); + if (strcasecmp(uf->conf->make, raw->make) != 0 || + strcasecmp(uf->conf->model, raw->model) != 0) + uf->WBDirty = TRUE; // Re-calculate channel multipliers. + if (uf->LoadingID) + uf->WBDirty = TRUE; // Re-calculate channel multipliers. + g_strlcpy(uf->conf->make, raw->make, max_name); + g_strlcpy(uf->conf->model, raw->model, max_name); + if (!uf->LoadingID) + uf->WBDirty = TRUE; // Re-calculate channel multipliers. + + const wb_data *lastPreset = NULL; + uf->wb_presets_make_model_match = FALSE; + char model[max_name]; + if (strcasecmp(uf->conf->make, "Minolta") == 0 && + (strncmp(uf->conf->model, "ALPHA", 5) == 0 || + strncmp(uf->conf->model, "MAXXUM", 6) == 0)) { + /* Canonize Minolta model names (copied from dcraw) */ + g_snprintf(model, max_name, "DYNAX %s", + uf->conf->model + 6 + (uf->conf->model[0] == 'M')); + } else { + g_strlcpy(model, uf->conf->model, max_name); + } + UFArray &wb = (*this)[ufWB]; + for (int i = 0; i < wb_preset_count; i++) { + if (strcasecmp(wb_preset[i].make, "") == 0) { + /* Common presets */ + if (strcmp(wb_preset[i].name, uf_camera_wb) == 0) { + // Get the camera's presets. + int status = dcraw_set_color_scale(raw, TRUE); + // Failure means that dcraw does not support this model. + if (status != DCRAW_SUCCESS) { + if (wb.IsEqual(uf_camera_wb)) { + ufraw_message(UFRAW_SET_LOG, + _("Cannot use camera white balance, " + "reverting to auto white balance.\n")); + wb.Set(uf_auto_wb); + } + continue; + } + } + wb << new UFString(ufPreset, wb_preset[i].name); + } else if (strcasecmp(wb_preset[i].make, uf->conf->make) == 0 && + strcasecmp(wb_preset[i].model, model) == 0) { + /* Camera specific presets */ + uf->wb_presets_make_model_match = TRUE; + if (lastPreset == NULL || + strcmp(wb_preset[i].name, lastPreset->name) != 0) { + wb << new UFString(ufPreset, wb_preset[i].name); + } + lastPreset = &wb_preset[i]; + } + } +} + +extern "C" { + UFName ufRawResources = "Resources"; +} +class Resources : public UFGroup +{ +public: + Resources(): UFGroup(ufRawResources) { + *this << new Image(this); + } +}; + +class CommandLineImage : public ImageCommon +{ +public: + CommandLineImage(): ImageCommon() { } + void Event(UFEventType type) { + if (type != uf_element_added) + return UFObject::Event(type); + if (Has(ufTemperature) || Has(ufGreen)) { + if (Has(ufWB)) { + UFArray &wb = (*this)[ufWB]; + if (!wb.IsEqual(uf_manual_wb) && !wb.IsEqual(uf_camera_wb)) { + ufraw_message(UFRAW_WARNING, + _("--temperature and --green options override " + "the --wb=%s option."), wb.StringValue()); + } + } else { + *this << new WB; + } + (*this)[ufWB].Set(uf_manual_wb); + } else { + if (Has(ufWB)) { + // We don't have green or temperature so this must be from --wb + UFArray &wb = (*this)[ufWB]; + if (wb.IsEqual(uf_auto_wb) || wb.IsEqual(uf_camera_wb)) + return UFObject::Event(type); + if (wb.IsEqual("camera")) + wb.Set(uf_camera_wb); + else if (wb.IsEqual("auto")) + wb.Set(uf_auto_wb); + else + Throw(_("'%s' is not a valid white balance setting."), + wb.StringValue()); + } + } + return UFObject::Event(type); + } +}; + +extern "C" { + UFName ufCommandLine = "CommandLine"; +} +class CommandLine : public UFGroup +{ +public: + CommandLine(): UFGroup(ufCommandLine) { + *this << new CommandLineImage; + } + void Message(const char *Format, ...) const { + if (Format == NULL) + return; + va_list ap; + va_start(ap, Format); + char *message = g_strdup_vprintf(Format, ap); + va_end(ap); + ufraw_message(UFRAW_ERROR, "%s: %s\n", Name(), message); + g_free(message); + } +}; + +} // namespace UFRaw + +extern "C" { + + UFObject *ufraw_image_new() + { + return new UFRaw::Image; + } + + void ufraw_image_set_data(UFObject *obj, struct ufraw_struct *uf) + { + dynamic_cast(obj)->SetUFRawData(uf); + } + + struct ufraw_struct *ufraw_image_get_data(UFObject *obj) + { + return UFRaw::Image::UFRawData(obj); + } + + UFObject *ufraw_resources_new() + { + return new UFRaw::Resources; + } + + UFObject *ufraw_command_line_new() + { + return new UFRaw::CommandLine; + } + +} // extern "C" diff --git a/plugins/load-dcraw/ufraw_ufraw.c b/plugins/load-dcraw/ufraw_ufraw.c new file mode 100644 index 00000000..197d5198 --- /dev/null +++ b/plugins/load-dcraw/ufraw_ufraw.c @@ -0,0 +1,2388 @@ +/* + * UFRaw - Unidentified Flying Raw converter for digital camera images + * + * ufraw_ufraw.c - program interface to all the components + * Copyright 2004-2016 by Udi Fuchs + * + * 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. + */ + +#include "ufraw.h" +#include "dcraw_api.h" +#ifdef HAVE_LENSFUN +#include +#endif +#include +#include +#include /* for fstat() */ +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_LIBZ +#include +#endif +#ifdef HAVE_LIBBZ2 +#include +#endif + +void (*ufraw_progress)(int what, int ticks) = NULL; + +#ifdef HAVE_LENSFUN +#define UF_LF_TRANSFORM ( \ + LF_MODIFY_DISTORTION | LF_MODIFY_GEOMETRY | LF_MODIFY_SCALE) +static void ufraw_convert_image_vignetting(ufraw_data *uf, + ufraw_image_data *img, UFRectangle *area); +static void ufraw_convert_image_tca(ufraw_data *uf, ufraw_image_data *img, + ufraw_image_data *outimg, + UFRectangle *area); +void ufraw_prepare_tca(ufraw_data *uf); +#endif +static void ufraw_image_format(int *colors, int *bytes, ufraw_image_data *img, + const char *formats, const char *caller); +static void ufraw_convert_image_raw(ufraw_data *uf, UFRawPhase phase); +static void ufraw_convert_image_first(ufraw_data *uf, UFRawPhase phase); +static void ufraw_convert_image_transform(ufraw_data *uf, ufraw_image_data *img, + ufraw_image_data *outimg, UFRectangle *area); +static void ufraw_convert_prepare_first_buffer(ufraw_data *uf, + ufraw_image_data *img); +static void ufraw_convert_prepare_transform_buffer(ufraw_data *uf, + ufraw_image_data *img, int width, int height); +static void ufraw_convert_reverse_wb(ufraw_data *uf, UFRawPhase phase); +static void ufraw_convert_import_buffer(ufraw_data *uf, UFRawPhase phase, + dcraw_image_data *dcimg); + +static int make_temporary(char *basefilename, char **tmpfilename) +{ + int fd; + char *basename = g_path_get_basename(basefilename); + char *template = g_strconcat(basename, ".tmp.XXXXXX", NULL); + fd = g_file_open_tmp(template, tmpfilename, NULL); + g_free(template); + g_free(basename); + return fd; +} + +static ssize_t writeall(int fd, const char *buf, ssize_t size) +{ + ssize_t written; + ssize_t wr; + for (written = 0; size > 0; size -= wr, written += wr, buf += wr) + if ((wr = write(fd, buf, size)) < 0) + break; + return written; +} + +static char *decompress_gz(char *origfilename) +{ +#ifdef HAVE_LIBZ + char *tempfilename; + int tmpfd; + gzFile gzfile; + char buf[8192]; + ssize_t size; + if ((tmpfd = make_temporary(origfilename, &tempfilename)) == -1) + return NULL; + char *filename = uf_win32_locale_filename_from_utf8(origfilename); + gzfile = gzopen(filename, "rb"); + uf_win32_locale_filename_free(filename); + if (gzfile != NULL) { + while ((size = gzread(gzfile, buf, sizeof buf)) > 0) { + if (writeall(tmpfd, buf, size) != size) + break; + } + gzclose(gzfile); + if (size == 0) + if (close(tmpfd) == 0) + return tempfilename; + } + close(tmpfd); + g_unlink(tempfilename); + g_free(tempfilename); + return NULL; +#else + (void)origfilename; + ufraw_message(UFRAW_SET_ERROR, + "Cannot open gzip compressed images.\n"); + return NULL; +#endif +} + +static char *decompress_bz2(char *origfilename) +{ +#ifdef HAVE_LIBBZ2 + char *tempfilename; + int tmpfd; + FILE *compfile; + BZFILE *bzfile; + int bzerror; + char buf[8192]; + ssize_t size; + + if ((tmpfd = make_temporary(origfilename, &tempfilename)) == -1) + return NULL; + compfile = g_fopen(origfilename, "rb"); + if (compfile != NULL) { + if ((bzfile = BZ2_bzReadOpen(&bzerror, compfile, 0, 0, 0, 0)) != 0) { + while ((size = BZ2_bzRead(&bzerror, bzfile, buf, sizeof buf)) > 0) + if (writeall(tmpfd, buf, size) != size) + break; + BZ2_bzReadClose(&bzerror, bzfile); + fclose(compfile); + if (size == 0) { + close(tmpfd); + return tempfilename; + } + } + } + close(tmpfd); + g_unlink(tempfilename); + g_free(tempfilename); + return NULL; +#else + (void)origfilename; + ufraw_message(UFRAW_SET_ERROR, + "Cannot open bzip2 compressed images.\n"); + return NULL; +#endif +} + +ufraw_data *ufraw_open(char *filename) +{ + int status; + ufraw_data *uf; + dcraw_data *raw; + ufraw_message(UFRAW_CLEAN, NULL); + conf_data *conf = NULL; + char *fname, *hostname; + char *origfilename; + gchar *unzippedBuf = NULL; + gsize unzippedBufLen = 0; + + fname = g_filename_from_uri(filename, &hostname, NULL); + if (fname != NULL) { + if (hostname != NULL) { + ufraw_message(UFRAW_SET_ERROR, _("Remote URI is not supported")); + g_free(hostname); + g_free(fname); + return NULL; + } + g_strlcpy(filename, fname, max_path); + g_free(fname); + } + /* First handle ufraw ID files. */ + if (strcasecmp(filename + strlen(filename) - 6, ".ufraw") == 0) { + conf = g_new(conf_data, 1); + status = conf_load(conf, filename); + if (status != UFRAW_SUCCESS) { + g_free(conf); + return NULL; + } + + /* If inputFilename and outputFilename have the same path, + * then inputFilename is searched for in the path of the ID file. + * This allows moving raw and ID files together between folders. */ + char *inPath = g_path_get_dirname(conf->inputFilename); + char *outPath = g_path_get_dirname(conf->outputFilename); + if (strcmp(inPath, outPath) == 0) { + char *path = g_path_get_dirname(filename); + char *inName = g_path_get_basename(conf->inputFilename); + char *inFile = g_build_filename(path, inName , NULL); + if (g_file_test(inFile, G_FILE_TEST_EXISTS)) { + g_strlcpy(conf->inputFilename, inFile, max_path); + } + g_free(path); + g_free(inName); + g_free(inFile); + } + g_free(inPath); + g_free(outPath); + + /* Output image should be created in the path of the ID file */ + char *path = g_path_get_dirname(filename); + g_strlcpy(conf->outputPath, path, max_path); + g_free(path); + + filename = conf->inputFilename; + } + origfilename = filename; + if (!strcasecmp(filename + strlen(filename) - 3, ".gz")) + filename = decompress_gz(filename); + else if (!strcasecmp(filename + strlen(filename) - 4, ".bz2")) + filename = decompress_bz2(filename); + if (filename == 0) { + ufraw_message(UFRAW_SET_ERROR, + "Error creating temporary file for compressed data."); + return NULL; + } + raw = g_new(dcraw_data, 1); + status = dcraw_open(raw, filename); + if (filename != origfilename) { + g_file_get_contents(filename, &unzippedBuf, &unzippedBufLen, NULL); + g_unlink(filename); + g_free(filename); + filename = origfilename; + } + if (status != DCRAW_SUCCESS) { + /* Hold the message without displaying it */ + ufraw_message(UFRAW_SET_WARNING, raw->message); + if (status != DCRAW_WARNING) { + g_free(raw); + g_free(unzippedBuf); + return NULL; + } + } + uf = g_new0(ufraw_data, 1); + ufraw_message_init(uf); + uf->rgbMax = 0; // This indicates that the raw file was not loaded yet. + uf->unzippedBuf = unzippedBuf; + uf->unzippedBufLen = unzippedBufLen; + uf->conf = conf; + g_strlcpy(uf->filename, filename, max_path); + int i; + for (i = ufraw_raw_phase; i < ufraw_phases_num; i++) { + uf->Images[i].buffer = NULL; + uf->Images[i].width = 0; + uf->Images[i].height = 0; + uf->Images[i].valid = 0; + uf->Images[i].invalidate_event = TRUE; + } + uf->thumb.buffer = NULL; + uf->raw = raw; + uf->colors = raw->colors; + uf->raw_color = raw->raw_color; + uf->developer = NULL; + uf->AutoDeveloper = NULL; + uf->displayProfile = NULL; + uf->displayProfileSize = 0; + uf->RawHistogram = NULL; + uf->HaveFilters = raw->filters != 0; + uf->IsXTrans = raw->filters == 9; +#ifdef HAVE_LENSFUN + uf->modFlags = 0; + uf->TCAmodifier = NULL; + uf->modifier = NULL; +#endif + uf->inputExifBuf = NULL; + uf->outputExifBuf = NULL; + ufraw_message(UFRAW_SET_LOG, "ufraw_open: w:%d h:%d curvesize:%d\n", + raw->width, raw->height, raw->toneCurveSize); + + return uf; +} + +int ufraw_load_darkframe(ufraw_data *uf) +{ + if (strlen(uf->conf->darkframeFile) == 0) + return UFRAW_SUCCESS; + if (uf->conf->darkframe != NULL) { + // If the same file was already openned, there is nothing to do. + if (strcmp(uf->conf->darkframeFile, uf->conf->darkframe->filename) == 0) + return UFRAW_SUCCESS; + // Otherwise we need to close the previous darkframe + ufraw_close_darkframe(uf->conf); + } + ufraw_data *dark = uf->conf->darkframe = + ufraw_open(uf->conf->darkframeFile); + if (dark == NULL) { + ufraw_message(UFRAW_ERROR, _("darkframe error: %s is not a raw file\n"), + uf->conf->darkframeFile); + uf->conf->darkframeFile[0] = '\0'; + return UFRAW_ERROR; + } + dark->conf = g_new(conf_data, 1); + conf_init(dark->conf); + /* initialize ufobject member */ + dark->conf->ufobject = ufraw_image_new(); + /* disable all auto settings on darkframe */ + dark->conf->autoExposure = disabled_state; + dark->conf->autoBlack = disabled_state; + if (ufraw_load_raw(dark) != UFRAW_SUCCESS) { + ufraw_message(UFRAW_ERROR, _("error loading darkframe '%s'\n"), + uf->conf->darkframeFile); + ufraw_close(dark); + g_free(dark); + uf->conf->darkframe = NULL; + uf->conf->darkframeFile[0] = '\0'; + return UFRAW_ERROR; + } + // Make sure the darkframe matches the main data + dcraw_data *raw = uf->raw; + dcraw_data *darkRaw = dark->raw; + if (raw->width != darkRaw->width || + raw->height != darkRaw->height || + raw->colors != darkRaw->colors) { + ufraw_message(UFRAW_WARNING, + _("Darkframe '%s' is incompatible with main image"), + uf->conf->darkframeFile); + ufraw_close(dark); + g_free(dark); + uf->conf->darkframe = NULL; + uf->conf->darkframeFile[0] = '\0'; + return UFRAW_ERROR; + } + ufraw_message(UFRAW_BATCH_MESSAGE, _("using darkframe '%s'\n"), + uf->conf->darkframeFile); + /* Calculate dark frame hot pixel thresholds as the 99.99th percentile + * value. That is, the value at which 99.99% of the pixels are darker. + * Pixels below this threshold are considered to be bias noise, and + * those above are "hot". */ + int color; + int i; + long frequency[65536]; + long sum; + long point = darkRaw->raw.width * darkRaw->raw.height / 10000; + + for (color = 0; color < darkRaw->raw.colors; ++color) { + memset(frequency, 0, sizeof frequency); + for (i = 0; i < darkRaw->raw.width * darkRaw->raw.height; ++i) + frequency[darkRaw->raw.image[i][color]]++; + for (sum = 0, i = 65535; i > 1; --i) { + sum += frequency[i]; + if (sum >= point) + break; + } + darkRaw->thresholds[color] = i + 1; + } + return UFRAW_SUCCESS; +} + +// Get the dimensions of the unshrunk, rotated image.autoCrop +// The crop coordinates are calculated based on these dimensions. +void ufraw_get_image_dimensions(ufraw_data *uf) +{ + dcraw_image_dimensions(uf->raw, uf->conf->orientation, 1, + &uf->initialHeight, &uf->initialWidth); + + ufraw_get_image(uf, ufraw_transform_phase, FALSE); + + if (uf->conf->fullCrop || uf->conf->CropX1 < 0) uf->conf->CropX1 = 0; + if (uf->conf->fullCrop || uf->conf->CropY1 < 0) uf->conf->CropY1 = 0; + if (uf->conf->fullCrop || uf->conf->CropX2 < 0) uf->conf->CropX2 = uf->rotatedWidth; + if (uf->conf->fullCrop || uf->conf->CropY2 < 0) uf->conf->CropY2 = uf->rotatedHeight; + + if (uf->conf->fullCrop) + uf->conf->aspectRatio = (double)uf->rotatedWidth / uf->rotatedHeight; + else if (uf->conf->aspectRatio <= 0) { + if (uf->conf->autoCrop) + /* preserve the initial aspect ratio - this should be consistent + with ufraw_convert_prepare_transform */ + uf->conf->aspectRatio = ((double)uf->initialWidth) / uf->initialHeight; + else + /* full rotated image / manually entered crop */ + uf->conf->aspectRatio = ((double)uf->conf->CropX2 - uf->conf->CropX1) + / (uf->conf->CropY2 - uf->conf->CropY1); + } else { + /* given aspectRatio */ + int cropWidth = uf->conf->CropX2 - uf->conf->CropX1; + int cropHeight = uf->conf->CropY2 - uf->conf->CropY1; + + if (cropWidth != (int)floor(cropHeight * uf->conf->aspectRatio + 0.5)) { + /* aspectRatio does not match the crop area - shrink the area */ + + if ((double)cropWidth / cropHeight > uf->conf->aspectRatio) { + cropWidth = floor(cropHeight * uf->conf->aspectRatio + 0.5); + uf->conf->CropX1 = (uf->conf->CropX1 + uf->conf->CropX2 - cropWidth) / 2; + uf->conf->CropX2 = uf->conf->CropX1 + cropWidth; + } else { + cropHeight = floor(cropWidth / uf->conf->aspectRatio + 0.5); + uf->conf->CropY1 = (uf->conf->CropY1 + uf->conf->CropY2 - cropHeight) / 2; + uf->conf->CropY2 = uf->conf->CropY1 + cropHeight; + } + } + } +} + +/* Get scaled crop coordinates in final image coordinates */ +void ufraw_get_scaled_crop(ufraw_data *uf, UFRectangle *crop) +{ + ufraw_image_data *img = ufraw_get_image(uf, ufraw_transform_phase, FALSE); + + float scale_x = ((float)img->width) / uf->rotatedWidth; + float scale_y = ((float)img->height) / uf->rotatedHeight; + crop->x = MAX(floor(uf->conf->CropX1 * scale_x), 0); + int x2 = MIN(ceil(uf->conf->CropX2 * scale_x), img->width); + crop->width = x2 - crop->x; + crop->y = MAX(floor(uf->conf->CropY1 * scale_y), 0); + int y2 = MIN(ceil(uf->conf->CropY2 * scale_y), img->height); + crop->height = y2 - crop->y; +} + +int ufraw_config(ufraw_data *uf, conf_data *rc, conf_data *conf, conf_data *cmd) +{ + int status; + + if (rc->autoExposure == enabled_state) rc->autoExposure = apply_state; + if (rc->autoBlack == enabled_state) rc->autoBlack = apply_state; + + g_assert(uf != NULL); + + /* Check if we are loading an ID file */ + if (uf->conf != NULL) { + /* ID file configuration is put "on top" of the rc data */ + uf->LoadingID = TRUE; + conf_data tmp = *rc; + tmp.ufobject = uf->conf->ufobject; + conf_copy_image(&tmp, uf->conf); + conf_copy_transform(&tmp, uf->conf); + conf_copy_save(&tmp, uf->conf); + g_strlcpy(tmp.outputFilename, uf->conf->outputFilename, max_path); + g_strlcpy(tmp.outputPath, uf->conf->outputPath, max_path); + *uf->conf = tmp; + } else { + uf->LoadingID = FALSE; + uf->conf = g_new(conf_data, 1); + *uf->conf = *rc; + uf->conf->ufobject = ufraw_image_new(); + ufobject_copy(uf->conf->ufobject, + ufgroup_element(rc->ufobject, ufRawImage)); + } + if (conf != NULL && conf->version != 0) { + conf_copy_image(uf->conf, conf); + conf_copy_save(uf->conf, conf); + if (uf->conf->autoExposure == enabled_state) + uf->conf->autoExposure = apply_state; + if (uf->conf->autoBlack == enabled_state) + uf->conf->autoBlack = apply_state; + } + if (cmd != NULL) { + status = conf_set_cmd(uf->conf, cmd); + if (status != UFRAW_SUCCESS) return status; + } + dcraw_data *raw = uf->raw; + if (ufobject_name(uf->conf->ufobject) != ufRawImage) + g_warning("uf->conf->ufobject is not a ufRawImage"); + /*Reset EXIF data text fields to avoid spill over between images.*/ + strcpy(uf->conf->isoText, ""); + strcpy(uf->conf->shutterText, ""); + strcpy(uf->conf->apertureText, ""); + strcpy(uf->conf->focalLenText, ""); + strcpy(uf->conf->focalLen35Text, ""); + strcpy(uf->conf->lensText, ""); + strcpy(uf->conf->flashText, ""); + // lensText is used in ufraw_lensfun_init() + if (!uf->conf->embeddedImage) { + if (ufraw_exif_read_input(uf) != UFRAW_SUCCESS) { + ufraw_message(UFRAW_SET_LOG, "Error reading EXIF data from %s\n", + uf->filename); + // If exiv2 fails to read the EXIF data, use the EXIF tags read + // by dcraw. + g_strlcpy(uf->conf->exifSource, "DCRaw", max_name); + uf->conf->iso_speed = raw->iso_speed; + g_snprintf(uf->conf->isoText, max_name, "%d", + (int)uf->conf->iso_speed); + uf->conf->shutter = raw->shutter; + if (uf->conf->shutter > 0 && uf->conf->shutter < 1) + g_snprintf(uf->conf->shutterText, max_name, "1/%0.1f s", + 1 / uf->conf->shutter); + else + g_snprintf(uf->conf->shutterText, max_name, "%0.1f s", + uf->conf->shutter); + uf->conf->aperture = raw->aperture; + g_snprintf(uf->conf->apertureText, max_name, "F/%0.1f", + uf->conf->aperture); + uf->conf->focal_len = raw->focal_len; + g_snprintf(uf->conf->focalLenText, max_name, "%0.1f mm", + uf->conf->focal_len); + } + } + ufraw_image_set_data(uf->conf->ufobject, uf); +#ifdef HAVE_LENSFUN + // Do not reset lensfun settings while loading ID. + UFBoolean reset = !uf->LoadingID; + if (conf != NULL && conf->version > 0 && conf->ufobject != NULL) { + UFObject *conf_lensfun_auto = ufgroup_element(conf->ufobject, + ufLensfunAuto); + // Do not reset lensfun settings from conf file. + if (ufstring_is_equal(conf_lensfun_auto, "no")) + reset = FALSE; + } + ufraw_lensfun_init(ufgroup_element(uf->conf->ufobject, ufLensfun), reset); +#endif + + char *absname = uf_file_set_absolute(uf->filename); + g_strlcpy(uf->conf->inputFilename, absname, max_path); + g_free(absname); + if (!uf->LoadingID) { + g_snprintf(uf->conf->inputURI, max_path, "file://%s", + uf->conf->inputFilename); + struct stat s; + fstat(fileno(raw->ifp), &s); + g_snprintf(uf->conf->inputModTime, max_name, "%d", (int)s.st_mtime); + } + if (strlen(uf->conf->outputFilename) == 0) { + /* If output filename wasn't specified use input filename */ + char *filename = uf_file_set_type(uf->filename, + file_type[uf->conf->type]); + if (strlen(uf->conf->outputPath) > 0) { + char *cp = g_path_get_basename(filename); + g_free(filename); + filename = g_build_filename(uf->conf->outputPath, cp , NULL); + g_free(cp); + } + g_strlcpy(uf->conf->outputFilename, filename, max_path); + g_free(filename); + } + g_free(uf->unzippedBuf); + uf->unzippedBuf = NULL; + /* Set the EXIF data */ +#ifdef __MINGW32__ + /* MinG32 does not have ctime_r(). */ + g_strlcpy(uf->conf->timestampText, ctime(&raw->timestamp), max_name); +#elif defined(__sun) && !defined(_POSIX_PTHREAD_SEMANTICS) /* Solaris */ + /* + * Some versions of Solaris followed a draft POSIX.1c standard + * where ctime_r took a third length argument. + */ + ctime_r(&raw->timestamp, uf->conf->timestampText, + sizeof(uf->conf->timestampText)); +#else + /* POSIX.1c version of ctime_r() */ + ctime_r(&raw->timestamp, uf->conf->timestampText); +#endif + if (uf->conf->timestampText[strlen(uf->conf->timestampText) - 1] == '\n') + uf->conf->timestampText[strlen(uf->conf->timestampText) - 1] = '\0'; + + uf->conf->timestamp = raw->timestamp; + + uf->conf->CameraOrientation = raw->flip; + + if (!uf->conf->rotate) { + uf->conf->orientation = 0; + uf->conf->rotationAngle = 0; + } else { + if (!uf->LoadingID || uf->conf->orientation < 0) + uf->conf->orientation = uf->conf->CameraOrientation; + // Normalise rotations to a flip, then rotation of 0 < a < 90 degrees. + ufraw_normalize_rotation(uf); + } + /* If there is an embeded curve we "turn on" the custom/camera curve + * mechanism */ + if (raw->toneCurveSize != 0) { + CurveData nc; + long pos = ftell(raw->ifp); + if (RipNikonNEFCurve(raw->ifp, raw->toneCurveOffset, &nc, NULL) + != UFRAW_SUCCESS) { + ufraw_message(UFRAW_ERROR, _("Error reading NEF curve")); + return UFRAW_WARNING; + } + fseek(raw->ifp, pos, SEEK_SET); + if (nc.m_numAnchors < 2) nc = conf_default.BaseCurve[0]; + + g_strlcpy(nc.name, uf->conf->BaseCurve[custom_curve].name, max_name); + uf->conf->BaseCurve[custom_curve] = nc; + + int use_custom_curve = 0; + if (raw->toneModeSize) { + // "AUTO " "HIGH " "CS " "MID.L " "MID.H "NORMAL " "LOW " + long pos = ftell(raw->ifp); + char buf[9]; + fseek(raw->ifp, raw->toneModeOffset, SEEK_SET); + // read it in. + size_t num = fread(&buf, 9, 1, raw->ifp); + if (num != 1) + // Maybe this should be a UFRAW_WARNING + ufraw_message(UFRAW_SET_LOG, + "Warning: tone mode fread %d != %d\n", num, 1); + fseek(raw->ifp, pos, SEEK_SET); + + if (!strncmp(buf, "CS ", sizeof(buf))) use_custom_curve = 1; + + // down the line, we need to translate the other values into + // tone curves! + } + + if (use_custom_curve) { + uf->conf->BaseCurve[camera_curve] = + uf->conf->BaseCurve[custom_curve]; + g_strlcpy(uf->conf->BaseCurve[camera_curve].name, + conf_default.BaseCurve[camera_curve].name, max_name); + } else { + uf->conf->BaseCurve[camera_curve] = + conf_default.BaseCurve[camera_curve]; + } + } else { + /* If there is no embeded curve we "turn off" the custom/camera curve + * mechanism */ + uf->conf->BaseCurve[camera_curve].m_numAnchors = 0; + uf->conf->BaseCurve[custom_curve].m_numAnchors = 0; + if (uf->conf->BaseCurveIndex == custom_curve || + uf->conf->BaseCurveIndex == camera_curve) + uf->conf->BaseCurveIndex = linear_curve; + } + ufraw_load_darkframe(uf); + + ufraw_get_image_dimensions(uf); + + return UFRAW_SUCCESS; +} + +/* Scale pixel values: occupy 16 bits to get more precision. In addition + * this normalizes the pixel values which is good for non-linear algorithms + * which forget to check rgbMax or assume a particular value. */ +static unsigned ufraw_scale_raw(dcraw_data *raw) +{ + guint16 *p, *end; + int scale; + + scale = 0; + while ((raw->rgbMax << 1) <= 0xffff) { + raw->rgbMax <<= 1; + ++scale; + } + if (scale) { + end = (guint16 *)(raw->raw.image + raw->raw.width * raw->raw.height); + /* OpenMP overhead appears to be too large in this case */ + int max = 0x10000 >> scale; + for (p = (guint16 *)raw->raw.image; p < end; ++p) + if (*p < max) + *p <<= scale; + else + *p = 0xffff; + raw->black <<= scale; + } + return 1 << scale; +} + +int ufraw_load_raw(ufraw_data *uf) +{ + int status; + dcraw_data *raw = uf->raw; + + if (uf->conf->embeddedImage) { + dcraw_image_data thumb; + if ((status = dcraw_load_thumb(raw, &thumb)) != DCRAW_SUCCESS) { + ufraw_message(status, raw->message); + return status; + } + uf->thumb.height = thumb.height; + uf->thumb.width = thumb.width; + return ufraw_read_embedded(uf); + } + if ((status = dcraw_load_raw(raw)) != DCRAW_SUCCESS) { + ufraw_message(UFRAW_SET_LOG, raw->message); + ufraw_message(status, raw->message); + if (status != DCRAW_WARNING) return status; + } + uf->HaveFilters = raw->filters != 0; + uf->raw_multiplier = ufraw_scale_raw(raw); + /* Canon EOS cameras require special exposure normalization */ + if (strcasecmp(uf->conf->make, "Canon") == 0 && + strncmp(uf->conf->model, "EOS", 3) == 0) { + int c, max = raw->cam_mul[0]; + for (c = 1; c < raw->colors; c++) max = MAX(raw->cam_mul[c], max); + /* Camera multipliers in DNG file are normalized to 1. + * Therefore, they can not be used to normalize exposure. + * Also, for some Canon DSLR cameras dcraw cannot read the + * camera multipliers (1D for example). */ + if (max < 100) { + uf->conf->ExposureNorm = 0; + ufraw_message(UFRAW_SET_LOG, "Failed to normalizing exposure\n"); + } else { + /* Convert exposure value from old ID files from before + * ExposureNorm */ + if (uf->LoadingID && uf->conf->ExposureNorm == 0) + uf->conf->exposure -= log(1.0 * raw->rgbMax / max) / log(2); + uf->conf->ExposureNorm = max * raw->rgbMax / 4095; + ufraw_message(UFRAW_SET_LOG, + "Exposure Normalization set to %d (%.2f EV)\n", + uf->conf->ExposureNorm, + log(1.0 * raw->rgbMax / uf->conf->ExposureNorm) / log(2)); + } + /* FUJIFILM cameras have a special tag for exposure normalization */ + } else if (strcasecmp(uf->conf->make, "FUJIFILM") == 0) { + if (raw->fuji_dr == 0) { + uf->conf->ExposureNorm = 0; + } else { + int c, max = raw->cam_mul[0]; + for (c = 1; c < raw->colors; c++) max = MAX(raw->cam_mul[c], max); + if (uf->LoadingID && uf->conf->ExposureNorm == 0) + uf->conf->exposure -= log(1.0 * raw->rgbMax / max) / log(2); + uf->conf->ExposureNorm = (int)(1.0 * raw->rgbMax * pow(2, (double)raw->fuji_dr / 100)); + ufraw_message(UFRAW_SET_LOG, + "Exposure Normalization set to %d (%.2f EV)\n", + uf->conf->ExposureNorm, -(float)raw->fuji_dr / 100); + } + } else { + uf->conf->ExposureNorm = 0; + } + uf->rgbMax = raw->rgbMax - raw->black; + memcpy(uf->rgb_cam, raw->rgb_cam, sizeof uf->rgb_cam); + + /* Foveon image dimensions are knows only after load_raw()*/ + ufraw_get_image_dimensions(uf); + if (uf->conf->CropX2 > uf->rotatedWidth) + uf->conf->CropX2 = uf->rotatedWidth; + if (uf->conf->CropY2 > uf->rotatedHeight) + uf->conf->CropY2 = uf->rotatedHeight; + + // Now we can finally calculate the channel multipliers. + if (uf->WBDirty) { + UFObject *wb = ufgroup_element(uf->conf->ufobject, ufWB); + char *oldWB = g_strdup(ufobject_string_value(wb)); + UFObject *wbTuning = ufgroup_element(uf->conf->ufobject, + ufWBFineTuning); + double oldTuning = ufnumber_value(wbTuning); + ufraw_set_wb(uf, FALSE); + /* Here ufobject's automation goes against us. A change in + * ChannelMultipliers might change ufWB to uf_manual_wb. + * So we need to change it back. */ + if (ufarray_is_equal(wb, uf_manual_wb)) + ufobject_set_string(wb, oldWB); + ufnumber_set(wbTuning, oldTuning); + g_free(oldWB); + } + ufraw_auto_expose(uf); + ufraw_auto_black(uf); + return UFRAW_SUCCESS; +} + +/* Free any darkframe associated with conf */ +void ufraw_close_darkframe(conf_data *conf) +{ + if (conf && conf->darkframe != NULL) { + ufraw_close(conf->darkframe); + g_free(conf->darkframe); + conf->darkframe = NULL; + conf->darkframeFile[0] = '\0'; + } +} + +void ufraw_close(ufraw_data *uf) +{ + dcraw_close(uf->raw); + g_free(uf->unzippedBuf); + g_free(uf->raw); + g_free(uf->inputExifBuf); + g_free(uf->outputExifBuf); + int i; + for (i = ufraw_raw_phase; i < ufraw_phases_num; i++) + g_free(uf->Images[i].buffer); + g_free(uf->thumb.buffer); + developer_destroy(uf->developer); + developer_destroy(uf->AutoDeveloper); + g_free(uf->displayProfile); + g_free(uf->RawHistogram); +#ifdef HAVE_LENSFUN + if (uf->TCAmodifier != NULL) + lf_modifier_destroy(uf->TCAmodifier); + if (uf->modifier != NULL) + lf_modifier_destroy(uf->modifier); +#endif + ufobject_delete(uf->conf->ufobject); + g_free(uf->conf); + ufraw_message_reset(uf); + ufraw_message(UFRAW_CLEAN, NULL); +} + +/* Return the coordinates and the size of given image subarea. + * There are always 32 subareas, numbered 0 to 31, ordered in a 4x8 matrix. + */ +UFRectangle ufraw_image_get_subarea_rectangle(ufraw_image_data *img, + unsigned saidx) +{ + int saw = (img->width + 3) / 4; + int sah = (img->height + 7) / 8; + int sax = saidx % 4; + int say = saidx / 4; + UFRectangle area; + area.x = saw * sax; + area.y = sah * say; + area.width = (sax < 3) ? saw : (img->width - saw * 3); + area.height = (say < 7) ? sah : (img->height - sah * 7); + return area; +} + +/* Return the subarea index given some X,Y image coordinates. + */ +unsigned ufraw_img_get_subarea_idx(ufraw_image_data *img, int x, int y) +{ + int saw = (img->width + 3) / 4; + int sah = (img->height + 7) / 8; + return (x / saw) + (y / sah) * 4; +} + +void ufraw_developer_prepare(ufraw_data *uf, DeveloperMode mode) +{ + int useMatrix = uf->conf->profileIndex[0] == 1 || uf->colors == 4; + + if (mode == auto_developer) { + if (uf->AutoDeveloper == NULL) + uf->AutoDeveloper = developer_init(); + developer_prepare(uf->AutoDeveloper, uf->conf, + uf->rgbMax, uf->rgb_cam, uf->colors, useMatrix, mode); + } else { + if (uf->developer == NULL) + uf->developer = developer_init(); + if (mode == display_developer) { + if (uf->conf->profileIndex[display_profile] != 0) { + g_free(uf->displayProfile); + uf->displayProfile = NULL; + } + developer_display_profile(uf->developer, uf->displayProfile, + uf->displayProfileSize, + uf->conf->profile[display_profile] + [uf->conf->profileIndex[display_profile]].productName); + } + developer_prepare(uf->developer, uf->conf, + uf->rgbMax, uf->rgb_cam, uf->colors, useMatrix, mode); + } +} + +int ufraw_convert_image(ufraw_data *uf) +{ + uf->mark_hotpixels = FALSE; + ufraw_developer_prepare(uf, file_developer); + ufraw_convert_image_raw(uf, ufraw_raw_phase); + + ufraw_image_data *img = &uf->Images[ufraw_first_phase]; + ufraw_convert_prepare_first_buffer(uf, img); + ufraw_convert_image_first(uf, ufraw_first_phase); + + UFRectangle area = { 0, 0, img->width, img->height }; + // prepare_transform has to be called before applying vignetting + ufraw_image_data *img2 = &uf->Images[ufraw_transform_phase]; + ufraw_convert_prepare_transform_buffer(uf, img2, img->width, img->height); +#ifdef HAVE_LENSFUN + if (uf->modifier != NULL) { + ufraw_convert_image_vignetting(uf, img, &area); + } +#endif + if (img2->buffer != NULL) { + area.width = img2->width; + area.height = img2->height; + /* Apply distortion, geometry and rotation */ + ufraw_convert_image_transform(uf, img, img2, &area); + g_free(img->buffer); + *img = *img2; + img2->buffer = NULL; + } + if (uf->conf->autoCrop && !uf->LoadingID) { + ufraw_get_image_dimensions(uf); + uf->conf->CropX1 = (uf->rotatedWidth - uf->autoCropWidth) / 2; + uf->conf->CropX2 = uf->conf->CropX1 + uf->autoCropWidth; + uf->conf->CropY1 = (uf->rotatedHeight - uf->autoCropHeight) / 2; + uf->conf->CropY2 = uf->conf->CropY1 + uf->autoCropHeight; + } + return UFRAW_SUCCESS; +} + +#ifdef HAVE_LENSFUN +static void ufraw_convert_image_vignetting(ufraw_data *uf, + ufraw_image_data *img, UFRectangle *area) +{ + /* Apply vignetting correction first, before distorting the image */ + if (uf->modFlags & LF_MODIFY_VIGNETTING) + lf_modifier_apply_color_modification( + uf->modifier, img->buffer, + area->x, area->y, area->width, area->height, + LF_CR_4(RED, GREEN, BLUE, UNKNOWN), img->rowstride); +} +#endif + +/* + ufraw_interpolate_pixel_linearly() + Interpolate a new pixel value, for one or all colors, from a 2x2 pixel + patch around coordinates x and y in the image, and write it to dst. +*/ +/* + Because integer arithmetic is faster than floating point operations, + on popular CISC architectures, we cast floats to 32 bit integers, + scaling them first will maintain sufficient precision. +*/ +#define SCALAR 256 + +static inline void ufraw_interpolate_pixel_linearly(ufraw_image_data *image, float x, float y, ufraw_image_type *dst, int color) +{ + + int i, j, c, cmax, xx, yy; + unsigned int dx, dy, v, weights[2][2]; + ufraw_image_type *src; + + /* + When casting a float to an integer it will be rounded toward zero, + that will cause problems when x or y is negative (along the top and + left border) so, we add 2 and subtract that later, using floor() + and round() is much slower. + */ + x += 2; + y += 2; + + xx = x; + yy = y; + + /* + Calculate weights for every pixel in the patch using the fractional + part of the coordinates. + */ + dx = (int)(x * SCALAR + 0.5) - (xx * SCALAR); + dy = (int)(y * SCALAR + 0.5) - (yy * SCALAR); + + weights[0][0] = (SCALAR - dy) * (SCALAR - dx); + weights[0][1] = (SCALAR - dy) * dx; + weights[1][0] = dy * (SCALAR - dx); + weights[1][1] = dy * dx; + + xx -= 2; + yy -= 2; + + src = (ufraw_image_type *)image->buffer + yy * image->width + xx; + + /* If an existing color number is given, then only that color will be interpolated, else all will be. */ + if (color < 0 || color >= (3 + (image->rgbg == TRUE))) + c = 0, cmax = 2 + (image->rgbg == TRUE); + else + c = cmax = color; + + /* Check if the source pixels are near a border, if they aren't we can use faster code. */ + if (xx >= 0 && yy >= 0 && xx + 1 < image->width && yy + 1 < image->height) { + + for (; c <= cmax ; c++) { + + v = 0; + + for (i = 0 ; i < 2 ; i++) + for (j = 0 ; j < 2 ; j++) + v += weights[i][j] * src[i * image->width + j][c]; + + dst[0][c] = v / (SCALAR * SCALAR); + } + + } else { /* Near a border. */ + + for (; c <= cmax ; c++) { + + v = 0; + + for (i = 0 ; i < 2 ; i++) + for (j = 0 ; j < 2 ; j++) + /* Check if the source pixel lies inside the image */ + if (xx + j >= 0 && yy + i >= 0 && xx + j < image->width && yy + i < image->height) + v += weights[i][j] * src[i * image->width + j][c]; + + dst[0][c] = v / (SCALAR * SCALAR); + } + } +} + +#undef SCALAR + + +/* Apply distortion, geometry and rotation in a single pass */ +static void ufraw_convert_image_transform(ufraw_data *uf, ufraw_image_data *img, + ufraw_image_data *outimg, UFRectangle *area) +{ + float sine = sin(uf->conf->rotationAngle * 2 * M_PI / 360); + float cosine = cos(uf->conf->rotationAngle * 2 * M_PI / 360); + + // If we rotate around the center: + // srcX = (X-outimg->width/2)*cosine + (Y-outimg->height/2)*sine; + // srcY = -(X-outimg->width/2)*sine + (Y-outimg->height/2)*cosine; + // Then the base offset is: + // baseX = img->width/2; + // baseY = img->height/2; + // Since we rotate around the top-left corner, the base offset is: + float baseX = img->width / 2 - outimg->width / 2 * cosine - outimg->height / 2 * sine; + float baseY = img->height / 2 + outimg->width / 2 * sine - outimg->height / 2 * cosine; +#ifdef HAVE_LENSFUN + gboolean applyLF = uf->modifier != NULL && (uf->modFlags & UF_LF_TRANSFORM); +#endif + int x, y; + for (y = area->y; y < area->y + area->height; y++) { + guint8 *cur0 = outimg->buffer + y * outimg->rowstride; + float srcX0 = y * sine + baseX; + float srcY0 = y * cosine + baseY; + for (x = area->x; x < area->x + area->width; x++) { + guint16 *cur = (guint16 *)(cur0 + x * outimg->depth); + float srcX = srcX0 + x * cosine; + float srcY = srcY0 - x * sine; +#ifdef HAVE_LENSFUN + if (applyLF) { + float buff[2]; + lf_modifier_apply_geometry_distortion(uf->modifier, + srcX, srcY, 1, 1, buff); + srcX = buff[0]; + srcY = buff[1]; + } +#endif + ufraw_interpolate_pixel_linearly(img, srcX, srcY, (ufraw_image_type *)cur, -1); + } + } +} + +/* + * A pixel with a significantly larger value than all of its four direct + * neighbours is considered "hot". It will be replaced by the maximum value + * of its neighbours. For simplicity border pixels are not considered. + * + * Reasonable values for uf->conf->hotpixel are in the range 0.5-10. + * + * Note that the algorithm uses pixel values from previous (processed) and + * next (unprocessed) row and whether or not pixels are marked may make a + * difference for the hot pixel count. + * + * Cleanup issue: + * - change prototype to void x(ufraw_data *uf, UFRawPhase phase) + * - use ufraw_image_format() + * - use uf->rgbMax (check, must be about 64k) + */ +static void ufraw_shave_hotpixels(ufraw_data *uf, dcraw_image_type *img, + int width, int height, int colors, + unsigned rgbMax) +{ + int w, h, c, i, count; + unsigned delta, t, v, hi; + dcraw_image_type *p; + + uf->hotpixels = 0; + if (uf->conf->hotpixel <= 0.0) + return; + delta = rgbMax / (uf->conf->hotpixel + 1.0); + count = 0; +#ifdef _OPENMP + #pragma omp parallel for schedule(static) \ + shared(uf,img,width,height,colors,rgbMax,delta) \ +reduction(+:count) \ + private(h,p,w,c,t,v,hi,i) +#endif + for (h = 1; h < height - 1; ++h) { + p = img + 1 + h * width; + for (w = 1; w < width - 1; ++w, ++p) { + for (c = 0; c < colors; ++c) { + t = p[0][c]; + if (t <= delta) + continue; + t -= delta; + v = p[-1][c]; + if (v > t) + continue; + hi = v; + v = p[1][c]; + if (v > t) + continue; + if (v > hi) + hi = v; + v = p[-width][c]; + if (v > t) + continue; + if (v > hi) + hi = v; + v = p[width][c]; + if (v > t) + continue; + if (v > hi) + hi = v; + /* mark the pixel using the original hot value */ + if (uf->mark_hotpixels) { + for (i = -10; i >= -20 && w + i >= 0; --i) + memcpy(p[i], p[0], sizeof(p[i])); + for (i = 10; i <= 20 && w + i < width; ++i) + memcpy(p[i], p[0], sizeof(p[i])); + } + p[0][c] = hi; + ++count; + } + } + } + uf->hotpixels = count; +} + +static void ufraw_despeckle_line(guint16 *base, int step, int size, int window, + double decay, int colors, int c) +{ + unsigned lum[size]; + int i, j, start, end, next, v, cold, hot, coldj, hotj, fix; + guint16 *p; + + if (colors == 4) { + for (i = 0; i < size; ++i) { + p = base + i * step; + lum[i] = (p[0] + p[1] + p[2] + p[3] - p[c]) / 3; + } + } else { + for (i = 0; i < size; ++i) { + p = base + i * step; + lum[i] = (p[0] + p[1] + p[2] - p[c]) / 2; + } + } + p = base + c; + for (i = 1 - window; i < size; i = next) { + start = i; + end = i + window; + if (start < 0) + start = 0; + if (end > size) + end = size; + cold = hot = p[start * step] - lum[start]; + coldj = hotj = start; + for (j = start + 1; j < end; ++j) { + v = p[j * step] - lum[j]; + if (v < cold) { + cold = v; + coldj = j; + } else if (v > hot) { + hot = v; + hotj = j; + } + } + if (cold < 0 && hot > 0) { + fix = -cold; + if (fix > hot) + fix = hot; + p[coldj * step] += fix; + p[hotj * step] -= fix; + hot -= fix; + } + if (hot > 0 && decay) + p[hotj * step] -= hot * decay; + next = coldj < hotj ? coldj : hotj; + if (next == start) + ++next; + } +} + +void ufraw_despeckle(ufraw_data *uf, UFRawPhase phase) +{ + ufraw_image_data *img = &uf->Images[phase]; + const int depth = img->depth / 2, rowstride = img->rowstride / 2; + int passes[4], pass, maxpass; + int win[4], i, c, colors; + guint16 *base; + double decay[4]; + + ufraw_image_format(&colors, NULL, img, "68", G_STRFUNC); + maxpass = 0; + for (c = 0; c < colors; ++c) { + win[c] = uf->conf->despeckleWindow[c < 3 ? c : 1] + 0.01; + decay[c] = uf->conf->despeckleDecay[c < 3 ? c : 1]; + passes[c] = uf->conf->despecklePasses[c < 3 ? c : 1] + 0.01; + if (!win[c]) + passes[c] = 0; + if (passes[c] > maxpass) + maxpass = passes[c]; + } + progress(PROGRESS_DESPECKLE, -maxpass * colors); + for (pass = maxpass - 1; pass >= 0; --pass) { + for (c = 0; c < colors; ++c) { + progress(PROGRESS_DESPECKLE, 1); + if (pass >= passes[c]) + continue; +#ifdef _OPENMP + #pragma omp parallel for default(shared) private(i,base) +#endif + for (i = 0; i < img->height; ++i) { + base = (guint16 *)img->buffer + i * rowstride; + ufraw_despeckle_line(base, depth, img->width, win[c], + decay[c], colors, c); + } +#ifdef _OPENMP + #pragma omp parallel for default(shared) private(i,base) +#endif + for (i = 0; i < img->width; ++i) { + base = (guint16 *)img->buffer + i * depth; + ufraw_despeckle_line(base, rowstride, img->height, win[c], + decay[c], colors, c); + } + } + } +} + +static gboolean ufraw_despeckle_active(ufraw_data *uf) +{ + int i; + gboolean active = FALSE; + + for (i = 0; i < 3; ++i) { + if (uf->conf->despeckleWindow[i] && uf->conf->despecklePasses[i]) + active = TRUE; + } + return active; +} + +static int ufraw_calculate_scale(ufraw_data *uf) +{ + /* In the first call to ufraw_calculate_scale() the crop coordinates + * are not set. They cannot be set, since uf->rotatedHeight/Width are + * only calculated later in ufraw_convert_prepare_transform_buffer(). + * Therefore, if size > 0, scale = 1 will be returned. + * Since the first call is from ufraw_convert_prepare_first_buffer(), + * this is not a real issue. There should always be a second call to + * this function before the actual buffer allocation. */ + dcraw_data *raw = uf->raw; + int scale = 1; + + /* We can do a simple interpolation in the following cases: + * We shrink by an integer value. + * If pixel_aspect<1 (e.g. NIKON D1X) shrink must be at least 4. */ + if (uf->conf->size == 0 && uf->conf->shrink > 1) { + scale = uf->conf->shrink * MIN(raw->pixel_aspect, 1 / raw->pixel_aspect); + } else if (uf->conf->interpolation == half_interpolation) { + scale = 2; + /* Wanted size is smaller than raw size (size is after a raw->shrink) + * (assuming there are filters). */ + } else if (uf->conf->size > 0 && uf->HaveFilters && !uf->IsXTrans) { + int cropHeight = uf->conf->CropY2 - uf->conf->CropY1; + int cropWidth = uf->conf->CropX2 - uf->conf->CropX1; + int cropSize = MAX(cropHeight, cropWidth); + if (cropSize / uf->conf->size >= 2) + scale = cropSize / uf->conf->size; + } + return scale; +} + +// Any change to ufraw_convertshrink() that might change the final image +// dimensions should also be applied to ufraw_convert_prepare_first_buffer(). +static void ufraw_convertshrink(ufraw_data *uf, dcraw_image_data *final) +{ + dcraw_data *raw = uf->raw; + int scale = ufraw_calculate_scale(uf); + + if (uf->HaveFilters && scale == 1) + dcraw_finalize_interpolate(final, raw, uf->conf->interpolation, + uf->conf->smoothing); + else + dcraw_finalize_shrink(final, raw, scale); + + dcraw_image_stretch(final, raw->pixel_aspect); + if (uf->conf->size == 0 && uf->conf->shrink > 1) { + dcraw_image_resize(final, + scale * MAX(final->height, final->width) / uf->conf->shrink); + } + if (uf->conf->size > 0) { + int finalSize = scale * MAX(final->height, final->width); + int cropSize; + if (uf->conf->CropX1 == -1) { + cropSize = finalSize; + } else { + int cropHeight = uf->conf->CropY2 - uf->conf->CropY1; + int cropWidth = uf->conf->CropX2 - uf->conf->CropX1; + cropSize = MAX(cropHeight, cropWidth); + } + // cropSize needs to be a integer multiplier of scale + cropSize = cropSize / scale * scale; + if (uf->conf->size > cropSize) { + ufraw_message(UFRAW_ERROR, _("Can not downsize from %d to %d."), + cropSize, uf->conf->size); + } else { + /* uf->conf->size holds the size of the cropped image. + * We need to calculate from it the desired size of + * the uncropped image. */ + dcraw_image_resize(final, uf->conf->size * finalSize / cropSize); + } + } +} + +/* + * Interface of ufraw_shave_hotpixels(), dcraw_finalize_raw() and preferably + * dcraw_wavelet_denoise() too should change to accept a phase argument and + * no longer require type casts. + */ +static void ufraw_convert_image_raw(ufraw_data *uf, UFRawPhase phase) +{ + ufraw_image_data *img = &uf->Images[phase]; + dcraw_data *dark = uf->conf->darkframe ? uf->conf->darkframe->raw : NULL; + dcraw_data *raw = uf->raw; + dcraw_image_type *rawimage; + + ufraw_convert_import_buffer(uf, phase, &raw->raw); + img->rgbg = raw->raw.colors == 4; + ufraw_shave_hotpixels(uf, (dcraw_image_type *)(img->buffer), img->width, + img->height, raw->raw.colors, raw->rgbMax); + rawimage = raw->raw.image; + raw->raw.image = (dcraw_image_type *)img->buffer; + /* The threshold is scaled for compatibility */ + if (!uf->IsXTrans) dcraw_wavelet_denoise(raw, uf->conf->threshold * sqrt(uf->raw_multiplier)); + dcraw_finalize_raw(raw, dark, uf->developer->rgbWB); + raw->raw.image = rawimage; + ufraw_despeckle(uf, phase); +#ifdef HAVE_LENSFUN + ufraw_prepare_tca(uf); + if (uf->TCAmodifier != NULL) { + ufraw_image_data inImg = *img; + img->buffer = g_malloc(img->height * img->rowstride); + UFRectangle area = {0, 0, img->width, img->height }; + ufraw_convert_image_tca(uf, &inImg, img, &area); + g_free(inImg.buffer); + } +#endif +} + +/* + * Interface of ufraw_convertshrink() and dcraw_flip_image() should change + * to accept a phase argument and no longer require type casts. + */ +static void ufraw_convert_image_first(ufraw_data *uf, UFRawPhase phase) +{ + ufraw_image_data *in = &uf->Images[phase - 1]; + ufraw_image_data *out = &uf->Images[phase]; + dcraw_data *raw = uf->raw; + + dcraw_image_data final; + final.image = (ufraw_image_type *)out->buffer; + + dcraw_image_type *rawimage = raw->raw.image; + raw->raw.image = (dcraw_image_type *)in->buffer; + ufraw_convertshrink(uf, &final); + raw->raw.image = rawimage; + dcraw_flip_image(&final, uf->conf->orientation); + /* The threshold is scaled for compatibility */ + if (uf->IsXTrans) dcraw_wavelet_denoise_shrinked(&final, uf->conf->threshold * sqrt(uf->raw_multiplier)); + + // The 'out' image contains the predicted image dimensions. + // We want to be sure that our predictions were correct. + if (out->height != final.height) { + g_warning("ufraw_convert_image_first: height mismatch %d!=%d", + out->height, final.height); + out->height = final.height; + } + if (out->width != final.width) { + g_warning("ufraw_convert_image_first: width mismatch %d!=%d", + out->width, final.width); + out->width = final.width; + } + out->depth = sizeof(dcraw_image_type); + out->rowstride = out->width * out->depth; + out->buffer = (guint8 *)final.image; + + ufraw_convert_reverse_wb(uf, phase); +} + +static void ufraw_convert_reverse_wb(ufraw_data *uf, UFRawPhase phase) +{ + ufraw_image_data *img = &uf->Images[phase]; + guint32 mul[4], px; + guint16 *p16; + int i, size, c; + + ufraw_image_format(NULL, NULL, img, "6", G_STRFUNC); + /* The speedup trick is to keep the non-constant (or ugly constant) + * divider out of the pixel iteration. If you really have to then + * use double division (can be much faster, apparently). */ + for (i = 0; i < uf->colors; ++i) + mul[i] = (guint64)0x10000 * 0x10000 / uf->developer->rgbWB[i]; + size = img->height * img->width; +#ifdef _OPENMP + #pragma omp parallel for schedule(static) \ + shared(uf,phase,img,mul,size) \ + private(i,p16,c,px) +#endif + for (i = 0; i < size; ++i) { + p16 = (guint16 *)&img->buffer[i * img->depth]; + for (c = 0; c < uf->colors; ++c) { + px = p16[c] * (guint64)mul[c] / 0x10000; + if (px > 0xffff) + px = 0xffff; + p16[c] = px; + } + } +} + +#ifdef HAVE_LENSFUN +/* Apply TCA */ +static void ufraw_convert_image_tca(ufraw_data *uf, ufraw_image_data *img, + ufraw_image_data *outimg, + UFRectangle *area) +{ + if (uf->TCAmodifier == NULL) + return; + int y; +#ifdef _OPENMP + #pragma omp parallel for schedule(static) \ + shared(uf,img,outimg,area) +#endif + for (y = area->y; y < area->y + area->height; y++) { + guint16 *dst = (guint16*)(outimg->buffer + y * outimg->rowstride + + area->x * outimg->depth); + ufraw_image_type *src = (ufraw_image_type *)(img->buffer + + y * img->rowstride + area->x * img->depth); + ufraw_image_type *srcEnd = (ufraw_image_type *)(img->buffer + + y * img->rowstride + (area->x + area->width) * img->depth); + float buff[3 * 2 * area->width]; + lf_modifier_apply_subpixel_distortion(uf->TCAmodifier, + area->x, y, area->width, 1, buff); + float *modcoord = buff; + for (; src < srcEnd; src++, dst += outimg->depth / 2) { + int c; + // Only red and blue channels get corrected + for (c = 0; c <= 2; c += 2, modcoord += 4) + ufraw_interpolate_pixel_linearly(img, modcoord[0], modcoord[1], (ufraw_image_type *)dst, c); + + modcoord -= 2; + // Green channels are intact + for (c = 1; c <= 3; c += 2) + dst[c] = src[0][c]; + } + } +} +#endif // HAVE_LENSFUN + +static void ufraw_convert_import_buffer(ufraw_data *uf, UFRawPhase phase, + dcraw_image_data *dcimg) +{ + ufraw_image_data *img = &uf->Images[phase]; + + img->height = dcimg->height; + img->width = dcimg->width; + img->depth = sizeof(dcraw_image_type); + img->rowstride = img->width * img->depth; + g_free(img->buffer); + img->buffer = g_memdup(dcimg->image, img->height * img->rowstride); +} + +static void ufraw_image_init(ufraw_image_data *img, + int width, int height, int bitdepth) +{ + if (img->height == height && img->width == width && + img->depth == bitdepth && img->buffer != NULL) + return; + + img->valid = 0; + img->height = height; + img->width = width; + img->depth = bitdepth; + img->rowstride = img->width * img->depth; + img->buffer = g_realloc(img->buffer, img->height * img->rowstride); +} + +static void ufraw_convert_prepare_first_buffer(ufraw_data *uf, + ufraw_image_data *img) +{ + // The actual buffer allocation is done in ufraw_convertshrink(). + int scale = ufraw_calculate_scale(uf); + dcraw_image_dimensions(uf->raw, uf->conf->orientation, scale, + &img->height, &img->width); + // The final resizing in ufraw_convertshrink() is calculate here: + if (uf->conf->size == 0 && uf->conf->shrink > 1) { + // This is the effect of first call to dcraw_image_resize(). + // It only relevant when raw->pixel_aspect != 1. + img->width = img->width * scale / uf->conf->shrink; + img->height = img->height * scale / uf->conf->shrink; + } + if (uf->conf->size > 0) { + int finalSize = scale * MAX(img->height, img->width); + int cropSize; + if (uf->conf->CropX1 == -1) { + cropSize = finalSize; + } else { + int cropHeight = uf->conf->CropY2 - uf->conf->CropY1; + int cropWidth = uf->conf->CropX2 - uf->conf->CropX1; + cropSize = MAX(cropHeight, cropWidth); + } + // cropSize needs to be a integer multiplier of scale + cropSize = cropSize / scale * scale; + if (uf->conf->size > cropSize) { + ufraw_message(UFRAW_ERROR, _("Can not downsize from %d to %d."), + cropSize, uf->conf->size); + } else { + /* uf->conf->size holds the size of the cropped image. + * We need to calculate from it the desired size of + * the uncropped image. */ + int mul = uf->conf->size * finalSize / cropSize; + int div = MAX(img->height, img->width); + img->height = img->height * mul / div; + img->width = img->width * mul / div; + } + } +} + +#ifdef HAVE_LENSFUN +void ufraw_convert_prepare_transform(ufraw_data *uf, + int width, int height, gboolean reverse, + float scale); +#endif + +static void ufraw_convert_prepare_transform_buffer(ufraw_data *uf, + ufraw_image_data *img, int width, int height) +{ + const int iWidth = uf->initialWidth; + const int iHeight = uf->initialHeight; + + double aspectRatio = uf->conf->aspectRatio; + + if (aspectRatio == 0) + aspectRatio = ((double)iWidth) / iHeight; + +#ifdef HAVE_LENSFUN + ufraw_convert_prepare_transform(uf, iWidth, iHeight, TRUE, 1.0); + if (uf->conf->rotationAngle == 0 && + (uf->modifier == NULL || !(uf->modFlags & UF_LF_TRANSFORM))) { +#else + if (uf->conf->rotationAngle == 0) { +#endif + g_free(img->buffer); + img->buffer = NULL; + img->width = width; + img->height = height; + // We still need the transform for vignetting +#ifdef HAVE_LENSFUN + ufraw_convert_prepare_transform(uf, width, height, FALSE, 1.0); +#endif + uf->rotatedWidth = iWidth; + uf->rotatedHeight = iHeight; + uf->autoCropWidth = iWidth; + uf->autoCropHeight = iHeight; + if ((double)uf->autoCropWidth / uf->autoCropHeight > aspectRatio) + uf->autoCropWidth = floor(uf->autoCropHeight * aspectRatio + 0.5); + else + uf->autoCropHeight = floor(uf->autoCropWidth / aspectRatio + 0.5); + + return; + } + const double sine = sin(uf->conf->rotationAngle * 2 * M_PI / 360); + const double cosine = cos(uf->conf->rotationAngle * 2 * M_PI / 360); + + const float midX = iWidth / 2.0 - 0.5; + const float midY = iHeight / 2.0 - 0.5; +#ifdef HAVE_LENSFUN + gboolean applyLF = uf->modifier != NULL && (uf->modFlags & UF_LF_TRANSFORM); +#endif + float maxX = 0, maxY = 0; + float minX = 999999, minY = 999999; + double lastX = 0, lastY = 0, area = 0; + int i; + for (i = 0; i < iWidth + iHeight - 1; i++) { + int x, y; + if (i < iWidth) { // Trace the left border of the image + x = i; + y = 0; + } else { // Trace the bottom border of the image + x = iWidth - 1; + y = i - iWidth + 1; + } + float buff[2]; +#ifdef HAVE_LENSFUN + if (applyLF) { + lf_modifier_apply_geometry_distortion(uf->modifier, + x, y, 1, 1, buff); + } else { + buff[0] = x; + buff[1] = y; + } +#else + buff[0] = x; + buff[1] = y; +#endif + double srcX = (buff[0] - midX) * cosine - (buff[1] - midY) * sine; + double srcY = (buff[0] - midX) * sine + (buff[1] - midY) * cosine; + // A digital planimeter: + area += srcY * lastX - srcX * lastY; + lastX = srcX; + lastY = srcY; + maxX = MAX(maxX, fabs(srcX)); + maxY = MAX(maxY, fabs(srcY)); + if (fabs(srcX / srcY) > aspectRatio) + minX = MIN(minX, fabs(srcX)); + else + minY = MIN(minY, fabs(srcY)); + } + float scale = sqrt((iWidth - 1) * (iHeight - 1) / area); + // Do not allow increasing canvas size by more than a factor of 2 + uf->rotatedWidth = MIN(ceil(2 * maxX + 1.0) * scale, 2 * iWidth); + uf->rotatedHeight = MIN(ceil(2 * maxY + 1.0) * scale, 2 * iHeight); + + uf->autoCropWidth = MIN(floor(2 * minX) * scale, 2 * iWidth); + uf->autoCropHeight = MIN(floor(2 * minY) * scale, 2 * iHeight); + + if ((double)uf->autoCropWidth / uf->autoCropHeight > aspectRatio) + uf->autoCropWidth = floor(uf->autoCropHeight * aspectRatio + 0.5); + else + uf->autoCropHeight = floor(uf->autoCropWidth / aspectRatio + 0.5); + + int newWidth = uf->rotatedWidth * width / iWidth; + int newHeight = uf->rotatedHeight * height / iHeight; + ufraw_image_init(img, newWidth, newHeight, 8); +#ifdef HAVE_LENSFUN + ufraw_convert_prepare_transform(uf, width, height, FALSE, scale); +#endif +} + +/* + * This function does not set img->invalidate_event because the + * invalidation here is a secondary effect of the need to resize + * buffers. The invalidate events should all have been set already. + */ +static void ufraw_convert_prepare_buffers(ufraw_data *uf, UFRawPhase phase) +{ + ufraw_image_data *img = &uf->Images[phase]; + if (!img->invalidate_event) + return; + img->invalidate_event = FALSE; + int width = 0, height = 0; + if (phase > ufraw_first_phase) { + ufraw_convert_prepare_buffers(uf, phase - 1); + width = uf->Images[phase - 1].width; + height = uf->Images[phase - 1].height; + } + switch (phase) { + case ufraw_raw_phase: + return; + case ufraw_first_phase: + ufraw_convert_prepare_first_buffer(uf, img); + return; + case ufraw_transform_phase: + ufraw_convert_prepare_transform_buffer(uf, img, width, height); + return; + case ufraw_develop_phase: + ufraw_image_init(img, width, height, 3); + return; + case ufraw_display_phase: + if (uf->developer->working2displayTransform == NULL) { + g_free(img->buffer); + img->buffer = NULL; + img->width = width; + img->height = height; + } else { + ufraw_image_init(img, width, height, 3); + } + return; + default: + g_warning("ufraw_convert_prepare_buffers: unsupported phase %d", phase); + } +} + +/* + * This function is very permissive in accepting NULL pointers but it does + * so to make it easy to call this function: consider it documentation with + * a free consistency check. It is not necessarily good to change existing + * algorithms all over the place to accept more image formats: replacing + * constants by variables may turn off some compiler optimizations. + */ +static void ufraw_image_format(int *colors, int *bytes, ufraw_image_data *img, + const char *formats, const char *caller) +{ + int b, c; + + switch (img->depth) { + case 3: + c = 3; + b = 1; + break; + case 4: + c = img->rgbg ? 4 : 3; + b = 1; + break; + case 6: + c = 3; + b = 2; + break; + case 8: + c = img->rgbg ? 4 : 3; + b = 2; + break; + default: + g_error("%s -> %s: unsupported depth %d\n", caller, G_STRFUNC, img->depth); + } + if (!strchr(formats, '0' + c * b)) + g_error("%s: unsupported depth %d (rgbg=%d)\n", caller, img->depth, img->rgbg); + if (colors) + *colors = c; + if (bytes) + *bytes = b; +} + +ufraw_image_data *ufraw_get_image(ufraw_data *uf, UFRawPhase phase, + gboolean bufferok) +{ + ufraw_convert_prepare_buffers(uf, phase); + // Find the closest phase that is actually rendered: + while (phase > ufraw_raw_phase && uf->Images[phase].buffer == NULL) + phase--; + + if (bufferok) { + /* It should never be necessary to actually finish the conversion + * because it can break render_preview_image() which uses the + * final image "valid" mask for deciding what to update in the + * pixbuf. That can be fixed but is suboptimal anyway. The best + * we can do is print a warning in case we need to finish the + * conversion and finish it here. */ + if (uf->Images[phase].valid != 0xffffffff) { + g_warning("%s: fixing unfinished conversion for phase %d.\n", + G_STRFUNC, phase); + int i; + for (i = 0; i < 32; ++i) + ufraw_convert_image_area(uf, i, phase); + } + } + return &uf->Images[phase]; +} + +ufraw_image_data *ufraw_convert_image_area(ufraw_data *uf, unsigned saidx, + UFRawPhase phase) +{ + int yy; + ufraw_image_data *out = &uf->Images[phase]; + + if (out->valid & (1 << saidx)) + return out; // the subarea has been already computed + + /* Get the subarea image for previous phase */ + ufraw_image_data *in = NULL; + if (phase > ufraw_raw_phase) { + in = ufraw_convert_image_area(uf, saidx, phase - 1); + } + // ufraw_convert_prepare_buffers() may set out->buffer to NULL. + ufraw_convert_prepare_buffers(uf, phase); + if (phase > ufraw_first_phase && out->buffer == NULL) + return in; // skip phase + + /* Get subarea coordinates */ + UFRectangle area = ufraw_image_get_subarea_rectangle(out, saidx); + guint8 *dest = out->buffer + area.y * out->rowstride + area.x * out->depth; + guint8 *src = NULL; + if (in != NULL) + src = in->buffer + area.y * in->rowstride + area.x * in->depth; + + switch (phase) { + case ufraw_raw_phase: + ufraw_convert_image_raw(uf, phase); + out->valid = 0xffffffff; + return out; + + case ufraw_first_phase: + ufraw_convert_image_first(uf, phase); + out->valid = 0xffffffff; +#ifdef HAVE_LENSFUN + UFRectangle allArea = { 0, 0, out->width, out->height }; + ufraw_convert_image_vignetting(uf, out, &allArea); +#endif /* HAVE_LENSFUN */ + return out; + + case ufraw_transform_phase: { + /* Area calculation is not needed at the moment since + * ufraw_first_phase is not tiled yet. */ + /* + int yy; + float *buff = g_new (float, (w < 8) ? 8 * 2 * 3 : w * 2 * 3); + + // Compute the previous stage subareas, if needed + lf_modifier_apply_subpixel_geometry_distortion ( + uf->modifier, x, y, 1, 1, buff); + lf_modifier_apply_subpixel_geometry_distortion ( + uf->modifier, x + w/2, y, 1, 1, buff + 2 * 3); + lf_modifier_apply_subpixel_geometry_distortion ( + uf->modifier, x + w-1, y, 1, 1, buff + 4 * 3); + lf_modifier_apply_subpixel_geometry_distortion ( + uf->modifier, x, y + h/2, 1, 1, buff + 6 * 3); + lf_modifier_apply_subpixel_geometry_distortion ( + uf->modifier, x + w-1, y + h/2, 1, 1, buff + 8 * 3); + lf_modifier_apply_subpixel_geometry_distortion ( + uf->modifier, x, y + h-1, 1, 1, buff + 10 * 3); + lf_modifier_apply_subpixel_geometry_distortion ( + uf->modifier, x + w/2, y + h-1, 1, 1, buff + 12 * 3); + lf_modifier_apply_subpixel_geometry_distortion ( + uf->modifier, x + w-1, y + h-1, 1, 1, buff + 14 * 3); + + for (yy = 0; yy < 8 * 2 * 3; yy += 2) + { + int idx = ufraw_img_get_subarea_idx (in, buff [yy], buff [yy + 1]); + if (idx <= 31) + ufraw_convert_image_area (uf, idx, phase - 1); + } + */ + ufraw_convert_image_transform(uf, in, out, &area); + } + break; + + case ufraw_develop_phase: + for (yy = 0; yy < area.height; yy++, dest += out->rowstride, + src += in->rowstride) { + develop(dest, (void *)src, uf->developer, 8, area.width); + } + break; + + case ufraw_display_phase: + for (yy = 0; yy < area.height; yy++, dest += out->rowstride, + src += in->rowstride) { + develop_display(dest, src, uf->developer, area.width); + } + break; + + default: + g_warning("%s: invalid phase %d\n", G_STRFUNC, phase); + return in; + } + +#ifdef _OPENMP + #pragma omp critical +#endif + // Mark the subarea as valid + out->valid |= (1 << saidx); + + return out; +} + +static void ufraw_flip_image_buffer(ufraw_image_data *img, int flip) +{ + if (img->buffer == NULL) + return; + /* Following code was copied from dcraw's flip_image() + * and modified to work with any pixel depth. */ + int base, dest, next, row, col; + guint8 *image = img->buffer; + int height = img->height; + int width = img->width; + int depth = img->depth; + int size = height * width; + guint8 hold[8]; + unsigned *flag = g_new0(unsigned, (size + 31) >> 5); + for (base = 0; base < size; base++) { + if (flag[base >> 5] & (1 << (base & 31))) + continue; + dest = base; + memcpy(hold, image + base * depth, depth); + while (1) { + if (flip & 4) { + row = dest % height; + col = dest / height; + } else { + row = dest / width; + col = dest % width; + } + if (flip & 2) + row = height - 1 - row; + if (flip & 1) + col = width - 1 - col; + next = row * width + col; + if (next == base) break; + flag[next >> 5] |= 1 << (next & 31); + memcpy(image + dest * depth, image + next * depth, depth); + dest = next; + } + memcpy(image + dest * depth, hold, depth); + } + g_free(flag); + if (flip & 4) { + img->height = width; + img->width = height; + img->rowstride = height * depth; + } +} + +void ufraw_flip_orientation(ufraw_data *uf, int flip) +{ + const char flipMatrix[8][8] = { + { 0, 1, 2, 3, 4, 5, 6, 7 }, /* No flip */ + { 1, 0, 3, 2, 5, 4, 7, 6 }, /* Flip horizontal */ + { 2, 3, 0, 1, 6, 7, 4, 5 }, /* Flip vertical */ + { 3, 2, 1, 0, 7, 6, 5, 4 }, /* Rotate 180 */ + { 4, 6, 5, 7, 0, 2, 1, 3 }, /* Flip over diagonal "\" */ + { 5, 7, 4, 6, 1, 3, 0, 2 }, /* Rotate 270 */ + { 6, 4, 7, 5, 2, 0, 3, 1 }, /* Rotate 90 */ + { 7, 5, 6, 4, 3, 1, 2, 0 } /* Flip over diagonal "/" */ + }; + uf->conf->orientation = flipMatrix[uf->conf->orientation][flip]; +} + +/* + * Normalize arbitrary rotations into a 0..90 degree range. + */ +void ufraw_normalize_rotation(ufraw_data *uf) +{ + int angle, flip = 0; + + uf->conf->rotationAngle = fmod(uf->conf->rotationAngle, 360.0); + if (uf->conf->rotationAngle < 0.0) + uf->conf->rotationAngle += 360.0; + angle = floor(uf->conf->rotationAngle / 90) * 90; + switch (angle) { + case 90: + flip = 6; + break; + case 180: + flip = 3; + break; + case 270: + flip = 5; + break; + } + ufraw_flip_orientation(uf, flip); + uf->conf->rotationAngle -= angle; +} + +/* + * Unnormalize a normalized rotaion into a -180..180 degree range, + * while orientation can be either 0 (normal) or 1 (flipped). + * All image processing code assumes normalized rotation, therefore + * each call to ufraw_unnormalize_rotation() must be followed by a call + * to ufraw_normalize_rotation(). + */ +void ufraw_unnormalize_rotation(ufraw_data *uf) +{ + switch (uf->conf->orientation) { + case 5: /* Rotate 270 */ + uf->conf->rotationAngle += 90; + // fall through + case 3: /* Rotate 180 */ + uf->conf->rotationAngle += 90; + // fall through + case 6: /* Rotate 90 */ + uf->conf->rotationAngle += 90; + uf->conf->orientation = 0; + // fall through + case 0: /* No flip */ + break; + case 4: /* Flip over diagonal "\" */ + uf->conf->rotationAngle += 90; + // fall through + case 2: /* Flip vertical */ + uf->conf->rotationAngle += 90; + // fall through + case 7: /* Flip over diagonal "/" */ + uf->conf->rotationAngle += 90; + uf->conf->orientation = 1; + // fall through + case 1: /* Flip horizontal */ + break; + default: + g_error("ufraw_unnormalized_roation(): orientation=%d out of range", + uf->conf->orientation); + } + uf->conf->rotationAngle = remainder(uf->conf->rotationAngle, 360.0); +} + +void ufraw_flip_image(ufraw_data *uf, int flip) +{ + if (flip == 0) + return; + ufraw_flip_orientation(uf, flip); + /* Usually orientation is applied before rotationAngle. + * Here we are flipping after rotationAngle was applied. + * We need to correct rotationAngle for this since these + * operations do no commute. + */ + if (flip == 1 || flip == 2 || flip == 4 || flip == 7) { + uf->conf->rotationAngle = -uf->conf->rotationAngle; + ufraw_normalize_rotation(uf); + } + UFRawPhase phase; + for (phase = ufraw_first_phase; phase < ufraw_phases_num; phase++) + ufraw_flip_image_buffer(&uf->Images[phase], flip); +} + +void ufraw_invalidate_layer(ufraw_data *uf, UFRawPhase phase) +{ + for (; phase < ufraw_phases_num; phase++) { + uf->Images[phase].valid = 0; + uf->Images[phase].invalidate_event = TRUE; + } +} + +void ufraw_invalidate_tca_layer(ufraw_data *uf) +{ + ufraw_invalidate_layer(uf, ufraw_raw_phase); +} + +void ufraw_invalidate_hotpixel_layer(ufraw_data *uf) +{ + ufraw_invalidate_layer(uf, ufraw_raw_phase); +} + +void ufraw_invalidate_denoise_layer(ufraw_data *uf) +{ + ufraw_invalidate_layer(uf, ufraw_raw_phase); +} + +void ufraw_invalidate_darkframe_layer(ufraw_data *uf) +{ + ufraw_invalidate_layer(uf, ufraw_raw_phase); +} + +void ufraw_invalidate_despeckle_layer(ufraw_data *uf) +{ + ufraw_invalidate_layer(uf, ufraw_raw_phase); +} + +/* + * This one is special. The raw layer applies WB in preparation for optimal + * interpolation but the first layer undoes it for develop() et.al. So, the + * first layer stays valid but all the others must be invalidated upon WB + * adjustments. + */ +void ufraw_invalidate_whitebalance_layer(ufraw_data *uf) +{ + ufraw_invalidate_layer(uf, ufraw_develop_phase); + uf->Images[ufraw_raw_phase].valid = 0; + uf->Images[ufraw_raw_phase].invalidate_event = TRUE; + + /* Despeckling is sensitive for WB changes because it is nonlinear. */ + if (ufraw_despeckle_active(uf)) + ufraw_invalidate_despeckle_layer(uf); +} + +/* + * This should be a no-op in case we don't interpolate but we don't care: the + * delay will at least give the illusion that it matters. Color smoothing + * implementation is a bit too simplistic. + */ +void ufraw_invalidate_smoothing_layer(ufraw_data *uf) +{ + ufraw_invalidate_layer(uf, ufraw_first_phase); +} + +int ufraw_set_wb(ufraw_data *uf, gboolean interactive) +{ + dcraw_data *raw = uf->raw; + double rgbWB[3]; + int c, cc, i; + UFObject *temperature = ufgroup_element(uf->conf->ufobject, ufTemperature); + UFObject *green = ufgroup_element(uf->conf->ufobject, ufGreen); + UFObject *chanMul = ufgroup_element(uf->conf->ufobject, + ufChannelMultipliers); + UFObject *wb = ufgroup_element(uf->conf->ufobject, ufWB); + UFObject *wbTuning = ufgroup_element(uf->conf->ufobject, ufWBFineTuning); + + ufraw_invalidate_whitebalance_layer(uf); + + /* For uf_manual_wb we calculate chanMul from the temperature/green. */ + /* For all other it is the other way around. */ + if (ufarray_is_equal(wb, uf_manual_wb)) { + if (interactive) { + double chanMulArray[4] = {1, 1, 1, 1 }; + Temperature_to_RGB(ufnumber_value(temperature), rgbWB); + rgbWB[1] = rgbWB[1] / ufnumber_value(green); + /* Suppose we shot a white card at some temperature: + * rgbWB[3] = rgb_cam[3][4] * preMul[4] * camWhite[4] + * Now we want to make it white (1,1,1), so we replace preMul + * with chanMul, which is defined as: + * chanMul[4][4] = cam_rgb[4][3] * (1/rgbWB[3][3]) * rgb_cam[3][4] + * * preMul[4][4] + * We "upgraded" preMul, chanMul and rgbWB to diagonal matrices. + * This allows for the manipulation: + * (1/chanMul)[4][4] = (1/preMul)[4][4] * cam_rgb[4][3] * rgbWB[3][3] + * * rgb_cam[3][4] + * We use the fact that rgb_cam[3][4] * (1,1,1,1) = (1,1,1) and get: + * (1/chanMul)[4] = (1/preMul)[4][4] * cam_rgb[4][3] * rgbWB[3] + */ + if (uf->raw_color) { + /* If there is no color matrix it is simple */ + if (uf->colors > 1) + for (c = 0; c < 3; c++) + chanMulArray[c] = raw->pre_mul[c] / rgbWB[c]; + ufnumber_array_set(chanMul, chanMulArray); + } else { + for (c = 0; c < uf->colors; c++) { + double chanMulInv = 0; + for (cc = 0; cc < 3; cc++) + chanMulInv += 1 / raw->pre_mul[c] * raw->cam_rgb[c][cc] + * rgbWB[cc]; + chanMulArray[c] = 1 / chanMulInv; + } + ufnumber_array_set(chanMul, chanMulArray); + } + } + ufnumber_set(wbTuning, 0); + return UFRAW_SUCCESS; + } + if (ufarray_is_equal(wb, uf_spot_wb)) { + /* do nothing */ + ufnumber_set(wbTuning, 0); + } else if (ufarray_is_equal(wb, uf_auto_wb)) { + int p; + /* Build a raw channel histogram */ + ufraw_image_type *histogram = g_new0(ufraw_image_type, uf->rgbMax + 1); + for (i = 0; i < raw->raw.height * raw->raw.width; i++) { + gboolean countPixel = TRUE; + /* The -25 bound was copied from dcraw */ + for (c = 0; c < raw->raw.colors; c++) + if (raw->raw.image[i][c] > uf->rgbMax + raw->black - 25) + countPixel = FALSE; + if (countPixel) { + for (c = 0; c < raw->raw.colors; c++) { + p = MIN(MAX(raw->raw.image[i][c] - raw->black, 0), uf->rgbMax); + histogram[p][c]++; + } + } + } + double chanMulArray[4] = {1.0, 1.0, 1.0, 1.0 }; + double min = 1.0; + for (c = 0; c < uf->colors; c++) { + gint64 sum = 0; + for (i = 0; i < uf->rgbMax + 1; i++) + sum += (gint64)i * histogram[i][c]; + if (sum == 0) chanMulArray[c] = 1.0; + else chanMulArray[c] = 1.0 / sum; + if (chanMulArray[c] < min) + min = chanMulArray[c]; + } + for (c = 0; c < uf->colors; c++) + chanMulArray[c] /= min; + g_free(histogram); + ufnumber_array_set(chanMul, chanMulArray); + ufnumber_set(wbTuning, 0); + } else if (ufarray_is_equal(wb, uf_camera_wb)) { + double chanMulArray[4] = { 1.0, 1.0, 1.0, 1.0 }; + for (c = 0; c < uf->colors; c++) + chanMulArray[c] = raw->post_mul[c]; + ufnumber_array_set(chanMul, chanMulArray); + ufnumber_set(wbTuning, 0); + } else { + int lastTuning = -1; + char model[max_name]; + if (strcasecmp(uf->conf->make, "Minolta") == 0 && + (strncmp(uf->conf->model, "ALPHA", 5) == 0 || + strncmp(uf->conf->model, "MAXXUM", 6) == 0)) { + /* Canonize Minolta model names (copied from dcraw) */ + g_snprintf(model, max_name, "DYNAX %s", + uf->conf->model + 6 + (uf->conf->model[0] == 'M')); + } else { + g_strlcpy(model, uf->conf->model, max_name); + } + for (i = 0; i < wb_preset_count; i++) { + if (ufarray_is_equal(wb, wb_preset[i].name) && + !strcasecmp(uf->conf->make, wb_preset[i].make) && + !strcasecmp(model, wb_preset[i].model)) { + if (ufnumber_value(wbTuning) == wb_preset[i].tuning) { + double chanMulArray[4] = {1, 1, 1, 1 }; + for (c = 0; c < uf->colors; c++) + chanMulArray[c] = wb_preset[i].channel[c]; + ufnumber_array_set(chanMul, chanMulArray); + break; + } else if (ufnumber_value(wbTuning) < wb_preset[i].tuning) { + if (lastTuning == -1) { + /* wbTuning was set to a value smaller than possible */ + ufnumber_set(wbTuning, wb_preset[i].tuning); + double chanMulArray[4] = {1, 1, 1, 1 }; + for (c = 0; c < uf->colors; c++) + chanMulArray[c] = wb_preset[i].channel[c]; + ufnumber_array_set(chanMul, chanMulArray); + break; + } else { + /* Extrapolate WB tuning values: + * f(x) = f(a) + (x-a)*(f(b)-f(a))/(b-a) */ + double chanMulArray[4] = {1, 1, 1, 1 }; + for (c = 0; c < uf->colors; c++) + chanMulArray[c] = wb_preset[i].channel[c] + + (ufnumber_value(wbTuning) - wb_preset[i].tuning) * + (wb_preset[lastTuning].channel[c] - + wb_preset[i].channel[c]) / + (wb_preset[lastTuning].tuning - + wb_preset[i].tuning); + ufnumber_array_set(chanMul, chanMulArray); + break; + } + } else if (ufnumber_value(wbTuning) > wb_preset[i].tuning) { + lastTuning = i; + } + } else if (lastTuning != -1) { + /* wbTuning was set to a value larger than possible */ + ufnumber_set(wbTuning, wb_preset[lastTuning].tuning); + double chanMulArray[4] = {1, 1, 1, 1 }; + for (c = 0; c < uf->colors; c++) + chanMulArray[c] = wb_preset[lastTuning].channel[c]; + ufnumber_array_set(chanMul, chanMulArray); + break; + } + } + if (i == wb_preset_count) { + if (lastTuning != -1) { + /* wbTuning was set to a value larger than possible */ + ufnumber_set(wbTuning, wb_preset[lastTuning].tuning); + ufnumber_array_set(chanMul, wb_preset[lastTuning].channel); + } else { + ufobject_set_string(wb, uf_manual_wb); + ufraw_set_wb(uf, interactive); + return UFRAW_WARNING; + } + } + } + /* (1/chanMul)[4] = (1/preMul)[4][4] * cam_rgb[4][3] * rgbWB[3] + * Therefore: + * rgbWB[3] = rgb_cam[3][4] * preMul[4][4] * (1/chanMul)[4] + */ + if (uf->raw_color) { + /* If there is no color matrix it is simple */ + for (c = 0; c < 3; c++) { + rgbWB[c] = raw->pre_mul[c] / ufnumber_array_value(chanMul, c); + } + } else { + for (c = 0; c < 3; c++) { + rgbWB[c] = 0; + for (cc = 0; cc < uf->colors; cc++) + rgbWB[c] += raw->rgb_cam[c][cc] * raw->pre_mul[cc] + / ufnumber_array_value(chanMul, cc); + } + } + /* From these values we calculate temperature, green values */ + double temperatureValue, greenValue; + RGB_to_Temperature(rgbWB, &temperatureValue, &greenValue); + ufnumber_set(temperature, temperatureValue); + ufnumber_set(green, greenValue); + return UFRAW_SUCCESS; +} + +static void ufraw_build_raw_histogram(ufraw_data *uf) +{ + int i, c; + dcraw_data *raw = uf->raw; + gboolean updateHistogram = FALSE; + + if (uf->RawHistogram == NULL) { + uf->RawHistogram = g_new(int, uf->rgbMax + 1); + updateHistogram = TRUE; + } + double maxChan = 0; + UFObject *chanMul = ufgroup_element(uf->conf->ufobject, + ufChannelMultipliers); + for (c = 0; c < uf->colors; c++) + maxChan = MAX(ufnumber_array_value(chanMul, c), maxChan); + for (c = 0; c < uf->colors; c++) { + int tmp = floor(ufnumber_array_value(chanMul, c) / maxChan * 0x10000); + if (uf->RawChanMul[c] != tmp) { + updateHistogram = TRUE; + uf->RawChanMul[c] = tmp; + } + } + if (!updateHistogram) return; + + if (uf->colors == 3) uf->RawChanMul[3] = uf->RawChanMul[1]; + memset(uf->RawHistogram, 0, (uf->rgbMax + 1)*sizeof(int)); + int count = raw->raw.height * raw->raw.width; + for (i = 0; i < count; i++) + for (c = 0; c < raw->raw.colors; c++) + uf->RawHistogram[MIN( + (gint64)MAX(raw->raw.image[i][c] - raw->black, 0) * + uf->RawChanMul[c] / 0x10000, uf->rgbMax)]++; + + uf->RawCount = count * raw->raw.colors; +} + +void ufraw_auto_expose(ufraw_data *uf) +{ + int sum, stop, wp, c, pMax, pMin, p; + ufraw_image_type pix; + guint16 p16[3]; + + if (uf->conf->autoExposure != apply_state) return; + + /* Reset the exposure and luminosityCurve */ + uf->conf->exposure = 0; + /* If we normalize the exposure then 0 EV also gets normalized */ + if (uf->conf->ExposureNorm > 0) + uf->conf->exposure = -log(1.0 * uf->rgbMax / uf->conf->ExposureNorm) / log(2); + ufraw_developer_prepare(uf, auto_developer); + /* Find the grey value that gives 99% luminosity */ + double maxChan = 0; + UFObject *chanMul = ufgroup_element(uf->conf->ufobject, + ufChannelMultipliers); + for (c = 0; c < uf->colors; c++) + maxChan = MAX(ufnumber_array_value(chanMul, c), maxChan); + for (pMax = uf->rgbMax, pMin = 0, p = (pMax + pMin) / 2; pMin < pMax - 1; p = (pMax + pMin) / 2) { + for (c = 0; c < uf->colors; c++) + pix[c] = MIN(p * maxChan / ufnumber_array_value(chanMul, c), + uf->rgbMax); + develop(p16, pix, uf->AutoDeveloper, 16, 1); + for (c = 0, wp = 0; c < 3; c++) wp = MAX(wp, p16[c]); + if (wp < 0x10000 * 99 / 100) pMin = p; + else pMax = p; + } + /* set cutoff at 99% of the histogram */ + ufraw_build_raw_histogram(uf); + stop = uf->RawCount * 1 / 100; + /* Calculate the white point */ + for (wp = uf->rgbMax, sum = 0; wp > 1 && sum < stop; wp--) + sum += uf->RawHistogram[wp]; + /* Set 99% of the luminosity values with luminosity below 99% */ + uf->conf->exposure = log((double)p / wp) / log(2); + /* If we are going to normalize the exposure later, + * we need to cancel its effect here. */ + if (uf->conf->ExposureNorm > 0) + uf->conf->exposure -= + log(1.0 * uf->rgbMax / uf->conf->ExposureNorm) / log(2); + uf->conf->autoExposure = enabled_state; +// ufraw_message(UFRAW_SET_LOG, "ufraw_auto_expose: " +// "Exposure %f (white point %d/%d)\n", uf->conf->exposure, wp, p); +} + +void ufraw_auto_black(ufraw_data *uf) +{ + int sum, stop, bp, c; + ufraw_image_type pix; + guint16 p16[3]; + + if (uf->conf->autoBlack == disabled_state) return; + + /* Reset the luminosityCurve */ + ufraw_developer_prepare(uf, auto_developer); + /* Calculate the black point */ + ufraw_build_raw_histogram(uf); + stop = uf->RawCount / 256 / 4; + for (bp = 0, sum = 0; bp < uf->rgbMax && sum < stop; bp++) + sum += uf->RawHistogram[bp]; + double maxChan = 0; + UFObject *chanMul = ufgroup_element(uf->conf->ufobject, + ufChannelMultipliers); + for (c = 0; c < uf->colors; c++) + maxChan = MAX(ufnumber_array_value(chanMul, c), maxChan); + for (c = 0; c < uf->colors; c++) + pix[c] = MIN(bp * maxChan / ufnumber_array_value(chanMul, c), uf->rgbMax); + develop(p16, pix, uf->AutoDeveloper, 16, 1); + for (c = 0, bp = 0; c < 3; c++) bp = MAX(bp, p16[c]); + + CurveDataSetPoint(&uf->conf->curve[uf->conf->curveIndex], + 0, (double)bp / 0x10000, 0); + + uf->conf->autoBlack = enabled_state; +// ufraw_message(UFRAW_SET_LOG, "ufraw_auto_black: " +// "Black %f (black point %d)\n", +// uf->conf->curve[uf->conf->curveIndex].m_anchors[0].x, bp); +} + +/* ufraw_auto_curve sets the black-point and then distribute the (step-1) + * parts of the histogram with the weights: w_i = pow(decay,i). */ +void ufraw_auto_curve(ufraw_data *uf) +{ + int sum, stop, steps = 8, bp, p, i, j, c; + ufraw_image_type pix; + guint16 p16[3]; + CurveData *curve = &uf->conf->curve[uf->conf->curveIndex]; + double decay = 0.90; + double norm = (1 - pow(decay, steps)) / (1 - decay); + + CurveDataReset(curve); + ufraw_developer_prepare(uf, auto_developer); + /* Calculate curve points */ + ufraw_build_raw_histogram(uf); + stop = uf->RawCount / 256 / 4; + double maxChan = 0; + UFObject *chanMul = ufgroup_element(uf->conf->ufobject, + ufChannelMultipliers); + for (c = 0; c < uf->colors; c++) + maxChan = MAX(ufnumber_array_value(chanMul, c), maxChan); + for (bp = 0, sum = 0, p = 0, i = j = 0; i < steps && bp < uf->rgbMax && p < 0xFFFF; i++) { + for (; bp < uf->rgbMax && sum < stop; bp++) + sum += uf->RawHistogram[bp]; + for (c = 0; c < uf->colors; c++) + pix[c] = MIN(bp * maxChan / ufnumber_array_value(chanMul, c), + uf->rgbMax); + develop(p16, pix, uf->AutoDeveloper, 16, 1); + for (c = 0, p = 0; c < 3; c++) p = MAX(p, p16[c]); + stop += uf->RawCount * pow(decay, i) / norm; + /* Skip adding point if slope is too big (more than 4) */ + if (j > 0 && p - curve->m_anchors[j - 1].x * 0x10000 < (i + 1 - j) * 0x04000 / steps) + continue; + curve->m_anchors[j].x = (double)p / 0x10000; + curve->m_anchors[j].y = (double)i / steps; + j++; + } + if (bp == 0x10000) { + curve->m_numAnchors = j; + } else { + curve->m_anchors[j].x = 1.0; + /* The last point can be up to twice the height of a linear + * interpolation of the last two points */ + if (j > 1) { + curve->m_anchors[j].y = curve->m_anchors[j - 1].y + + 2 * (1.0 - curve->m_anchors[j - 1].x) * + (curve->m_anchors[j - 1].y - curve->m_anchors[j - 2].y) / + (curve->m_anchors[j - 1].x - curve->m_anchors[j - 2].x); + if (curve->m_anchors[j].y > 1.0) curve->m_anchors[j].y = 1.0; + } else { + curve->m_anchors[j].y = 1.0; + } + curve->m_numAnchors = j + 1; + } +} diff --git a/plugins/load-dcraw/ufraw_writer.c b/plugins/load-dcraw/ufraw_writer.c new file mode 100644 index 00000000..cd20e178 --- /dev/null +++ b/plugins/load-dcraw/ufraw_writer.c @@ -0,0 +1,879 @@ +/* + * UFRaw - Unidentified Flying Raw converter for digital camera images + * + * ufraw_writer.c - functions to output image files in different formats. + * Copyright 2004-2016 by Udi Fuchs + * + * 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. + */ + +#include "ufraw.h" +#include +#include /* for errno */ +#include +#include +#include "ufraw_colorspaces.h" +#ifdef HAVE_LIBTIFF +#include +#endif +#ifdef HAVE_LIBJPEG +#include +#include "iccjpeg.h" +#endif +#ifdef HAVE_LIBPNG +#include +#ifdef HAVE_LIBZ +#include /* for libpng 1.5.x */ +#endif +#if PNG_LIBPNG_VER_MAJOR == 1 && (PNG_LIBPNG_VER_MINOR < 5 || \ + (PNG_LIBPNG_VER_MINOR == 5 && PNG_LIBPNG_VER_RELEASE < 1)) +#define png_const_bytep png_charp +#endif +#endif + +#ifdef _OPENMP +#include +#define uf_omp_get_thread_num() omp_get_thread_num() +#else +#define uf_omp_get_thread_num() 0 +#endif + +#ifdef HAVE_LIBCFITSIO +#include +#endif + +#define DEVELOP_BATCH 64 + +static void grayscale_buffer(void *graybuf, int width, int bitDepth) +{ + int i; + if (bitDepth > 8) { + guint16 *pixbuf16 = graybuf; + guint16 *graybuf16 = graybuf; + for (i = 0; i < width; ++i, ++graybuf16, pixbuf16 += 3) + * graybuf16 = pixbuf16[1]; + } else { + guint8 *pixbuf8 = graybuf; + guint8 *graybuf8 = graybuf; + for (i = 0; i < width; ++i, ++graybuf8, pixbuf8 += 3) + * graybuf8 = pixbuf8[1]; + } +} + +static int ppm_row_writer(ufraw_data *uf, void *volatile out, void *pixbuf, + int row, int width, int height, int grayscale, int bitDepth) +{ + (void)row; + int rowStride = width * (grayscale ? 1 : 3) * (bitDepth > 8 ? 2 : 1); + int i; + if (bitDepth > 8) { + guint16 *pixbuf16 = (guint16 *)pixbuf; + for (i = 0; i < 3 * width * height; i++) + pixbuf16[i] = g_htons(pixbuf16[i]); + } + for (i = 0; i < height; i++) { + if ((int)fwrite(pixbuf + i * width * (bitDepth > 8 ? 6 : 3), rowStride, 1, out) < 1) { + ufraw_set_error(uf, _("Error creating file '%s'."), + uf->conf->outputFilename); + ufraw_set_error(uf, g_strerror(errno)); + return UFRAW_ERROR; + } + } + return UFRAW_SUCCESS; +} + +#ifdef HAVE_LIBTIFF +// There seem to be no way to get the libtiff message without a static variable +// Therefore the folloing code is not thread-safe. +static char ufraw_tiff_message[max_path]; + +static void tiff_messenger(const char *module, const char *fmt, va_list ap) +{ + (void)module; + vsnprintf(ufraw_tiff_message, max_path, fmt, ap); +} + +int tiff_row_writer(ufraw_data *uf, void *volatile out, void *pixbuf, + int row, int width, int height, int grayscale, int bitDepth) +{ + (void)grayscale; + int rowStride = width * (bitDepth > 8 ? 6 : 3); + int i; + for (i = 0; i < height; i++) { + if (TIFFWriteScanline(out, pixbuf + i * rowStride, row + i, 0) < 0) { + // 'errno' does seem to contain useful information + ufraw_set_error(uf, _("Error creating file.")); + ufraw_set_error(uf, ufraw_tiff_message); + ufraw_tiff_message[0] = '\0'; + return UFRAW_ERROR; + } + } + return UFRAW_SUCCESS; +} +#endif /*HAVE_LIBTIFF*/ + +#ifdef HAVE_LIBJPEG +static void jpeg_warning_handler(j_common_ptr cinfo) +{ + ufraw_data *uf = cinfo->client_data; + ufraw_set_warning(uf, + cinfo->err->jpeg_message_table[cinfo->err->msg_code], + cinfo->err->msg_parm.i[0], + cinfo->err->msg_parm.i[1], + cinfo->err->msg_parm.i[2], + cinfo->err->msg_parm.i[3]); +} + +static void jpeg_error_handler(j_common_ptr cinfo) +{ + /* We ignore the SOI error if second byte is 0xd8 since Minolta's + * SOI is known to be wrong */ + ufraw_data *uf = cinfo->client_data; + if (cinfo->err->msg_code == JERR_NO_SOI && + cinfo->err->msg_parm.i[1] == 0xd8) { + ufraw_set_info(uf, + cinfo->err->jpeg_message_table[cinfo->err->msg_code], + cinfo->err->msg_parm.i[0], + cinfo->err->msg_parm.i[1], + cinfo->err->msg_parm.i[2], + cinfo->err->msg_parm.i[3]); + return; + } + ufraw_set_error(uf, + cinfo->err->jpeg_message_table[cinfo->err->msg_code], + cinfo->err->msg_parm.i[0], + cinfo->err->msg_parm.i[1], + cinfo->err->msg_parm.i[2], + cinfo->err->msg_parm.i[3]); +} + +static int jpeg_row_writer(ufraw_data *uf, void *volatile out, void *pixbuf, + int row, int width, int height, int grayscale, int bitDepth) +{ + (void)row; + (void)grayscale; + (void)bitDepth; + int i; + for (i = 0; i < height; i++) { + guint8 *pixbuf8 = pixbuf + 3 * width * i; + jpeg_write_scanlines((struct jpeg_compress_struct *)out, &pixbuf8, 1); + if (ufraw_is_error(uf)) + return UFRAW_ERROR; + } + return UFRAW_SUCCESS; +} +#endif /*HAVE_LIBJPEG*/ + +#ifdef HAVE_LIBPNG +static void png_error_handler(png_structp png, + png_const_charp error_msg) +{ + ufraw_data *uf = png_get_error_ptr(png); + ufraw_set_error(uf, "%s: %s.", error_msg, g_strerror(errno)); + longjmp(png_jmpbuf(png), 1); +} + +static void png_warning_handler(png_structp png, + png_const_charp warning_msg) +{ + ufraw_data *uf = png_get_error_ptr(png); + ufraw_set_warning(uf, "%s.", warning_msg); +} + +static void PNGwriteRawProfile(png_struct *ping, + png_info *ping_info, char *profile_type, guint8 *profile_data, + png_uint_32 length); + +int png_row_writer(ufraw_data *uf, void *volatile out, void *pixbuf, + int row, int width, int height, int grayscale, int bitDepth) +{ + (void)uf; + (void)row; + (void)grayscale; + int rowStride = width * (bitDepth > 8 ? 6 : 3); + + int i; + for (i = 0; i < height; i++) + png_write_row(out, (guint8 *)pixbuf + rowStride * i); + + return UFRAW_SUCCESS; +} +#endif /*HAVE_LIBPNG*/ + +#if defined(HAVE_LIBCFITSIO) && defined(_WIN32) +/* localtime_r() is not included in the _WIN32 API. */ +static struct tm *localtime_r(const time_t *timep, struct tm *result) +{ + struct tm *p = localtime(timep); + memset(result, 0, sizeof(*result)); + if (p) { + *result = *p; + p = result; + } + return p; +} +#endif /*HAVE_LIBCFITSIO && _WIN32*/ + +void ufraw_write_image_data( + ufraw_data *uf, void * volatile out, + const UFRectangle *Crop, int bitDepth, int grayscaleMode, + int (*row_writer)(ufraw_data *, void * volatile, void *, int, int, int, int, int)) +{ + int row, row0; + int rowStride = uf->Images[ufraw_first_phase].width; + ufraw_image_type *rawImage = + (ufraw_image_type *)uf->Images[ufraw_first_phase].buffer; + int byteDepth = (bitDepth + 7) / 8; + guint8 *pixbuf8 = g_new(guint8, + Crop->width * 3 * byteDepth * DEVELOP_BATCH); + + progress(PROGRESS_SAVE, -Crop->height); + for (row0 = 0; row0 < Crop->height; row0 += DEVELOP_BATCH) { + progress(PROGRESS_SAVE, DEVELOP_BATCH); +#ifdef _OPENMP + #pragma omp parallel for default(shared) private(row) +#endif + for (row = 0; row < DEVELOP_BATCH; row++) { + if (row + row0 >= Crop->height) + continue; + guint8 *rowbuf = &pixbuf8[row * Crop->width * 3 * byteDepth]; + develop(rowbuf, rawImage[(Crop->y + row + row0)*rowStride + Crop->x], + uf->developer, bitDepth, Crop->width); + if (grayscaleMode) + grayscale_buffer(rowbuf, Crop->width, bitDepth); + } + int batchHeight = MIN(Crop->height - row0, DEVELOP_BATCH); + if (row_writer(uf, out, pixbuf8, row0, Crop->width, batchHeight, + grayscaleMode, bitDepth) != UFRAW_SUCCESS) + break; + } + g_free(pixbuf8); +} + +int ufraw_write_image(ufraw_data *uf) +{ + /* 'volatile' supresses clobbering warning */ + void * volatile out; /* out is a pointer to FILE or TIFF */ +#ifdef HAVE_LIBCFITSIO + fitsfile *fitsFile; +#endif + char * volatile confFilename = NULL; + int volatile grayscaleMode = uf->conf->grayscaleMode != grayscale_none || + uf->colors == 1; + ufraw_message_reset(uf); + + if (uf->conf->createID == only_id || + uf->conf->createID == also_id) { + confFilename = uf_file_set_type(uf->conf->outputFilename, ".ufraw"); + if (!strcmp(confFilename, uf->conf->outputFilename)) { + ufraw_set_error(uf, _("Image filename can not be the " + "same as ID filename '%s'"), confFilename); + g_free(confFilename); + return ufraw_get_status(uf); + } + } + if (uf->conf->createID == only_id) { + if (uf->conf->autoCrop && !uf->LoadingID) { + ufraw_get_image_dimensions(uf); + uf->conf->CropX1 = (uf->rotatedWidth - uf->autoCropWidth) / 2; + uf->conf->CropX2 = uf->conf->CropX1 + uf->autoCropWidth; + uf->conf->CropY1 = (uf->rotatedHeight - uf->autoCropHeight) / 2; + uf->conf->CropY2 = uf->conf->CropY1 + uf->autoCropHeight; + } + int status = conf_save(uf->conf, confFilename, NULL); + g_free(confFilename); + return status; + } +#ifdef HAVE_LIBTIFF + if (uf->conf->type == tiff_type) { + TIFFSetErrorHandler(tiff_messenger); + TIFFSetWarningHandler(tiff_messenger); + ufraw_tiff_message[0] = '\0'; + if (!strcmp(uf->conf->outputFilename, "-")) { + out = TIFFFdOpen(fileno((FILE *)stdout), + uf->conf->outputFilename, "w"); + } else { + char *filename = + uf_win32_locale_filename_from_utf8(uf->conf->outputFilename); + out = TIFFOpen(filename, "w"); + uf_win32_locale_filename_free(filename); + } + if (out == NULL) { + ufraw_set_error(uf, _("Error creating file.")); + ufraw_set_error(uf, ufraw_tiff_message); + ufraw_set_error(uf, g_strerror(errno)); + ufraw_tiff_message[0] = '\0'; + return ufraw_get_status(uf); + } + } else +#endif +#ifdef HAVE_LIBCFITSIO + if (uf->conf->type == fits_type) { + if (strcmp(uf->conf->outputFilename, "-") != 0) { + if (g_file_test(uf->conf->outputFilename, G_FILE_TEST_EXISTS)) { + if (g_unlink(uf->conf->outputFilename)) { + ufraw_set_error(uf, _("Error creating file '%s'."), + uf->conf->outputFilename); + ufraw_set_error(uf, g_strerror(errno)); + return ufraw_get_status(uf); + } + } + } + int status = 0; + char *filename = + uf_win32_locale_filename_from_utf8(uf->conf->outputFilename); + if (strcmp(filename, "-") != 0) + // Use fits_create_diskfile() to allow more characters in + // filenames. + fits_create_diskfile(&fitsFile, filename, &status); + else + // fits_create_file() can write to stdout. + fits_create_file(&fitsFile, filename, &status); + uf_win32_locale_filename_free(filename); + if (status) { + ufraw_set_error(uf, _("Error creating file '%s'."), + uf->conf->outputFilename); + char errBuffer[max_name]; + fits_get_errstatus(status, errBuffer); + ufraw_set_error(uf, errBuffer); + while (fits_read_errmsg(errBuffer)) + ufraw_set_error(uf, errBuffer); + return ufraw_get_status(uf); + } + } else +#endif + { + if (!strcmp(uf->conf->outputFilename, "-")) { + out = stdout; + } else { + if ((out = g_fopen(uf->conf->outputFilename, "wb")) == NULL) { + ufraw_set_error(uf, _("Error creating file '%s'."), + uf->conf->outputFilename); + ufraw_set_error(uf, g_strerror(errno)); + return ufraw_get_status(uf); + } + } + } + // TODO: error handling + ufraw_convert_image(uf); + UFRectangle Crop; + ufraw_get_scaled_crop(uf, &Crop); + volatile int BitDepth = uf->conf->profile[out_profile] + [uf->conf->profileIndex[out_profile]].BitDepth; + if (BitDepth != 16) BitDepth = 8; + if (uf->conf->type == ppm_type && BitDepth == 8) { + fprintf(out, "P%c\n%d %d\n%d\n", + grayscaleMode ? '5' : '6', Crop.width, Crop.height, 0xFF); + ufraw_write_image_data(uf, out, &Crop, BitDepth, grayscaleMode, + ppm_row_writer); + } else if (uf->conf->type == ppm_type && BitDepth == 16) { + fprintf(out, "P%c\n%d %d\n%d\n", + grayscaleMode ? '5' : '6', Crop.width, Crop.height, 0xFFFF); + ufraw_write_image_data(uf, out, &Crop, BitDepth, grayscaleMode, + ppm_row_writer); +#ifdef HAVE_LIBTIFF + } else if (uf->conf->type == tiff_type) { + TIFFSetField(out, TIFFTAG_IMAGEWIDTH, Crop.width); + TIFFSetField(out, TIFFTAG_IMAGELENGTH, Crop.height); + TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); + TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, grayscaleMode ? 1 : 3); + TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, BitDepth); + TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField(out, TIFFTAG_PHOTOMETRIC, grayscaleMode + ? PHOTOMETRIC_MINISBLACK : PHOTOMETRIC_RGB); +#ifdef HAVE_LIBZ + if (uf->conf->losslessCompress) { + TIFFSetField(out, TIFFTAG_COMPRESSION, COMPRESSION_ADOBE_DEFLATE); + TIFFSetField(out, TIFFTAG_ZIPQUALITY, 9); + TIFFSetField(out, TIFFTAG_PREDICTOR, 2); + } else +#endif + TIFFSetField(out, TIFFTAG_COMPRESSION, COMPRESSION_NONE); + /* Embed output profile if it is not the internal sRGB. */ + if (strcmp(uf->developer->profileFile[out_profile], "")) { + char *buf; + gsize len; + if (g_file_get_contents(uf->developer->profileFile[out_profile], + &buf, &len, NULL)) { + TIFFSetField(out, TIFFTAG_ICCPROFILE, len, buf); + g_free(buf); + } else { + ufraw_set_warning(uf, + _("Failed to embed output profile '%s' in '%s'."), + uf->developer->profileFile[out_profile], + uf->conf->outputFilename); + } + } else if (uf->conf->profileIndex[out_profile] == 1) { // Embed sRGB. + cmsHPROFILE hOutProfile = uf_colorspaces_create_srgb_profile(); + cmsUInt32Number len = 0; + cmsSaveProfileToMem(hOutProfile, 0, &len); // Calculate len. + if (len > 0) { + unsigned char buf[len]; + cmsSaveProfileToMem(hOutProfile, buf, &len); + TIFFSetField(out, TIFFTAG_ICCPROFILE, len, buf); + } else { + ufraw_set_warning(uf, + _("Failed to embed output profile '%s' in '%s'."), + uf->conf->profile[out_profile] + [uf->conf->profileIndex[out_profile]].name, + uf->conf->outputFilename); + } + cmsCloseProfile(hOutProfile); + } + TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(out, 0)); + + ufraw_write_image_data(uf, out, &Crop, BitDepth, grayscaleMode, + tiff_row_writer); + +#endif /*HAVE_LIBTIFF*/ +#ifdef HAVE_LIBJPEG + } else if (uf->conf->type == jpeg_type) { + if (BitDepth != 8) + ufraw_set_warning(uf, + _("Unsupported bit depth '%d' ignored."), BitDepth); + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + + cinfo.err = jpeg_std_error(&jerr); + cinfo.err->output_message = jpeg_warning_handler; + cinfo.err->error_exit = jpeg_error_handler; + cinfo.client_data = uf; + jpeg_create_compress(&cinfo); + jpeg_stdio_dest(&cinfo, out); + cinfo.image_width = Crop.width; + cinfo.image_height = Crop.height; + if (grayscaleMode) { + cinfo.input_components = 1; + cinfo.in_color_space = JCS_GRAYSCALE; + } else { + cinfo.input_components = 3; + cinfo.in_color_space = JCS_RGB; + } + jpeg_set_defaults(&cinfo); + jpeg_set_quality(&cinfo, uf->conf->compression, TRUE); + if (uf->conf->compression > 90) + cinfo.comp_info[0].v_samp_factor = 1; + if (uf->conf->compression > 92) + cinfo.comp_info[0].h_samp_factor = 1; + if (uf->conf->progressiveJPEG) + jpeg_simple_progression(&cinfo); + + cinfo.optimize_coding = 1; + + jpeg_start_compress(&cinfo, TRUE); + + /* Embed output profile if it is not the internal sRGB. */ + if (strcmp(uf->developer->profileFile[out_profile], "")) { + char *buf; + gsize len; + if (g_file_get_contents(uf->developer->profileFile[out_profile], + &buf, &len, NULL)) { + write_icc_profile(&cinfo, (unsigned char *)buf, len); + g_free(buf); + } else { + ufraw_set_warning(uf, + _("Failed to embed output profile '%s' in '%s'."), + uf->developer->profileFile[out_profile], + uf->conf->outputFilename); + } + } else if (uf->conf->profileIndex[out_profile] == 1) { // Embed sRGB. + cmsHPROFILE hOutProfile = uf_colorspaces_create_srgb_profile(); + cmsUInt32Number len = 0; + cmsSaveProfileToMem(hOutProfile, 0, &len); // Calculate len. + if (len > 0) { + unsigned char buf[len]; + cmsSaveProfileToMem(hOutProfile, buf, &len); + write_icc_profile(&cinfo, buf, len); + } else { + ufraw_set_warning(uf, + _("Failed to embed output profile '%s' in '%s'."), + uf->conf->profile[out_profile] + [uf->conf->profileIndex[out_profile]].name, + uf->conf->outputFilename); + } + cmsCloseProfile(hOutProfile); + } + if (uf->conf->embedExif) { + ufraw_exif_prepare_output(uf); + if (uf->outputExifBuf != NULL) { + if (uf->outputExifBufLen > 65533) { + ufraw_set_warning(uf, + _("EXIF buffer length %d, too long, ignored."), + uf->outputExifBufLen); + } else { + jpeg_write_marker(&cinfo, JPEG_APP0 + 1, + uf->outputExifBuf, uf->outputExifBufLen); + } + } + } + + ufraw_write_image_data(uf, &cinfo, &Crop, 8, grayscaleMode, + jpeg_row_writer); + + if (ufraw_is_error(uf)) { + char *message = g_strdup(ufraw_get_message(uf)); + ufraw_message_reset(uf); + ufraw_set_error(uf, _("Error creating file '%s'."), + uf->conf->outputFilename); + ufraw_set_error(uf, message); + g_free(message); + } else + jpeg_finish_compress(&cinfo); + jpeg_destroy_compress(&cinfo); +#endif /*HAVE_LIBJPEG*/ +#ifdef HAVE_LIBPNG + } else if (uf->conf->type == png_type) { + png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, + uf, png_error_handler, png_warning_handler); + png_infop info = png_create_info_struct(png); + if (setjmp(png_jmpbuf(png))) { + char *message = g_strdup(ufraw_get_message(uf)); + ufraw_message_reset(uf); + ufraw_set_error(uf, _("Error creating file '%s'."), + uf->conf->outputFilename); + ufraw_set_error(uf, message); + g_free(message); + png_destroy_write_struct(&png, &info); + } else { + png_init_io(png, out); + png_set_IHDR(png, info, Crop.width, Crop.height, BitDepth, + grayscaleMode ? PNG_COLOR_TYPE_GRAY : PNG_COLOR_TYPE_RGB, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, + PNG_FILTER_TYPE_BASE); + png_set_compression_level(png, Z_BEST_COMPRESSION); + png_text text[2]; + text[0].compression = PNG_TEXT_COMPRESSION_NONE; + text[0].key = "Software"; + text[0].text = "UFRaw"; + text[1].compression = PNG_TEXT_COMPRESSION_NONE; + text[1].key = "Source"; + text[1].text = g_strdup_printf("%s%s", + uf->conf->make, uf->conf->model); + png_set_text(png, info, text, 2); + g_free(text[1].text); + /* Embed output profile if it is not the internal sRGB. */ + if (strcmp(uf->developer->profileFile[out_profile], "")) { + char *buf; + gsize len; + if (g_file_get_contents(uf->developer->profileFile[out_profile], + &buf, &len, NULL)) { + png_set_iCCP(png, info, + uf->developer->profileFile[out_profile], + PNG_COMPRESSION_TYPE_BASE, + (png_const_bytep) buf, len); + g_free(buf); + } else { + ufraw_set_warning(uf, + _("Failed to embed output profile '%s' in '%s'."), + uf->developer->profileFile[out_profile], + uf->conf->outputFilename); + } + } else if (uf->conf->profileIndex[out_profile] == 1) { // Embed sRGB. + cmsHPROFILE hOutProfile = uf_colorspaces_create_srgb_profile(); + cmsUInt32Number len = 0; + cmsSaveProfileToMem(hOutProfile, 0, &len); // Calculate len. + if (len > 0) { + char buf[len]; + cmsSaveProfileToMem(hOutProfile, buf, &len); + png_set_iCCP(png, info, + uf->conf->profile[out_profile] + [uf->conf->profileIndex[out_profile]].name, + PNG_COMPRESSION_TYPE_BASE, + (png_const_bytep) buf, len); + } else { + ufraw_set_warning(uf, + _("Failed to embed output profile '%s' in '%s'."), + uf->conf->profile[out_profile] + [uf->conf->profileIndex[out_profile]].name, + uf->conf->outputFilename); + } + cmsCloseProfile(hOutProfile); + } + if (uf->conf->embedExif) { + ufraw_exif_prepare_output(uf); + if (uf->outputExifBuf != NULL) + PNGwriteRawProfile(png, info, "exif", + uf->outputExifBuf, uf->outputExifBufLen); + } + png_write_info(png, info); + if (BitDepth != 8 && G_BYTE_ORDER == G_LITTLE_ENDIAN) + png_set_swap(png); // Swap byte order to big-endian + + ufraw_write_image_data(uf, png, &Crop, BitDepth, grayscaleMode, + png_row_writer); + + png_write_end(png, NULL); + png_destroy_write_struct(&png, &info); + } +#endif /*HAVE_LIBPNG*/ +#ifdef HAVE_LIBCFITSIO + } else if (uf->conf->type == fits_type) { + + // image data and min/max values + guint16 *image; + guint16 max[3] = { 0, 0, 0 }, min[3] = { 65535, 65535, 65535 }; + guint64 sum[3] = { 0, 0, 0 }; + + // FITS Header (taken from cookbook.c) + int bitpix = USHORT_IMG; // Use float format + int naxis = 3; // 3-dimensional image + int status = 0; // status variable for fitsio + + long naxes[3] = { Crop.width, Crop.height, 3 }; + long dim = Crop.width * Crop.height; + long offset = 0; + + image = g_new(guint16, 3 * dim); + + int row; + int i; + ufraw_image_type *rawImage = + (ufraw_image_type *)uf->Images[ufraw_first_phase].buffer; + int rowStride = uf->Images[ufraw_first_phase].width; + guint16 pixbuf16[3]; + + // Avoid FITS images being saved upside down + ufraw_flip_image(uf, 2); + + progress(PROGRESS_SAVE, -Crop.height); + for (row = 0; row < Crop.height; row++) { + progress(PROGRESS_SAVE, 1); + for (i = 0; i < Crop.width; i++) { + offset = row * Crop.width + i; + develop_linear(rawImage[(Crop.y + row)*rowStride + Crop.x + i], pixbuf16, + uf->developer); + int c; + for (c = 0; c < 3; c++) { + sum[c] += image[c * dim + offset] = pixbuf16[c]; + max[c] = MAX(pixbuf16[c], max[c]); + min[c] = MIN(pixbuf16[c], min[c]); + } + } + } + // calculate averages + float average[3]; + int c; + for (c = 0; c < 3; c++) + average[c] = (float)sum[c] / dim; + + guint16 maxAll = MAX(MAX(max[0], max[1]), max[2]); + guint16 minAll = MIN(MIN(min[0], min[1]), min[2]); + + fits_create_img(fitsFile, bitpix, naxis, naxes, &status); + + fits_write_img(fitsFile, TUSHORT, 1, 3 * dim, image, &status); + g_free(image); + + fits_update_key(fitsFile, TUSHORT, "DATAMIN", &minAll, + "minimum data (overall)", &status); + fits_update_key(fitsFile, TUSHORT, "DATAMAX", &maxAll, + "maximum data (overall)", &status); + + fits_update_key(fitsFile, TUSHORT, "DATAMINR", &min[0], + "minimum data (red channel)", &status); + fits_update_key(fitsFile, TUSHORT, "DATAMAXR", &max[0], + "maximum data (red channel)", &status); + + fits_update_key(fitsFile, TUSHORT, "DATAMING", &min[1], + "minimum data (green channel)", &status); + fits_update_key(fitsFile, TUSHORT, "DATAMAXG", &max[1], + "maximum data (green channel)", &status); + + fits_update_key(fitsFile, TUSHORT, "DATAMINB", &min[2], + "minimum data (blue channel)", &status); + fits_update_key(fitsFile, TUSHORT, "DATAMAXB", &max[2], + "maximum data (blue channel)", &status); + + fits_update_key(fitsFile, TFLOAT, "AVERAGER", &average[0], + "average (red channel)", &status); + fits_update_key(fitsFile, TFLOAT, "AVERAGEG", &average[1], + "average (green channel)", &status); + fits_update_key(fitsFile, TFLOAT, "AVERAGEB", &average[2], + "average (blue channel)", &status); + + // Save known EXIF properties + if (strlen(uf->conf->shutterText) > 0) + fits_update_key(fitsFile, TSTRING, "EXPOSURE", + &uf->conf->shutterText, "Exposure Time", &status); + + if (strlen(uf->conf->isoText) > 0) + fits_update_key(fitsFile, TSTRING, "ISO", &uf->conf->isoText, + "ISO Speed", &status); + + if (strlen(uf->conf->apertureText) > 0) + fits_update_key(fitsFile, TSTRING, "APERTURE", + &uf->conf->apertureText, "Aperture", &status); + + if (strlen(uf->conf->focalLenText) > 0) + fits_update_key(fitsFile, TSTRING, "FOCALLEN", + &uf->conf->focalLenText, "Focal Length", &status); + + if (strlen(uf->conf->focalLen35Text) > 0) + fits_update_key(fitsFile, TSTRING, "FOCALLE2", + &uf->conf->focalLen35Text, "Focal Length (resp. 35mm)", + &status); + + if (strlen(uf->conf->lensText) > 0) + fits_update_key(fitsFile, TSTRING, "LENS", + &uf->conf->lensText, "Lens", &status); + + // formating the date according to the FITS standard + // http://archive.stsci.edu/fits/fits_standard/node40.html#s:dhist + if (uf->conf->timestamp != 0) { + char *time = g_new(char, 40); + struct tm tmStamp; + strftime(time, 40, "%Y-%m-%dT%H:%M:%S", + localtime_r(&uf->conf->timestamp, &tmStamp)); + fits_update_key(fitsFile, TSTRING, "DATE", time, + "Image taken at this date", &status); + g_free(time); + } + + if (strlen(uf->conf->make) > 0) + fits_update_key(fitsFile, TSTRING, "MANUFACT", &uf->conf->make, + "Camera Manufacturer", &status); + + if (strlen(uf->conf->model) > 0) + fits_update_key(fitsFile, TSTRING, "INSTRUME", &uf->conf->model, + "Camera Model", &status); + + fits_write_comment(fitsFile, "This file contains one RGB color image.", + &status); + + // Creator Ufraw + fits_update_key(fitsFile, TSTRING, "CREATOR", "UFRaw " VERSION, + "Creator Software", &status); + + fits_close_file(fitsFile, &status); + + if (status) { + ufraw_set_error(uf, _("Error creating file '%s'."), + uf->conf->outputFilename); + char errBuffer[max_name]; + fits_get_errstatus(status, errBuffer); + ufraw_set_error(uf, errBuffer); + while (fits_read_errmsg(errBuffer)) + ufraw_set_error(uf, errBuffer); + return ufraw_get_status(uf); + } +#endif /* HAVE_LIBCFITSIO */ + } else { + ufraw_set_error(uf, _("Error creating file '%s'."), + uf->conf->outputFilename); + ufraw_set_error(uf, _("Unknown file type %d."), uf->conf->type); + } +#ifdef HAVE_LIBTIFF + if (uf->conf->type == tiff_type) { + TIFFClose(out); + if (ufraw_tiff_message[0] != '\0') { + if (!ufraw_is_error(uf)) { // Error was not already set before + ufraw_set_error(uf, _("Error creating file.")); + ufraw_set_error(uf, ufraw_tiff_message); + } + ufraw_tiff_message[0] = '\0'; + } else { + if (uf->conf->embedExif) + ufraw_exif_write(uf); + } + } else +#endif +#ifdef HAVE_LIBCFITSIO + // Dummy to prevent fclose + if (uf->conf->type == fits_type) {} + else +#endif + { + if (strcmp(uf->conf->outputFilename, "-")) + if (fclose(out) != 0) { + if (!ufraw_is_error(uf)) { // Error was not already set before + ufraw_set_error(uf, _("Error creating file '%s'."), + uf->conf->outputFilename); + ufraw_set_error(uf, g_strerror(errno)); + } + } + } + if (uf->conf->createID == also_id) { + if (ufraw_get_message(uf) != NULL) + ufraw_message(UFRAW_SET_LOG, ufraw_get_message(uf)); + // TODO: error handling + conf_save(uf->conf, confFilename, NULL); + g_free(confFilename); + } + return ufraw_get_status(uf); +} + + +/* Write EXIF data to PNG file. + * Code copied from DigiKam's libs/dimg/loaders/pngloader.cpp. + * The EXIF embeding is defined by ImageMagicK. + * It is documented in the ExifTool page: + * http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PNG.html + */ + +#ifdef HAVE_LIBPNG +static void PNGwriteRawProfile(png_struct *ping, + png_info *ping_info, char *profile_type, guint8 *profile_data, + png_uint_32 length) +{ + png_textp text; + long i; + guint8 *sp; + png_charp dp; + png_uint_32 allocated_length, description_length; + + const guint8 hex[16] = + {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + text = png_malloc(ping, sizeof(png_text)); + description_length = strlen(profile_type); + allocated_length = length * 2 + (length >> 5) + 20 + description_length; + + text[0].text = png_malloc(ping, allocated_length); + text[0].key = png_malloc(ping, 80); + text[0].key[0] = '\0'; + + g_strlcat(text[0].key, "Raw profile type ", 80); + g_strlcat(text[0].key, profile_type, 80); + + sp = profile_data; + dp = text[0].text; + *dp++ = '\n'; + + g_strlcpy(dp, profile_type, allocated_length); + + dp += description_length; + *dp++ = '\n'; + *dp = '\0'; + +#if (PNG_LIBPNG_VER_MAJOR > 1 || (PNG_LIBPNG_VER_MAJOR == 1 && \ + PNG_LIBPNG_VER_MINOR > 2)) && (defined(INT_MAX) && INT_MAX > 0x7ffffffeL) + g_snprintf(dp, allocated_length - strlen(text[0].text), "%8u ", length); +#else + g_snprintf(dp, allocated_length - strlen(text[0].text), "%8lu ", length); +#endif + + dp += 8; + + for (i = 0; i < (long) length; i++) { + if (i % 36 == 0) + *dp++ = '\n'; + + *(dp++) = hex[((*sp >> 4) & 0x0f)]; + *(dp++) = hex[((*sp++) & 0x0f)]; + } + + *dp++ = '\n'; + *dp = '\0'; + text[0].text_length = (dp - text[0].text); + text[0].compression = -1; + + if (text[0].text_length <= allocated_length) + png_set_text(ping, ping_info, text, 1); + + png_free(ping, text[0].text); + png_free(ping, text[0].key); + png_free(ping, text); +} +#endif /*HAVE_LIBPNG*/ diff --git a/plugins/load-dcraw/wb_presets.c b/plugins/load-dcraw/wb_presets.c new file mode 100644 index 00000000..79fc2045 --- /dev/null +++ b/plugins/load-dcraw/wb_presets.c @@ -0,0 +1,10002 @@ +/* + * UFRaw - Unidentified Flying Raw converter for digital camera images + * + * wb_presets.c - White balance preset values for various cameras + * Copyright 2004-2016 by Udi Fuchs + * + * Thanks goes for all the people who sent in the preset values + * for their cameras. + * + * 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. + */ + +#include "ufraw.h" +#include + +/* Column 1 - "make" of the camera. + * Column 2 - "model" (use the "make" and "model" as provided by DCRaw). + * Column 3 - WB name. + * Column 4 - Fine tuning. MUST be in increasing order. 0 for no fine tuning. + * It is enough to give only the extreme values, the other values + * will be interpolated. + * Column 5 - Channel multipliers. + * + * MINOLTA's ALPHA and MAXXUM models are treated as the DYNAX model. + * + * WB name is standardized to one of the following: */ +// "Sunlight" and other variation should be switched to this: +static const char Daylight[] = N_("Daylight"); +// Probably same as above: +static const char DirectSunlight[] = N_("Direct sunlight"); +static const char Cloudy[] = N_("Cloudy"); +// "Shadows" should be switched to this: +static const char Shade[] = N_("Shade"); +static const char Incandescent[] = N_("Incandescent"); +static const char IncandescentWarm[] = N_("Incandescent warm"); +// Same as "Incandescent": +static const char Tungsten[] = N_("Tungsten"); +static const char Fluorescent[] = N_("Fluorescent"); +// In Canon cameras and some newer NIKON cameras: +static const char FluorescentHigh[] = N_("Fluorescent high"); +static const char CoolWhiteFluorescent[] = N_("Cool white fluorescent"); +static const char WarmWhiteFluorescent[] = N_("Warm white fluorescent"); +static const char DaylightFluorescent[] = N_("Daylight fluorescent"); +static const char NeutralFluorescent[] = N_("Neutral fluorescent"); +static const char WhiteFluorescent[] = N_("White fluorescent"); +// In some newer NIKON cameras: +static const char SodiumVaporFluorescent[] = N_("Sodium-vapor fluorescent"); +static const char DayWhiteFluorescent[] = N_("Day white fluorescent"); +static const char HighTempMercuryVaporFluorescent[] = N_("High temp. mercury-vapor fluorescent"); + +static const char Flash[] = N_("Flash"); +// For OLYMPUS with no real "Flash" preset: +static const char FlashAuto[] = N_("Flash (auto mode)"); +static const char EveningSun[] = N_("Evening sun"); +static const char Underwater[] = N_("Underwater"); +static const char BlackNWhite[] = N_("Black & white"); + +const char uf_spot_wb[] = "Spot WB"; +const char uf_manual_wb[] = N_("Manual WB"); +const char uf_camera_wb[] = N_("Camera WB"); +const char uf_auto_wb[] = N_("Auto WB"); + +const wb_data wb_preset[] = { + + { "", "", uf_camera_wb, 0, { 0, 0, 0, 0 } }, + { "", "", uf_manual_wb, 0, { 0, 0, 0, 0 } }, + { "", "", uf_auto_wb, 0, { 0, 0, 0, 0 } }, + + { "Canon", "PowerShot A630", Daylight, 0, { 1.831422, 1, 1.245671, 0 } }, + { "Canon", "PowerShot A630", Cloudy, 0, { 1.669924, 1, 1.326299, 0 } }, + { "Canon", "PowerShot A630", Tungsten, 0, { 1.696768, 1, 1.268658, 0 } }, + { "Canon", "PowerShot A630", Fluorescent, 0, { 1.869859, 1, 1.209110, 0 } }, + { "Canon", "PowerShot A630", FluorescentHigh, 0, { 1.855491, 1, 1.206855, 0 } }, + + { "Canon", "PowerShot A710 IS", Daylight, 0, { 1.683007, 1, 1.893246, 0 } }, + { "Canon", "PowerShot A710 IS", Cloudy, 0, { 1.871320, 1, 1.718648, 0 } }, + { "Canon", "PowerShot A710 IS", Tungsten, 0, { 1.268692, 1, 2.707944, 0 } }, + { "Canon", "PowerShot A710 IS", Fluorescent, 0, { 1.589857, 1, 2.051819, 0 } }, + { "Canon", "PowerShot A710 IS", FluorescentHigh, 0, { 1.820287, 1, 1.820287, 0 } }, + { "Canon", "PowerShot A710 IS", Underwater, 0, { 2.926108, 1, 1.376847, 0 } }, + + /* These presets were extracted from CHDK-generated DNG files. */ + { "Canon", "PowerShot A720 IS", Daylight, 0, { 2.059371, 1, 1.975553, 0 } }, + { "Canon", "PowerShot A720 IS", Cloudy, 0, { 2.262722, 1, 1.818935, 0 } }, + { "Canon", "PowerShot A720 IS", Tungsten, 0, { 1.632258, 1, 2.974194, 0 } }, + { "Canon", "PowerShot A720 IS", Fluorescent, 0, { 1.902728, 1, 2.365362, 0 } }, + { "Canon", "PowerShot A720 IS", FluorescentHigh, 0, { 2.243961, 1, 1.935990, 0 } }, + { "Canon", "PowerShot A720 IS", Underwater, 0, { 2.303465, 1, 1.882915, 0 } }, + { "Canon", "PowerShot A720 IS", Flash, 0, { 2.151586, 1, 1.864865, 0 } }, + + { "Canon", "PowerShot G1 X", Daylight, 0, { 1.950873, 1, 1.720524, 0 } }, + { "Canon", "PowerShot G1 X", Cloudy, 0, { 2.123060, 1, 1.578714, 0 } }, + { "Canon", "PowerShot G1 X", Tungsten, 0, { 1.244848, 1, 3.175758, 0 } }, + { "Canon", "PowerShot G1 X", Fluorescent, 0, { 1.674806, 1, 2.216426, 0 } }, + { "Canon", "PowerShot G1 X", Flash, 0, { 2.468997, 1, 1.299887, 0 } }, + + { "Canon", "PowerShot G1 X Mark II", Daylight, 0, { 1.981522, 1, 1.579348, 0 } }, + { "Canon", "PowerShot G1 X Mark II", Shade, 0, { 2.258772, 1, 1.350877, 0 } }, + { "Canon", "PowerShot G1 X Mark II", Cloudy, 0, { 2.138344, 1, 1.435730, 0 } }, + { "Canon", "PowerShot G1 X Mark II", Tungsten, 0, { 1.371036, 1, 2.464059, 0 } }, + { "Canon", "PowerShot G1 X Mark II", Fluorescent, 0, { 1.800680, 1, 2.060023, 0 } }, + { "Canon", "PowerShot G1 X Mark II", Flash, 0, { 2.442968, 1, 1.221484, 0 } }, + + { "Canon", "PowerShot G2", Daylight, 0, { 2.011483, 1, 1.299522, 0 } }, + { "Canon", "PowerShot G2", Cloudy, 0, { 2.032505, 1, 1.285851, 0 } }, + { "Canon", "PowerShot G2", Tungsten, 0, { 1.976008, 1, 1.332054, 0 } }, + { "Canon", "PowerShot G2", Fluorescent, 0, { 2.022010, 1, 1.295694, 0 } }, + { "Canon", "PowerShot G2", FluorescentHigh, 0, { 2.029637, 1, 1.286807, 0 } }, + { "Canon", "PowerShot G2", Flash, 0, { 2.153576, 1, 1.140680, 0 } }, + + { "Canon", "PowerShot G3", Daylight, 0, { 1.858513, 1, 1.387290, 0 } }, + { "Canon", "PowerShot G3", Cloudy, 0, { 1.951132, 1, 1.305125, 0 } }, + { "Canon", "PowerShot G3", Tungsten, 0, { 1.128386, 1, 2.313310, 0 } }, + { "Canon", "PowerShot G3", Fluorescent, 0, { 1.715573, 1, 2.194337, 0 } }, + { "Canon", "PowerShot G3", FluorescentHigh, 0, { 2.580563, 1, 1.496164, 0 } }, + { "Canon", "PowerShot G3", Flash, 0, { 2.293173, 1, 1.187416, 0 } }, + + { "Canon", "PowerShot G3 X", Daylight, 0, { 2.090493, 1, 1.770905, 0 } }, + { "Canon", "PowerShot G3 X", Shade, 0, { 2.371264, 1, 1.511494, 0 } }, + { "Canon", "PowerShot G3 X", Cloudy, 0, { 2.242286, 1, 1.608000, 0 } }, + { "Canon", "PowerShot G3 X", Tungsten, 0, { 1.463675, 1, 2.698718, 0 } }, + { "Canon", "PowerShot G3 X", Fluorescent, 0, { 2.119710, 1, 2.443773, 0 } }, + { "Canon", "PowerShot G3 X", Flash, 0, { 2.555426, 1, 1.417736, 0 } }, + + { "Canon", "PowerShot G5", Daylight, 0, { 1.639521, 1, 1.528144, 0 } }, + { "Canon", "PowerShot G5", Cloudy, 0, { 1.702153, 1, 1.462919, 0 } }, + { "Canon", "PowerShot G5", Tungsten, 0, { 1.135071, 1, 2.374408, 0 } }, + { "Canon", "PowerShot G5", Fluorescent, 0, { 1.660281, 1, 2.186462, 0 } }, + { "Canon", "PowerShot G5", FluorescentHigh, 0, { 1.463297, 1, 1.764140, 0 } }, + { "Canon", "PowerShot G5", Flash, 0, { 1.603593, 1, 1.562874, 0 } }, + + { "Canon", "PowerShot G5 X", Daylight, 0, { 2.210405, 1, 1.705202, 0 } }, + { "Canon", "PowerShot G5 X", Shade, 0, { 2.544601, 1, 1.462441, 0 } }, + { "Canon", "PowerShot G5 X", Cloudy, 0, { 2.389277, 1, 1.574592, 0 } }, + { "Canon", "PowerShot G5 X", Tungsten, 0, { 1.497868, 1, 2.715352, 0 } }, + { "Canon", "PowerShot G5 X", Fluorescent, 0, { 2.185766, 1, 2.396864, 0 } }, + { "Canon", "PowerShot G5 X", Flash, 0, { 2.637647, 1, 1.384706, 0 } }, + + { "Canon", "PowerShot G6", Daylight, 0, { 1.769704, 1, 1.637931, 0 } }, + { "Canon", "PowerShot G6", Cloudy, 0, { 2.062731, 1, 1.442804, 0 } }, + { "Canon", "PowerShot G6", Tungsten, 0, { 1.077106, 1, 2.721234, 0 } }, + { "Canon", "PowerShot G6", Fluorescent, 0, { 1.914922, 1, 2.142670, 0 } }, + { "Canon", "PowerShot G6", FluorescentHigh, 0, { 2.543677, 1, 1.650587, 0 } }, + { "Canon", "PowerShot G6", Flash, 0, { 2.285322, 1, 1.333333, 0 } }, + + /* Canon PowerShot G7 X Firmware Version 1.0.0 */ + { "Canon", "PowerShot G7 X", Daylight, -9, { 1.783160, 1, 2.119954, 0 } }, + { "Canon", "PowerShot G7 X", Daylight, -8, { 1.808266, 1, 2.072331, 0 } }, + { "Canon", "PowerShot G7 X", Daylight, -7, { 1.836197, 1, 2.028637, 0 } }, + { "Canon", "PowerShot G7 X", Daylight, -6, { 1.865143, 1, 1.986286, 0 } }, + { "Canon", "PowerShot G7 X", Daylight, -5, { 1.901938, 1, 1.930445, 0 } }, + { "Canon", "PowerShot G7 X", Daylight, -4, { 1.939773, 1, 1.878409, 0 } }, + { "Canon", "PowerShot G7 X", Daylight, -3, { 1.984091, 1, 1.831818, 0 } }, + { "Canon", "PowerShot G7 X", Daylight, -2, { 2.037500, 1, 1.780682, 0 } }, + { "Canon", "PowerShot G7 X", Daylight, -1, { 2.087699, 1, 1.739180, 0 } }, + { "Canon", "PowerShot G7 X", Daylight, 0, { 2.125285, 1, 1.703872, 0 } }, + { "Canon", "PowerShot G7 X", Daylight, 1, { 2.170091, 1, 1.670091, 0 } }, + { "Canon", "PowerShot G7 X", Daylight, 2, { 2.213227, 1, 1.624857, 0 } }, + { "Canon", "PowerShot G7 X", Daylight, 3, { 2.262857, 1, 1.584000, 0 } }, + { "Canon", "PowerShot G7 X", Daylight, 4, { 2.306286, 1, 1.544000, 0 } }, + { "Canon", "PowerShot G7 X", Daylight, 5, { 2.375000, 1, 1.494266, 0 } }, + { "Canon", "PowerShot G7 X", Daylight, 6, { 2.454441, 1, 1.445213, 0 } }, + { "Canon", "PowerShot G7 X", Daylight, 7, { 2.538636, 1, 1.396591, 0 } }, + { "Canon", "PowerShot G7 X", Daylight, 8, { 2.644444, 1, 1.340351, 0 } }, + { "Canon", "PowerShot G7 X", Daylight, 9, { 2.788849, 1, 1.282325, 0 } }, + { "Canon", "PowerShot G7 X", Shade, -9, { 1.964813, 1, 1.847900, 0 } }, + { "Canon", "PowerShot G7 X", Shade, -8, { 2.010216, 1, 1.800227, 0 } }, + { "Canon", "PowerShot G7 X", Shade, -7, { 2.062429, 1, 1.748014, 0 } }, + { "Canon", "PowerShot G7 X", Shade, -6, { 2.109339, 1, 1.716401, 0 } }, + { "Canon", "PowerShot G7 X", Shade, -5, { 2.144647, 1, 1.685649, 0 } }, + { "Canon", "PowerShot G7 X", Shade, -4, { 2.191562, 1, 1.644242, 0 } }, + { "Canon", "PowerShot G7 X", Shade, -3, { 2.238041, 1, 1.600228, 0 } }, + { "Canon", "PowerShot G7 X", Shade, -2, { 2.284247, 1, 1.559361, 0 } }, + { "Canon", "PowerShot G7 X", Shade, -1, { 2.342497, 1, 1.517755, 0 } }, + { "Canon", "PowerShot G7 X", Shade, 0, { 2.413318, 1, 1.463835, 0 } }, + { "Canon", "PowerShot G7 X", Shade, 1, { 2.494226, 1, 1.414550, 0 } }, + { "Canon", "PowerShot G7 X", Shade, 2, { 2.588372, 1, 1.363953, 0 } }, + { "Canon", "PowerShot G7 X", Shade, 3, { 2.720000, 1, 1.302353, 0 } }, + { "Canon", "PowerShot G7 X", Shade, 4, { 2.874402, 1, 1.247608, 0 } }, + { "Canon", "PowerShot G7 X", Shade, 5, { 3.064792, 1, 1.189487, 0 } }, + { "Canon", "PowerShot G7 X", Shade, 6, { 3.337121, 1, 1.126263, 0 } }, + { "Canon", "PowerShot G7 X", Shade, 7, { 3.668421, 1, 1.068421, 0 } }, + { "Canon", "PowerShot G7 X", Shade, 8, { 4.072022, 1, 1.015235, 0 } }, + { "Canon", "PowerShot G7 X", Shade, 9, { 4.596750, 1, 0.964549, 0 } }, + { "Canon", "PowerShot G7 X", Cloudy, -9, { 1.872872, 1, 1.937571, 0 } }, + { "Canon", "PowerShot G7 X", Cloudy, -8, { 1.918275, 1, 1.892168, 0 } }, + { "Canon", "PowerShot G7 X", Cloudy, -7, { 1.958050, 1, 1.843537, 0 } }, + { "Canon", "PowerShot G7 X", Cloudy, -6, { 2.002265, 1, 1.792752, 0 } }, + { "Canon", "PowerShot G7 X", Cloudy, -5, { 2.058957, 1, 1.746032, 0 } }, + { "Canon", "PowerShot G7 X", Cloudy, -4, { 2.097616, 1, 1.709421, 0 } }, + { "Canon", "PowerShot G7 X", Cloudy, -3, { 2.133939, 1, 1.675369, 0 } }, + { "Canon", "PowerShot G7 X", Cloudy, -2, { 2.186788, 1, 1.640091, 0 } }, + { "Canon", "PowerShot G7 X", Cloudy, -1, { 2.230068, 1, 1.595672, 0 } }, + { "Canon", "PowerShot G7 X", Cloudy, 0, { 2.278221, 1, 1.553022, 0 } }, + { "Canon", "PowerShot G7 X", Cloudy, 1, { 2.327252, 1, 1.508552, 0 } }, + { "Canon", "PowerShot G7 X", Cloudy, 2, { 2.403207, 1, 1.460481, 0 } }, + { "Canon", "PowerShot G7 X", Cloudy, 3, { 2.485023, 1, 1.411290, 0 } }, + { "Canon", "PowerShot G7 X", Cloudy, 4, { 2.575406, 1, 1.359629, 0 } }, + { "Canon", "PowerShot G7 X", Cloudy, 5, { 2.707746, 1, 1.299296, 0 } }, + { "Canon", "PowerShot G7 X", Cloudy, 6, { 2.860382, 1, 1.244630, 0 } }, + { "Canon", "PowerShot G7 X", Cloudy, 7, { 3.046285, 1, 1.187576, 0 } }, + { "Canon", "PowerShot G7 X", Cloudy, 8, { 3.316981, 1, 1.122013, 0 } }, + { "Canon", "PowerShot G7 X", Cloudy, 9, { 3.644823, 1, 1.064220, 0 } }, + { "Canon", "PowerShot G7 X", Tungsten, -9, { 1.257614, 1, 3.238579, 0 } }, + { "Canon", "PowerShot G7 X", Tungsten, -8, { 1.277778, 1, 3.184343, 0 } }, + { "Canon", "PowerShot G7 X", Tungsten, -7, { 1.301887, 1, 3.138365, 0 } }, + { "Canon", "PowerShot G7 X", Tungsten, -6, { 1.323714, 1, 3.094103, 0 } }, + { "Canon", "PowerShot G7 X", Tungsten, -5, { 1.344569, 1, 3.047441, 0 } }, + { "Canon", "PowerShot G7 X", Tungsten, -4, { 1.368486, 1, 2.980149, 0 } }, + { "Canon", "PowerShot G7 X", Tungsten, -3, { 1.389163, 1, 2.913793, 0 } }, + { "Canon", "PowerShot G7 X", Tungsten, -2, { 1.415441, 1, 2.857843, 0 } }, + { "Canon", "PowerShot G7 X", Tungsten, -1, { 1.437424, 1, 2.780073, 0 } }, + { "Canon", "PowerShot G7 X", Tungsten, 0, { 1.466102, 1, 2.727603, 0 } }, + { "Canon", "PowerShot G7 X", Tungsten, 1, { 1.492788, 1, 2.658654, 0 } }, + { "Canon", "PowerShot G7 X", Tungsten, 2, { 1.523353, 1, 2.605988, 0 } }, + { "Canon", "PowerShot G7 X", Tungsten, 3, { 1.546539, 1, 2.562053, 0 } }, + { "Canon", "PowerShot G7 X", Tungsten, 4, { 1.570749, 1, 2.516052, 0 } }, + { "Canon", "PowerShot G7 X", Tungsten, 5, { 1.601423, 1, 2.469751, 0 } }, + { "Canon", "PowerShot G7 X", Tungsten, 6, { 1.629586, 1, 2.427219, 0 } }, + { "Canon", "PowerShot G7 X", Tungsten, 7, { 1.659198, 1, 2.378538, 0 } }, + { "Canon", "PowerShot G7 X", Tungsten, 8, { 1.676023, 1, 2.311111, 0 } }, + { "Canon", "PowerShot G7 X", Tungsten, 9, { 1.709790, 1, 2.251748, 0 } }, + { "Canon", "PowerShot G7 X", Fluorescent, -9, { 1.784211, 1, 2.950000, 0 } }, + { "Canon", "PowerShot G7 X", Fluorescent, -8, { 1.817824, 1, 2.891219, 0 } }, + { "Canon", "PowerShot G7 X", Fluorescent, -7, { 1.851175, 1, 2.828982, 0 } }, + { "Canon", "PowerShot G7 X", Fluorescent, -6, { 1.883117, 1, 2.762338, 0 } }, + { "Canon", "PowerShot G7 X", Fluorescent, -5, { 1.916129, 1, 2.686452, 0 } }, + { "Canon", "PowerShot G7 X", Fluorescent, -4, { 1.948718, 1, 2.611538, 0 } }, + { "Canon", "PowerShot G7 X", Fluorescent, -3, { 1.984713, 1, 2.536306, 0 } }, + { "Canon", "PowerShot G7 X", Fluorescent, -2, { 2.017766, 1, 2.475888, 0 } }, + { "Canon", "PowerShot G7 X", Fluorescent, -1, { 2.049242, 1, 2.411616, 0 } }, + { "Canon", "PowerShot G7 X", Fluorescent, 0, { 2.083019, 1, 2.355975, 0 } }, + { "Canon", "PowerShot G7 X", Fluorescent, 1, { 2.116688, 1, 2.303639, 0 } }, + { "Canon", "PowerShot G7 X", Fluorescent, 2, { 2.158750, 1, 2.241250, 0 } }, + { "Canon", "PowerShot G7 X", Fluorescent, 3, { 2.212235, 1, 2.179775, 0 } }, + { "Canon", "PowerShot G7 X", Fluorescent, 4, { 2.265918, 1, 2.122347, 0 } }, + { "Canon", "PowerShot G7 X", Fluorescent, 5, { 2.324594, 1, 2.063670, 0 } }, + { "Canon", "PowerShot G7 X", Fluorescent, 6, { 2.384040, 1, 1.997506, 0 } }, + { "Canon", "PowerShot G7 X", Fluorescent, 7, { 2.434457, 1, 1.957553, 0 } }, + { "Canon", "PowerShot G7 X", Fluorescent, 8, { 2.488722, 1, 1.921053, 0 } }, + { "Canon", "PowerShot G7 X", Fluorescent, 9, { 2.547051, 1, 1.870765, 0 } }, + { "Canon", "PowerShot G7 X", FluorescentHigh, -9, { 2.137845, 1, 2.271930, 0 } }, + { "Canon", "PowerShot G7 X", FluorescentHigh, -8, { 2.186017, 1, 2.203496, 0 } }, + { "Canon", "PowerShot G7 X", FluorescentHigh, -7, { 2.238155, 1, 2.142145, 0 } }, + { "Canon", "PowerShot G7 X", FluorescentHigh, -6, { 2.288917, 1, 2.080946, 0 } }, + { "Canon", "PowerShot G7 X", FluorescentHigh, -5, { 2.348039, 1, 2.015931, 0 } }, + { "Canon", "PowerShot G7 X", FluorescentHigh, -4, { 2.413965, 1, 1.967581, 0 } }, + { "Canon", "PowerShot G7 X", FluorescentHigh, -3, { 2.460674, 1, 1.930087, 0 } }, + { "Canon", "PowerShot G7 X", FluorescentHigh, -2, { 2.513750, 1, 1.885000, 0 } }, + { "Canon", "PowerShot G7 X", FluorescentHigh, -1, { 2.576441, 1, 1.835840, 0 } }, + { "Canon", "PowerShot G7 X", FluorescentHigh, 0, { 2.637390, 1, 1.784191, 0 } }, + { "Canon", "PowerShot G7 X", FluorescentHigh, 1, { 2.700629, 1, 1.738365, 0 } }, + { "Canon", "PowerShot G7 X", FluorescentHigh, 2, { 2.790139, 1, 1.677623, 0 } }, + { "Canon", "PowerShot G7 X", FluorescentHigh, 3, { 2.891858, 1, 1.618321, 0 } }, + { "Canon", "PowerShot G7 X", FluorescentHigh, 4, { 3.001282, 1, 1.561538, 0 } }, + { "Canon", "PowerShot G7 X", FluorescentHigh, 5, { 3.157143, 1, 1.494805, 0 } }, + { "Canon", "PowerShot G7 X", FluorescentHigh, 6, { 3.352318, 1, 1.426490, 0 } }, + { "Canon", "PowerShot G7 X", FluorescentHigh, 7, { 3.576662, 1, 1.366350, 0 } }, + { "Canon", "PowerShot G7 X", FluorescentHigh, 8, { 3.911392, 1, 1.288326, 0 } }, + { "Canon", "PowerShot G7 X", FluorescentHigh, 9, { 4.358519, 1, 1.223704, 0 } }, + { "Canon", "PowerShot G7 X", Flash, -9, { 2.063564, 1, 1.745743, 0 } }, + { "Canon", "PowerShot G7 X", Flash, -8, { 2.097616, 1, 1.711691, 0 } }, + { "Canon", "PowerShot G7 X", Flash, -7, { 2.137500, 1, 1.678409, 0 } }, + { "Canon", "PowerShot G7 X", Flash, -6, { 2.181818, 1, 1.637500, 0 } }, + { "Canon", "PowerShot G7 X", Flash, -5, { 2.233485, 1, 1.596811, 0 } }, + { "Canon", "PowerShot G7 X", Flash, -4, { 2.281642, 1, 1.557583, 0 } }, + { "Canon", "PowerShot G7 X", Flash, -3, { 2.337143, 1, 1.514286, 0 } }, + { "Canon", "PowerShot G7 X", Flash, -2, { 2.405963, 1, 1.462156, 0 } }, + { "Canon", "PowerShot G7 X", Flash, -1, { 2.489043, 1, 1.414072, 0 } }, + { "Canon", "PowerShot G7 X", Flash, 0, { 2.585366, 1, 1.361208, 0 } }, + { "Canon", "PowerShot G7 X", Flash, 1, { 2.710928, 1, 1.301998, 0 } }, + { "Canon", "PowerShot G7 X", Flash, 2, { 2.869773, 1, 1.244922, 0 } }, + { "Canon", "PowerShot G7 X", Flash, 3, { 3.054878, 1, 1.185366, 0 } }, + { "Canon", "PowerShot G7 X", Flash, 4, { 3.318239, 1, 1.122013, 0 } }, + { "Canon", "PowerShot G7 X", Flash, 5, { 3.649606, 1, 1.066929, 0 } }, + { "Canon", "PowerShot G7 X", Flash, 6, { 4.066390, 1, 1.013831, 0 } }, + { "Canon", "PowerShot G7 X", Flash, 7, { 4.593796, 1, 0.964549, 0 } }, + { "Canon", "PowerShot G7 X", Flash, 8, { 5.258786, 1, 0.918530, 0 } }, + { "Canon", "PowerShot G7 X", Flash, 9, { 6.229537, 1, 0.875445, 0 } }, + { "Canon", "PowerShot G7 X", Underwater, -9, { 1.826772, 1, 2.085489, 0 } }, + { "Canon", "PowerShot G7 X", Underwater, -8, { 1.858889, 1, 2.036667, 0 } }, + { "Canon", "PowerShot G7 X", Underwater, -7, { 1.890258, 1, 1.995521, 0 } }, + { "Canon", "PowerShot G7 X", Underwater, -6, { 1.937984, 1, 1.937984, 0 } }, + { "Canon", "PowerShot G7 X", Underwater, -5, { 1.979911, 1, 1.888393, 0 } }, + { "Canon", "PowerShot G7 X", Underwater, -4, { 2.030963, 1, 1.837156, 0 } }, + { "Canon", "PowerShot G7 X", Underwater, -3, { 2.079365, 1, 1.783447, 0 } }, + { "Canon", "PowerShot G7 X", Underwater, -2, { 2.114317, 1, 1.744728, 0 } }, + { "Canon", "PowerShot G7 X", Underwater, -1, { 2.151025, 1, 1.714132, 0 } }, + { "Canon", "PowerShot G7 X", Underwater, 0, { 2.202198, 1, 1.675824, 0 } }, + { "Canon", "PowerShot G7 X", Underwater, 1, { 2.261521, 1, 1.632488, 0 } }, + { "Canon", "PowerShot G7 X", Underwater, 2, { 2.308370, 1, 1.591410, 0 } }, + { "Canon", "PowerShot G7 X", Underwater, 3, { 2.361392, 1, 1.551066, 0 } }, + { "Canon", "PowerShot G7 X", Underwater, 4, { 2.437355, 1, 1.497680, 0 } }, + { "Canon", "PowerShot G7 X", Underwater, 5, { 2.508869, 1, 1.444568, 0 } }, + { "Canon", "PowerShot G7 X", Underwater, 6, { 2.603859, 1, 1.398411, 0 } }, + { "Canon", "PowerShot G7 X", Underwater, 7, { 2.734624, 1, 1.337130, 0 } }, + { "Canon", "PowerShot G7 X", Underwater, 8, { 2.882016, 1, 1.278351, 0 } }, + { "Canon", "PowerShot G7 X", Underwater, 9, { 3.025362, 1, 1.225845, 0 } }, + + { "Canon", "PowerShot G7 X Mark II", Daylight, 0, { 2.111328, 1, 1.791992, 0 } }, + { "Canon", "PowerShot G7 X Mark II", Shade, 0, { 2.419922, 1, 1.485351, 0 } }, + { "Canon", "PowerShot G7 X Mark II", Cloudy, 0, { 2.274414, 1, 1.631836, 0 } }, + { "Canon", "PowerShot G7 X Mark II", Tungsten, 0, { 1.440430, 1, 2.782227, 0 } }, + { "Canon", "PowerShot G7 X Mark II", Fluorescent, 0, { 2.149414, 1, 2.474609, 0 } }, + { "Canon", "PowerShot G7 X Mark II", FluorescentHigh, 0, { 2.419922, 1, 1.485352, 0 } }, + { "Canon", "PowerShot G7 X Mark II", Underwater, 0, { 2.327148, 1, 1.642578, 0 } }, + { "Canon", "PowerShot G7 X Mark II", Flash, 0, { 2.576172, 1, 1.362305, 0 } }, + + { "Canon", "PowerShot G9", Daylight, 0, { 2.089552, 1, 1.786452, 0 } }, + { "Canon", "PowerShot G9", Cloudy, 0, { 2.208716, 1, 1.660550, 0 } }, + { "Canon", "PowerShot G9", Tungsten, 0, { 1.533493, 1, 2.586124, 0 } }, + { "Canon", "PowerShot G9", Fluorescent, 0, { 2.065668, 1, 1.829493, 0 } }, + { "Canon", "PowerShot G9", FluorescentHigh, 0, { 2.237601, 1, 1.668974, 0 } }, + { "Canon", "PowerShot G9", Flash, 0, { 2.461538, 1, 1.498834, 0 } }, + { "Canon", "PowerShot G9", Underwater, 0, { 2.237327, 1, 1.661290, 0 } }, + + /* Does the Canon PowerShot G10 support native WB presets? Please test. */ + { "Canon", "PowerShot G10", Daylight, 0, { 1.598980, 1, 1.830612, 0 } }, + { "Canon", "PowerShot G10", Cloudy, 0, { 1.738120, 1, 1.722281, 0 } }, + { "Canon", "PowerShot G10", Tungsten, 0, { 1, 1.035550, 3.569954, 0 } }, + { "Canon", "PowerShot G10", Fluorescent, 0, { 1.341633, 1, 2.434263, 0 } }, + { "Canon", "PowerShot G10", FluorescentHigh, 0, { 1.749171, 1, 1.907182, 0 } }, + { "Canon", "PowerShot G10", Flash, 0, { 1.926829, 1, 1.501591, 0 } }, + { "Canon", "PowerShot G10", Underwater, 0, { 1.822314, 1, 1.841942, 0 } }, + + { "Canon", "PowerShot G11", Daylight, 0, { 1.721591, 1, 2.097727, 0 } }, + { "Canon", "PowerShot G11", Cloudy, 0, { 1.910936, 1, 1.856821, 0 } }, + { "Canon", "PowerShot G11", Tungsten, 0, { 1.380435, 1, 3.576087, 0 } }, + { "Canon", "PowerShot G11", Fluorescent, 0, { 1.649143, 1, 2.693714, 0 } }, + { "Canon", "PowerShot G11", FluorescentHigh, 0, { 2.008168, 1, 1.961494, 0 } }, + { "Canon", "PowerShot G11", Flash, 0, { 1.985556, 1, 1.703333, 0 } }, + { "Canon", "PowerShot G11", Underwater, 0, { 2.225624, 1, 1.577098, 0 } }, + + { "Canon", "PowerShot G12", Daylight, 0, { 1.785877, 1, 2.042141, 0 } }, + { "Canon", "PowerShot G12", Cloudy, 0, { 1.804323, 1, 2.021615, 0 } }, + { "Canon", "PowerShot G12", Tungsten, 0, { 1.310127, 1, 3.170886, 0 } }, + { "Canon", "PowerShot G12", Fluorescent, 0, { 1.771139, 1, 2.064262, 0 } }, + { "Canon", "PowerShot G12", FluorescentHigh, 0, { 1.806122, 1, 2.032880, 0 } }, + { "Canon", "PowerShot G12", Flash, 0, { 2.102157, 1, 1.706016, 0 } }, + { "Canon", "PowerShot G12", Underwater, 0, { 1.807650, 1, 2.112568, 0 } }, + + { "Canon", "PowerShot G15", Daylight, 0, { 2.321149, 1, 2.357702, 0 } }, + { "Canon", "PowerShot G15", Cloudy, 0, { 2.733601, 1, 2.116466, 0 } }, + { "Canon", "PowerShot G15", Tungsten, 0, { 1.599064, 1, 4.386895, 0 } }, + { "Canon", "PowerShot G15", Fluorescent, 0, { 2.233933, 1, 2.728792, 0 } }, + { "Canon", "PowerShot G15", Flash, 0, { 2.919028, 1, 1.987854, 0 } }, + + { "Canon", "PowerShot G16", Daylight, 0, { 2.042745, 1, 1.786277, 0 } }, + { "Canon", "PowerShot G16", Cloudy, 0, { 2.212571, 1, 1.657143, 0 } }, + { "Canon", "PowerShot G16", Tungsten, 0, { 1.678571, 1, 2.625616, 0 } }, + { "Canon", "PowerShot G16", Fluorescent, 0, { 2.075472, 1, 1.957547, 0 } }, + { "Canon", "PowerShot G16", Flash, 0, { 2.634884, 1, 1.317442, 0 } }, + + /* Canon PowerShot S3 IS does not support native WB presets. These are made + as custom WB presets. */ + { "Canon", "PowerShot S3 IS", Daylight, 0, { 1.627271, 1, 1.823491, 0 } }, + { "Canon", "PowerShot S3 IS", Cloudy, 0, { 1.794382, 1, 1.618412, 0 } }, + { "Canon", "PowerShot S3 IS", Tungsten, 0, { 1, 1.192243, 4.546950, 0 } }, + { "Canon", "PowerShot S3 IS", Flash, 0, { 1.884691, 1, 1.553869, 0 } }, + + { "Canon", "PowerShot S30", Daylight, 0, { 1.741088, 1, 1.318949, 0 } }, + { "Canon", "PowerShot S30", Cloudy, 0, { 1.766635, 1, 1.298969, 0 } }, + { "Canon", "PowerShot S30", Tungsten, 0, { 1.498106, 1, 1.576705, 0 } }, + { "Canon", "PowerShot S30", Fluorescent, 0, { 1.660075, 1, 1.394539, 0 } }, + { "Canon", "PowerShot S30", FluorescentHigh, 0, { 1.753515, 1, 1.306467, 0 } }, + { "Canon", "PowerShot S30", Flash, 0, { 2.141705, 1, 1.097926, 0 } }, + + { "Canon", "PowerShot S45", Daylight, 0, { 2.325175, 1, 1.080420, 0 } }, + { "Canon", "PowerShot S45", Cloudy, 0, { 2.145047, 1, 1.173349, 0 } }, + { "Canon", "PowerShot S45", Tungsten, 0, { 1.213018, 1, 2.087574, 0 } }, + { "Canon", "PowerShot S45", Fluorescent, 0, { 1.888183, 1, 1.822109, 0 } }, + { "Canon", "PowerShot S45", FluorescentHigh, 0, { 2.964422, 1, 1.354511, 0 } }, + { "Canon", "PowerShot S45", Flash, 0, { 2.534884, 1, 1.065663, 0 } }, + + { "Canon", "PowerShot S50", Daylight, 0, { 1.772506, 1, 1.536496, 0 } }, + { "Canon", "PowerShot S50", Cloudy, 0, { 1.831311, 1, 1.484223, 0 } }, + { "Canon", "PowerShot S50", Tungsten, 0, { 1.185542, 1, 2.480723, 0 } }, + { "Canon", "PowerShot S50", Fluorescent, 0, { 1.706410, 1, 2.160256, 0 } }, + { "Canon", "PowerShot S50", FluorescentHigh, 0, { 1.562500, 1, 1.817402, 0 } }, + { "Canon", "PowerShot S50", Flash, 0, { 1.776156, 1, 1.531630, 0 } }, + + { "Canon", "PowerShot S60", Daylight, 0, { 1.759169, 1, 1.590465, 0 } }, + { "Canon", "PowerShot S60", Cloudy, 0, { 1.903659, 1, 1.467073, 0 } }, + { "Canon", "PowerShot S60", Tungsten, 0, { 1.138554, 1, 2.704819, 0 } }, + { "Canon", "PowerShot S60", Fluorescent, 0, { 1.720721, 1, 2.185328, 0 } }, + { "Canon", "PowerShot S60", FluorescentHigh, 0, { 2.877095, 1, 2.216480, 0 } }, + { "Canon", "PowerShot S60", Flash, 0, { 2.182540, 1, 1.236773, 0 } }, + { "Canon", "PowerShot S60", Underwater, 0, { 2.725369, 1, 1.240148, 0 } }, + + { "Canon", "PowerShot S70", Daylight, 0, { 1.943834, 1, 1.456654, 0 } }, + { "Canon", "PowerShot S70", Cloudy, 0, { 2.049939, 1, 1.382460, 0 } }, + { "Canon", "PowerShot S70", Tungsten, 0, { 1.169492, 1, 2.654964, 0 } }, + { "Canon", "PowerShot S70", Fluorescent, 0, { 1.993456, 1, 2.056283, 0 } }, + { "Canon", "PowerShot S70", FluorescentHigh, 0, { 2.645914, 1, 1.565499, 0 } }, + { "Canon", "PowerShot S70", Flash, 0, { 2.389189, 1, 1.147297, 0 } }, + { "Canon", "PowerShot S70", Underwater, 0, { 3.110565, 1, 1.162162, 0 } }, + + { "Canon", "PowerShot S90", Daylight, 0, { 1.955056, 1, 1.797753, 0 } }, + { "Canon", "PowerShot S90", Cloudy, 0, { 1.945067, 1, 1.795964, 0 } }, + { "Canon", "PowerShot S90", Tungsten, 0, { 2.000000, 1, 1.828018, 0 } }, + { "Canon", "PowerShot S90", Fluorescent, 0, { 2.019473, 1, 1.841924, 0 } }, + { "Canon", "PowerShot S90", FluorescentHigh, 0, { 2.009143, 1, 1.840000, 0 } }, + { "Canon", "PowerShot S90", Flash, 0, { 2.045784, 1, 1.671692, 0 } }, + { "Canon", "PowerShot S90", Underwater, 0, { 2.022297, 1, 1.830546, 0 } }, + + { "Canon", "PowerShot S95", Daylight, 0, { 1.6182, 1, 2.1430, 0 } }, + { "Canon", "PowerShot S95", Cloudy, 0, { 1.6920, 1, 2.0179, 0 } }, + { "Canon", "PowerShot S95", Tungsten, 0, { 1.2314, 1, 3.1015, 0 } }, + { "Canon", "PowerShot S95", Fluorescent, 0, { 1.6593, 1, 2.0940, 0 } }, + { "Canon", "PowerShot S95", FluorescentHigh, 0, { 1.7272, 1, 1.9811, 0 } }, + { "Canon", "PowerShot S95", Flash, 0, { 1.9955, 1, 1.7768, 0 } }, + { "Canon", "PowerShot S95", Underwater, 0, { 1.7607, 1, 2.1224, 0 } }, + + { "Canon", "PowerShot S100", Daylight, 0, { 2.077707, 1, 2.551592, 0 } }, + { "Canon", "PowerShot S100", Cloudy, 0, { 2.276402, 1, 2.393742, 0 } }, + { "Canon", "PowerShot S100", Tungsten, 0, { 1.267936, 1, 4.224012, 0 } }, + { "Canon", "PowerShot S100", Fluorescent, 0, { 1.815115, 1, 3.093117, 0 } }, + { "Canon", "PowerShot S100", FluorescentHigh, 0, { 2.398148, 1, 2.374339, 0 } }, + { "Canon", "PowerShot S100", Flash, 0, { 2.615783, 1, 2.001294, 0 } }, + { "Canon", "PowerShot S100", Underwater, 0, { 2.248391, 1, 2.338481, 0 } }, + + { "Canon", "PowerShot S110", Daylight, 0, { 2.111842, 1, 2.622368, 0 } }, + { "Canon", "PowerShot S110", Cloudy, 0, { 2.317460, 1, 2.449735, 0 } }, + { "Canon", "PowerShot S110", Tungsten, 0, { 1.520661, 1, 4.009642, 0 } }, + { "Canon", "PowerShot S110", Fluorescent, 0, { 1.879781, 1, 3.114754, 0 } }, + { "Canon", "PowerShot S110", Flash, 0, { 2.627968, 1, 2.121372, 0 } }, + + { "Canon", "PowerShot S120", Daylight, 0, { 2.333333, 1, 1.469388, 0 } }, + { "Canon", "PowerShot S120", Cloudy, 0, { 2.500000, 1, 1.370413, 0 } }, + { "Canon", "PowerShot S120", Tungsten, 0, { 1.754505, 1, 2.006757, 0 } }, + { "Canon", "PowerShot S120", Fluorescent, 0, { 2.523645, 1, 1.378316, 0 } }, + { "Canon", "PowerShot S120", Flash, 0, { 2.635198, 1, 1.329837, 0 } }, + + { "Canon", "PowerShot Pro1", Daylight, 0, { 1.829238, 1, 1.571253, 0 } }, + { "Canon", "PowerShot Pro1", Cloudy, 0, { 1.194139, 1, 2.755800, 0 } }, + { "Canon", "PowerShot Pro1", Tungsten, 0, { 1.701416, 1, 2.218790, 0 } }, + { "Canon", "PowerShot Pro1", Fluorescent, 0, { 2.014066, 1, 1.776215, 0 } }, + { "Canon", "PowerShot Pro1", FluorescentHigh, 0, { 2.248663, 1, 1.227273, 0 } }, + { "Canon", "PowerShot Pro1", Flash, 0, { 2.130081, 1, 1.422764, 0 } }, + + { "Canon", "PowerShot SX1 IS", Daylight, 0, { 1.574586, 1, 2.114917, 0 } }, + { "Canon", "PowerShot SX1 IS", Cloudy, 0, { 1.682628, 1, 2.015590, 0 } }, + { "Canon", "PowerShot SX1 IS", Tungsten, 0, { 1.088836, 1, 3.056423, 0 } }, + { "Canon", "PowerShot SX1 IS", Fluorescent, 0, { 1.398259, 1, 2.414581, 0 } }, + { "Canon", "PowerShot SX1 IS", FluorescentHigh, 0, { 1.687500, 1, 2.025670, 0 } }, + { "Canon", "PowerShot SX1 IS", Flash, 0, { 1.909699, 1, 1.795987, 0 } }, + + /* -9/+9 fine tuning is B9/A9 in blue-amber and zero in magenta-green */ + { "Canon", "PowerShot SX50 HS", Daylight, -9, { 1.260171, 1, 2.286938, 0 } }, + { "Canon", "PowerShot SX50 HS", Daylight, 0, { 1.502585, 1, 1.871768, 0 } }, + { "Canon", "PowerShot SX50 HS", Daylight, 9, { 1.868853, 1, 1.460041, 0 } }, + { "Canon", "PowerShot SX50 HS", Cloudy, -9, { 1.413865, 1, 1.962185, 0 } }, + { "Canon", "PowerShot SX50 HS", Cloudy, 0, { 1.767708, 1, 1.563542, 0 } }, + { "Canon", "PowerShot SX50 HS", Cloudy, 9, { 2.782759, 1, 1.100000, 0 } }, + { "Canon", "PowerShot SX50 HS", Tungsten, -9, { 1, 1.092348, 3.565963, 0 } }, + { "Canon", "PowerShot SX50 HS", Tungsten, 0, { 1.056582, 1, 2.853349, 0 } }, + { "Canon", "PowerShot SX50 HS", Tungsten, 9, { 1.251378, 1, 2.389195, 0 } }, + { "Canon", "PowerShot SX50 HS", Fluorescent, -9, { 1.197637, 1, 2.493018, 0 } }, + { "Canon", "PowerShot SX50 HS", Fluorescent, 0, { 1.383910, 1, 2.011202, 0 } }, + { "Canon", "PowerShot SX50 HS", Fluorescent, 9, { 1.677323, 1, 1.619381, 0 } }, + { "Canon", "PowerShot SX50 HS", FluorescentHigh, -9, { 1.468421, 1, 1.918947, 0 } }, + { "Canon", "PowerShot SX50 HS", FluorescentHigh, 0, { 1.805208, 1, 1.527083, 0 } }, + { "Canon", "PowerShot SX50 HS", FluorescentHigh, 9, { 3.464467, 1, 1.029188, 0 } }, + { "Canon", "PowerShot SX50 HS", Flash, -9, { 1.488683, 1, 1.777778, 0 } }, + { "Canon", "PowerShot SX50 HS", Flash, 0, { 1.876289, 1, 1.398969, 0 } }, + { "Canon", "PowerShot SX50 HS", Flash, 9, { 4.536036, 1.073574, 1, 0 } }, + + { "Canon", "PowerShot SX60 HS", Daylight, 0, { 1.605208, 1, 1.726042, 0 } }, + { "Canon", "PowerShot SX60 HS", Shade, 0, { 1.993697, 1, 1.379202, 0 } }, + { "Canon", "PowerShot SX60 HS", Cloudy, 0, { 1.876042, 1, 1.456250, 0 } }, + { "Canon", "PowerShot SX60 HS", Tungsten, 0, { 1.158014, 1, 2.616253, 0 } }, + { "Canon", "PowerShot SX60 HS", Fluorescent, 0, { 1.675497, 1, 2.254967, 0 } }, + { "Canon", "PowerShot SX60 HS", FluorescentHigh, 0, { 2.098851, 1, 1.785057, 0 } }, + { "Canon", "PowerShot SX60 HS", Flash, 0, { 1.966387, 1, 1.408613, 0 } }, + + { "Canon", "PowerShot SX160 IS", Daylight, 0, { 1.725252, 1, 1.444444, 0 } }, + { "Canon", "PowerShot SX160 IS", Cloudy, 0, { 1.843781, 1, 1.359204, 0 } }, + { "Canon", "PowerShot SX160 IS", Tungsten, 0, { 1.103726, 1, 2.322256, 0 } }, + { "Canon", "PowerShot SX160 IS", Fluorescent, 0, { 1.704705, 1, 1.463463, 0 } }, + { "Canon", "PowerShot SX160 IS", FluorescentHigh, 0, { 1.848423, 1, 1.355036, 0 } }, + + { "Canon", "EOS D60", Daylight, 0, { 2.472594, 1, 1.225335, 0 } }, + { "Canon", "EOS D60", Cloudy, 0, { 2.723926, 1, 1.137423, 0 } }, + { "Canon", "EOS D60", Tungsten, 0, { 1.543054, 1, 1.907003, 0 } }, + { "Canon", "EOS D60", Fluorescent, 0, { 1.957346, 1, 1.662322, 0 } }, + { "Canon", "EOS D60", Flash, 0, { 2.829840, 1, 1.108508, 0 } }, + + { "Canon", "EOS 5D", Flash, 0, { 2.211914, 1, 1.260742, 0 } }, /*6550K*/ + { "Canon", "EOS 5D", WhiteFluorescent, 0, { 1.726054, 1, 2.088123, 0 } }, /*3850K*/ + { "Canon", "EOS 5D", Tungsten, 0, { 1.373285, 1, 2.301006, 0 } }, /*3250K*/ + { "Canon", "EOS 5D", Cloudy, 0, { 2.151367, 1, 1.321289, 0 } }, /*6100K*/ + { "Canon", "EOS 5D", Shade, 0, { 2.300781, 1, 1.208008, 0 } }, /*7200K*/ + { "Canon", "EOS 5D", Daylight, 0, { 1.988281, 1, 1.457031, 0 } }, /*5250K*/ + + /* Canon EOS 5D Mark II firmware 2.0.7 */ + { "Canon", "EOS 5D Mark II", Daylight, -9, { 1.954102, 1, 1.984375, 0 } }, + { "Canon", "EOS 5D Mark II", Daylight, -8, { 1.976563, 1, 1.954102, 0 } }, + { "Canon", "EOS 5D Mark II", Daylight, -7, { 2.003906, 1, 1.917969, 0 } }, + { "Canon", "EOS 5D Mark II", Daylight, -6, { 2.032227, 1, 1.885742, 0 } }, + { "Canon", "EOS 5D Mark II", Daylight, -5, { 2.060547, 1, 1.851563, 0 } }, + { "Canon", "EOS 5D Mark II", Daylight, -4, { 2.093750, 1, 1.818359, 0 } }, + { "Canon", "EOS 5D Mark II", Daylight, -3, { 2.120117, 1, 1.787109, 0 } }, + { "Canon", "EOS 5D Mark II", Daylight, -2, { 2.151367, 1, 1.756836, 0 } }, + { "Canon", "EOS 5D Mark II", Daylight, -1, { 2.183594, 1, 1.723633, 0 } }, + { "Canon", "EOS 5D Mark II", Daylight, 0, { 2.216797, 1, 1.689453, 0 } }, + { "Canon", "EOS 5D Mark II", Daylight, 1, { 2.250977, 1, 1.659180, 0 } }, + { "Canon", "EOS 5D Mark II", Daylight, 2, { 2.291016, 1, 1.627930, 0 } }, + { "Canon", "EOS 5D Mark II", Daylight, 3, { 2.327148, 1, 1.594727, 0 } }, + { "Canon", "EOS 5D Mark II", Daylight, 4, { 2.359375, 1, 1.563477, 0 } }, + { "Canon", "EOS 5D Mark II", Daylight, 5, { 2.392578, 1, 1.528320, 0 } }, + { "Canon", "EOS 5D Mark II", Daylight, 6, { 2.420898, 1, 1.503906, 0 } }, + { "Canon", "EOS 5D Mark II", Daylight, 7, { 2.450195, 1, 1.477539, 0 } }, + { "Canon", "EOS 5D Mark II", Daylight, 8, { 2.485352, 1, 1.450195, 0 } }, + { "Canon", "EOS 5D Mark II", Daylight, 9, { 2.528320, 1, 1.421875, 0 } }, + { "Canon", "EOS 5D Mark II", Shade, -9, { 2.250977, 1, 1.662109, 0 } }, + { "Canon", "EOS 5D Mark II", Shade, -8, { 2.286133, 1, 1.630859, 0 } }, + { "Canon", "EOS 5D Mark II", Shade, -7, { 2.322266, 1, 1.599609, 0 } }, + { "Canon", "EOS 5D Mark II", Shade, -6, { 2.354492, 1, 1.565430, 0 } }, + { "Canon", "EOS 5D Mark II", Shade, -5, { 2.386719, 1, 1.533203, 0 } }, + { "Canon", "EOS 5D Mark II", Shade, -4, { 2.415039, 1, 1.505859, 0 } }, + { "Canon", "EOS 5D Mark II", Shade, -3, { 2.450195, 1, 1.479492, 0 } }, + { "Canon", "EOS 5D Mark II", Shade, -2, { 2.485352, 1, 1.452148, 0 } }, + { "Canon", "EOS 5D Mark II", Shade, -1, { 2.522461, 1, 1.425781, 0 } }, + { "Canon", "EOS 5D Mark II", Shade, 0, { 2.559570, 1, 1.397461, 0 } }, + { "Canon", "EOS 5D Mark II", Shade, 1, { 2.585938, 1, 1.383789, 0 } }, + { "Canon", "EOS 5D Mark II", Shade, 2, { 2.605469, 1, 1.371094, 0 } }, + { "Canon", "EOS 5D Mark II", Shade, 3, { 2.632813, 1, 1.354492, 0 } }, + { "Canon", "EOS 5D Mark II", Shade, 4, { 2.660156, 1, 1.338867, 0 } }, + { "Canon", "EOS 5D Mark II", Shade, 5, { 2.687500, 1, 1.316406, 0 } }, + { "Canon", "EOS 5D Mark II", Shade, 6, { 2.723633, 1, 1.290039, 0 } }, + { "Canon", "EOS 5D Mark II", Shade, 7, { 2.767578, 1, 1.260742, 0 } }, + { "Canon", "EOS 5D Mark II", Shade, 8, { 2.821289, 1, 1.232422, 0 } }, + { "Canon", "EOS 5D Mark II", Shade, 9, { 2.868164, 1, 1.203125, 0 } }, + { "Canon", "EOS 5D Mark II", Cloudy, -9, { 2.098633, 1, 1.812500, 0 } }, + { "Canon", "EOS 5D Mark II", Cloudy, -8, { 2.124023, 1, 1.784180, 0 } }, + { "Canon", "EOS 5D Mark II", Cloudy, -7, { 2.156250, 1, 1.750000, 0 } }, + { "Canon", "EOS 5D Mark II", Cloudy, -6, { 2.188477, 1, 1.717773, 0 } }, + { "Canon", "EOS 5D Mark II", Cloudy, -5, { 2.221680, 1, 1.686523, 0 } }, + { "Canon", "EOS 5D Mark II", Cloudy, -4, { 2.255859, 1, 1.657227, 0 } }, + { "Canon", "EOS 5D Mark II", Cloudy, -3, { 2.295898, 1, 1.623047, 0 } }, + { "Canon", "EOS 5D Mark II", Cloudy, -2, { 2.333008, 1, 1.592773, 0 } }, + { "Canon", "EOS 5D Mark II", Cloudy, -1, { 2.359375, 1, 1.558594, 0 } }, + { "Canon", "EOS 5D Mark II", Cloudy, 0, { 2.392578, 1, 1.523438, 0 } }, + { "Canon", "EOS 5D Mark II", Cloudy, 1, { 2.426758, 1, 1.499023, 0 } }, + { "Canon", "EOS 5D Mark II", Cloudy, 2, { 2.456055, 1, 1.473633, 0 } }, + { "Canon", "EOS 5D Mark II", Cloudy, 3, { 2.491211, 1, 1.446289, 0 } }, + { "Canon", "EOS 5D Mark II", Cloudy, 4, { 2.528320, 1, 1.419922, 0 } }, + { "Canon", "EOS 5D Mark II", Cloudy, 5, { 2.566406, 1, 1.395508, 0 } }, + { "Canon", "EOS 5D Mark II", Cloudy, 6, { 2.585938, 1, 1.379883, 0 } }, + { "Canon", "EOS 5D Mark II", Cloudy, 7, { 2.612305, 1, 1.367188, 0 } }, + { "Canon", "EOS 5D Mark II", Cloudy, 8, { 2.639648, 1, 1.350586, 0 } }, + { "Canon", "EOS 5D Mark II", Cloudy, 9, { 2.660156, 1, 1.334961, 0 } }, + { "Canon", "EOS 5D Mark II", Tungsten, -9, { 1.383128, 1, 3.084359, 0 } }, + { "Canon", "EOS 5D Mark II", Tungsten, -8, { 1.399119, 1, 3.026432, 0 } }, + { "Canon", "EOS 5D Mark II", Tungsten, -7, { 1.419098, 1, 2.984085, 0 } }, + { "Canon", "EOS 5D Mark II", Tungsten, -6, { 1.439219, 1, 2.935226, 0 } }, + { "Canon", "EOS 5D Mark II", Tungsten, -5, { 1.460374, 1, 2.886910, 0 } }, + { "Canon", "EOS 5D Mark II", Tungsten, -4, { 1.484361, 1, 2.840036, 0 } }, + { "Canon", "EOS 5D Mark II", Tungsten, -3, { 1.503139, 1, 2.787444, 0 } }, + { "Canon", "EOS 5D Mark II", Tungsten, -2, { 1.527027, 1, 2.740541, 0 } }, + { "Canon", "EOS 5D Mark II", Tungsten, -1, { 1.550226, 1, 2.695023, 0 } }, + { "Canon", "EOS 5D Mark II", Tungsten, 0, { 1.573115, 1, 2.646685, 0 } }, + { "Canon", "EOS 5D Mark II", Tungsten, 1, { 1.594891, 1, 2.596715, 0 } }, + { "Canon", "EOS 5D Mark II", Tungsten, 2, { 1.615949, 1, 2.549038, 0 } }, + { "Canon", "EOS 5D Mark II", Tungsten, 3, { 1.638710, 1, 2.494009, 0 } }, + { "Canon", "EOS 5D Mark II", Tungsten, 4, { 1.661111, 1, 2.443519, 0 } }, + { "Canon", "EOS 5D Mark II", Tungsten, 5, { 1.689013, 1, 2.391993, 0 } }, + { "Canon", "EOS 5D Mark II", Tungsten, 6, { 1.712816, 1, 2.349860, 0 } }, + { "Canon", "EOS 5D Mark II", Tungsten, 7, { 1.736595, 1, 2.305738, 0 } }, + { "Canon", "EOS 5D Mark II", Tungsten, 8, { 1.760417, 1, 2.266098, 0 } }, + { "Canon", "EOS 5D Mark II", Tungsten, 9, { 1.787417, 1, 2.222116, 0 } }, + { "Canon", "EOS 5D Mark II", WhiteFluorescent, -9, { 1.669691, 1, 2.900181, 0 } }, + { "Canon", "EOS 5D Mark II", WhiteFluorescent, -8, { 1.695533, 1, 2.849590, 0 } }, + { "Canon", "EOS 5D Mark II", WhiteFluorescent, -7, { 1.717033, 1, 2.806777, 0 } }, + { "Canon", "EOS 5D Mark II", WhiteFluorescent, -6, { 1.740809, 1, 2.761029, 0 } }, + { "Canon", "EOS 5D Mark II", WhiteFluorescent, -5, { 1.765683, 1, 2.716790, 0 } }, + { "Canon", "EOS 5D Mark II", WhiteFluorescent, -4, { 1.794063, 1, 2.667904, 0 } }, + { "Canon", "EOS 5D Mark II", WhiteFluorescent, -3, { 1.820298, 1, 2.619181, 0 } }, + { "Canon", "EOS 5D Mark II", WhiteFluorescent, -2, { 1.841760, 1, 2.567416, 0 } }, + { "Canon", "EOS 5D Mark II", WhiteFluorescent, -1, { 1.870056, 1, 2.516949, 0 } }, + { "Canon", "EOS 5D Mark II", WhiteFluorescent, 0, { 1.895833, 1, 2.461174, 0 } }, + { "Canon", "EOS 5D Mark II", WhiteFluorescent, 1, { 1.928503, 1, 2.416587, 0 } }, + { "Canon", "EOS 5D Mark II", WhiteFluorescent, 2, { 1.956772, 1, 2.365994, 0 } }, + { "Canon", "EOS 5D Mark II", WhiteFluorescent, 3, { 1.978744, 1, 2.320773, 0 } }, + { "Canon", "EOS 5D Mark II", WhiteFluorescent, 4, { 2.009718, 1, 2.281827, 0 } }, + { "Canon", "EOS 5D Mark II", WhiteFluorescent, 5, { 2.036133, 1, 2.240234, 0 } }, + { "Canon", "EOS 5D Mark II", WhiteFluorescent, 6, { 2.068359, 1, 2.197266, 0 } }, + { "Canon", "EOS 5D Mark II", WhiteFluorescent, 7, { 2.098633, 1, 2.160156, 0 } }, + { "Canon", "EOS 5D Mark II", WhiteFluorescent, 8, { 2.128906, 1, 2.120117, 0 } }, + { "Canon", "EOS 5D Mark II", WhiteFluorescent, 9, { 2.156250, 1, 2.081055, 0 } }, + { "Canon", "EOS 5D Mark II", Flash, -9, { 2.111328, 1, 1.792969, 0 } }, + { "Canon", "EOS 5D Mark II", Flash, -8, { 2.142578, 1, 1.762695, 0 } }, + { "Canon", "EOS 5D Mark II", Flash, -7, { 2.173828, 1, 1.732422, 0 } }, + { "Canon", "EOS 5D Mark II", Flash, -6, { 2.207031, 1, 1.698242, 0 } }, + { "Canon", "EOS 5D Mark II", Flash, -5, { 2.240234, 1, 1.667969, 0 } }, + { "Canon", "EOS 5D Mark II", Flash, -4, { 2.280273, 1, 1.635742, 0 } }, + { "Canon", "EOS 5D Mark II", Flash, -3, { 2.316406, 1, 1.602539, 0 } }, + { "Canon", "EOS 5D Mark II", Flash, -2, { 2.348633, 1, 1.570313, 0 } }, + { "Canon", "EOS 5D Mark II", Flash, -1, { 2.381836, 1, 1.537109, 0 } }, + { "Canon", "EOS 5D Mark II", Flash, 0, { 2.409180, 1, 1.507813, 0 } }, + { "Canon", "EOS 5D Mark II", Flash, 1, { 2.444336, 1, 1.484375, 0 } }, + { "Canon", "EOS 5D Mark II", Flash, 2, { 2.479492, 1, 1.457031, 0 } }, + { "Canon", "EOS 5D Mark II", Flash, 3, { 2.515625, 1, 1.429688, 0 } }, + { "Canon", "EOS 5D Mark II", Flash, 4, { 2.553711, 1, 1.402344, 0 } }, + { "Canon", "EOS 5D Mark II", Flash, 5, { 2.579102, 1, 1.385742, 0 } }, + { "Canon", "EOS 5D Mark II", Flash, 6, { 2.598633, 1, 1.373047, 0 } }, + { "Canon", "EOS 5D Mark II", Flash, 7, { 2.625977, 1, 1.356445, 0 } }, + { "Canon", "EOS 5D Mark II", Flash, 8, { 2.653320, 1, 1.339844, 0 } }, + { "Canon", "EOS 5D Mark II", Flash, 9, { 2.680664, 1, 1.321289, 0 } }, + + /* Canon EOS 5D Mark III Firmware Version 1.1.3 */ + /* Fine-tuning is the camera's Amber-Blue bracketing. */ + { "Canon", "EOS 5D Mark III", Daylight, -9, { 1.784180, 1, 1.907227, 0 } }, + { "Canon", "EOS 5D Mark III", Daylight, -8, { 1.805664, 1, 1.878906, 0 } }, + { "Canon", "EOS 5D Mark III", Daylight, -7, { 1.828125, 1, 1.848633, 0 } }, + { "Canon", "EOS 5D Mark III", Daylight, -6, { 1.855469, 1, 1.818359, 0 } }, + { "Canon", "EOS 5D Mark III", Daylight, -5, { 1.882813, 1, 1.790039, 0 } }, + { "Canon", "EOS 5D Mark III", Daylight, -4, { 1.910156, 1, 1.759766, 0 } }, + { "Canon", "EOS 5D Mark III", Daylight, -3, { 1.931641, 1, 1.726563, 0 } }, + { "Canon", "EOS 5D Mark III", Daylight, -2, { 1.958008, 1, 1.695313, 0 } }, + { "Canon", "EOS 5D Mark III", Daylight, -1, { 1.980469, 1, 1.665039, 0 } }, + { "Canon", "EOS 5D Mark III", Daylight, 0, { 2.007813, 1, 1.630859, 0 } }, + { "Canon", "EOS 5D Mark III", Daylight, 1, { 2.036133, 1, 1.607422, 0 } }, + { "Canon", "EOS 5D Mark III", Daylight, 2, { 2.064453, 1, 1.583008, 0 } }, + { "Canon", "EOS 5D Mark III", Daylight, 3, { 2.093750, 1, 1.556641, 0 } }, + { "Canon", "EOS 5D Mark III", Daylight, 4, { 2.124023, 1, 1.533203, 0 } }, + { "Canon", "EOS 5D Mark III", Daylight, 5, { 2.160156, 1, 1.507813, 0 } }, + { "Canon", "EOS 5D Mark III", Daylight, 6, { 2.183594, 1, 1.486328, 0 } }, + { "Canon", "EOS 5D Mark III", Daylight, 7, { 2.211914, 1, 1.462891, 0 } }, + { "Canon", "EOS 5D Mark III", Daylight, 8, { 2.240234, 1, 1.440430, 0 } }, + { "Canon", "EOS 5D Mark III", Daylight, 9, { 2.275391, 1, 1.416016, 0 } }, + { "Canon", "EOS 5D Mark III", Shade, -9, { 2.032227, 1, 1.610352, 0 } }, + { "Canon", "EOS 5D Mark III", Shade, -8, { 2.060547, 1, 1.584961, 0 } }, + { "Canon", "EOS 5D Mark III", Shade, -7, { 2.089844, 1, 1.558594, 0 } }, + { "Canon", "EOS 5D Mark III", Shade, -6, { 2.120117, 1, 1.535156, 0 } }, + { "Canon", "EOS 5D Mark III", Shade, -5, { 2.156250, 1, 1.510742, 0 } }, + { "Canon", "EOS 5D Mark III", Shade, -4, { 2.183594, 1, 1.488281, 0 } }, + { "Canon", "EOS 5D Mark III", Shade, -3, { 2.211914, 1, 1.464844, 0 } }, + { "Canon", "EOS 5D Mark III", Shade, -2, { 2.240234, 1, 1.442383, 0 } }, + { "Canon", "EOS 5D Mark III", Shade, -1, { 2.270508, 1, 1.417969, 0 } }, + { "Canon", "EOS 5D Mark III", Shade, 0, { 2.306641, 1, 1.393555, 0 } }, + { "Canon", "EOS 5D Mark III", Shade, 1, { 2.337891, 1, 1.374023, 0 } }, + { "Canon", "EOS 5D Mark III", Shade, 2, { 2.370117, 1, 1.352539, 0 } }, + { "Canon", "EOS 5D Mark III", Shade, 3, { 2.403320, 1, 1.332031, 0 } }, + { "Canon", "EOS 5D Mark III", Shade, 4, { 2.444336, 1, 1.307617, 0 } }, + { "Canon", "EOS 5D Mark III", Shade, 5, { 2.479492, 1, 1.286133, 0 } }, + { "Canon", "EOS 5D Mark III", Shade, 6, { 2.509766, 1, 1.267578, 0 } }, + { "Canon", "EOS 5D Mark III", Shade, 7, { 2.541016, 1, 1.246094, 0 } }, + { "Canon", "EOS 5D Mark III", Shade, 8, { 2.579102, 1, 1.224609, 0 } }, + { "Canon", "EOS 5D Mark III", Shade, 9, { 2.612305, 1, 1.203125, 0 } }, + { "Canon", "EOS 5D Mark III", Cloudy, -9, { 1.914063, 1, 1.753906, 0 } }, + { "Canon", "EOS 5D Mark III", Cloudy, -8, { 1.935547, 1, 1.723633, 0 } }, + { "Canon", "EOS 5D Mark III", Cloudy, -7, { 1.958008, 1, 1.692383, 0 } }, + { "Canon", "EOS 5D Mark III", Cloudy, -6, { 1.984375, 1, 1.659180, 0 } }, + { "Canon", "EOS 5D Mark III", Cloudy, -5, { 2.011719, 1, 1.627930, 0 } }, + { "Canon", "EOS 5D Mark III", Cloudy, -4, { 2.040039, 1, 1.605469, 0 } }, + { "Canon", "EOS 5D Mark III", Cloudy, -3, { 2.068359, 1, 1.578125, 0 } }, + { "Canon", "EOS 5D Mark III", Cloudy, -2, { 2.098633, 1, 1.553711, 0 } }, + { "Canon", "EOS 5D Mark III", Cloudy, -1, { 2.128906, 1, 1.528320, 0 } }, + { "Canon", "EOS 5D Mark III", Cloudy, 0, { 2.160156, 1, 1.503906, 0 } }, + { "Canon", "EOS 5D Mark III", Cloudy, 1, { 2.188477, 1, 1.484375, 0 } }, + { "Canon", "EOS 5D Mark III", Cloudy, 2, { 2.216797, 1, 1.460938, 0 } }, + { "Canon", "EOS 5D Mark III", Cloudy, 3, { 2.246094, 1, 1.436523, 0 } }, + { "Canon", "EOS 5D Mark III", Cloudy, 4, { 2.280273, 1, 1.412109, 0 } }, + { "Canon", "EOS 5D Mark III", Cloudy, 5, { 2.316406, 1, 1.389648, 0 } }, + { "Canon", "EOS 5D Mark III", Cloudy, 6, { 2.342773, 1, 1.369141, 0 } }, + { "Canon", "EOS 5D Mark III", Cloudy, 7, { 2.375977, 1, 1.347656, 0 } }, + { "Canon", "EOS 5D Mark III", Cloudy, 8, { 2.415039, 1, 1.326172, 0 } }, + { "Canon", "EOS 5D Mark III", Cloudy, 9, { 2.456055, 1, 1.302734, 0 } }, + { "Canon", "EOS 5D Mark III", Tungsten, -9, { 1.283203, 1, 2.782227, 0 } }, + { "Canon", "EOS 5D Mark III", Tungsten, -8, { 1.297852, 1, 2.752930, 0 } }, + { "Canon", "EOS 5D Mark III", Tungsten, -7, { 1.314453, 1, 2.723633, 0 } }, + { "Canon", "EOS 5D Mark III", Tungsten, -6, { 1.333008, 1, 2.694336, 0 } }, + { "Canon", "EOS 5D Mark III", Tungsten, -5, { 1.350586, 1, 2.666992, 0 } }, + { "Canon", "EOS 5D Mark III", Tungsten, -4, { 1.371094, 1, 2.632813, 0 } }, + { "Canon", "EOS 5D Mark III", Tungsten, -3, { 1.387695, 1, 2.579102, 0 } }, + { "Canon", "EOS 5D Mark III", Tungsten, -2, { 1.404297, 1, 2.528320, 0 } }, + { "Canon", "EOS 5D Mark III", Tungsten, -1, { 1.423828, 1, 2.479492, 0 } }, + { "Canon", "EOS 5D Mark III", Tungsten, 0, { 1.442383, 1, 2.426758, 0 } }, + { "Canon", "EOS 5D Mark III", Tungsten, 1, { 1.460938, 1, 2.392578, 0 } }, + { "Canon", "EOS 5D Mark III", Tungsten, 2, { 1.479492, 1, 2.354492, 0 } }, + { "Canon", "EOS 5D Mark III", Tungsten, 3, { 1.501953, 1, 2.316406, 0 } }, + { "Canon", "EOS 5D Mark III", Tungsten, 4, { 1.523438, 1, 2.280273, 0 } }, + { "Canon", "EOS 5D Mark III", Tungsten, 5, { 1.546875, 1, 2.240234, 0 } }, + { "Canon", "EOS 5D Mark III", Tungsten, 6, { 1.568359, 1, 2.207031, 0 } }, + { "Canon", "EOS 5D Mark III", Tungsten, 7, { 1.587891, 1, 2.169922, 0 } }, + { "Canon", "EOS 5D Mark III", Tungsten, 8, { 1.610352, 1, 2.133789, 0 } }, + { "Canon", "EOS 5D Mark III", Tungsten, 9, { 1.632813, 1, 2.098633, 0 } }, + { "Canon", "EOS 5D Mark III", WhiteFluorescent, -9, { 1.551758, 1, 2.702148, 0 } }, + { "Canon", "EOS 5D Mark III", WhiteFluorescent, -8, { 1.573242, 1, 2.673828, 0 } }, + { "Canon", "EOS 5D Mark III", WhiteFluorescent, -7, { 1.592773, 1, 2.645508, 0 } }, + { "Canon", "EOS 5D Mark III", WhiteFluorescent, -6, { 1.615234, 1, 2.592773, 0 } }, + { "Canon", "EOS 5D Mark III", WhiteFluorescent, -5, { 1.638672, 1, 2.541016, 0 } }, + { "Canon", "EOS 5D Mark III", WhiteFluorescent, -4, { 1.662109, 1, 2.491211, 0 } }, + { "Canon", "EOS 5D Mark III", WhiteFluorescent, -3, { 1.684570, 1, 2.438477, 0 } }, + { "Canon", "EOS 5D Mark III", WhiteFluorescent, -2, { 1.709961, 1, 2.398438, 0 } }, + { "Canon", "EOS 5D Mark III", WhiteFluorescent, -1, { 1.732422, 1, 2.365234, 0 } }, + { "Canon", "EOS 5D Mark III", WhiteFluorescent, 0, { 1.759766, 1, 2.322266, 0 } }, + { "Canon", "EOS 5D Mark III", WhiteFluorescent, 1, { 1.787109, 1, 2.286133, 0 } }, + { "Canon", "EOS 5D Mark III", WhiteFluorescent, 2, { 1.809570, 1, 2.250977, 0 } }, + { "Canon", "EOS 5D Mark III", WhiteFluorescent, 3, { 1.832031, 1, 2.211914, 0 } }, + { "Canon", "EOS 5D Mark III", WhiteFluorescent, 4, { 1.858398, 1, 2.178711, 0 } }, + { "Canon", "EOS 5D Mark III", WhiteFluorescent, 5, { 1.885742, 1, 2.142578, 0 } }, + { "Canon", "EOS 5D Mark III", WhiteFluorescent, 6, { 1.914063, 1, 2.107422, 0 } }, + { "Canon", "EOS 5D Mark III", WhiteFluorescent, 7, { 1.935547, 1, 2.068359, 0 } }, + { "Canon", "EOS 5D Mark III", WhiteFluorescent, 8, { 1.961914, 1, 2.040039, 0 } }, + { "Canon", "EOS 5D Mark III", WhiteFluorescent, 9, { 1.988281, 1, 2.007813, 0 } }, + { "Canon", "EOS 5D Mark III", Flash, -9, { 1.976563, 1, 1.717773, 0 } }, + { "Canon", "EOS 5D Mark III", Flash, -8, { 2.003906, 1, 1.686523, 0 } }, + { "Canon", "EOS 5D Mark III", Flash, -7, { 2.032227, 1, 1.654297, 0 } }, + { "Canon", "EOS 5D Mark III", Flash, -6, { 2.060547, 1, 1.623047, 0 } }, + { "Canon", "EOS 5D Mark III", Flash, -5, { 2.089844, 1, 1.599609, 0 } }, + { "Canon", "EOS 5D Mark III", Flash, -4, { 2.120117, 1, 1.573242, 0 } }, + { "Canon", "EOS 5D Mark III", Flash, -3, { 2.151367, 1, 1.548828, 0 } }, + { "Canon", "EOS 5D Mark III", Flash, -2, { 2.178711, 1, 1.523438, 0 } }, + { "Canon", "EOS 5D Mark III", Flash, -1, { 2.207031, 1, 1.501953, 0 } }, + { "Canon", "EOS 5D Mark III", Flash, 0, { 2.235352, 1, 1.477539, 0 } }, + { "Canon", "EOS 5D Mark III", Flash, 1, { 2.270508, 1, 1.457031, 0 } }, + { "Canon", "EOS 5D Mark III", Flash, 2, { 2.306641, 1, 1.432617, 0 } }, + { "Canon", "EOS 5D Mark III", Flash, 3, { 2.337891, 1, 1.408203, 0 } }, + { "Canon", "EOS 5D Mark III", Flash, 4, { 2.370117, 1, 1.385742, 0 } }, + { "Canon", "EOS 5D Mark III", Flash, 5, { 2.403320, 1, 1.365234, 0 } }, + { "Canon", "EOS 5D Mark III", Flash, 6, { 2.444336, 1, 1.343750, 0 } }, + { "Canon", "EOS 5D Mark III", Flash, 7, { 2.479492, 1, 1.321289, 0 } }, + { "Canon", "EOS 5D Mark III", Flash, 8, { 2.509766, 1, 1.297852, 0 } }, + { "Canon", "EOS 5D Mark III", Flash, 9, { 2.541016, 1, 1.278320, 0 } }, + + { "Canon", "EOS 5D Mark IV", Daylight, 0, { 1.976563, 1, 1.434570, 0 } }, + { "Canon", "EOS 5D Mark IV", Shade, 0, { 2.260742, 1, 1.243164, 0 } }, + { "Canon", "EOS 5D Mark IV", Cloudy, 0, { 2.115234, 1, 1.333008, 0 } }, + { "Canon", "EOS 5D Mark IV", Tungsten, 0, { 1.416016, 1, 2.019531, 0 } }, + { "Canon", "EOS 5D Mark IV", WhiteFluorescent, 0, { 1.672852, 1, 1.946289, 0 } }, + { "Canon", "EOS 5D Mark IV", Flash, 0, { 2.165039, 1, 1.330078, 0 } }, + + { "Canon", "EOS 5DS", Daylight, 0, { 2.255859, 1, 1.717773, 0 } }, + { "Canon", "EOS 5DS", Shade, 0, { 2.605469, 1, 1.484375, 0 } }, + { "Canon", "EOS 5DS", Cloudy, 0, { 2.438477, 1, 1.589844, 0 } }, + { "Canon", "EOS 5DS", Tungsten, 0, { 1.605469, 1, 2.467773, 0 } }, + { "Canon", "EOS 5DS", WhiteFluorescent, 0, { 1.931641, 1, 2.354492, 0 } }, + { "Canon", "EOS 5DS", Flash, 0, { 2.528320, 1, 1.583008, 0 } }, + + { "Canon", "EOS 5DS R", Daylight, 0, { 2.192383, 1, 1.738281, 0 } }, + { "Canon", "EOS 5DS R", Shade, 0, { 2.541016, 1, 1.497070, 0 } }, + { "Canon", "EOS 5DS R", Cloudy, 0, { 2.370117, 1, 1.607422, 0 } }, + { "Canon", "EOS 5DS R", Tungsten, 0, { 1.546875, 1, 2.503906, 0 } }, + { "Canon", "EOS 5DS R", WhiteFluorescent, 0, { 1.865234, 1, 2.386719, 0 } }, + { "Canon", "EOS 5DS R", Flash, 0, { 2.461914, 1, 1.599609, 0 } }, + + /* Canon EOS 6D Firmware Version 1.0.9 */ + { "Canon", "EOS 6D", Daylight, 0, { 1.976562, 1, 1.635742, 0 } }, + { "Canon", "EOS 6D", Shade, 0, { 2.265625, 1, 1.371094, 0 } }, + { "Canon", "EOS 6D", Cloudy, 0, { 2.128906, 1, 1.497070, 0 } }, + { "Canon", "EOS 6D", Tungsten, 0, { 1.412109, 1, 2.473633, 0 } }, + { "Canon", "EOS 6D", WhiteFluorescent, 0, { 1.726562, 1, 2.337891, 0 } }, + { "Canon", "EOS 6D", Flash, 0, { 2.192383, 1, 1.458984, 0 } }, + + /* Canon EOS 7D Firmware Version 2.0.3 */ + /* Fine-tuning for the 7D are the camera's Amber-Blue bracketing. */ + { "Canon", "EOS 7D", Daylight, -9, { 1.8281, 1, 1.8281, 0 } }, + { "Canon", "EOS 7D", Daylight, -8, { 1.8516, 1, 1.7969, 0 } }, + { "Canon", "EOS 7D", Daylight, -7, { 1.8750, 1, 1.7656, 0 } }, + { "Canon", "EOS 7D", Daylight, -6, { 1.9033, 1, 1.7354, 0 } }, + { "Canon", "EOS 7D", Daylight, -5, { 1.9316, 1, 1.7041, 0 } }, + { "Canon", "EOS 7D", Daylight, -4, { 1.9619, 1, 1.6729, 0 } }, + { "Canon", "EOS 7D", Daylight, -3, { 1.9844, 1, 1.6406, 0 } }, + { "Canon", "EOS 7D", Daylight, -2, { 2.0117, 1, 1.6123, 0 } }, + { "Canon", "EOS 7D", Daylight, -1, { 2.0361, 1, 1.5801, 0 } }, + { "Canon", "EOS 7D", Daylight, 0, { 2.0645, 1, 1.5488, 0 } }, + { "Canon", "EOS 7D", Daylight, 1, { 2.0938, 1, 1.5234, 0 } }, + { "Canon", "EOS 7D", Daylight, 2, { 2.1289, 1, 1.4990, 0 } }, + { "Canon", "EOS 7D", Daylight, 3, { 2.1602, 1, 1.4736, 0 } }, + { "Canon", "EOS 7D", Daylight, 4, { 2.1924, 1, 1.4482, 0 } }, + { "Canon", "EOS 7D", Daylight, 5, { 2.2266, 1, 1.4219, 0 } }, + { "Canon", "EOS 7D", Daylight, 6, { 2.2559, 1, 1.4004, 0 } }, + { "Canon", "EOS 7D", Daylight, 7, { 2.2910, 1, 1.3779, 0 } }, + { "Canon", "EOS 7D", Daylight, 8, { 2.3271, 1, 1.3545, 0 } }, + { "Canon", "EOS 7D", Daylight, 9, { 2.3652, 1, 1.3301, 0 } }, + { "Canon", "EOS 7D", Shade, -9, { 2.0938, 1, 1.5283, 0 } }, + { "Canon", "EOS 7D", Shade, -8, { 2.1240, 1, 1.5020, 0 } }, + { "Canon", "EOS 7D", Shade, -7, { 2.1562, 1, 1.4756, 0 } }, + { "Canon", "EOS 7D", Shade, -6, { 2.1885, 1, 1.4502, 0 } }, + { "Canon", "EOS 7D", Shade, -5, { 2.2217, 1, 1.4258, 0 } }, + { "Canon", "EOS 7D", Shade, -4, { 2.2510, 1, 1.4023, 0 } }, + { "Canon", "EOS 7D", Shade, -3, { 2.2861, 1, 1.3799, 0 } }, + { "Canon", "EOS 7D", Shade, -2, { 2.3223, 1, 1.3564, 0 } }, + { "Canon", "EOS 7D", Shade, -1, { 2.3594, 1, 1.3330, 0 } }, + { "Canon", "EOS 7D", Shade, 0, { 2.4033, 1, 1.3076, 0 } }, + { "Canon", "EOS 7D", Shade, 1, { 2.4326, 1, 1.2930, 0 } }, + { "Canon", "EOS 7D", Shade, 2, { 2.4678, 1, 1.2754, 0 } }, + { "Canon", "EOS 7D", Shade, 3, { 2.4980, 1, 1.2568, 0 } }, + { "Canon", "EOS 7D", Shade, 4, { 2.5342, 1, 1.2383, 0 } }, + { "Canon", "EOS 7D", Shade, 5, { 2.5664, 1, 1.2188, 0 } }, + { "Canon", "EOS 7D", Shade, 6, { 2.5928, 1, 1.2021, 0 } }, + { "Canon", "EOS 7D", Shade, 7, { 2.6260, 1, 1.1826, 0 } }, + { "Canon", "EOS 7D", Shade, 8, { 2.6602, 1, 1.1641, 0 } }, + { "Canon", "EOS 7D", Shade, 9, { 2.6943, 1, 1.1416, 0 } }, + { "Canon", "EOS 7D", Cloudy, -9, { 1.9658, 1, 1.6680, 0 } }, + { "Canon", "EOS 7D", Cloudy, -8, { 1.9883, 1, 1.6387, 0 } }, + { "Canon", "EOS 7D", Cloudy, -7, { 2.0117, 1, 1.6074, 0 } }, + { "Canon", "EOS 7D", Cloudy, -6, { 2.0400, 1, 1.5781, 0 } }, + { "Canon", "EOS 7D", Cloudy, -5, { 2.0684, 1, 1.5469, 0 } }, + { "Canon", "EOS 7D", Cloudy, -4, { 2.0986, 1, 1.5215, 0 } }, + { "Canon", "EOS 7D", Cloudy, -3, { 2.1338, 1, 1.4951, 0 } }, + { "Canon", "EOS 7D", Cloudy, -2, { 2.1650, 1, 1.4687, 0 } }, + { "Canon", "EOS 7D", Cloudy, -1, { 2.1924, 1, 1.4443, 0 } }, + { "Canon", "EOS 7D", Cloudy, 0, { 2.2266, 1, 1.4180, 0 } }, + { "Canon", "EOS 7D", Cloudy, 1, { 2.2607, 1, 1.3975, 0 } }, + { "Canon", "EOS 7D", Cloudy, 2, { 2.2959, 1, 1.3740, 0 } }, + { "Canon", "EOS 7D", Cloudy, 3, { 2.3330, 1, 1.3506, 0 } }, + { "Canon", "EOS 7D", Cloudy, 4, { 2.3701, 1, 1.3281, 0 } }, + { "Canon", "EOS 7D", Cloudy, 5, { 2.4150, 1, 1.3047, 0 } }, + { "Canon", "EOS 7D", Cloudy, 6, { 2.4443, 1, 1.2881, 0 } }, + { "Canon", "EOS 7D", Cloudy, 7, { 2.4736, 1, 1.2705, 0 } }, + { "Canon", "EOS 7D", Cloudy, 8, { 2.5098, 1, 1.2520, 0 } }, + { "Canon", "EOS 7D", Cloudy, 9, { 2.5469, 1, 1.2334, 0 } }, + { "Canon", "EOS 7D", Tungsten, -9, { 1.2686, 1, 2.7158, 0 } }, + { "Canon", "EOS 7D", Tungsten, -8, { 1.2861, 1, 2.6807, 0 } }, + { "Canon", "EOS 7D", Tungsten, -7, { 1.3047, 1, 2.6533, 0 } }, + { "Canon", "EOS 7D", Tungsten, -6, { 1.3232, 1, 2.6191, 0 } }, + { "Canon", "EOS 7D", Tungsten, -5, { 1.3418, 1, 2.5859, 0 } }, + { "Canon", "EOS 7D", Tungsten, -4, { 1.3633, 1, 2.5469, 0 } }, + { "Canon", "EOS 7D", Tungsten, -3, { 1.3838, 1, 2.4980, 0 } }, + { "Canon", "EOS 7D", Tungsten, -2, { 1.4023, 1, 2.4502, 0 } }, + { "Canon", "EOS 7D", Tungsten, -1, { 1.4258, 1, 2.3984, 0 } }, + { "Canon", "EOS 7D", Tungsten, 0, { 1.4482, 1, 2.3486, 0 } }, + { "Canon", "EOS 7D", Tungsten, 1, { 1.4687, 1, 2.3115, 0 } }, + { "Canon", "EOS 7D", Tungsten, 2, { 1.4902, 1, 2.2754, 0 } }, + { "Canon", "EOS 7D", Tungsten, 3, { 1.5127, 1, 2.2354, 0 } }, + { "Canon", "EOS 7D", Tungsten, 4, { 1.5352, 1, 2.1973, 0 } }, + { "Canon", "EOS 7D", Tungsten, 5, { 1.5605, 1, 2.1602, 0 } }, + { "Canon", "EOS 7D", Tungsten, 6, { 1.5850, 1, 2.1240, 0 } }, + { "Canon", "EOS 7D", Tungsten, 7, { 1.6104, 1, 2.0859, 0 } }, + { "Canon", "EOS 7D", Tungsten, 8, { 1.6328, 1, 2.0518, 0 } }, + { "Canon", "EOS 7D", Tungsten, 9, { 1.6592, 1, 2.0156, 0 } }, + { "Canon", "EOS 7D", WhiteFluorescent, -9, { 1.5850, 1, 2.5859, 0 } }, + { "Canon", "EOS 7D", WhiteFluorescent, -8, { 1.6104, 1, 2.5469, 0 } }, + { "Canon", "EOS 7D", WhiteFluorescent, -7, { 1.6328, 1, 2.4980, 0 } }, + { "Canon", "EOS 7D", WhiteFluorescent, -6, { 1.6621, 1, 2.4502, 0 } }, + { "Canon", "EOS 7D", WhiteFluorescent, -5, { 1.6895, 1, 2.3984, 0 } }, + { "Canon", "EOS 7D", WhiteFluorescent, -4, { 1.7119, 1, 2.3486, 0 } }, + { "Canon", "EOS 7D", WhiteFluorescent, -3, { 1.7383, 1, 2.3115, 0 } }, + { "Canon", "EOS 7D", WhiteFluorescent, -2, { 1.7656, 1, 2.2754, 0 } }, + { "Canon", "EOS 7D", WhiteFluorescent, -1, { 1.7969, 1, 2.2354, 0 } }, + { "Canon", "EOS 7D", WhiteFluorescent, 0, { 1.8252, 1, 2.1924, 0 } }, + { "Canon", "EOS 7D", WhiteFluorescent, 1, { 1.8486, 1, 2.1562, 0 } }, + { "Canon", "EOS 7D", WhiteFluorescent, 2, { 1.8750, 1, 2.1201, 0 } }, + { "Canon", "EOS 7D", WhiteFluorescent, 3, { 1.9033, 1, 2.0859, 0 } }, + { "Canon", "EOS 7D", WhiteFluorescent, 4, { 1.9316, 1, 2.0518, 0 } }, + { "Canon", "EOS 7D", WhiteFluorescent, 5, { 1.9619, 1, 2.0156, 0 } }, + { "Canon", "EOS 7D", WhiteFluorescent, 6, { 1.9844, 1, 1.9805, 0 } }, + { "Canon", "EOS 7D", WhiteFluorescent, 7, { 2.0078, 1, 1.9502, 0 } }, + { "Canon", "EOS 7D", WhiteFluorescent, 8, { 2.0361, 1, 1.9209, 0 } }, + { "Canon", "EOS 7D", WhiteFluorescent, 9, { 2.0645, 1, 1.8896, 0 } }, + { "Canon", "EOS 7D", Flash, -9, { 2.0039, 1, 1.6572, 0 } }, + { "Canon", "EOS 7D", Flash, -8, { 2.0322, 1, 1.6279, 0 } }, + { "Canon", "EOS 7D", Flash, -7, { 2.0605, 1, 1.5977, 0 } }, + { "Canon", "EOS 7D", Flash, -6, { 2.0898, 1, 1.5654, 0 } }, + { "Canon", "EOS 7D", Flash, -5, { 2.1201, 1, 1.5371, 0 } }, + { "Canon", "EOS 7D", Flash, -4, { 2.1562, 1, 1.5127, 0 } }, + { "Canon", "EOS 7D", Flash, -3, { 2.1836, 1, 1.4863, 0 } }, + { "Canon", "EOS 7D", Flash, -2, { 2.2168, 1, 1.4609, 0 } }, + { "Canon", "EOS 7D", Flash, -1, { 2.2510, 1, 1.4365, 0 } }, + { "Canon", "EOS 7D", Flash, 0, { 2.2803, 1, 1.4102, 0 } }, + { "Canon", "EOS 7D", Flash, 1, { 2.3164, 1, 1.3896, 0 } }, + { "Canon", "EOS 7D", Flash, 2, { 2.3594, 1, 1.3672, 0 } }, + { "Canon", "EOS 7D", Flash, 3, { 2.4033, 1, 1.3438, 0 } }, + { "Canon", "EOS 7D", Flash, 4, { 2.4326, 1, 1.3184, 0 } }, + { "Canon", "EOS 7D", Flash, 5, { 2.4619, 1, 1.2998, 0 } }, + { "Canon", "EOS 7D", Flash, 6, { 2.4980, 1, 1.2812, 0 } }, + { "Canon", "EOS 7D", Flash, 7, { 2.5342, 1, 1.2646, 0 } }, + { "Canon", "EOS 7D", Flash, 8, { 2.5664, 1, 1.2461, 0 } }, + { "Canon", "EOS 7D", Flash, 9, { 2.5928, 1, 1.2266, 0 } }, + + { "Canon", "EOS 7D Mark II", Daylight, 0, { 1.946289, 1, 1.638672, 0 } }, + { "Canon", "EOS 7D Mark II", Shade, 0, { 2.240234, 1, 1.410156, 0 } }, + { "Canon", "EOS 7D Mark II", Cloudy, 0, { 2.093750, 1, 1.519531, 0 } }, + { "Canon", "EOS 7D Mark II", Tungsten, 0, { 1.373047, 1, 2.342773, 0 } }, + { "Canon", "EOS 7D Mark II", WhiteFluorescent, 0, { 1.717773, 1, 2.250977, 0 } }, + { "Canon", "EOS 7D Mark II", Flash, 0, { 2.160156, 1, 1.488281, 0 } }, + + { "Canon", "EOS 10D", Daylight, 0, { 2.159856, 1, 1.218750, 0 } }, + { "Canon", "EOS 10D", Shade, 0, { 2.533654, 1, 1.036058, 0 } }, + { "Canon", "EOS 10D", Cloudy, 0, { 2.348558, 1, 1.116587, 0 } }, + { "Canon", "EOS 10D", Tungsten, 0, { 1.431544, 1, 1.851040, 0 } }, + { "Canon", "EOS 10D", WhiteFluorescent, 0, { 1.891509, 1, 1.647406, 0 } }, + { "Canon", "EOS 10D", Flash, 0, { 2.385817, 1, 1.115385, 0 } }, + + { "Canon", "EOS 20D", Daylight, 0, { 1.954680, 1, 1.478818, 0 } }, + { "Canon", "EOS 20D", Shade, 0, { 2.248276, 1, 1.227586, 0 } }, + { "Canon", "EOS 20D", Cloudy, 0, { 2.115271, 1, 1.336946, 0 } }, + { "Canon", "EOS 20D", Tungsten, 0, { 1.368087, 1, 2.417044, 0 } }, + { "Canon", "EOS 20D", WhiteFluorescent, 0, { 1.752709, 1, 2.060098, 0 } }, + { "Canon", "EOS 20D", Flash, 0, { 2.145813, 1, 1.293596, 0 } }, + + { "Canon", "EOS 30D", Daylight, 0, { 2.032227, 1, 1.537109, 0 } }, + { "Canon", "EOS 30D", Shade, 0, { 2.354492, 1, 1.264648, 0 } }, + { "Canon", "EOS 30D", Cloudy, 0, { 2.197266, 1, 1.389648, 0 } }, + { "Canon", "EOS 30D", Tungsten, 0, { 1.411084, 1, 2.447477, 0 } }, + { "Canon", "EOS 30D", WhiteFluorescent, 0, { 1.761601, 1, 2.303913, 0 } }, + { "Canon", "EOS 30D", Flash, 0, { 2.226562, 1, 1.347656, 0 } }, + + { "Canon", "EOS 40D", Daylight, 0, { 2.197266, 1, 1.438477, 0 } }, + { "Canon", "EOS 40D", Shade, 0, { 2.546875, 1, 1.185547, 0 } }, + { "Canon", "EOS 40D", Cloudy, 0, { 2.370117, 1, 1.290039, 0 } }, + { "Canon", "EOS 40D", Tungsten, 0, { 1.510563, 1, 2.235915, 0 } }, + { "Canon", "EOS 40D", WhiteFluorescent, 0, { 2.019084, 1, 2.129771, 0 } }, + { "Canon", "EOS 40D", Flash, 0, { 2.409180, 1, 1.260742, 0 } }, + + // Canon EOS 50D (firmware 1.0.3) + { "Canon", "EOS 50D", Daylight, -9, { 1.865234, 1, 1.599609, 0 } }, + { "Canon", "EOS 50D", Daylight, -8, { 1.889648, 1, 1.580078, 0 } }, + { "Canon", "EOS 50D", Daylight, -7, { 1.910156, 1, 1.556641, 0 } }, + { "Canon", "EOS 50D", Daylight, -6, { 1.935547, 1, 1.535156, 0 } }, + { "Canon", "EOS 50D", Daylight, -5, { 1.965820, 1, 1.512695, 0 } }, + { "Canon", "EOS 50D", Daylight, -4, { 1.992188, 1, 1.490234, 0 } }, + { "Canon", "EOS 50D", Daylight, -3, { 2.015625, 1, 1.468750, 0 } }, + { "Canon", "EOS 50D", Daylight, -2, { 2.043945, 1, 1.448242, 0 } }, + { "Canon", "EOS 50D", Daylight, -1, { 2.068359, 1, 1.425781, 0 } }, + { "Canon", "EOS 50D", Daylight, 0, { 2.098633, 1, 1.402344, 0 } }, + { "Canon", "EOS 50D", Daylight, 1, { 2.124023, 1, 1.381836, 0 } }, + { "Canon", "EOS 50D", Daylight, 2, { 2.156250, 1, 1.358398, 0 } }, + { "Canon", "EOS 50D", Daylight, 3, { 2.183594, 1, 1.334961, 0 } }, + { "Canon", "EOS 50D", Daylight, 4, { 2.211914, 1, 1.312500, 0 } }, + { "Canon", "EOS 50D", Daylight, 5, { 2.240234, 1, 1.288086, 0 } }, + { "Canon", "EOS 50D", Daylight, 6, { 2.265625, 1, 1.270508, 0 } }, + { "Canon", "EOS 50D", Daylight, 7, { 2.291016, 1, 1.251953, 0 } }, + { "Canon", "EOS 50D", Daylight, 8, { 2.322266, 1, 1.233398, 0 } }, + { "Canon", "EOS 50D", Daylight, 9, { 2.359375, 1, 1.214844, 0 } }, + { "Canon", "EOS 50D", Shade, -9, { 2.124023, 1, 1.383789, 0 } }, + { "Canon", "EOS 50D", Shade, -8, { 2.151367, 1, 1.361328, 0 } }, + { "Canon", "EOS 50D", Shade, -7, { 2.178711, 1, 1.338867, 0 } }, + { "Canon", "EOS 50D", Shade, -6, { 2.207031, 1, 1.314453, 0 } }, + { "Canon", "EOS 50D", Shade, -5, { 2.235352, 1, 1.291016, 0 } }, + { "Canon", "EOS 50D", Shade, -4, { 2.260742, 1, 1.272461, 0 } }, + { "Canon", "EOS 50D", Shade, -3, { 2.291016, 1, 1.254883, 0 } }, + { "Canon", "EOS 50D", Shade, -2, { 2.322266, 1, 1.236328, 0 } }, + { "Canon", "EOS 50D", Shade, -1, { 2.354492, 1, 1.215820, 0 } }, + { "Canon", "EOS 50D", Shade, 0, { 2.386719, 1, 1.196289, 0 } }, + { "Canon", "EOS 50D", Shade, 1, { 2.403320, 1, 1.186523, 0 } }, + { "Canon", "EOS 50D", Shade, 2, { 2.420898, 1, 1.175781, 0 } }, + { "Canon", "EOS 50D", Shade, 3, { 2.438477, 1, 1.165039, 0 } }, + { "Canon", "EOS 50D", Shade, 4, { 2.461914, 1, 1.152344, 0 } }, + { "Canon", "EOS 50D", Shade, 5, { 2.485352, 1, 1.136719, 0 } }, + { "Canon", "EOS 50D", Shade, 6, { 2.522461, 1, 1.115234, 0 } }, + { "Canon", "EOS 50D", Shade, 7, { 2.559570, 1, 1.094727, 0 } }, + { "Canon", "EOS 50D", Shade, 8, { 2.598633, 1, 1.072266, 0 } }, + { "Canon", "EOS 50D", Shade, 9, { 2.645508, 1, 1.051758, 0 } }, + { "Canon", "EOS 50D", Cloudy, -9, { 1.996094, 1, 1.486328, 0 } }, + { "Canon", "EOS 50D", Cloudy, -8, { 2.019531, 1, 1.466797, 0 } }, + { "Canon", "EOS 50D", Cloudy, -7, { 2.043945, 1, 1.444336, 0 } }, + { "Canon", "EOS 50D", Cloudy, -6, { 2.073242, 1, 1.421875, 0 } }, + { "Canon", "EOS 50D", Cloudy, -5, { 2.102539, 1, 1.400391, 0 } }, + { "Canon", "EOS 50D", Cloudy, -4, { 2.128906, 1, 1.377930, 0 } }, + { "Canon", "EOS 50D", Cloudy, -3, { 2.156250, 1, 1.356445, 0 } }, + { "Canon", "EOS 50D", Cloudy, -2, { 2.188477, 1, 1.333008, 0 } }, + { "Canon", "EOS 50D", Cloudy, -1, { 2.211914, 1, 1.309570, 0 } }, + { "Canon", "EOS 50D", Cloudy, 0, { 2.240234, 1, 1.285156, 0 } }, + { "Canon", "EOS 50D", Cloudy, 1, { 2.270508, 1, 1.268555, 0 } }, + { "Canon", "EOS 50D", Cloudy, 2, { 2.295898, 1, 1.250000, 0 } }, + { "Canon", "EOS 50D", Cloudy, 3, { 2.327148, 1, 1.232422, 0 } }, + { "Canon", "EOS 50D", Cloudy, 4, { 2.359375, 1, 1.211914, 0 } }, + { "Canon", "EOS 50D", Cloudy, 5, { 2.392578, 1, 1.195313, 0 } }, + { "Canon", "EOS 50D", Cloudy, 6, { 2.409180, 1, 1.183594, 0 } }, + { "Canon", "EOS 50D", Cloudy, 7, { 2.426758, 1, 1.172852, 0 } }, + { "Canon", "EOS 50D", Cloudy, 8, { 2.444336, 1, 1.161133, 0 } }, + { "Canon", "EOS 50D", Cloudy, 9, { 2.467773, 1, 1.149414, 0 } }, + { "Canon", "EOS 50D", Tungsten, -9, { 1.379189, 1, 2.206349, 0 } }, + { "Canon", "EOS 50D", Tungsten, -8, { 1.394690, 1, 2.176991, 0 } }, + { "Canon", "EOS 50D", Tungsten, -7, { 1.412600, 1, 2.155280, 0 } }, + { "Canon", "EOS 50D", Tungsten, -6, { 1.428317, 1, 2.127337, 0 } }, + { "Canon", "EOS 50D", Tungsten, -5, { 1.448122, 1, 2.101073, 0 } }, + { "Canon", "EOS 50D", Tungsten, -4, { 1.467684, 1, 2.078097, 0 } }, + { "Canon", "EOS 50D", Tungsten, -3, { 1.484220, 1, 2.054103, 0 } }, + { "Canon", "EOS 50D", Tungsten, -2, { 1.501357, 1, 2.027149, 0 } }, + { "Canon", "EOS 50D", Tungsten, -1, { 1.521818, 1, 2.003636, 0 } }, + { "Canon", "EOS 50D", Tungsten, 0, { 1.542466, 1, 1.976256, 0 } }, + { "Canon", "EOS 50D", Tungsten, 1, { 1.561468, 1, 1.949541, 0 } }, + { "Canon", "EOS 50D", Tungsten, 2, { 1.581567, 1, 1.923502, 0 } }, + { "Canon", "EOS 50D", Tungsten, 3, { 1.602778, 1, 1.894444, 0 } }, + { "Canon", "EOS 50D", Tungsten, 4, { 1.624767, 1, 1.867784, 0 } }, + { "Canon", "EOS 50D", Tungsten, 5, { 1.647940, 1, 1.841760, 0 } }, + { "Canon", "EOS 50D", Tungsten, 6, { 1.669492, 1, 1.815443, 0 } }, + { "Canon", "EOS 50D", Tungsten, 7, { 1.686553, 1, 1.789773, 0 } }, + { "Canon", "EOS 50D", Tungsten, 8, { 1.708294, 1, 1.766444, 0 } }, + { "Canon", "EOS 50D", Tungsten, 9, { 1.729626, 1, 1.738255, 0 } }, + { "Canon", "EOS 50D", WhiteFluorescent, -9, { 1.683196, 1, 2.110193, 0 } }, + { "Canon", "EOS 50D", WhiteFluorescent, -8, { 1.704797, 1, 2.084871, 0 } }, + { "Canon", "EOS 50D", WhiteFluorescent, -7, { 1.727778, 1, 2.061111, 0 } }, + { "Canon", "EOS 50D", WhiteFluorescent, -6, { 1.747907, 1, 2.036279, 0 } }, + { "Canon", "EOS 50D", WhiteFluorescent, -5, { 1.767507, 1, 2.013072, 0 } }, + { "Canon", "EOS 50D", WhiteFluorescent, -4, { 1.791745, 1, 1.988743, 0 } }, + { "Canon", "EOS 50D", WhiteFluorescent, -3, { 1.812264, 1, 1.963208, 0 } }, + { "Canon", "EOS 50D", WhiteFluorescent, -2, { 1.834758, 1, 1.932574, 0 } }, + { "Canon", "EOS 50D", WhiteFluorescent, -1, { 1.863419, 1, 1.907354, 0 } }, + { "Canon", "EOS 50D", WhiteFluorescent, 0, { 1.882805, 1, 1.876081, 0 } }, + { "Canon", "EOS 50D", WhiteFluorescent, 1, { 1.908124, 1, 1.852998, 0 } }, + { "Canon", "EOS 50D", WhiteFluorescent, 2, { 1.931774, 1, 1.822612, 0 } }, + { "Canon", "EOS 50D", WhiteFluorescent, 3, { 1.958008, 1, 1.799805, 0 } }, + { "Canon", "EOS 50D", WhiteFluorescent, 4, { 1.988281, 1, 1.771484, 0 } }, + { "Canon", "EOS 50D", WhiteFluorescent, 5, { 2.011719, 1, 1.747070, 0 } }, + { "Canon", "EOS 50D", WhiteFluorescent, 6, { 2.036133, 1, 1.720703, 0 } }, + { "Canon", "EOS 50D", WhiteFluorescent, 7, { 2.064453, 1, 1.698242, 0 } }, + { "Canon", "EOS 50D", WhiteFluorescent, 8, { 2.093750, 1, 1.678711, 0 } }, + { "Canon", "EOS 50D", WhiteFluorescent, 9, { 2.120117, 1, 1.654297, 0 } }, + { "Canon", "EOS 50D", Flash, -9, { 2.027344, 1, 1.466797, 0 } }, + { "Canon", "EOS 50D", Flash, -8, { 2.056641, 1, 1.446289, 0 } }, + { "Canon", "EOS 50D", Flash, -7, { 2.085938, 1, 1.423828, 0 } }, + { "Canon", "EOS 50D", Flash, -6, { 2.111328, 1, 1.402344, 0 } }, + { "Canon", "EOS 50D", Flash, -5, { 2.137695, 1, 1.379883, 0 } }, + { "Canon", "EOS 50D", Flash, -4, { 2.169922, 1, 1.358398, 0 } }, + { "Canon", "EOS 50D", Flash, -3, { 2.192383, 1, 1.334961, 0 } }, + { "Canon", "EOS 50D", Flash, -2, { 2.221680, 1, 1.311523, 0 } }, + { "Canon", "EOS 50D", Flash, -1, { 2.250977, 1, 1.288086, 0 } }, + { "Canon", "EOS 50D", Flash, 0, { 2.275391, 1, 1.268555, 0 } }, + { "Canon", "EOS 50D", Flash, 1, { 2.306641, 1, 1.251953, 0 } }, + { "Canon", "EOS 50D", Flash, 2, { 2.337891, 1, 1.233398, 0 } }, + { "Canon", "EOS 50D", Flash, 3, { 2.375977, 1, 1.212891, 0 } }, + { "Canon", "EOS 50D", Flash, 4, { 2.398438, 1, 1.195313, 0 } }, + { "Canon", "EOS 50D", Flash, 5, { 2.415039, 1, 1.185547, 0 } }, + { "Canon", "EOS 50D", Flash, 6, { 2.432617, 1, 1.173828, 0 } }, + { "Canon", "EOS 50D", Flash, 7, { 2.450195, 1, 1.162109, 0 } }, + { "Canon", "EOS 50D", Flash, 8, { 2.473633, 1, 1.150391, 0 } }, + { "Canon", "EOS 50D", Flash, 9, { 2.503906, 1, 1.132813, 0 } }, + { "Canon", "EOS 50D", "5000K", 0, { 2.056641, 1, 1.438477, 0 } }, + { "Canon", "EOS 50D", "6500K", 0, { 2.311523, 1, 1.239258, 0 } }, + + /* Canon EOS 60D Firmware Version 1.1.1 */ + { "Canon", "EOS 60D", Daylight, -9, { 1.765625, 1, 1.792969, 0 } }, + { "Canon", "EOS 60D", Daylight, -8, { 1.787109, 1, 1.765625, 0 } }, + { "Canon", "EOS 60D", Daylight, -7, { 1.812500, 1, 1.735352, 0 } }, + { "Canon", "EOS 60D", Daylight, -6, { 1.838867, 1, 1.707031, 0 } }, + { "Canon", "EOS 60D", Daylight, -5, { 1.865234, 1, 1.678711, 0 } }, + { "Canon", "EOS 60D", Daylight, -4, { 1.896484, 1, 1.649414, 0 } }, + { "Canon", "EOS 60D", Daylight, -3, { 1.917969, 1, 1.618164, 0 } }, + { "Canon", "EOS 60D", Daylight, -2, { 1.943359, 1, 1.587891, 0 } }, + { "Canon", "EOS 60D", Daylight, -1, { 1.965820, 1, 1.558594, 0 } }, + { "Canon", "EOS 60D", Daylight, 0, { 1.992188, 1, 1.526367, 0 } }, + { "Canon", "EOS 60D", Daylight, 1, { 2.019531, 1, 1.503906, 0 } }, + { "Canon", "EOS 60D", Daylight, 2, { 2.051758, 1, 1.477539, 0 } }, + { "Canon", "EOS 60D", Daylight, 3, { 2.081055, 1, 1.454102, 0 } }, + { "Canon", "EOS 60D", Daylight, 4, { 2.111328, 1, 1.429688, 0 } }, + { "Canon", "EOS 60D", Daylight, 5, { 2.146484, 1, 1.406250, 0 } }, + { "Canon", "EOS 60D", Daylight, 6, { 2.173828, 1, 1.385742, 0 } }, + { "Canon", "EOS 60D", Daylight, 7, { 2.207031, 1, 1.363281, 0 } }, + { "Canon", "EOS 60D", Daylight, 8, { 2.240234, 1, 1.341797, 0 } }, + { "Canon", "EOS 60D", Daylight, 9, { 2.275391, 1, 1.318359, 0 } }, + { "Canon", "EOS 60D", Shade, -9, { 2.019531, 1, 1.505859, 0 } }, + { "Canon", "EOS 60D", Shade, -8, { 2.047852, 1, 1.481445, 0 } }, + { "Canon", "EOS 60D", Shade, -7, { 2.077148, 1, 1.457031, 0 } }, + { "Canon", "EOS 60D", Shade, -6, { 2.107422, 1, 1.434570, 0 } }, + { "Canon", "EOS 60D", Shade, -5, { 2.142578, 1, 1.410156, 0 } }, + { "Canon", "EOS 60D", Shade, -4, { 2.169922, 1, 1.387695, 0 } }, + { "Canon", "EOS 60D", Shade, -3, { 2.202148, 1, 1.365234, 0 } }, + { "Canon", "EOS 60D", Shade, -2, { 2.235352, 1, 1.343750, 0 } }, + { "Canon", "EOS 60D", Shade, -1, { 2.270508, 1, 1.321289, 0 } }, + { "Canon", "EOS 60D", Shade, 0, { 2.311523, 1, 1.295898, 0 } }, + { "Canon", "EOS 60D", Shade, 1, { 2.337891, 1, 1.281250, 0 } }, + { "Canon", "EOS 60D", Shade, 2, { 2.365234, 1, 1.264648, 0 } }, + { "Canon", "EOS 60D", Shade, 3, { 2.398438, 1, 1.247070, 0 } }, + { "Canon", "EOS 60D", Shade, 4, { 2.432617, 1, 1.229492, 0 } }, + { "Canon", "EOS 60D", Shade, 5, { 2.461914, 1, 1.209961, 0 } }, + { "Canon", "EOS 60D", Shade, 6, { 2.485352, 1, 1.193359, 0 } }, + { "Canon", "EOS 60D", Shade, 7, { 2.515625, 1, 1.173828, 0 } }, + { "Canon", "EOS 60D", Shade, 8, { 2.546875, 1, 1.154297, 0 } }, + { "Canon", "EOS 60D", Shade, 9, { 2.585938, 1, 1.132813, 0 } }, + { "Canon", "EOS 60D", Cloudy, -9, { 1.899414, 1, 1.643555, 0 } }, + { "Canon", "EOS 60D", Cloudy, -8, { 1.920898, 1, 1.615234, 0 } }, + { "Canon", "EOS 60D", Cloudy, -7, { 1.943359, 1, 1.584961, 0 } }, + { "Canon", "EOS 60D", Cloudy, -6, { 1.968750, 1, 1.553711, 0 } }, + { "Canon", "EOS 60D", Cloudy, -5, { 1.996094, 1, 1.523438, 0 } }, + { "Canon", "EOS 60D", Cloudy, -4, { 2.023438, 1, 1.499023, 0 } }, + { "Canon", "EOS 60D", Cloudy, -3, { 2.056641, 1, 1.475586, 0 } }, + { "Canon", "EOS 60D", Cloudy, -2, { 2.085938, 1, 1.450195, 0 } }, + { "Canon", "EOS 60D", Cloudy, -1, { 2.115234, 1, 1.427734, 0 } }, + { "Canon", "EOS 60D", Cloudy, 0, { 2.146484, 1, 1.402344, 0 } }, + { "Canon", "EOS 60D", Cloudy, 1, { 2.178711, 1, 1.381836, 0 } }, + { "Canon", "EOS 60D", Cloudy, 2, { 2.211914, 1, 1.361328, 0 } }, + { "Canon", "EOS 60D", Cloudy, 3, { 2.246094, 1, 1.338867, 0 } }, + { "Canon", "EOS 60D", Cloudy, 4, { 2.280273, 1, 1.314453, 0 } }, + { "Canon", "EOS 60D", Cloudy, 5, { 2.322266, 1, 1.292969, 0 } }, + { "Canon", "EOS 60D", Cloudy, 6, { 2.342773, 1, 1.276367, 0 } }, + { "Canon", "EOS 60D", Cloudy, 7, { 2.370117, 1, 1.260742, 0 } }, + { "Canon", "EOS 60D", Cloudy, 8, { 2.403320, 1, 1.243164, 0 } }, + { "Canon", "EOS 60D", Cloudy, 9, { 2.438477, 1, 1.224609, 0 } }, + { "Canon", "EOS 60D", Tungsten, -9, { 1.249023, 1, 2.645508, 0 } }, + { "Canon", "EOS 60D", Tungsten, -8, { 1.265625, 1, 2.619141, 0 } }, + { "Canon", "EOS 60D", Tungsten, -7, { 1.283203, 1, 2.592773, 0 } }, + { "Canon", "EOS 60D", Tungsten, -6, { 1.300781, 1, 2.566406, 0 } }, + { "Canon", "EOS 60D", Tungsten, -5, { 1.319336, 1, 2.534180, 0 } }, + { "Canon", "EOS 60D", Tungsten, -4, { 1.339844, 1, 2.503906, 0 } }, + { "Canon", "EOS 60D", Tungsten, -3, { 1.358398, 1, 2.456055, 0 } }, + { "Canon", "EOS 60D", Tungsten, -2, { 1.375977, 1, 2.403320, 0 } }, + { "Canon", "EOS 60D", Tungsten, -1, { 1.397461, 1, 2.359375, 0 } }, + { "Canon", "EOS 60D", Tungsten, 0, { 1.417969, 1, 2.306641, 0 } }, + { "Canon", "EOS 60D", Tungsten, 1, { 1.438477, 1, 2.270508, 0 } }, + { "Canon", "EOS 60D", Tungsten, 2, { 1.458984, 1, 2.235352, 0 } }, + { "Canon", "EOS 60D", Tungsten, 3, { 1.479492, 1, 2.197266, 0 } }, + { "Canon", "EOS 60D", Tungsten, 4, { 1.501953, 1, 2.160156, 0 } }, + { "Canon", "EOS 60D", Tungsten, 5, { 1.526367, 1, 2.124023, 0 } }, + { "Canon", "EOS 60D", Tungsten, 6, { 1.548828, 1, 2.085938, 0 } }, + { "Canon", "EOS 60D", Tungsten, 7, { 1.570313, 1, 2.051758, 0 } }, + { "Canon", "EOS 60D", Tungsten, 8, { 1.592773, 1, 2.019531, 0 } }, + { "Canon", "EOS 60D", Tungsten, 9, { 1.618164, 1, 1.984375, 0 } }, + { "Canon", "EOS 60D", WhiteFluorescent, -9, { 1.573242, 1, 2.534180, 0 } }, + { "Canon", "EOS 60D", WhiteFluorescent, -8, { 1.594727, 1, 2.498047, 0 } }, + { "Canon", "EOS 60D", WhiteFluorescent, -7, { 1.620117, 1, 2.450195, 0 } }, + { "Canon", "EOS 60D", WhiteFluorescent, -6, { 1.643555, 1, 2.398438, 0 } }, + { "Canon", "EOS 60D", WhiteFluorescent, -5, { 1.665039, 1, 2.348633, 0 } }, + { "Canon", "EOS 60D", WhiteFluorescent, -4, { 1.686523, 1, 2.300781, 0 } }, + { "Canon", "EOS 60D", WhiteFluorescent, -3, { 1.711914, 1, 2.265625, 0 } }, + { "Canon", "EOS 60D", WhiteFluorescent, -2, { 1.738281, 1, 2.230469, 0 } }, + { "Canon", "EOS 60D", WhiteFluorescent, -1, { 1.765625, 1, 2.192383, 0 } }, + { "Canon", "EOS 60D", WhiteFluorescent, 0, { 1.787109, 1, 2.151367, 0 } }, + { "Canon", "EOS 60D", WhiteFluorescent, 1, { 1.812500, 1, 2.115234, 0 } }, + { "Canon", "EOS 60D", WhiteFluorescent, 2, { 1.838867, 1, 2.081055, 0 } }, + { "Canon", "EOS 60D", WhiteFluorescent, 3, { 1.868164, 1, 2.047852, 0 } }, + { "Canon", "EOS 60D", WhiteFluorescent, 4, { 1.896484, 1, 2.011719, 0 } }, + { "Canon", "EOS 60D", WhiteFluorescent, 5, { 1.917969, 1, 1.976563, 0 } }, + { "Canon", "EOS 60D", WhiteFluorescent, 6, { 1.943359, 1, 1.943359, 0 } }, + { "Canon", "EOS 60D", WhiteFluorescent, 7, { 1.968750, 1, 1.914063, 0 } }, + { "Canon", "EOS 60D", WhiteFluorescent, 8, { 1.996094, 1, 1.882813, 0 } }, + { "Canon", "EOS 60D", WhiteFluorescent, 9, { 2.023438, 1, 1.851563, 0 } }, + { "Canon", "EOS 60D", Flash, -9, { 1.950195, 1, 1.627930, 0 } }, + { "Canon", "EOS 60D", Flash, -8, { 1.976563, 1, 1.597656, 0 } }, + { "Canon", "EOS 60D", Flash, -7, { 2.003906, 1, 1.568359, 0 } }, + { "Canon", "EOS 60D", Flash, -6, { 2.032227, 1, 1.537109, 0 } }, + { "Canon", "EOS 60D", Flash, -5, { 2.064453, 1, 1.510742, 0 } }, + { "Canon", "EOS 60D", Flash, -4, { 2.093750, 1, 1.486328, 0 } }, + { "Canon", "EOS 60D", Flash, -3, { 2.124023, 1, 1.462891, 0 } }, + { "Canon", "EOS 60D", Flash, -2, { 2.156250, 1, 1.438477, 0 } }, + { "Canon", "EOS 60D", Flash, -1, { 2.188477, 1, 1.414063, 0 } }, + { "Canon", "EOS 60D", Flash, 0, { 2.216797, 1, 1.391602, 0 } }, + { "Canon", "EOS 60D", Flash, 1, { 2.255859, 1, 1.371094, 0 } }, + { "Canon", "EOS 60D", Flash, 2, { 2.295898, 1, 1.349609, 0 } }, + { "Canon", "EOS 60D", Flash, 3, { 2.327148, 1, 1.326172, 0 } }, + { "Canon", "EOS 60D", Flash, 4, { 2.354492, 1, 1.302734, 0 } }, + { "Canon", "EOS 60D", Flash, 5, { 2.381836, 1, 1.285156, 0 } }, + { "Canon", "EOS 60D", Flash, 6, { 2.415039, 1, 1.268555, 0 } }, + { "Canon", "EOS 60D", Flash, 7, { 2.450195, 1, 1.251953, 0 } }, + { "Canon", "EOS 60D", Flash, 8, { 2.473633, 1, 1.232422, 0 } }, + { "Canon", "EOS 60D", Flash, 9, { 2.503906, 1, 1.214844, 0 } }, + + /* Canon EOS 70D Firmware Version 1.1.1 */ + { "Canon", "EOS 70D", Daylight, 0, { 2.068359, 1, 1.672852, 0 } }, + { "Canon", "EOS 70D", Shade, 0, { 2.403320, 1, 1.446289, 0 } }, + { "Canon", "EOS 70D", Cloudy, 0, { 2.226563, 1, 1.551758, 0 } }, + { "Canon", "EOS 70D", Tungsten, 0, { 1.448242, 1, 2.409180, 0 } }, + { "Canon", "EOS 70D", WhiteFluorescent, 0, { 1.790039, 1, 2.280273, 0 } }, + { "Canon", "EOS 70D", Flash, 0, { 2.286133, 1, 1.548828, 0 } }, + + /* Canon EOS 80D Firmware Version Ver.1.0.1 */ + /* Fine-tuning is the camera's Amber-Blue bracketing. */ + { "Canon", "EOS 80D", Daylight, -9, { 1.551758, 1, 1.892578, 0 } }, + { "Canon", "EOS 80D", Daylight, -8, { 1.570313, 1, 1.865234, 0 } }, + { "Canon", "EOS 80D", Daylight, -7, { 1.594727, 1, 1.838867, 0 } }, + { "Canon", "EOS 80D", Daylight, -6, { 1.618164, 1, 1.809570, 0 } }, + { "Canon", "EOS 80D", Daylight, -5, { 1.643555, 1, 1.781250, 0 } }, + { "Canon", "EOS 80D", Daylight, -4, { 1.670898, 1, 1.753906, 0 } }, + { "Canon", "EOS 80D", Daylight, -3, { 1.692383, 1, 1.723633, 0 } }, + { "Canon", "EOS 80D", Daylight, -2, { 1.717773, 1, 1.695313, 0 } }, + { "Canon", "EOS 80D", Daylight, -1, { 1.741211, 1, 1.665039, 0 } }, + { "Canon", "EOS 80D", Daylight, 0, { 1.768555, 1, 1.632813, 0 } }, + { "Canon", "EOS 80D", Daylight, 1, { 1.790039, 1, 1.612305, 0 } }, + { "Canon", "EOS 80D", Daylight, 2, { 1.815430, 1, 1.589844, 0 } }, + { "Canon", "EOS 80D", Daylight, 3, { 1.838867, 1, 1.565430, 0 } }, + { "Canon", "EOS 80D", Daylight, 4, { 1.862305, 1, 1.544922, 0 } }, + { "Canon", "EOS 80D", Daylight, 5, { 1.889648, 1, 1.523438, 0 } }, + { "Canon", "EOS 80D", Daylight, 6, { 1.914063, 1, 1.501953, 0 } }, + { "Canon", "EOS 80D", Daylight, 7, { 1.939453, 1, 1.479492, 0 } }, + { "Canon", "EOS 80D", Daylight, 8, { 1.972656, 1, 1.458984, 0 } }, + { "Canon", "EOS 80D", Daylight, 9, { 2.003906, 1, 1.434570, 0 } }, + { "Canon", "EOS 80D", Shade, -9, { 1.790039, 1, 1.615234, 0 } }, + { "Canon", "EOS 80D", Shade, -8, { 1.812500, 1, 1.592773, 0 } }, + { "Canon", "EOS 80D", Shade, -7, { 1.834961, 1, 1.568359, 0 } }, + { "Canon", "EOS 80D", Shade, -6, { 1.858398, 1, 1.546875, 0 } }, + { "Canon", "EOS 80D", Shade, -5, { 1.885742, 1, 1.526367, 0 } }, + { "Canon", "EOS 80D", Shade, -4, { 1.910156, 1, 1.503906, 0 } }, + { "Canon", "EOS 80D", Shade, -3, { 1.939453, 1, 1.481445, 0 } }, + { "Canon", "EOS 80D", Shade, -2, { 1.968750, 1, 1.460938, 0 } }, + { "Canon", "EOS 80D", Shade, -1, { 2.000000, 1, 1.438477, 0 } }, + { "Canon", "EOS 80D", Shade, 0, { 2.036133, 1, 1.412109, 0 } }, + { "Canon", "EOS 80D", Shade, 1, { 2.060547, 1, 1.395508, 0 } }, + { "Canon", "EOS 80D", Shade, 2, { 2.085938, 1, 1.375977, 0 } }, + { "Canon", "EOS 80D", Shade, 3, { 2.111328, 1, 1.356445, 0 } }, + { "Canon", "EOS 80D", Shade, 4, { 2.142578, 1, 1.334961, 0 } }, + { "Canon", "EOS 80D", Shade, 5, { 2.169922, 1, 1.316406, 0 } }, + { "Canon", "EOS 80D", Shade, 6, { 2.197266, 1, 1.297852, 0 } }, + { "Canon", "EOS 80D", Shade, 7, { 2.226563, 1, 1.278320, 0 } }, + { "Canon", "EOS 80D", Shade, 8, { 2.260742, 1, 1.259766, 0 } }, + { "Canon", "EOS 80D", Shade, 9, { 2.295898, 1, 1.238281, 0 } }, + { "Canon", "EOS 80D", Cloudy, -9, { 1.672852, 1, 1.747070, 0 } }, + { "Canon", "EOS 80D", Cloudy, -8, { 1.695313, 1, 1.720703, 0 } }, + { "Canon", "EOS 80D", Cloudy, -7, { 1.720703, 1, 1.689453, 0 } }, + { "Canon", "EOS 80D", Cloudy, -6, { 1.744141, 1, 1.659180, 0 } }, + { "Canon", "EOS 80D", Cloudy, -5, { 1.771484, 1, 1.630859, 0 } }, + { "Canon", "EOS 80D", Cloudy, -4, { 1.792969, 1, 1.610352, 0 } }, + { "Canon", "EOS 80D", Cloudy, -3, { 1.818359, 1, 1.587891, 0 } }, + { "Canon", "EOS 80D", Cloudy, -2, { 1.841797, 1, 1.563477, 0 } }, + { "Canon", "EOS 80D", Cloudy, -1, { 1.865234, 1, 1.541992, 0 } }, + { "Canon", "EOS 80D", Cloudy, 0, { 1.889648, 1, 1.519531, 0 } }, + { "Canon", "EOS 80D", Cloudy, 1, { 1.917969, 1, 1.499023, 0 } }, + { "Canon", "EOS 80D", Cloudy, 2, { 1.943359, 1, 1.477539, 0 } }, + { "Canon", "EOS 80D", Cloudy, 3, { 1.976563, 1, 1.454102, 0 } }, + { "Canon", "EOS 80D", Cloudy, 4, { 2.007813, 1, 1.432617, 0 } }, + { "Canon", "EOS 80D", Cloudy, 5, { 2.043945, 1, 1.408203, 0 } }, + { "Canon", "EOS 80D", Cloudy, 6, { 2.064453, 1, 1.391602, 0 } }, + { "Canon", "EOS 80D", Cloudy, 7, { 2.089844, 1, 1.373047, 0 } }, + { "Canon", "EOS 80D", Cloudy, 8, { 2.120117, 1, 1.350586, 0 } }, + { "Canon", "EOS 80D", Cloudy, 9, { 2.151367, 1, 1.330078, 0 } }, + { "Canon", "EOS 80D", Tungsten, -9, { 1.097656, 1, 2.702148, 0 } }, + { "Canon", "EOS 80D", Tungsten, -8, { 1.112305, 1, 2.673828, 0 } }, + { "Canon", "EOS 80D", Tungsten, -7, { 1.127930, 1, 2.639648, 0 } }, + { "Canon", "EOS 80D", Tungsten, -6, { 1.142578, 1, 2.605469, 0 } }, + { "Canon", "EOS 80D", Tungsten, -5, { 1.160156, 1, 2.579102, 0 } }, + { "Canon", "EOS 80D", Tungsten, -4, { 1.176758, 1, 2.541016, 0 } }, + { "Canon", "EOS 80D", Tungsten, -3, { 1.193359, 1, 2.503906, 0 } }, + { "Canon", "EOS 80D", Tungsten, -2, { 1.209961, 1, 2.461914, 0 } }, + { "Canon", "EOS 80D", Tungsten, -1, { 1.227539, 1, 2.420898, 0 } }, + { "Canon", "EOS 80D", Tungsten, 0, { 1.247070, 1, 2.375977, 0 } }, + { "Canon", "EOS 80D", Tungsten, 1, { 1.264648, 1, 2.342773, 0 } }, + { "Canon", "EOS 80D", Tungsten, 2, { 1.283203, 1, 2.311523, 0 } }, + { "Canon", "EOS 80D", Tungsten, 3, { 1.300781, 1, 2.275391, 0 } }, + { "Canon", "EOS 80D", Tungsten, 4, { 1.321289, 1, 2.240234, 0 } }, + { "Canon", "EOS 80D", Tungsten, 5, { 1.343750, 1, 2.202148, 0 } }, + { "Canon", "EOS 80D", Tungsten, 6, { 1.363281, 1, 2.169922, 0 } }, + { "Canon", "EOS 80D", Tungsten, 7, { 1.383789, 1, 2.137695, 0 } }, + { "Canon", "EOS 80D", Tungsten, 8, { 1.404297, 1, 2.102539, 0 } }, + { "Canon", "EOS 80D", Tungsten, 9, { 1.425781, 1, 2.073242, 0 } }, + { "Canon", "EOS 80D", WhiteFluorescent, -9, { 1.291016, 1, 2.559570, 0 } }, + { "Canon", "EOS 80D", WhiteFluorescent, -8, { 1.311523, 1, 2.522461, 0 } }, + { "Canon", "EOS 80D", WhiteFluorescent, -7, { 1.332031, 1, 2.479492, 0 } }, + { "Canon", "EOS 80D", WhiteFluorescent, -6, { 1.354492, 1, 2.438477, 0 } }, + { "Canon", "EOS 80D", WhiteFluorescent, -5, { 1.373047, 1, 2.398438, 0 } }, + { "Canon", "EOS 80D", WhiteFluorescent, -4, { 1.393555, 1, 2.359375, 0 } }, + { "Canon", "EOS 80D", WhiteFluorescent, -3, { 1.414063, 1, 2.327148, 0 } }, + { "Canon", "EOS 80D", WhiteFluorescent, -2, { 1.438477, 1, 2.291016, 0 } }, + { "Canon", "EOS 80D", WhiteFluorescent, -1, { 1.458984, 1, 2.255859, 0 } }, + { "Canon", "EOS 80D", WhiteFluorescent, 0, { 1.475586, 1, 2.216797, 0 } }, + { "Canon", "EOS 80D", WhiteFluorescent, 1, { 1.495117, 1, 2.183594, 0 } }, + { "Canon", "EOS 80D", WhiteFluorescent, 2, { 1.516602, 1, 2.151367, 0 } }, + { "Canon", "EOS 80D", WhiteFluorescent, 3, { 1.540039, 1, 2.120117, 0 } }, + { "Canon", "EOS 80D", WhiteFluorescent, 4, { 1.560547, 1, 2.085938, 0 } }, + { "Canon", "EOS 80D", WhiteFluorescent, 5, { 1.583008, 1, 2.051758, 0 } }, + { "Canon", "EOS 80D", WhiteFluorescent, 6, { 1.605469, 1, 2.023438, 0 } }, + { "Canon", "EOS 80D", WhiteFluorescent, 7, { 1.630859, 1, 1.996094, 0 } }, + { "Canon", "EOS 80D", WhiteFluorescent, 8, { 1.657227, 1, 1.965820, 0 } }, + { "Canon", "EOS 80D", WhiteFluorescent, 9, { 1.681641, 1, 1.935547, 0 } }, + { "Canon", "EOS 80D", Flash, -9, { 1.720703, 1, 1.720703, 0 } }, + { "Canon", "EOS 80D", Flash, -8, { 1.744141, 1, 1.692383, 0 } }, + { "Canon", "EOS 80D", Flash, -7, { 1.771484, 1, 1.662109, 0 } }, + { "Canon", "EOS 80D", Flash, -6, { 1.792969, 1, 1.632813, 0 } }, + { "Canon", "EOS 80D", Flash, -5, { 1.818359, 1, 1.610352, 0 } }, + { "Canon", "EOS 80D", Flash, -4, { 1.841797, 1, 1.587891, 0 } }, + { "Canon", "EOS 80D", Flash, -3, { 1.865234, 1, 1.565430, 0 } }, + { "Canon", "EOS 80D", Flash, -2, { 1.889648, 1, 1.544922, 0 } }, + { "Canon", "EOS 80D", Flash, -1, { 1.917969, 1, 1.521484, 0 } }, + { "Canon", "EOS 80D", Flash, 0, { 1.943359, 1, 1.499023, 0 } }, + { "Canon", "EOS 80D", Flash, 1, { 1.976563, 1, 1.477539, 0 } }, + { "Canon", "EOS 80D", Flash, 2, { 2.007813, 1, 1.457031, 0 } }, + { "Canon", "EOS 80D", Flash, 3, { 2.043945, 1, 1.432617, 0 } }, + { "Canon", "EOS 80D", Flash, 4, { 2.064453, 1, 1.410156, 0 } }, + { "Canon", "EOS 80D", Flash, 5, { 2.089844, 1, 1.391602, 0 } }, + { "Canon", "EOS 80D", Flash, 6, { 2.120117, 1, 1.373047, 0 } }, + { "Canon", "EOS 80D", Flash, 7, { 2.151367, 1, 1.352539, 0 } }, + { "Canon", "EOS 80D", Flash, 8, { 2.178711, 1, 1.332031, 0 } }, + { "Canon", "EOS 80D", Flash, 9, { 2.207031, 1, 1.312500, 0 } }, + + // Copied from Canon EOS 650D + { "Canon", "EOS 100D", Daylight, -3, { 1.9502, 1, 1.7539, 0 } }, + { "Canon", "EOS 100D", Daylight, 0, { 2.0322, 1, 1.6572, 0 } }, + { "Canon", "EOS 100D", Daylight, 3, { 2.1152, 1, 1.5850, 0 } }, + { "Canon", "EOS 100D", Shade, -3, { 2.2305, 1, 1.4951, 0 } }, + { "Canon", "EOS 100D", Shade, 0, { 2.3379, 1, 1.4238, 0 } }, + { "Canon", "EOS 100D", Shade, 3, { 2.4443, 1, 1.3604, 0 } }, + { "Canon", "EOS 100D", Cloudy, -3, { 2.0898, 1, 1.6074, 0 } }, + { "Canon", "EOS 100D", Cloudy, 0, { 2.1787, 1, 1.5332, 0 } }, + { "Canon", "EOS 100D", Cloudy, 3, { 2.2705, 1, 1.4668, 0 } }, + { "Canon", "EOS 100D", Tungsten, -3, { 1.3975, 1, 2.5928, 0 } }, + { "Canon", "EOS 100D", Tungsten, 0, { 1.4541, 1, 2.4561, 0 } }, + { "Canon", "EOS 100D", Tungsten, 3, { 1.5127, 1, 2.3428, 0 } }, + { "Canon", "EOS 100D", WhiteFluorescent, -3, { 1.6982, 1, 2.4268, 0 } }, + { "Canon", "EOS 100D", WhiteFluorescent, 0, { 1.7715, 1, 2.3066, 0 } }, + { "Canon", "EOS 100D", WhiteFluorescent, 3, { 1.8486, 1, 2.1973, 0 } }, + { "Canon", "EOS 100D", Flash, -3, { 2.1699, 1, 1.5879, 0 } }, + { "Canon", "EOS 100D", Flash, 0, { 2.2607, 1, 1.5166, 0 } }, + { "Canon", "EOS 100D", Flash, 3, { 2.3701, 1, 1.4502, 0 } }, + + { "Canon", "EOS REBEL SL1", Daylight, -3, { 1.9502, 1, 1.7539, 0 } }, + { "Canon", "EOS REBEL SL1", Daylight, 0, { 2.0322, 1, 1.6572, 0 } }, + { "Canon", "EOS REBEL SL1", Daylight, 3, { 2.1152, 1, 1.5850, 0 } }, + { "Canon", "EOS REBEL SL1", Shade, -3, { 2.2305, 1, 1.4951, 0 } }, + { "Canon", "EOS REBEL SL1", Shade, 0, { 2.3379, 1, 1.4238, 0 } }, + { "Canon", "EOS REBEL SL1", Shade, 3, { 2.4443, 1, 1.3604, 0 } }, + { "Canon", "EOS REBEL SL1", Cloudy, -3, { 2.0898, 1, 1.6074, 0 } }, + { "Canon", "EOS REBEL SL1", Cloudy, 0, { 2.1787, 1, 1.5332, 0 } }, + { "Canon", "EOS REBEL SL1", Cloudy, 3, { 2.2705, 1, 1.4668, 0 } }, + { "Canon", "EOS REBEL SL1", Tungsten, -3, { 1.3975, 1, 2.5928, 0 } }, + { "Canon", "EOS REBEL SL1", Tungsten, 0, { 1.4541, 1, 2.4561, 0 } }, + { "Canon", "EOS REBEL SL1", Tungsten, 3, { 1.5127, 1, 2.3428, 0 } }, + { "Canon", "EOS REBEL SL1", WhiteFluorescent, -3, { 1.6982, 1, 2.4268, 0 } }, + { "Canon", "EOS REBEL SL1", WhiteFluorescent, 0, { 1.7715, 1, 2.3066, 0 } }, + { "Canon", "EOS REBEL SL1", WhiteFluorescent, 3, { 1.8486, 1, 2.1973, 0 } }, + { "Canon", "EOS REBEL SL1", Flash, -3, { 2.1699, 1, 1.5879, 0 } }, + { "Canon", "EOS REBEL SL1", Flash, 0, { 2.2607, 1, 1.5166, 0 } }, + { "Canon", "EOS REBEL SL1", Flash, 3, { 2.3701, 1, 1.4502, 0 } }, + + { "Canon", "EOS Kiss X7", Daylight, -3, { 1.9502, 1, 1.7539, 0 } }, + { "Canon", "EOS Kiss X7", Daylight, 0, { 2.0322, 1, 1.6572, 0 } }, + { "Canon", "EOS Kiss X7", Daylight, 3, { 2.1152, 1, 1.5850, 0 } }, + { "Canon", "EOS Kiss X7", Shade, -3, { 2.2305, 1, 1.4951, 0 } }, + { "Canon", "EOS Kiss X7", Shade, 0, { 2.3379, 1, 1.4238, 0 } }, + { "Canon", "EOS Kiss X7", Shade, 3, { 2.4443, 1, 1.3604, 0 } }, + { "Canon", "EOS Kiss X7", Cloudy, -3, { 2.0898, 1, 1.6074, 0 } }, + { "Canon", "EOS Kiss X7", Cloudy, 0, { 2.1787, 1, 1.5332, 0 } }, + { "Canon", "EOS Kiss X7", Cloudy, 3, { 2.2705, 1, 1.4668, 0 } }, + { "Canon", "EOS Kiss X7", Tungsten, -3, { 1.3975, 1, 2.5928, 0 } }, + { "Canon", "EOS Kiss X7", Tungsten, 0, { 1.4541, 1, 2.4561, 0 } }, + { "Canon", "EOS Kiss X7", Tungsten, 3, { 1.5127, 1, 2.3428, 0 } }, + { "Canon", "EOS Kiss X7", WhiteFluorescent, -3, { 1.6982, 1, 2.4268, 0 } }, + { "Canon", "EOS Kiss X7", WhiteFluorescent, 0, { 1.7715, 1, 2.3066, 0 } }, + { "Canon", "EOS Kiss X7", WhiteFluorescent, 3, { 1.8486, 1, 2.1973, 0 } }, + { "Canon", "EOS Kiss X7", Flash, -3, { 2.1699, 1, 1.5879, 0 } }, + { "Canon", "EOS Kiss X7", Flash, 0, { 2.2607, 1, 1.5166, 0 } }, + { "Canon", "EOS Kiss X7", Flash, 3, { 2.3701, 1, 1.4502, 0 } }, + + { "Canon", "EOS 300D DIGITAL", Daylight, 0, { 2.072115, 1, 1.217548, 0 } }, + { "Canon", "EOS 300D DIGITAL", Shade, 0, { 2.455529, 1, 1.026442, 0 } }, + { "Canon", "EOS 300D DIGITAL", Cloudy, 0, { 2.254808, 1, 1.108173, 0 } }, + { "Canon", "EOS 300D DIGITAL", Tungsten, 0, { 1.349057, 1, 1.896226, 0 } }, + { "Canon", "EOS 300D DIGITAL", WhiteFluorescent, 0, { 1.794664, 1, 1.711137, 0 } }, + { "Canon", "EOS 300D DIGITAL", Flash, 0, { 2.326923, 1, 1.098558, 0 } }, + + { "Canon", "EOS DIGITAL REBEL", Daylight, 0, { 2.072115, 1, 1.217548, 0 } }, + { "Canon", "EOS DIGITAL REBEL", Shade, 0, { 2.455529, 1, 1.026442, 0 } }, + { "Canon", "EOS DIGITAL REBEL", Cloudy, 0, { 2.254808, 1, 1.108173, 0 } }, + { "Canon", "EOS DIGITAL REBEL", Tungsten, 0, { 1.349057, 1, 1.896226, 0 } }, + { "Canon", "EOS DIGITAL REBEL", WhiteFluorescent, 0, { 1.794664, 1, 1.711137, 0 } }, + { "Canon", "EOS DIGITAL REBEL", Flash, 0, { 2.326923, 1, 1.098558, 0 } }, + + { "Canon", "EOS Kiss Digital", Daylight, 0, { 2.072115, 1, 1.217548, 0 } }, + { "Canon", "EOS Kiss Digital", Shade, 0, { 2.455529, 1, 1.026442, 0 } }, + { "Canon", "EOS Kiss Digital", Cloudy, 0, { 2.254808, 1, 1.108173, 0 } }, + { "Canon", "EOS Kiss Digital", Tungsten, 0, { 1.349057, 1, 1.896226, 0 } }, + { "Canon", "EOS Kiss Digital", WhiteFluorescent, 0, { 1.794664, 1, 1.711137, 0 } }, + { "Canon", "EOS Kiss Digital", Flash, 0, { 2.326923, 1, 1.098558, 0 } }, + + // Firmware version 1.0.3. Fine tuning is from A9 to B9 on amber-blue. + { "Canon", "EOS 350D DIGITAL", Daylight, -9, { 2.7436, 1, 1.2240, 0 } }, + { "Canon", "EOS 350D DIGITAL", Daylight, 0, { 2.3605, 1, 1.4450, 0 } }, + { "Canon", "EOS 350D DIGITAL", Daylight, 9, { 2.0138, 1, 1.7151, 0 } }, + { "Canon", "EOS 350D DIGITAL", Shade, -9, { 3.1857, 1, 1.0285, 0 } }, + { "Canon", "EOS 350D DIGITAL", Shade, 0, { 2.7888, 1, 1.2024, 0 } }, + { "Canon", "EOS 350D DIGITAL", Shade, 9, { 2.3988, 1, 1.4214, 0 } }, + { "Canon", "EOS 350D DIGITAL", Cloudy, -9, { 2.9912, 1, 1.1169, 0 } }, + { "Canon", "EOS 350D DIGITAL", Cloudy, 0, { 2.5727, 1, 1.3075, 0 } }, + { "Canon", "EOS 350D DIGITAL", Cloudy, 9, { 2.2033, 1, 1.5589, 0 } }, + { "Canon", "EOS 350D DIGITAL", Tungsten, -9, { 1.5589, 1, 1.9205, 0 } }, + { "Canon", "EOS 350D DIGITAL", Tungsten, 0, { 1.5343, 1, 2.2880, 0 } }, + { "Canon", "EOS 350D DIGITAL", Tungsten, 9, { 1.3145, 1, 2.6873, 0 } }, + { "Canon", "EOS 350D DIGITAL", WhiteFluorescent, -9, { 2.3124, 1, 1.6356, 0 } }, + { "Canon", "EOS 350D DIGITAL", WhiteFluorescent, 0, { 1.9754, 1, 1.9303, 0 } }, + { "Canon", "EOS 350D DIGITAL", WhiteFluorescent, 9, { 1.6657, 1, 2.3034, 0 } }, + { "Canon", "EOS 350D DIGITAL", Flash, -9, { 3.0904, 1, 1.0756, 0 } }, + { "Canon", "EOS 350D DIGITAL", Flash, 0, { 2.6729, 1, 1.2613, 0 } }, + { "Canon", "EOS 350D DIGITAL", Flash, 9, { 2.3026, 1, 1.4961, 0 } }, + + // Firmware version 1.0.3. Fine tuning is from A9 to B9 on amber-blue. + { "Canon", "EOS DIGITAL REBEL XT", Daylight, -9, { 2.7436, 1, 1.2240, 0 } }, + { "Canon", "EOS DIGITAL REBEL XT", Daylight, 0, { 2.3605, 1, 1.4450, 0 } }, + { "Canon", "EOS DIGITAL REBEL XT", Daylight, 9, { 2.0138, 1, 1.7151, 0 } }, + { "Canon", "EOS DIGITAL REBEL XT", Shade, -9, { 3.1857, 1, 1.0285, 0 } }, + { "Canon", "EOS DIGITAL REBEL XT", Shade, 0, { 2.7888, 1, 1.2024, 0 } }, + { "Canon", "EOS DIGITAL REBEL XT", Shade, 9, { 2.3988, 1, 1.4214, 0 } }, + { "Canon", "EOS DIGITAL REBEL XT", Cloudy, -9, { 2.9912, 1, 1.1169, 0 } }, + { "Canon", "EOS DIGITAL REBEL XT", Cloudy, 0, { 2.5727, 1, 1.3075, 0 } }, + { "Canon", "EOS DIGITAL REBEL XT", Cloudy, 9, { 2.2033, 1, 1.5589, 0 } }, + { "Canon", "EOS DIGITAL REBEL XT", Tungsten, -9, { 1.5589, 1, 1.9205, 0 } }, + { "Canon", "EOS DIGITAL REBEL XT", Tungsten, 0, { 1.5343, 1, 2.2880, 0 } }, + { "Canon", "EOS DIGITAL REBEL XT", Tungsten, 9, { 1.3145, 1, 2.6873, 0 } }, + { "Canon", "EOS DIGITAL REBEL XT", WhiteFluorescent, -9, { 2.3124, 1, 1.6356, 0 } }, + { "Canon", "EOS DIGITAL REBEL XT", WhiteFluorescent, 0, { 1.9754, 1, 1.9303, 0 } }, + { "Canon", "EOS DIGITAL REBEL XT", WhiteFluorescent, 9, { 1.6657, 1, 2.3034, 0 } }, + { "Canon", "EOS DIGITAL REBEL XT", Flash, -9, { 3.0904, 1, 1.0756, 0 } }, + { "Canon", "EOS DIGITAL REBEL XT", Flash, 0, { 2.6729, 1, 1.2613, 0 } }, + { "Canon", "EOS DIGITAL REBEL XT", Flash, 9, { 2.3026, 1, 1.4961, 0 } }, + + // Firmware version 1.0.3. Fine tuning is from A9 to B9 on amber-blue. + { "Canon", "EOS Kiss Digital N", Daylight, -9, { 2.7436, 1, 1.2240, 0 } }, + { "Canon", "EOS Kiss Digital N", Daylight, 0, { 2.3605, 1, 1.4450, 0 } }, + { "Canon", "EOS Kiss Digital N", Daylight, 9, { 2.0138, 1, 1.7151, 0 } }, + { "Canon", "EOS Kiss Digital N", Shade, -9, { 3.1857, 1, 1.0285, 0 } }, + { "Canon", "EOS Kiss Digital N", Shade, 0, { 2.7888, 1, 1.2024, 0 } }, + { "Canon", "EOS Kiss Digital N", Shade, 9, { 2.3988, 1, 1.4214, 0 } }, + { "Canon", "EOS Kiss Digital N", Cloudy, -9, { 2.9912, 1, 1.1169, 0 } }, + { "Canon", "EOS Kiss Digital N", Cloudy, 0, { 2.5727, 1, 1.3075, 0 } }, + { "Canon", "EOS Kiss Digital N", Cloudy, 9, { 2.2033, 1, 1.5589, 0 } }, + { "Canon", "EOS Kiss Digital N", Tungsten, -9, { 1.5589, 1, 1.9205, 0 } }, + { "Canon", "EOS Kiss Digital N", Tungsten, 0, { 1.5343, 1, 2.2880, 0 } }, + { "Canon", "EOS Kiss Digital N", Tungsten, 9, { 1.3145, 1, 2.6873, 0 } }, + { "Canon", "EOS Kiss Digital N", WhiteFluorescent, -9, { 2.3124, 1, 1.6356, 0 } }, + { "Canon", "EOS Kiss Digital N", WhiteFluorescent, 0, { 1.9754, 1, 1.9303, 0 } }, + { "Canon", "EOS Kiss Digital N", WhiteFluorescent, 9, { 1.6657, 1, 2.3034, 0 } }, + { "Canon", "EOS Kiss Digital N", Flash, -9, { 3.0904, 1, 1.0756, 0 } }, + { "Canon", "EOS Kiss Digital N", Flash, 0, { 2.6729, 1, 1.2613, 0 } }, + { "Canon", "EOS Kiss Digital N", Flash, 9, { 2.3026, 1, 1.4961, 0 } }, + + // Canon EOS 400D (firmware 1.1.1) white balance presets, 5 mireds per step + { "Canon", "EOS 400D DIGITAL", Daylight, -9, { 1.972656, 1, 1.735352, 0 } }, + { "Canon", "EOS 400D DIGITAL", Daylight, -8, { 2.003906, 1, 1.707031, 0 } }, + { "Canon", "EOS 400D DIGITAL", Daylight, -7, { 2.036133, 1, 1.675781, 0 } }, + { "Canon", "EOS 400D DIGITAL", Daylight, -6, { 2.073242, 1, 1.646484, 0 } }, + { "Canon", "EOS 400D DIGITAL", Daylight, -5, { 2.111328, 1, 1.615234, 0 } }, + { "Canon", "EOS 400D DIGITAL", Daylight, -4, { 2.151367, 1, 1.583008, 0 } }, + { "Canon", "EOS 400D DIGITAL", Daylight, -3, { 2.183594, 1, 1.553711, 0 } }, + { "Canon", "EOS 400D DIGITAL", Daylight, -2, { 2.221680, 1, 1.523438, 0 } }, + { "Canon", "EOS 400D DIGITAL", Daylight, -1, { 2.260742, 1, 1.495117, 0 } }, + { "Canon", "EOS 400D DIGITAL", Daylight, 0, { 2.300781, 1, 1.462891, 0 } }, + { "Canon", "EOS 400D DIGITAL", Daylight, 1, { 2.337891, 1, 1.436523, 0 } }, + { "Canon", "EOS 400D DIGITAL", Daylight, 2, { 2.375977, 1, 1.408203, 0 } }, + { "Canon", "EOS 400D DIGITAL", Daylight, 3, { 2.415039, 1, 1.379883, 0 } }, + { "Canon", "EOS 400D DIGITAL", Daylight, 4, { 2.461914, 1, 1.354492, 0 } }, + { "Canon", "EOS 400D DIGITAL", Daylight, 5, { 2.503906, 1, 1.328125, 0 } }, + { "Canon", "EOS 400D DIGITAL", Daylight, 6, { 2.541016, 1, 1.304688, 0 } }, + { "Canon", "EOS 400D DIGITAL", Daylight, 7, { 2.579102, 1, 1.280273, 0 } }, + { "Canon", "EOS 400D DIGITAL", Daylight, 8, { 2.619141, 1, 1.256836, 0 } }, + { "Canon", "EOS 400D DIGITAL", Daylight, 9, { 2.666992, 1, 1.232422, 0 } }, + { "Canon", "EOS 400D DIGITAL", Shade, -9, { 2.333008, 1, 1.440430, 0 } }, + { "Canon", "EOS 400D DIGITAL", Shade, -8, { 2.370117, 1, 1.410156, 0 } }, + { "Canon", "EOS 400D DIGITAL", Shade, -7, { 2.409180, 1, 1.383789, 0 } }, + { "Canon", "EOS 400D DIGITAL", Shade, -6, { 2.456055, 1, 1.356445, 0 } }, + { "Canon", "EOS 400D DIGITAL", Shade, -5, { 2.503906, 1, 1.330078, 0 } }, + { "Canon", "EOS 400D DIGITAL", Shade, -4, { 2.541016, 1, 1.305664, 0 } }, + { "Canon", "EOS 400D DIGITAL", Shade, -3, { 2.579102, 1, 1.283203, 0 } }, + { "Canon", "EOS 400D DIGITAL", Shade, -2, { 2.619141, 1, 1.259766, 0 } }, + { "Canon", "EOS 400D DIGITAL", Shade, -1, { 2.660156, 1, 1.235352, 0 } }, + { "Canon", "EOS 400D DIGITAL", Shade, 0, { 2.708984, 1, 1.208984, 0 } }, + { "Canon", "EOS 400D DIGITAL", Shade, 1, { 2.745117, 1, 1.189453, 0 } }, + { "Canon", "EOS 400D DIGITAL", Shade, 2, { 2.782227, 1, 1.168945, 0 } }, + { "Canon", "EOS 400D DIGITAL", Shade, 3, { 2.829102, 1, 1.148438, 0 } }, + { "Canon", "EOS 400D DIGITAL", Shade, 4, { 2.875977, 1, 1.125000, 0 } }, + { "Canon", "EOS 400D DIGITAL", Shade, 5, { 2.916992, 1, 1.105469, 0 } }, + { "Canon", "EOS 400D DIGITAL", Shade, 6, { 2.951172, 1, 1.087891, 0 } }, + { "Canon", "EOS 400D DIGITAL", Shade, 7, { 2.994141, 1, 1.069336, 0 } }, + { "Canon", "EOS 400D DIGITAL", Shade, 8, { 3.039063, 1, 1.048828, 0 } }, + { "Canon", "EOS 400D DIGITAL", Shade, 9, { 3.083984, 1, 1.030273, 0 } }, + { "Canon", "EOS 400D DIGITAL", Cloudy, -9, { 2.156250, 1, 1.580078, 0 } }, + { "Canon", "EOS 400D DIGITAL", Cloudy, -8, { 2.188477, 1, 1.551758, 0 } }, + { "Canon", "EOS 400D DIGITAL", Cloudy, -7, { 2.226563, 1, 1.521484, 0 } }, + { "Canon", "EOS 400D DIGITAL", Cloudy, -6, { 2.265625, 1, 1.490234, 0 } }, + { "Canon", "EOS 400D DIGITAL", Cloudy, -5, { 2.306641, 1, 1.460938, 0 } }, + { "Canon", "EOS 400D DIGITAL", Cloudy, -4, { 2.342773, 1, 1.432617, 0 } }, + { "Canon", "EOS 400D DIGITAL", Cloudy, -3, { 2.381836, 1, 1.404297, 0 } }, + { "Canon", "EOS 400D DIGITAL", Cloudy, -2, { 2.420898, 1, 1.375977, 0 } }, + { "Canon", "EOS 400D DIGITAL", Cloudy, -1, { 2.467773, 1, 1.350586, 0 } }, + { "Canon", "EOS 400D DIGITAL", Cloudy, 0, { 2.509766, 1, 1.323242, 0 } }, + { "Canon", "EOS 400D DIGITAL", Cloudy, 1, { 2.546875, 1, 1.300781, 0 } }, + { "Canon", "EOS 400D DIGITAL", Cloudy, 2, { 2.585938, 1, 1.278320, 0 } }, + { "Canon", "EOS 400D DIGITAL", Cloudy, 3, { 2.625977, 1, 1.252930, 0 } }, + { "Canon", "EOS 400D DIGITAL", Cloudy, 4, { 2.673828, 1, 1.229492, 0 } }, + { "Canon", "EOS 400D DIGITAL", Cloudy, 5, { 2.723633, 1, 1.205078, 0 } }, + { "Canon", "EOS 400D DIGITAL", Cloudy, 6, { 2.752930, 1, 1.185547, 0 } }, + { "Canon", "EOS 400D DIGITAL", Cloudy, 7, { 2.790039, 1, 1.165039, 0 } }, + { "Canon", "EOS 400D DIGITAL", Cloudy, 8, { 2.836914, 1, 1.142578, 0 } }, + { "Canon", "EOS 400D DIGITAL", Cloudy, 9, { 2.884766, 1, 1.120117, 0 } }, + { "Canon", "EOS 400D DIGITAL", Tungsten, -9, { 1.320106, 1, 2.752205, 0 } }, + { "Canon", "EOS 400D DIGITAL", Tungsten, -8, { 1.340708, 1, 2.703540, 0 } }, + { "Canon", "EOS 400D DIGITAL", Tungsten, -7, { 1.359680, 1, 2.655417, 0 } }, + { "Canon", "EOS 400D DIGITAL", Tungsten, -6, { 1.381802, 1, 2.606601, 0 } }, + { "Canon", "EOS 400D DIGITAL", Tungsten, -5, { 1.406446, 1, 2.555953, 0 } }, + { "Canon", "EOS 400D DIGITAL", Tungsten, -4, { 1.428957, 1, 2.504496, 0 } }, + { "Canon", "EOS 400D DIGITAL", Tungsten, -3, { 1.452575, 1, 2.459801, 0 } }, + { "Canon", "EOS 400D DIGITAL", Tungsten, -2, { 1.475931, 1, 2.419619, 0 } }, + { "Canon", "EOS 400D DIGITAL", Tungsten, -1, { 1.501825, 1, 2.377737, 0 } }, + { "Canon", "EOS 400D DIGITAL", Tungsten, 0, { 1.526123, 1, 2.330889, 0 } }, + { "Canon", "EOS 400D DIGITAL", Tungsten, 1, { 1.548893, 1, 2.286900, 0 } }, + { "Canon", "EOS 400D DIGITAL", Tungsten, 2, { 1.572753, 1, 2.238184, 0 } }, + { "Canon", "EOS 400D DIGITAL", Tungsten, 3, { 1.599254, 1, 2.198509, 0 } }, + { "Canon", "EOS 400D DIGITAL", Tungsten, 4, { 1.624765, 1, 2.149156, 0 } }, + { "Canon", "EOS 400D DIGITAL", Tungsten, 5, { 1.653774, 1, 2.102830, 0 } }, + { "Canon", "EOS 400D DIGITAL", Tungsten, 6, { 1.681861, 1, 2.064577, 0 } }, + { "Canon", "EOS 400D DIGITAL", Tungsten, 7, { 1.709369, 1, 2.022945, 0 } }, + { "Canon", "EOS 400D DIGITAL", Tungsten, 8, { 1.737247, 1, 1.982676, 0 } }, + { "Canon", "EOS 400D DIGITAL", Tungsten, 9, { 1.770349, 1, 1.946705, 0 } }, + { "Canon", "EOS 400D DIGITAL", WhiteFluorescent, -9, { 1.638122, 1, 2.485267, 0 } }, + { "Canon", "EOS 400D DIGITAL", WhiteFluorescent, -8, { 1.667900, 1, 2.445883, 0 } }, + { "Canon", "EOS 400D DIGITAL", WhiteFluorescent, -7, { 1.695814, 1, 2.404651, 0 } }, + { "Canon", "EOS 400D DIGITAL", WhiteFluorescent, -6, { 1.723364, 1, 2.361682, 0 } }, + { "Canon", "EOS 400D DIGITAL", WhiteFluorescent, -5, { 1.752820, 1, 2.317669, 0 } }, + { "Canon", "EOS 400D DIGITAL", WhiteFluorescent, -4, { 1.788079, 1, 2.263009, 0 } }, + { "Canon", "EOS 400D DIGITAL", WhiteFluorescent, -3, { 1.815414, 1, 2.221694, 0 } }, + { "Canon", "EOS 400D DIGITAL", WhiteFluorescent, -2, { 1.844828, 1, 2.175287, 0 } }, + { "Canon", "EOS 400D DIGITAL", WhiteFluorescent, -1, { 1.880309, 1, 2.127413, 0 } }, + { "Canon", "EOS 400D DIGITAL", WhiteFluorescent, 0, { 1.910506, 1, 2.080739, 0 } }, + { "Canon", "EOS 400D DIGITAL", WhiteFluorescent, 1, { 1.950195, 1, 2.043945, 0 } }, + { "Canon", "EOS 400D DIGITAL", WhiteFluorescent, 2, { 1.984375, 1, 2.007813, 0 } }, + { "Canon", "EOS 400D DIGITAL", WhiteFluorescent, 3, { 2.015625, 1, 1.968750, 0 } }, + { "Canon", "EOS 400D DIGITAL", WhiteFluorescent, 4, { 2.047852, 1, 1.928711, 0 } }, + { "Canon", "EOS 400D DIGITAL", WhiteFluorescent, 5, { 2.085938, 1, 1.892578, 0 } }, + { "Canon", "EOS 400D DIGITAL", WhiteFluorescent, 6, { 2.124023, 1, 1.858398, 0 } }, + { "Canon", "EOS 400D DIGITAL", WhiteFluorescent, 7, { 2.165039, 1, 1.825195, 0 } }, + { "Canon", "EOS 400D DIGITAL", WhiteFluorescent, 8, { 2.197266, 1, 1.790039, 0 } }, + { "Canon", "EOS 400D DIGITAL", WhiteFluorescent, 9, { 2.235352, 1, 1.756836, 0 } }, + { "Canon", "EOS 400D DIGITAL", Flash, -9, { 2.398438, 1, 1.432617, 0 } }, + { "Canon", "EOS 400D DIGITAL", Flash, -8, { 2.438477, 1, 1.402344, 0 } }, + { "Canon", "EOS 400D DIGITAL", Flash, -7, { 2.485352, 1, 1.375977, 0 } }, + { "Canon", "EOS 400D DIGITAL", Flash, -6, { 2.528320, 1, 1.349609, 0 } }, + { "Canon", "EOS 400D DIGITAL", Flash, -5, { 2.566406, 1, 1.323242, 0 } }, + { "Canon", "EOS 400D DIGITAL", Flash, -4, { 2.605469, 1, 1.299805, 0 } }, + { "Canon", "EOS 400D DIGITAL", Flash, -3, { 2.645508, 1, 1.276367, 0 } }, + { "Canon", "EOS 400D DIGITAL", Flash, -2, { 2.694336, 1, 1.251953, 0 } }, + { "Canon", "EOS 400D DIGITAL", Flash, -1, { 2.738281, 1, 1.227539, 0 } }, + { "Canon", "EOS 400D DIGITAL", Flash, 0, { 2.767578, 1, 1.203125, 0 } }, + { "Canon", "EOS 400D DIGITAL", Flash, 1, { 2.813477, 1, 1.183594, 0 } }, + { "Canon", "EOS 400D DIGITAL", Flash, 2, { 2.860352, 1, 1.164063, 0 } }, + { "Canon", "EOS 400D DIGITAL", Flash, 3, { 2.900391, 1, 1.141602, 0 } }, + { "Canon", "EOS 400D DIGITAL", Flash, 4, { 2.942383, 1, 1.118164, 0 } }, + { "Canon", "EOS 400D DIGITAL", Flash, 5, { 2.976563, 1, 1.101563, 0 } }, + { "Canon", "EOS 400D DIGITAL", Flash, 6, { 3.020508, 1, 1.082031, 0 } }, + { "Canon", "EOS 400D DIGITAL", Flash, 7, { 3.065430, 1, 1.063477, 0 } }, + { "Canon", "EOS 400D DIGITAL", Flash, 8, { 3.122070, 1, 1.041992, 0 } }, + { "Canon", "EOS 400D DIGITAL", Flash, 9, { 3.169922, 1, 1.024414, 0 } }, + + { "Canon", "EOS DIGITAL REBEL XTi", Daylight, -9, { 1.972656, 1, 1.735352, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Daylight, -8, { 2.003906, 1, 1.707031, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Daylight, -7, { 2.036133, 1, 1.675781, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Daylight, -6, { 2.073242, 1, 1.646484, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Daylight, -5, { 2.111328, 1, 1.615234, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Daylight, -4, { 2.151367, 1, 1.583008, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Daylight, -3, { 2.183594, 1, 1.553711, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Daylight, -2, { 2.221680, 1, 1.523438, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Daylight, -1, { 2.260742, 1, 1.495117, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Daylight, 0, { 2.300781, 1, 1.462891, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Daylight, 1, { 2.337891, 1, 1.436523, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Daylight, 2, { 2.375977, 1, 1.408203, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Daylight, 3, { 2.415039, 1, 1.379883, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Daylight, 4, { 2.461914, 1, 1.354492, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Daylight, 5, { 2.503906, 1, 1.328125, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Daylight, 6, { 2.541016, 1, 1.304688, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Daylight, 7, { 2.579102, 1, 1.280273, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Daylight, 8, { 2.619141, 1, 1.256836, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Daylight, 9, { 2.666992, 1, 1.232422, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Shade, -9, { 2.333008, 1, 1.440430, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Shade, -8, { 2.370117, 1, 1.410156, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Shade, -7, { 2.409180, 1, 1.383789, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Shade, -6, { 2.456055, 1, 1.356445, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Shade, -5, { 2.503906, 1, 1.330078, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Shade, -4, { 2.541016, 1, 1.305664, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Shade, -3, { 2.579102, 1, 1.283203, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Shade, -2, { 2.619141, 1, 1.259766, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Shade, -1, { 2.660156, 1, 1.235352, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Shade, 0, { 2.708984, 1, 1.208984, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Shade, 1, { 2.745117, 1, 1.189453, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Shade, 2, { 2.782227, 1, 1.168945, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Shade, 3, { 2.829102, 1, 1.148438, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Shade, 4, { 2.875977, 1, 1.125000, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Shade, 5, { 2.916992, 1, 1.105469, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Shade, 6, { 2.951172, 1, 1.087891, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Shade, 7, { 2.994141, 1, 1.069336, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Shade, 8, { 3.039063, 1, 1.048828, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Shade, 9, { 3.083984, 1, 1.030273, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Cloudy, -9, { 2.156250, 1, 1.580078, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Cloudy, -8, { 2.188477, 1, 1.551758, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Cloudy, -7, { 2.226563, 1, 1.521484, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Cloudy, -6, { 2.265625, 1, 1.490234, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Cloudy, -5, { 2.306641, 1, 1.460938, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Cloudy, -4, { 2.342773, 1, 1.432617, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Cloudy, -3, { 2.381836, 1, 1.404297, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Cloudy, -2, { 2.420898, 1, 1.375977, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Cloudy, -1, { 2.467773, 1, 1.350586, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Cloudy, 0, { 2.509766, 1, 1.323242, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Cloudy, 1, { 2.546875, 1, 1.300781, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Cloudy, 2, { 2.585938, 1, 1.278320, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Cloudy, 3, { 2.625977, 1, 1.252930, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Cloudy, 4, { 2.673828, 1, 1.229492, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Cloudy, 5, { 2.723633, 1, 1.205078, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Cloudy, 6, { 2.752930, 1, 1.185547, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Cloudy, 7, { 2.790039, 1, 1.165039, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Cloudy, 8, { 2.836914, 1, 1.142578, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Cloudy, 9, { 2.884766, 1, 1.120117, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Tungsten, -9, { 1.320106, 1, 2.752205, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Tungsten, -8, { 1.340708, 1, 2.703540, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Tungsten, -7, { 1.359680, 1, 2.655417, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Tungsten, -6, { 1.381802, 1, 2.606601, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Tungsten, -5, { 1.406446, 1, 2.555953, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Tungsten, -4, { 1.428957, 1, 2.504496, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Tungsten, -3, { 1.452575, 1, 2.459801, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Tungsten, -2, { 1.475931, 1, 2.419619, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Tungsten, -1, { 1.501825, 1, 2.377737, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Tungsten, 0, { 1.526123, 1, 2.330889, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Tungsten, 1, { 1.548893, 1, 2.286900, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Tungsten, 2, { 1.572753, 1, 2.238184, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Tungsten, 3, { 1.599254, 1, 2.198509, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Tungsten, 4, { 1.624765, 1, 2.149156, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Tungsten, 5, { 1.653774, 1, 2.102830, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Tungsten, 6, { 1.681861, 1, 2.064577, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Tungsten, 7, { 1.709369, 1, 2.022945, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Tungsten, 8, { 1.737247, 1, 1.982676, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Tungsten, 9, { 1.770349, 1, 1.946705, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", WhiteFluorescent, -9, { 1.638122, 1, 2.485267, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", WhiteFluorescent, -8, { 1.667900, 1, 2.445883, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", WhiteFluorescent, -7, { 1.695814, 1, 2.404651, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", WhiteFluorescent, -6, { 1.723364, 1, 2.361682, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", WhiteFluorescent, -5, { 1.752820, 1, 2.317669, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", WhiteFluorescent, -4, { 1.788079, 1, 2.263009, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", WhiteFluorescent, -3, { 1.815414, 1, 2.221694, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", WhiteFluorescent, -2, { 1.844828, 1, 2.175287, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", WhiteFluorescent, -1, { 1.880309, 1, 2.127413, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", WhiteFluorescent, 0, { 1.910506, 1, 2.080739, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", WhiteFluorescent, 1, { 1.950195, 1, 2.043945, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", WhiteFluorescent, 2, { 1.984375, 1, 2.007813, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", WhiteFluorescent, 3, { 2.015625, 1, 1.968750, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", WhiteFluorescent, 4, { 2.047852, 1, 1.928711, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", WhiteFluorescent, 5, { 2.085938, 1, 1.892578, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", WhiteFluorescent, 6, { 2.124023, 1, 1.858398, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", WhiteFluorescent, 7, { 2.165039, 1, 1.825195, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", WhiteFluorescent, 8, { 2.197266, 1, 1.790039, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", WhiteFluorescent, 9, { 2.235352, 1, 1.756836, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Flash, -9, { 2.398438, 1, 1.432617, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Flash, -8, { 2.438477, 1, 1.402344, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Flash, -7, { 2.485352, 1, 1.375977, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Flash, -6, { 2.528320, 1, 1.349609, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Flash, -5, { 2.566406, 1, 1.323242, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Flash, -4, { 2.605469, 1, 1.299805, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Flash, -3, { 2.645508, 1, 1.276367, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Flash, -2, { 2.694336, 1, 1.251953, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Flash, -1, { 2.738281, 1, 1.227539, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Flash, 0, { 2.767578, 1, 1.203125, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Flash, 1, { 2.813477, 1, 1.183594, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Flash, 2, { 2.860352, 1, 1.164063, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Flash, 3, { 2.900391, 1, 1.141602, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Flash, 4, { 2.942383, 1, 1.118164, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Flash, 5, { 2.976563, 1, 1.101563, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Flash, 6, { 3.020508, 1, 1.082031, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Flash, 7, { 3.065430, 1, 1.063477, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Flash, 8, { 3.122070, 1, 1.041992, 0 } }, + { "Canon", "EOS DIGITAL REBEL XTi", Flash, 9, { 3.169922, 1, 1.024414, 0 } }, + + { "Canon", "EOS Kiss Digital X", Daylight, -9, { 1.972656, 1, 1.735352, 0 } }, + { "Canon", "EOS Kiss Digital X", Daylight, -8, { 2.003906, 1, 1.707031, 0 } }, + { "Canon", "EOS Kiss Digital X", Daylight, -7, { 2.036133, 1, 1.675781, 0 } }, + { "Canon", "EOS Kiss Digital X", Daylight, -6, { 2.073242, 1, 1.646484, 0 } }, + { "Canon", "EOS Kiss Digital X", Daylight, -5, { 2.111328, 1, 1.615234, 0 } }, + { "Canon", "EOS Kiss Digital X", Daylight, -4, { 2.151367, 1, 1.583008, 0 } }, + { "Canon", "EOS Kiss Digital X", Daylight, -3, { 2.183594, 1, 1.553711, 0 } }, + { "Canon", "EOS Kiss Digital X", Daylight, -2, { 2.221680, 1, 1.523438, 0 } }, + { "Canon", "EOS Kiss Digital X", Daylight, -1, { 2.260742, 1, 1.495117, 0 } }, + { "Canon", "EOS Kiss Digital X", Daylight, 0, { 2.300781, 1, 1.462891, 0 } }, + { "Canon", "EOS Kiss Digital X", Daylight, 1, { 2.337891, 1, 1.436523, 0 } }, + { "Canon", "EOS Kiss Digital X", Daylight, 2, { 2.375977, 1, 1.408203, 0 } }, + { "Canon", "EOS Kiss Digital X", Daylight, 3, { 2.415039, 1, 1.379883, 0 } }, + { "Canon", "EOS Kiss Digital X", Daylight, 4, { 2.461914, 1, 1.354492, 0 } }, + { "Canon", "EOS Kiss Digital X", Daylight, 5, { 2.503906, 1, 1.328125, 0 } }, + { "Canon", "EOS Kiss Digital X", Daylight, 6, { 2.541016, 1, 1.304688, 0 } }, + { "Canon", "EOS Kiss Digital X", Daylight, 7, { 2.579102, 1, 1.280273, 0 } }, + { "Canon", "EOS Kiss Digital X", Daylight, 8, { 2.619141, 1, 1.256836, 0 } }, + { "Canon", "EOS Kiss Digital X", Daylight, 9, { 2.666992, 1, 1.232422, 0 } }, + { "Canon", "EOS Kiss Digital X", Shade, -9, { 2.333008, 1, 1.440430, 0 } }, + { "Canon", "EOS Kiss Digital X", Shade, -8, { 2.370117, 1, 1.410156, 0 } }, + { "Canon", "EOS Kiss Digital X", Shade, -7, { 2.409180, 1, 1.383789, 0 } }, + { "Canon", "EOS Kiss Digital X", Shade, -6, { 2.456055, 1, 1.356445, 0 } }, + { "Canon", "EOS Kiss Digital X", Shade, -5, { 2.503906, 1, 1.330078, 0 } }, + { "Canon", "EOS Kiss Digital X", Shade, -4, { 2.541016, 1, 1.305664, 0 } }, + { "Canon", "EOS Kiss Digital X", Shade, -3, { 2.579102, 1, 1.283203, 0 } }, + { "Canon", "EOS Kiss Digital X", Shade, -2, { 2.619141, 1, 1.259766, 0 } }, + { "Canon", "EOS Kiss Digital X", Shade, -1, { 2.660156, 1, 1.235352, 0 } }, + { "Canon", "EOS Kiss Digital X", Shade, 0, { 2.708984, 1, 1.208984, 0 } }, + { "Canon", "EOS Kiss Digital X", Shade, 1, { 2.745117, 1, 1.189453, 0 } }, + { "Canon", "EOS Kiss Digital X", Shade, 2, { 2.782227, 1, 1.168945, 0 } }, + { "Canon", "EOS Kiss Digital X", Shade, 3, { 2.829102, 1, 1.148438, 0 } }, + { "Canon", "EOS Kiss Digital X", Shade, 4, { 2.875977, 1, 1.125000, 0 } }, + { "Canon", "EOS Kiss Digital X", Shade, 5, { 2.916992, 1, 1.105469, 0 } }, + { "Canon", "EOS Kiss Digital X", Shade, 6, { 2.951172, 1, 1.087891, 0 } }, + { "Canon", "EOS Kiss Digital X", Shade, 7, { 2.994141, 1, 1.069336, 0 } }, + { "Canon", "EOS Kiss Digital X", Shade, 8, { 3.039063, 1, 1.048828, 0 } }, + { "Canon", "EOS Kiss Digital X", Shade, 9, { 3.083984, 1, 1.030273, 0 } }, + { "Canon", "EOS Kiss Digital X", Cloudy, -9, { 2.156250, 1, 1.580078, 0 } }, + { "Canon", "EOS Kiss Digital X", Cloudy, -8, { 2.188477, 1, 1.551758, 0 } }, + { "Canon", "EOS Kiss Digital X", Cloudy, -7, { 2.226563, 1, 1.521484, 0 } }, + { "Canon", "EOS Kiss Digital X", Cloudy, -6, { 2.265625, 1, 1.490234, 0 } }, + { "Canon", "EOS Kiss Digital X", Cloudy, -5, { 2.306641, 1, 1.460938, 0 } }, + { "Canon", "EOS Kiss Digital X", Cloudy, -4, { 2.342773, 1, 1.432617, 0 } }, + { "Canon", "EOS Kiss Digital X", Cloudy, -3, { 2.381836, 1, 1.404297, 0 } }, + { "Canon", "EOS Kiss Digital X", Cloudy, -2, { 2.420898, 1, 1.375977, 0 } }, + { "Canon", "EOS Kiss Digital X", Cloudy, -1, { 2.467773, 1, 1.350586, 0 } }, + { "Canon", "EOS Kiss Digital X", Cloudy, 0, { 2.509766, 1, 1.323242, 0 } }, + { "Canon", "EOS Kiss Digital X", Cloudy, 1, { 2.546875, 1, 1.300781, 0 } }, + { "Canon", "EOS Kiss Digital X", Cloudy, 2, { 2.585938, 1, 1.278320, 0 } }, + { "Canon", "EOS Kiss Digital X", Cloudy, 3, { 2.625977, 1, 1.252930, 0 } }, + { "Canon", "EOS Kiss Digital X", Cloudy, 4, { 2.673828, 1, 1.229492, 0 } }, + { "Canon", "EOS Kiss Digital X", Cloudy, 5, { 2.723633, 1, 1.205078, 0 } }, + { "Canon", "EOS Kiss Digital X", Cloudy, 6, { 2.752930, 1, 1.185547, 0 } }, + { "Canon", "EOS Kiss Digital X", Cloudy, 7, { 2.790039, 1, 1.165039, 0 } }, + { "Canon", "EOS Kiss Digital X", Cloudy, 8, { 2.836914, 1, 1.142578, 0 } }, + { "Canon", "EOS Kiss Digital X", Cloudy, 9, { 2.884766, 1, 1.120117, 0 } }, + { "Canon", "EOS Kiss Digital X", Tungsten, -9, { 1.320106, 1, 2.752205, 0 } }, + { "Canon", "EOS Kiss Digital X", Tungsten, -8, { 1.340708, 1, 2.703540, 0 } }, + { "Canon", "EOS Kiss Digital X", Tungsten, -7, { 1.359680, 1, 2.655417, 0 } }, + { "Canon", "EOS Kiss Digital X", Tungsten, -6, { 1.381802, 1, 2.606601, 0 } }, + { "Canon", "EOS Kiss Digital X", Tungsten, -5, { 1.406446, 1, 2.555953, 0 } }, + { "Canon", "EOS Kiss Digital X", Tungsten, -4, { 1.428957, 1, 2.504496, 0 } }, + { "Canon", "EOS Kiss Digital X", Tungsten, -3, { 1.452575, 1, 2.459801, 0 } }, + { "Canon", "EOS Kiss Digital X", Tungsten, -2, { 1.475931, 1, 2.419619, 0 } }, + { "Canon", "EOS Kiss Digital X", Tungsten, -1, { 1.501825, 1, 2.377737, 0 } }, + { "Canon", "EOS Kiss Digital X", Tungsten, 0, { 1.526123, 1, 2.330889, 0 } }, + { "Canon", "EOS Kiss Digital X", Tungsten, 1, { 1.548893, 1, 2.286900, 0 } }, + { "Canon", "EOS Kiss Digital X", Tungsten, 2, { 1.572753, 1, 2.238184, 0 } }, + { "Canon", "EOS Kiss Digital X", Tungsten, 3, { 1.599254, 1, 2.198509, 0 } }, + { "Canon", "EOS Kiss Digital X", Tungsten, 4, { 1.624765, 1, 2.149156, 0 } }, + { "Canon", "EOS Kiss Digital X", Tungsten, 5, { 1.653774, 1, 2.102830, 0 } }, + { "Canon", "EOS Kiss Digital X", Tungsten, 6, { 1.681861, 1, 2.064577, 0 } }, + { "Canon", "EOS Kiss Digital X", Tungsten, 7, { 1.709369, 1, 2.022945, 0 } }, + { "Canon", "EOS Kiss Digital X", Tungsten, 8, { 1.737247, 1, 1.982676, 0 } }, + { "Canon", "EOS Kiss Digital X", Tungsten, 9, { 1.770349, 1, 1.946705, 0 } }, + { "Canon", "EOS Kiss Digital X", WhiteFluorescent, -9, { 1.638122, 1, 2.485267, 0 } }, + { "Canon", "EOS Kiss Digital X", WhiteFluorescent, -8, { 1.667900, 1, 2.445883, 0 } }, + { "Canon", "EOS Kiss Digital X", WhiteFluorescent, -7, { 1.695814, 1, 2.404651, 0 } }, + { "Canon", "EOS Kiss Digital X", WhiteFluorescent, -6, { 1.723364, 1, 2.361682, 0 } }, + { "Canon", "EOS Kiss Digital X", WhiteFluorescent, -5, { 1.752820, 1, 2.317669, 0 } }, + { "Canon", "EOS Kiss Digital X", WhiteFluorescent, -4, { 1.788079, 1, 2.263009, 0 } }, + { "Canon", "EOS Kiss Digital X", WhiteFluorescent, -3, { 1.815414, 1, 2.221694, 0 } }, + { "Canon", "EOS Kiss Digital X", WhiteFluorescent, -2, { 1.844828, 1, 2.175287, 0 } }, + { "Canon", "EOS Kiss Digital X", WhiteFluorescent, -1, { 1.880309, 1, 2.127413, 0 } }, + { "Canon", "EOS Kiss Digital X", WhiteFluorescent, 0, { 1.910506, 1, 2.080739, 0 } }, + { "Canon", "EOS Kiss Digital X", WhiteFluorescent, 1, { 1.950195, 1, 2.043945, 0 } }, + { "Canon", "EOS Kiss Digital X", WhiteFluorescent, 2, { 1.984375, 1, 2.007813, 0 } }, + { "Canon", "EOS Kiss Digital X", WhiteFluorescent, 3, { 2.015625, 1, 1.968750, 0 } }, + { "Canon", "EOS Kiss Digital X", WhiteFluorescent, 4, { 2.047852, 1, 1.928711, 0 } }, + { "Canon", "EOS Kiss Digital X", WhiteFluorescent, 5, { 2.085938, 1, 1.892578, 0 } }, + { "Canon", "EOS Kiss Digital X", WhiteFluorescent, 6, { 2.124023, 1, 1.858398, 0 } }, + { "Canon", "EOS Kiss Digital X", WhiteFluorescent, 7, { 2.165039, 1, 1.825195, 0 } }, + { "Canon", "EOS Kiss Digital X", WhiteFluorescent, 8, { 2.197266, 1, 1.790039, 0 } }, + { "Canon", "EOS Kiss Digital X", WhiteFluorescent, 9, { 2.235352, 1, 1.756836, 0 } }, + { "Canon", "EOS Kiss Digital X", Flash, -9, { 2.398438, 1, 1.432617, 0 } }, + { "Canon", "EOS Kiss Digital X", Flash, -8, { 2.438477, 1, 1.402344, 0 } }, + { "Canon", "EOS Kiss Digital X", Flash, -7, { 2.485352, 1, 1.375977, 0 } }, + { "Canon", "EOS Kiss Digital X", Flash, -6, { 2.528320, 1, 1.349609, 0 } }, + { "Canon", "EOS Kiss Digital X", Flash, -5, { 2.566406, 1, 1.323242, 0 } }, + { "Canon", "EOS Kiss Digital X", Flash, -4, { 2.605469, 1, 1.299805, 0 } }, + { "Canon", "EOS Kiss Digital X", Flash, -3, { 2.645508, 1, 1.276367, 0 } }, + { "Canon", "EOS Kiss Digital X", Flash, -2, { 2.694336, 1, 1.251953, 0 } }, + { "Canon", "EOS Kiss Digital X", Flash, -1, { 2.738281, 1, 1.227539, 0 } }, + { "Canon", "EOS Kiss Digital X", Flash, 0, { 2.767578, 1, 1.203125, 0 } }, + { "Canon", "EOS Kiss Digital X", Flash, 1, { 2.813477, 1, 1.183594, 0 } }, + { "Canon", "EOS Kiss Digital X", Flash, 2, { 2.860352, 1, 1.164063, 0 } }, + { "Canon", "EOS Kiss Digital X", Flash, 3, { 2.900391, 1, 1.141602, 0 } }, + { "Canon", "EOS Kiss Digital X", Flash, 4, { 2.942383, 1, 1.118164, 0 } }, + { "Canon", "EOS Kiss Digital X", Flash, 5, { 2.976563, 1, 1.101563, 0 } }, + { "Canon", "EOS Kiss Digital X", Flash, 6, { 3.020508, 1, 1.082031, 0 } }, + { "Canon", "EOS Kiss Digital X", Flash, 7, { 3.065430, 1, 1.063477, 0 } }, + { "Canon", "EOS Kiss Digital X", Flash, 8, { 3.122070, 1, 1.041992, 0 } }, + { "Canon", "EOS Kiss Digital X", Flash, 9, { 3.169922, 1, 1.024414, 0 } }, + + { "Canon", "EOS 450D", Daylight, 0, { 2.216797, 1, 1.471680, 0 } }, + { "Canon", "EOS 450D", Shade, 0, { 2.566406, 1, 1.241211, 0 } }, + { "Canon", "EOS 450D", Cloudy, 0, { 2.386719, 1, 1.345703, 0 } }, + { "Canon", "EOS 450D", Tungsten, 0, { 1.559034, 1, 2.170841, 0 } }, + { "Canon", "EOS 450D", WhiteFluorescent, 0, { 1.922857, 1, 1.996190, 0 } }, + { "Canon", "EOS 450D", Flash, 0, { 2.456055, 1, 1.318359, 0 } }, + + { "Canon", "EOS DIGITAL REBEL XSi", Daylight, 0, { 2.216797, 1, 1.471680, 0 } }, + { "Canon", "EOS DIGITAL REBEL XSi", Shade, 0, { 2.566406, 1, 1.241211, 0 } }, + { "Canon", "EOS DIGITAL REBEL XSi", Cloudy, 0, { 2.386719, 1, 1.345703, 0 } }, + { "Canon", "EOS DIGITAL REBEL XSi", Tungsten, 0, { 1.559034, 1, 2.170841, 0 } }, + { "Canon", "EOS DIGITAL REBEL XSi", WhiteFluorescent, 0, { 1.922857, 1, 1.996190, 0 } }, + { "Canon", "EOS DIGITAL REBEL XSi", Flash, 0, { 2.456055, 1, 1.318359, 0 } }, + + { "Canon", "EOS Kiss X2", Daylight, 0, { 2.216797, 1, 1.471680, 0 } }, + { "Canon", "EOS Kiss X2", Shade, 0, { 2.566406, 1, 1.241211, 0 } }, + { "Canon", "EOS Kiss X2", Cloudy, 0, { 2.386719, 1, 1.345703, 0 } }, + { "Canon", "EOS Kiss X2", Tungsten, 0, { 1.559034, 1, 2.170841, 0 } }, + { "Canon", "EOS Kiss X2", WhiteFluorescent, 0, { 1.922857, 1, 1.996190, 0 } }, + { "Canon", "EOS Kiss X2", Flash, 0, { 2.456055, 1, 1.318359, 0 } }, + + { "Canon", "EOS 500D", Daylight, 0, { 2.023438, 1, 1.417969, 0 } }, + { "Canon", "EOS 500D", Shade, 0, { 2.291016, 1, 1.217773, 0 } }, + { "Canon", "EOS 500D", Cloudy, 0, { 2.156250, 1, 1.304687, 0 } }, + { "Canon", "EOS 500D", Tungsten, 0, { 1.481347, 1, 1.976342, 0 } }, + { "Canon", "EOS 500D", WhiteFluorescent, 0, { 1.799224, 1, 1.824442, 0 } }, + { "Canon", "EOS 500D", Flash, 0, { 2.207031, 1, 1.295898, 0 } }, + + { "Canon", "EOS REBEL T1i", Daylight, 0, { 2.023438, 1, 1.417969, 0 } }, + { "Canon", "EOS REBEL T1i", Shade, 0, { 2.291016, 1, 1.217773, 0 } }, + { "Canon", "EOS REBEL T1i", Cloudy, 0, { 2.156250, 1, 1.304687, 0 } }, + { "Canon", "EOS REBEL T1i", Tungsten, 0, { 1.481347, 1, 1.976342, 0 } }, + { "Canon", "EOS REBEL T1i", WhiteFluorescent, 0, { 1.799224, 1, 1.824442, 0 } }, + { "Canon", "EOS REBEL T1i", Flash, 0, { 2.207031, 1, 1.295898, 0 } }, + + { "Canon", "EOS Kiss X3", Daylight, 0, { 2.023438, 1, 1.417969, 0 } }, + { "Canon", "EOS Kiss X3", Shade, 0, { 2.291016, 1, 1.217773, 0 } }, + { "Canon", "EOS Kiss X3", Cloudy, 0, { 2.156250, 1, 1.304687, 0 } }, + { "Canon", "EOS Kiss X3", Tungsten, 0, { 1.481347, 1, 1.976342, 0 } }, + { "Canon", "EOS Kiss X3", WhiteFluorescent, 0, { 1.799224, 1, 1.824442, 0 } }, + { "Canon", "EOS Kiss X3", Flash, 0, { 2.207031, 1, 1.295898, 0 } }, + + /* Canon EOS 550D Firmware Version 1.0.9 */ + /* Fine-tuning is the camera's Amber-Blue bracketing. */ + { "Canon", "EOS 550D", Daylight, -9, { 1.903320, 1, 1.784180, 0 } }, + { "Canon", "EOS 550D", Daylight, -8, { 1.924805, 1, 1.756836, 0 } }, + { "Canon", "EOS 550D", Daylight, -7, { 1.950195, 1, 1.729492, 0 } }, + { "Canon", "EOS 550D", Daylight, -6, { 1.980469, 1, 1.701172, 0 } }, + { "Canon", "EOS 550D", Daylight, -5, { 2.007813, 1, 1.672852, 0 } }, + { "Canon", "EOS 550D", Daylight, -4, { 2.040039, 1, 1.646484, 0 } }, + { "Canon", "EOS 550D", Daylight, -3, { 2.064453, 1, 1.615234, 0 } }, + { "Canon", "EOS 550D", Daylight, -2, { 2.089844, 1, 1.587891, 0 } }, + { "Canon", "EOS 550D", Daylight, -1, { 2.120117, 1, 1.556641, 0 } }, + { "Canon", "EOS 550D", Daylight, 0, { 2.146484, 1, 1.526367, 0 } }, + { "Canon", "EOS 550D", Daylight, 1, { 2.178711, 1, 1.503906, 0 } }, + { "Canon", "EOS 550D", Daylight, 2, { 2.211914, 1, 1.481445, 0 } }, + { "Canon", "EOS 550D", Daylight, 3, { 2.246094, 1, 1.458984, 0 } }, + { "Canon", "EOS 550D", Daylight, 4, { 2.280273, 1, 1.436523, 0 } }, + { "Canon", "EOS 550D", Daylight, 5, { 2.316406, 1, 1.412109, 0 } }, + { "Canon", "EOS 550D", Daylight, 6, { 2.342773, 1, 1.391602, 0 } }, + { "Canon", "EOS 550D", Daylight, 7, { 2.375977, 1, 1.373047, 0 } }, + { "Canon", "EOS 550D", Daylight, 8, { 2.409180, 1, 1.350586, 0 } }, + { "Canon", "EOS 550D", Daylight, 9, { 2.444336, 1, 1.328125, 0 } }, + { "Canon", "EOS 550D", Shade, -9, { 2.173828, 1, 1.507813, 0 } }, + { "Canon", "EOS 550D", Shade, -8, { 2.207031, 1, 1.484375, 0 } }, + { "Canon", "EOS 550D", Shade, -7, { 2.240234, 1, 1.460938, 0 } }, + { "Canon", "EOS 550D", Shade, -6, { 2.275391, 1, 1.438477, 0 } }, + { "Canon", "EOS 550D", Shade, -5, { 2.311523, 1, 1.414063, 0 } }, + { "Canon", "EOS 550D", Shade, -4, { 2.342773, 1, 1.395508, 0 } }, + { "Canon", "EOS 550D", Shade, -3, { 2.370117, 1, 1.374023, 0 } }, + { "Canon", "EOS 550D", Shade, -2, { 2.403320, 1, 1.352539, 0 } }, + { "Canon", "EOS 550D", Shade, -1, { 2.444336, 1, 1.332031, 0 } }, + { "Canon", "EOS 550D", Shade, 0, { 2.479492, 1, 1.307617, 0 } }, + { "Canon", "EOS 550D", Shade, 1, { 2.509766, 1, 1.292969, 0 } }, + { "Canon", "EOS 550D", Shade, 2, { 2.541016, 1, 1.276367, 0 } }, + { "Canon", "EOS 550D", Shade, 3, { 2.573242, 1, 1.259766, 0 } }, + { "Canon", "EOS 550D", Shade, 4, { 2.612305, 1, 1.241211, 0 } }, + { "Canon", "EOS 550D", Shade, 5, { 2.645508, 1, 1.223633, 0 } }, + { "Canon", "EOS 550D", Shade, 6, { 2.673828, 1, 1.206055, 0 } }, + { "Canon", "EOS 550D", Shade, 7, { 2.702148, 1, 1.187500, 0 } }, + { "Canon", "EOS 550D", Shade, 8, { 2.738281, 1, 1.168945, 0 } }, + { "Canon", "EOS 550D", Shade, 9, { 2.782227, 1, 1.148438, 0 } }, + { "Canon", "EOS 550D", Cloudy, -9, { 2.043945, 1, 1.640625, 0 } }, + { "Canon", "EOS 550D", Cloudy, -8, { 2.068359, 1, 1.612305, 0 } }, + { "Canon", "EOS 550D", Cloudy, -7, { 2.093750, 1, 1.583008, 0 } }, + { "Canon", "EOS 550D", Cloudy, -6, { 2.120117, 1, 1.553711, 0 } }, + { "Canon", "EOS 550D", Cloudy, -5, { 2.151367, 1, 1.523438, 0 } }, + { "Canon", "EOS 550D", Cloudy, -4, { 2.183594, 1, 1.501953, 0 } }, + { "Canon", "EOS 550D", Cloudy, -3, { 2.216797, 1, 1.477539, 0 } }, + { "Canon", "EOS 550D", Cloudy, -2, { 2.250977, 1, 1.454102, 0 } }, + { "Canon", "EOS 550D", Cloudy, -1, { 2.280273, 1, 1.432617, 0 } }, + { "Canon", "EOS 550D", Cloudy, 0, { 2.316406, 1, 1.408203, 0 } }, + { "Canon", "EOS 550D", Cloudy, 1, { 2.348633, 1, 1.389648, 0 } }, + { "Canon", "EOS 550D", Cloudy, 2, { 2.381836, 1, 1.369141, 0 } }, + { "Canon", "EOS 550D", Cloudy, 3, { 2.415039, 1, 1.347656, 0 } }, + { "Canon", "EOS 550D", Cloudy, 4, { 2.450195, 1, 1.326172, 0 } }, + { "Canon", "EOS 550D", Cloudy, 5, { 2.491211, 1, 1.304688, 0 } }, + { "Canon", "EOS 550D", Cloudy, 6, { 2.515625, 1, 1.290039, 0 } }, + { "Canon", "EOS 550D", Cloudy, 7, { 2.546875, 1, 1.272461, 0 } }, + { "Canon", "EOS 550D", Cloudy, 8, { 2.579102, 1, 1.254883, 0 } }, + { "Canon", "EOS 550D", Cloudy, 9, { 2.619141, 1, 1.236328, 0 } }, + { "Canon", "EOS 550D", Tungsten, -9, { 1.345703, 1, 2.605469, 0 } }, + { "Canon", "EOS 550D", Tungsten, -8, { 1.361328, 1, 2.579102, 0 } }, + { "Canon", "EOS 550D", Tungsten, -7, { 1.379883, 1, 2.546875, 0 } }, + { "Canon", "EOS 550D", Tungsten, -6, { 1.398438, 1, 2.515625, 0 } }, + { "Canon", "EOS 550D", Tungsten, -5, { 1.417969, 1, 2.491211, 0 } }, + { "Canon", "EOS 550D", Tungsten, -4, { 1.440430, 1, 2.456055, 0 } }, + { "Canon", "EOS 550D", Tungsten, -3, { 1.460938, 1, 2.409180, 0 } }, + { "Canon", "EOS 550D", Tungsten, -2, { 1.479492, 1, 2.365234, 0 } }, + { "Canon", "EOS 550D", Tungsten, -1, { 1.503906, 1, 2.322266, 0 } }, + { "Canon", "EOS 550D", Tungsten, 0, { 1.526367, 1, 2.275391, 0 } }, + { "Canon", "EOS 550D", Tungsten, 1, { 1.546875, 1, 2.240234, 0 } }, + { "Canon", "EOS 550D", Tungsten, 2, { 1.568359, 1, 2.207031, 0 } }, + { "Canon", "EOS 550D", Tungsten, 3, { 1.589844, 1, 2.169922, 0 } }, + { "Canon", "EOS 550D", Tungsten, 4, { 1.612305, 1, 2.137695, 0 } }, + { "Canon", "EOS 550D", Tungsten, 5, { 1.638672, 1, 2.102539, 0 } }, + { "Canon", "EOS 550D", Tungsten, 6, { 1.662109, 1, 2.068359, 0 } }, + { "Canon", "EOS 550D", Tungsten, 7, { 1.684570, 1, 2.032227, 0 } }, + { "Canon", "EOS 550D", Tungsten, 8, { 1.707031, 1, 2.000000, 0 } }, + { "Canon", "EOS 550D", Tungsten, 9, { 1.732422, 1, 1.965820, 0 } }, + { "Canon", "EOS 550D", WhiteFluorescent, -9, { 1.662109, 1, 2.473633, 0 } }, + { "Canon", "EOS 550D", WhiteFluorescent, -8, { 1.684570, 1, 2.432617, 0 } }, + { "Canon", "EOS 550D", WhiteFluorescent, -7, { 1.709961, 1, 2.392578, 0 } }, + { "Canon", "EOS 550D", WhiteFluorescent, -6, { 1.735352, 1, 2.342773, 0 } }, + { "Canon", "EOS 550D", WhiteFluorescent, -5, { 1.762695, 1, 2.300781, 0 } }, + { "Canon", "EOS 550D", WhiteFluorescent, -4, { 1.787109, 1, 2.260742, 0 } }, + { "Canon", "EOS 550D", WhiteFluorescent, -3, { 1.812500, 1, 2.226563, 0 } }, + { "Canon", "EOS 550D", WhiteFluorescent, -2, { 1.841797, 1, 2.188477, 0 } }, + { "Canon", "EOS 550D", WhiteFluorescent, -1, { 1.872070, 1, 2.156250, 0 } }, + { "Canon", "EOS 550D", WhiteFluorescent, 0, { 1.899414, 1, 2.115234, 0 } }, + { "Canon", "EOS 550D", WhiteFluorescent, 1, { 1.924805, 1, 2.081055, 0 } }, + { "Canon", "EOS 550D", WhiteFluorescent, 2, { 1.950195, 1, 2.051758, 0 } }, + { "Canon", "EOS 550D", WhiteFluorescent, 3, { 1.976563, 1, 2.015625, 0 } }, + { "Canon", "EOS 550D", WhiteFluorescent, 4, { 2.007813, 1, 1.984375, 0 } }, + { "Canon", "EOS 550D", WhiteFluorescent, 5, { 2.040039, 1, 1.950195, 0 } }, + { "Canon", "EOS 550D", WhiteFluorescent, 6, { 2.064453, 1, 1.920898, 0 } }, + { "Canon", "EOS 550D", WhiteFluorescent, 7, { 2.089844, 1, 1.889648, 0 } }, + { "Canon", "EOS 550D", WhiteFluorescent, 8, { 2.120117, 1, 1.862305, 0 } }, + { "Canon", "EOS 550D", WhiteFluorescent, 9, { 2.146484, 1, 1.832031, 0 } }, + { "Canon", "EOS 550D", Flash, -9, { 2.098633, 1, 1.625000, 0 } }, + { "Canon", "EOS 550D", Flash, -8, { 2.124023, 1, 1.594727, 0 } }, + { "Canon", "EOS 550D", Flash, -7, { 2.156250, 1, 1.565430, 0 } }, + { "Canon", "EOS 550D", Flash, -6, { 2.188477, 1, 1.535156, 0 } }, + { "Canon", "EOS 550D", Flash, -5, { 2.221680, 1, 1.510742, 0 } }, + { "Canon", "EOS 550D", Flash, -4, { 2.255859, 1, 1.488281, 0 } }, + { "Canon", "EOS 550D", Flash, -3, { 2.286133, 1, 1.464844, 0 } }, + { "Canon", "EOS 550D", Flash, -2, { 2.322266, 1, 1.442383, 0 } }, + { "Canon", "EOS 550D", Flash, -1, { 2.354492, 1, 1.419922, 0 } }, + { "Canon", "EOS 550D", Flash, 0, { 2.381836, 1, 1.397461, 0 } }, + { "Canon", "EOS 550D", Flash, 1, { 2.420898, 1, 1.377930, 0 } }, + { "Canon", "EOS 550D", Flash, 2, { 2.456055, 1, 1.356445, 0 } }, + { "Canon", "EOS 550D", Flash, 3, { 2.491211, 1, 1.334961, 0 } }, + { "Canon", "EOS 550D", Flash, 4, { 2.522461, 1, 1.312500, 0 } }, + { "Canon", "EOS 550D", Flash, 5, { 2.553711, 1, 1.295898, 0 } }, + { "Canon", "EOS 550D", Flash, 6, { 2.585938, 1, 1.280273, 0 } }, + { "Canon", "EOS 550D", Flash, 7, { 2.625977, 1, 1.262695, 0 } }, + { "Canon", "EOS 550D", Flash, 8, { 2.653320, 1, 1.244141, 0 } }, + { "Canon", "EOS 550D", Flash, 9, { 2.680664, 1, 1.226563, 0 } }, + + { "Canon", "EOS REBEL T2i", Daylight, -9, { 1.903320, 1, 1.784180, 0 } }, + { "Canon", "EOS REBEL T2i", Daylight, -8, { 1.924805, 1, 1.756836, 0 } }, + { "Canon", "EOS REBEL T2i", Daylight, -7, { 1.950195, 1, 1.729492, 0 } }, + { "Canon", "EOS REBEL T2i", Daylight, -6, { 1.980469, 1, 1.701172, 0 } }, + { "Canon", "EOS REBEL T2i", Daylight, -5, { 2.007813, 1, 1.672852, 0 } }, + { "Canon", "EOS REBEL T2i", Daylight, -4, { 2.040039, 1, 1.646484, 0 } }, + { "Canon", "EOS REBEL T2i", Daylight, -3, { 2.064453, 1, 1.615234, 0 } }, + { "Canon", "EOS REBEL T2i", Daylight, -2, { 2.089844, 1, 1.587891, 0 } }, + { "Canon", "EOS REBEL T2i", Daylight, -1, { 2.120117, 1, 1.556641, 0 } }, + { "Canon", "EOS REBEL T2i", Daylight, 0, { 2.146484, 1, 1.526367, 0 } }, + { "Canon", "EOS REBEL T2i", Daylight, 1, { 2.178711, 1, 1.503906, 0 } }, + { "Canon", "EOS REBEL T2i", Daylight, 2, { 2.211914, 1, 1.481445, 0 } }, + { "Canon", "EOS REBEL T2i", Daylight, 3, { 2.246094, 1, 1.458984, 0 } }, + { "Canon", "EOS REBEL T2i", Daylight, 4, { 2.280273, 1, 1.436523, 0 } }, + { "Canon", "EOS REBEL T2i", Daylight, 5, { 2.316406, 1, 1.412109, 0 } }, + { "Canon", "EOS REBEL T2i", Daylight, 6, { 2.342773, 1, 1.391602, 0 } }, + { "Canon", "EOS REBEL T2i", Daylight, 7, { 2.375977, 1, 1.373047, 0 } }, + { "Canon", "EOS REBEL T2i", Daylight, 8, { 2.409180, 1, 1.350586, 0 } }, + { "Canon", "EOS REBEL T2i", Daylight, 9, { 2.444336, 1, 1.328125, 0 } }, + { "Canon", "EOS REBEL T2i", Shade, -9, { 2.173828, 1, 1.507813, 0 } }, + { "Canon", "EOS REBEL T2i", Shade, -8, { 2.207031, 1, 1.484375, 0 } }, + { "Canon", "EOS REBEL T2i", Shade, -7, { 2.240234, 1, 1.460938, 0 } }, + { "Canon", "EOS REBEL T2i", Shade, -6, { 2.275391, 1, 1.438477, 0 } }, + { "Canon", "EOS REBEL T2i", Shade, -5, { 2.311523, 1, 1.414063, 0 } }, + { "Canon", "EOS REBEL T2i", Shade, -4, { 2.342773, 1, 1.395508, 0 } }, + { "Canon", "EOS REBEL T2i", Shade, -3, { 2.370117, 1, 1.374023, 0 } }, + { "Canon", "EOS REBEL T2i", Shade, -2, { 2.403320, 1, 1.352539, 0 } }, + { "Canon", "EOS REBEL T2i", Shade, -1, { 2.444336, 1, 1.332031, 0 } }, + { "Canon", "EOS REBEL T2i", Shade, 0, { 2.479492, 1, 1.307617, 0 } }, + { "Canon", "EOS REBEL T2i", Shade, 1, { 2.509766, 1, 1.292969, 0 } }, + { "Canon", "EOS REBEL T2i", Shade, 2, { 2.541016, 1, 1.276367, 0 } }, + { "Canon", "EOS REBEL T2i", Shade, 3, { 2.573242, 1, 1.259766, 0 } }, + { "Canon", "EOS REBEL T2i", Shade, 4, { 2.612305, 1, 1.241211, 0 } }, + { "Canon", "EOS REBEL T2i", Shade, 5, { 2.645508, 1, 1.223633, 0 } }, + { "Canon", "EOS REBEL T2i", Shade, 6, { 2.673828, 1, 1.206055, 0 } }, + { "Canon", "EOS REBEL T2i", Shade, 7, { 2.702148, 1, 1.187500, 0 } }, + { "Canon", "EOS REBEL T2i", Shade, 8, { 2.738281, 1, 1.168945, 0 } }, + { "Canon", "EOS REBEL T2i", Shade, 9, { 2.782227, 1, 1.148438, 0 } }, + { "Canon", "EOS REBEL T2i", Cloudy, -9, { 2.043945, 1, 1.640625, 0 } }, + { "Canon", "EOS REBEL T2i", Cloudy, -8, { 2.068359, 1, 1.612305, 0 } }, + { "Canon", "EOS REBEL T2i", Cloudy, -7, { 2.093750, 1, 1.583008, 0 } }, + { "Canon", "EOS REBEL T2i", Cloudy, -6, { 2.120117, 1, 1.553711, 0 } }, + { "Canon", "EOS REBEL T2i", Cloudy, -5, { 2.151367, 1, 1.523438, 0 } }, + { "Canon", "EOS REBEL T2i", Cloudy, -4, { 2.183594, 1, 1.501953, 0 } }, + { "Canon", "EOS REBEL T2i", Cloudy, -3, { 2.216797, 1, 1.477539, 0 } }, + { "Canon", "EOS REBEL T2i", Cloudy, -2, { 2.250977, 1, 1.454102, 0 } }, + { "Canon", "EOS REBEL T2i", Cloudy, -1, { 2.280273, 1, 1.432617, 0 } }, + { "Canon", "EOS REBEL T2i", Cloudy, 0, { 2.316406, 1, 1.408203, 0 } }, + { "Canon", "EOS REBEL T2i", Cloudy, 1, { 2.348633, 1, 1.389648, 0 } }, + { "Canon", "EOS REBEL T2i", Cloudy, 2, { 2.381836, 1, 1.369141, 0 } }, + { "Canon", "EOS REBEL T2i", Cloudy, 3, { 2.415039, 1, 1.347656, 0 } }, + { "Canon", "EOS REBEL T2i", Cloudy, 4, { 2.450195, 1, 1.326172, 0 } }, + { "Canon", "EOS REBEL T2i", Cloudy, 5, { 2.491211, 1, 1.304688, 0 } }, + { "Canon", "EOS REBEL T2i", Cloudy, 6, { 2.515625, 1, 1.290039, 0 } }, + { "Canon", "EOS REBEL T2i", Cloudy, 7, { 2.546875, 1, 1.272461, 0 } }, + { "Canon", "EOS REBEL T2i", Cloudy, 8, { 2.579102, 1, 1.254883, 0 } }, + { "Canon", "EOS REBEL T2i", Cloudy, 9, { 2.619141, 1, 1.236328, 0 } }, + { "Canon", "EOS REBEL T2i", Tungsten, -9, { 1.345703, 1, 2.605469, 0 } }, + { "Canon", "EOS REBEL T2i", Tungsten, -8, { 1.361328, 1, 2.579102, 0 } }, + { "Canon", "EOS REBEL T2i", Tungsten, -7, { 1.379883, 1, 2.546875, 0 } }, + { "Canon", "EOS REBEL T2i", Tungsten, -6, { 1.398438, 1, 2.515625, 0 } }, + { "Canon", "EOS REBEL T2i", Tungsten, -5, { 1.417969, 1, 2.491211, 0 } }, + { "Canon", "EOS REBEL T2i", Tungsten, -4, { 1.440430, 1, 2.456055, 0 } }, + { "Canon", "EOS REBEL T2i", Tungsten, -3, { 1.460938, 1, 2.409180, 0 } }, + { "Canon", "EOS REBEL T2i", Tungsten, -2, { 1.479492, 1, 2.365234, 0 } }, + { "Canon", "EOS REBEL T2i", Tungsten, -1, { 1.503906, 1, 2.322266, 0 } }, + { "Canon", "EOS REBEL T2i", Tungsten, 0, { 1.526367, 1, 2.275391, 0 } }, + { "Canon", "EOS REBEL T2i", Tungsten, 1, { 1.546875, 1, 2.240234, 0 } }, + { "Canon", "EOS REBEL T2i", Tungsten, 2, { 1.568359, 1, 2.207031, 0 } }, + { "Canon", "EOS REBEL T2i", Tungsten, 3, { 1.589844, 1, 2.169922, 0 } }, + { "Canon", "EOS REBEL T2i", Tungsten, 4, { 1.612305, 1, 2.137695, 0 } }, + { "Canon", "EOS REBEL T2i", Tungsten, 5, { 1.638672, 1, 2.102539, 0 } }, + { "Canon", "EOS REBEL T2i", Tungsten, 6, { 1.662109, 1, 2.068359, 0 } }, + { "Canon", "EOS REBEL T2i", Tungsten, 7, { 1.684570, 1, 2.032227, 0 } }, + { "Canon", "EOS REBEL T2i", Tungsten, 8, { 1.707031, 1, 2.000000, 0 } }, + { "Canon", "EOS REBEL T2i", Tungsten, 9, { 1.732422, 1, 1.965820, 0 } }, + { "Canon", "EOS REBEL T2i", WhiteFluorescent, -9, { 1.662109, 1, 2.473633, 0 } }, + { "Canon", "EOS REBEL T2i", WhiteFluorescent, -8, { 1.684570, 1, 2.432617, 0 } }, + { "Canon", "EOS REBEL T2i", WhiteFluorescent, -7, { 1.709961, 1, 2.392578, 0 } }, + { "Canon", "EOS REBEL T2i", WhiteFluorescent, -6, { 1.735352, 1, 2.342773, 0 } }, + { "Canon", "EOS REBEL T2i", WhiteFluorescent, -5, { 1.762695, 1, 2.300781, 0 } }, + { "Canon", "EOS REBEL T2i", WhiteFluorescent, -4, { 1.787109, 1, 2.260742, 0 } }, + { "Canon", "EOS REBEL T2i", WhiteFluorescent, -3, { 1.812500, 1, 2.226563, 0 } }, + { "Canon", "EOS REBEL T2i", WhiteFluorescent, -2, { 1.841797, 1, 2.188477, 0 } }, + { "Canon", "EOS REBEL T2i", WhiteFluorescent, -1, { 1.872070, 1, 2.156250, 0 } }, + { "Canon", "EOS REBEL T2i", WhiteFluorescent, 0, { 1.899414, 1, 2.115234, 0 } }, + { "Canon", "EOS REBEL T2i", WhiteFluorescent, 1, { 1.924805, 1, 2.081055, 0 } }, + { "Canon", "EOS REBEL T2i", WhiteFluorescent, 2, { 1.950195, 1, 2.051758, 0 } }, + { "Canon", "EOS REBEL T2i", WhiteFluorescent, 3, { 1.976563, 1, 2.015625, 0 } }, + { "Canon", "EOS REBEL T2i", WhiteFluorescent, 4, { 2.007813, 1, 1.984375, 0 } }, + { "Canon", "EOS REBEL T2i", WhiteFluorescent, 5, { 2.040039, 1, 1.950195, 0 } }, + { "Canon", "EOS REBEL T2i", WhiteFluorescent, 6, { 2.064453, 1, 1.920898, 0 } }, + { "Canon", "EOS REBEL T2i", WhiteFluorescent, 7, { 2.089844, 1, 1.889648, 0 } }, + { "Canon", "EOS REBEL T2i", WhiteFluorescent, 8, { 2.120117, 1, 1.862305, 0 } }, + { "Canon", "EOS REBEL T2i", WhiteFluorescent, 9, { 2.146484, 1, 1.832031, 0 } }, + { "Canon", "EOS REBEL T2i", Flash, -9, { 2.098633, 1, 1.625000, 0 } }, + { "Canon", "EOS REBEL T2i", Flash, -8, { 2.124023, 1, 1.594727, 0 } }, + { "Canon", "EOS REBEL T2i", Flash, -7, { 2.156250, 1, 1.565430, 0 } }, + { "Canon", "EOS REBEL T2i", Flash, -6, { 2.188477, 1, 1.535156, 0 } }, + { "Canon", "EOS REBEL T2i", Flash, -5, { 2.221680, 1, 1.510742, 0 } }, + { "Canon", "EOS REBEL T2i", Flash, -4, { 2.255859, 1, 1.488281, 0 } }, + { "Canon", "EOS REBEL T2i", Flash, -3, { 2.286133, 1, 1.464844, 0 } }, + { "Canon", "EOS REBEL T2i", Flash, -2, { 2.322266, 1, 1.442383, 0 } }, + { "Canon", "EOS REBEL T2i", Flash, -1, { 2.354492, 1, 1.419922, 0 } }, + { "Canon", "EOS REBEL T2i", Flash, 0, { 2.381836, 1, 1.397461, 0 } }, + { "Canon", "EOS REBEL T2i", Flash, 1, { 2.420898, 1, 1.377930, 0 } }, + { "Canon", "EOS REBEL T2i", Flash, 2, { 2.456055, 1, 1.356445, 0 } }, + { "Canon", "EOS REBEL T2i", Flash, 3, { 2.491211, 1, 1.334961, 0 } }, + { "Canon", "EOS REBEL T2i", Flash, 4, { 2.522461, 1, 1.312500, 0 } }, + { "Canon", "EOS REBEL T2i", Flash, 5, { 2.553711, 1, 1.295898, 0 } }, + { "Canon", "EOS REBEL T2i", Flash, 6, { 2.585938, 1, 1.280273, 0 } }, + { "Canon", "EOS REBEL T2i", Flash, 7, { 2.625977, 1, 1.262695, 0 } }, + { "Canon", "EOS REBEL T2i", Flash, 8, { 2.653320, 1, 1.244141, 0 } }, + { "Canon", "EOS REBEL T2i", Flash, 9, { 2.680664, 1, 1.226563, 0 } }, + + { "Canon", "EOS Kiss X4", Daylight, -9, { 1.903320, 1, 1.784180, 0 } }, + { "Canon", "EOS Kiss X4", Daylight, -8, { 1.924805, 1, 1.756836, 0 } }, + { "Canon", "EOS Kiss X4", Daylight, -7, { 1.950195, 1, 1.729492, 0 } }, + { "Canon", "EOS Kiss X4", Daylight, -6, { 1.980469, 1, 1.701172, 0 } }, + { "Canon", "EOS Kiss X4", Daylight, -5, { 2.007813, 1, 1.672852, 0 } }, + { "Canon", "EOS Kiss X4", Daylight, -4, { 2.040039, 1, 1.646484, 0 } }, + { "Canon", "EOS Kiss X4", Daylight, -3, { 2.064453, 1, 1.615234, 0 } }, + { "Canon", "EOS Kiss X4", Daylight, -2, { 2.089844, 1, 1.587891, 0 } }, + { "Canon", "EOS Kiss X4", Daylight, -1, { 2.120117, 1, 1.556641, 0 } }, + { "Canon", "EOS Kiss X4", Daylight, 0, { 2.146484, 1, 1.526367, 0 } }, + { "Canon", "EOS Kiss X4", Daylight, 1, { 2.178711, 1, 1.503906, 0 } }, + { "Canon", "EOS Kiss X4", Daylight, 2, { 2.211914, 1, 1.481445, 0 } }, + { "Canon", "EOS Kiss X4", Daylight, 3, { 2.246094, 1, 1.458984, 0 } }, + { "Canon", "EOS Kiss X4", Daylight, 4, { 2.280273, 1, 1.436523, 0 } }, + { "Canon", "EOS Kiss X4", Daylight, 5, { 2.316406, 1, 1.412109, 0 } }, + { "Canon", "EOS Kiss X4", Daylight, 6, { 2.342773, 1, 1.391602, 0 } }, + { "Canon", "EOS Kiss X4", Daylight, 7, { 2.375977, 1, 1.373047, 0 } }, + { "Canon", "EOS Kiss X4", Daylight, 8, { 2.409180, 1, 1.350586, 0 } }, + { "Canon", "EOS Kiss X4", Daylight, 9, { 2.444336, 1, 1.328125, 0 } }, + { "Canon", "EOS Kiss X4", Shade, -9, { 2.173828, 1, 1.507813, 0 } }, + { "Canon", "EOS Kiss X4", Shade, -8, { 2.207031, 1, 1.484375, 0 } }, + { "Canon", "EOS Kiss X4", Shade, -7, { 2.240234, 1, 1.460938, 0 } }, + { "Canon", "EOS Kiss X4", Shade, -6, { 2.275391, 1, 1.438477, 0 } }, + { "Canon", "EOS Kiss X4", Shade, -5, { 2.311523, 1, 1.414063, 0 } }, + { "Canon", "EOS Kiss X4", Shade, -4, { 2.342773, 1, 1.395508, 0 } }, + { "Canon", "EOS Kiss X4", Shade, -3, { 2.370117, 1, 1.374023, 0 } }, + { "Canon", "EOS Kiss X4", Shade, -2, { 2.403320, 1, 1.352539, 0 } }, + { "Canon", "EOS Kiss X4", Shade, -1, { 2.444336, 1, 1.332031, 0 } }, + { "Canon", "EOS Kiss X4", Shade, 0, { 2.479492, 1, 1.307617, 0 } }, + { "Canon", "EOS Kiss X4", Shade, 1, { 2.509766, 1, 1.292969, 0 } }, + { "Canon", "EOS Kiss X4", Shade, 2, { 2.541016, 1, 1.276367, 0 } }, + { "Canon", "EOS Kiss X4", Shade, 3, { 2.573242, 1, 1.259766, 0 } }, + { "Canon", "EOS Kiss X4", Shade, 4, { 2.612305, 1, 1.241211, 0 } }, + { "Canon", "EOS Kiss X4", Shade, 5, { 2.645508, 1, 1.223633, 0 } }, + { "Canon", "EOS Kiss X4", Shade, 6, { 2.673828, 1, 1.206055, 0 } }, + { "Canon", "EOS Kiss X4", Shade, 7, { 2.702148, 1, 1.187500, 0 } }, + { "Canon", "EOS Kiss X4", Shade, 8, { 2.738281, 1, 1.168945, 0 } }, + { "Canon", "EOS Kiss X4", Shade, 9, { 2.782227, 1, 1.148438, 0 } }, + { "Canon", "EOS Kiss X4", Cloudy, -9, { 2.043945, 1, 1.640625, 0 } }, + { "Canon", "EOS Kiss X4", Cloudy, -8, { 2.068359, 1, 1.612305, 0 } }, + { "Canon", "EOS Kiss X4", Cloudy, -7, { 2.093750, 1, 1.583008, 0 } }, + { "Canon", "EOS Kiss X4", Cloudy, -6, { 2.120117, 1, 1.553711, 0 } }, + { "Canon", "EOS Kiss X4", Cloudy, -5, { 2.151367, 1, 1.523438, 0 } }, + { "Canon", "EOS Kiss X4", Cloudy, -4, { 2.183594, 1, 1.501953, 0 } }, + { "Canon", "EOS Kiss X4", Cloudy, -3, { 2.216797, 1, 1.477539, 0 } }, + { "Canon", "EOS Kiss X4", Cloudy, -2, { 2.250977, 1, 1.454102, 0 } }, + { "Canon", "EOS Kiss X4", Cloudy, -1, { 2.280273, 1, 1.432617, 0 } }, + { "Canon", "EOS Kiss X4", Cloudy, 0, { 2.316406, 1, 1.408203, 0 } }, + { "Canon", "EOS Kiss X4", Cloudy, 1, { 2.348633, 1, 1.389648, 0 } }, + { "Canon", "EOS Kiss X4", Cloudy, 2, { 2.381836, 1, 1.369141, 0 } }, + { "Canon", "EOS Kiss X4", Cloudy, 3, { 2.415039, 1, 1.347656, 0 } }, + { "Canon", "EOS Kiss X4", Cloudy, 4, { 2.450195, 1, 1.326172, 0 } }, + { "Canon", "EOS Kiss X4", Cloudy, 5, { 2.491211, 1, 1.304688, 0 } }, + { "Canon", "EOS Kiss X4", Cloudy, 6, { 2.515625, 1, 1.290039, 0 } }, + { "Canon", "EOS Kiss X4", Cloudy, 7, { 2.546875, 1, 1.272461, 0 } }, + { "Canon", "EOS Kiss X4", Cloudy, 8, { 2.579102, 1, 1.254883, 0 } }, + { "Canon", "EOS Kiss X4", Cloudy, 9, { 2.619141, 1, 1.236328, 0 } }, + { "Canon", "EOS Kiss X4", Tungsten, -9, { 1.345703, 1, 2.605469, 0 } }, + { "Canon", "EOS Kiss X4", Tungsten, -8, { 1.361328, 1, 2.579102, 0 } }, + { "Canon", "EOS Kiss X4", Tungsten, -7, { 1.379883, 1, 2.546875, 0 } }, + { "Canon", "EOS Kiss X4", Tungsten, -6, { 1.398438, 1, 2.515625, 0 } }, + { "Canon", "EOS Kiss X4", Tungsten, -5, { 1.417969, 1, 2.491211, 0 } }, + { "Canon", "EOS Kiss X4", Tungsten, -4, { 1.440430, 1, 2.456055, 0 } }, + { "Canon", "EOS Kiss X4", Tungsten, -3, { 1.460938, 1, 2.409180, 0 } }, + { "Canon", "EOS Kiss X4", Tungsten, -2, { 1.479492, 1, 2.365234, 0 } }, + { "Canon", "EOS Kiss X4", Tungsten, -1, { 1.503906, 1, 2.322266, 0 } }, + { "Canon", "EOS Kiss X4", Tungsten, 0, { 1.526367, 1, 2.275391, 0 } }, + { "Canon", "EOS Kiss X4", Tungsten, 1, { 1.546875, 1, 2.240234, 0 } }, + { "Canon", "EOS Kiss X4", Tungsten, 2, { 1.568359, 1, 2.207031, 0 } }, + { "Canon", "EOS Kiss X4", Tungsten, 3, { 1.589844, 1, 2.169922, 0 } }, + { "Canon", "EOS Kiss X4", Tungsten, 4, { 1.612305, 1, 2.137695, 0 } }, + { "Canon", "EOS Kiss X4", Tungsten, 5, { 1.638672, 1, 2.102539, 0 } }, + { "Canon", "EOS Kiss X4", Tungsten, 6, { 1.662109, 1, 2.068359, 0 } }, + { "Canon", "EOS Kiss X4", Tungsten, 7, { 1.684570, 1, 2.032227, 0 } }, + { "Canon", "EOS Kiss X4", Tungsten, 8, { 1.707031, 1, 2.000000, 0 } }, + { "Canon", "EOS Kiss X4", Tungsten, 9, { 1.732422, 1, 1.965820, 0 } }, + { "Canon", "EOS Kiss X4", WhiteFluorescent, -9, { 1.662109, 1, 2.473633, 0 } }, + { "Canon", "EOS Kiss X4", WhiteFluorescent, -8, { 1.684570, 1, 2.432617, 0 } }, + { "Canon", "EOS Kiss X4", WhiteFluorescent, -7, { 1.709961, 1, 2.392578, 0 } }, + { "Canon", "EOS Kiss X4", WhiteFluorescent, -6, { 1.735352, 1, 2.342773, 0 } }, + { "Canon", "EOS Kiss X4", WhiteFluorescent, -5, { 1.762695, 1, 2.300781, 0 } }, + { "Canon", "EOS Kiss X4", WhiteFluorescent, -4, { 1.787109, 1, 2.260742, 0 } }, + { "Canon", "EOS Kiss X4", WhiteFluorescent, -3, { 1.812500, 1, 2.226563, 0 } }, + { "Canon", "EOS Kiss X4", WhiteFluorescent, -2, { 1.841797, 1, 2.188477, 0 } }, + { "Canon", "EOS Kiss X4", WhiteFluorescent, -1, { 1.872070, 1, 2.156250, 0 } }, + { "Canon", "EOS Kiss X4", WhiteFluorescent, 0, { 1.899414, 1, 2.115234, 0 } }, + { "Canon", "EOS Kiss X4", WhiteFluorescent, 1, { 1.924805, 1, 2.081055, 0 } }, + { "Canon", "EOS Kiss X4", WhiteFluorescent, 2, { 1.950195, 1, 2.051758, 0 } }, + { "Canon", "EOS Kiss X4", WhiteFluorescent, 3, { 1.976563, 1, 2.015625, 0 } }, + { "Canon", "EOS Kiss X4", WhiteFluorescent, 4, { 2.007813, 1, 1.984375, 0 } }, + { "Canon", "EOS Kiss X4", WhiteFluorescent, 5, { 2.040039, 1, 1.950195, 0 } }, + { "Canon", "EOS Kiss X4", WhiteFluorescent, 6, { 2.064453, 1, 1.920898, 0 } }, + { "Canon", "EOS Kiss X4", WhiteFluorescent, 7, { 2.089844, 1, 1.889648, 0 } }, + { "Canon", "EOS Kiss X4", WhiteFluorescent, 8, { 2.120117, 1, 1.862305, 0 } }, + { "Canon", "EOS Kiss X4", WhiteFluorescent, 9, { 2.146484, 1, 1.832031, 0 } }, + { "Canon", "EOS Kiss X4", Flash, -9, { 2.098633, 1, 1.625000, 0 } }, + { "Canon", "EOS Kiss X4", Flash, -8, { 2.124023, 1, 1.594727, 0 } }, + { "Canon", "EOS Kiss X4", Flash, -7, { 2.156250, 1, 1.565430, 0 } }, + { "Canon", "EOS Kiss X4", Flash, -6, { 2.188477, 1, 1.535156, 0 } }, + { "Canon", "EOS Kiss X4", Flash, -5, { 2.221680, 1, 1.510742, 0 } }, + { "Canon", "EOS Kiss X4", Flash, -4, { 2.255859, 1, 1.488281, 0 } }, + { "Canon", "EOS Kiss X4", Flash, -3, { 2.286133, 1, 1.464844, 0 } }, + { "Canon", "EOS Kiss X4", Flash, -2, { 2.322266, 1, 1.442383, 0 } }, + { "Canon", "EOS Kiss X4", Flash, -1, { 2.354492, 1, 1.419922, 0 } }, + { "Canon", "EOS Kiss X4", Flash, 0, { 2.381836, 1, 1.397461, 0 } }, + { "Canon", "EOS Kiss X4", Flash, 1, { 2.420898, 1, 1.377930, 0 } }, + { "Canon", "EOS Kiss X4", Flash, 2, { 2.456055, 1, 1.356445, 0 } }, + { "Canon", "EOS Kiss X4", Flash, 3, { 2.491211, 1, 1.334961, 0 } }, + { "Canon", "EOS Kiss X4", Flash, 4, { 2.522461, 1, 1.312500, 0 } }, + { "Canon", "EOS Kiss X4", Flash, 5, { 2.553711, 1, 1.295898, 0 } }, + { "Canon", "EOS Kiss X4", Flash, 6, { 2.585938, 1, 1.280273, 0 } }, + { "Canon", "EOS Kiss X4", Flash, 7, { 2.625977, 1, 1.262695, 0 } }, + { "Canon", "EOS Kiss X4", Flash, 8, { 2.653320, 1, 1.244141, 0 } }, + { "Canon", "EOS Kiss X4", Flash, 9, { 2.680664, 1, 1.226563, 0 } }, + + // Canon EOS 600D firmware version 1.0.2 + { "Canon", "EOS 600D", Daylight, 0, { 2.235352, 1, 1.612305, 0 } }, + { "Canon", "EOS 600D", Shade, 0, { 2.592773, 1, 1.377930, 0 } }, + { "Canon", "EOS 600D", Cloudy, 0, { 2.409180, 1, 1.486328, 0 } }, + { "Canon", "EOS 600D", Tungsten, 0, { 1.597656, 1, 2.409180, 0 } }, + { "Canon", "EOS 600D", WhiteFluorescent, 0, { 1.958008, 1, 2.260742, 0 } }, + { "Canon", "EOS 600D", Flash, 0, { 2.509766, 1, 1.464844, 0 } }, + + { "Canon", "EOS REBEL T3i", Daylight, 0, { 2.235352, 1, 1.612305, 0 } }, + { "Canon", "EOS REBEL T3i", Shade, 0, { 2.592773, 1, 1.377930, 0 } }, + { "Canon", "EOS REBEL T3i", Cloudy, 0, { 2.409180, 1, 1.486328, 0 } }, + { "Canon", "EOS REBEL T3i", Tungsten, 0, { 1.597656, 1, 2.409180, 0 } }, + { "Canon", "EOS REBEL T3i", WhiteFluorescent, 0, { 1.958008, 1, 2.260742, 0 } }, + { "Canon", "EOS REBEL T3i", Flash, 0, { 2.509766, 1, 1.464844, 0 } }, + + { "Canon", "EOS Kiss X5", Daylight, 0, { 2.235352, 1, 1.612305, 0 } }, + { "Canon", "EOS Kiss X5", Shade, 0, { 2.592773, 1, 1.377930, 0 } }, + { "Canon", "EOS Kiss X5", Cloudy, 0, { 2.409180, 1, 1.486328, 0 } }, + { "Canon", "EOS Kiss X5", Tungsten, 0, { 1.597656, 1, 2.409180, 0 } }, + { "Canon", "EOS Kiss X5", WhiteFluorescent, 0, { 1.958008, 1, 2.260742, 0 } }, + { "Canon", "EOS Kiss X5", Flash, 0, { 2.509766, 1, 1.464844, 0 } }, + + /* Fine-tuning is the camera's Amber-Blue bracketing. */ + { "Canon", "EOS 650D", Daylight, -3, { 1.9502, 1, 1.7539, 0 } }, + { "Canon", "EOS 650D", Daylight, 0, { 2.0322, 1, 1.6572, 0 } }, + { "Canon", "EOS 650D", Daylight, 3, { 2.1152, 1, 1.5850, 0 } }, + { "Canon", "EOS 650D", Shade, -3, { 2.2305, 1, 1.4951, 0 } }, + { "Canon", "EOS 650D", Shade, 0, { 2.3379, 1, 1.4238, 0 } }, + { "Canon", "EOS 650D", Shade, 3, { 2.4443, 1, 1.3604, 0 } }, + { "Canon", "EOS 650D", Cloudy, -3, { 2.0898, 1, 1.6074, 0 } }, + { "Canon", "EOS 650D", Cloudy, 0, { 2.1787, 1, 1.5332, 0 } }, + { "Canon", "EOS 650D", Cloudy, 3, { 2.2705, 1, 1.4668, 0 } }, + { "Canon", "EOS 650D", Tungsten, -3, { 1.3975, 1, 2.5928, 0 } }, + { "Canon", "EOS 650D", Tungsten, 0, { 1.4541, 1, 2.4561, 0 } }, + { "Canon", "EOS 650D", Tungsten, 3, { 1.5127, 1, 2.3428, 0 } }, + { "Canon", "EOS 650D", WhiteFluorescent, -3, { 1.6982, 1, 2.4268, 0 } }, + { "Canon", "EOS 650D", WhiteFluorescent, 0, { 1.7715, 1, 2.3066, 0 } }, + { "Canon", "EOS 650D", WhiteFluorescent, 3, { 1.8486, 1, 2.1973, 0 } }, + { "Canon", "EOS 650D", Flash, -3, { 2.1699, 1, 1.5879, 0 } }, + { "Canon", "EOS 650D", Flash, 0, { 2.2607, 1, 1.5166, 0 } }, + { "Canon", "EOS 650D", Flash, 3, { 2.3701, 1, 1.4502, 0 } }, + + { "Canon", "EOS REBEL T4i", Daylight, -3, { 1.9502, 1, 1.7539, 0 } }, + { "Canon", "EOS REBEL T4i", Daylight, 0, { 2.0322, 1, 1.6572, 0 } }, + { "Canon", "EOS REBEL T4i", Daylight, 3, { 2.1152, 1, 1.5850, 0 } }, + { "Canon", "EOS REBEL T4i", Shade, -3, { 2.2305, 1, 1.4951, 0 } }, + { "Canon", "EOS REBEL T4i", Shade, 0, { 2.3379, 1, 1.4238, 0 } }, + { "Canon", "EOS REBEL T4i", Shade, 3, { 2.4443, 1, 1.3604, 0 } }, + { "Canon", "EOS REBEL T4i", Cloudy, -3, { 2.0898, 1, 1.6074, 0 } }, + { "Canon", "EOS REBEL T4i", Cloudy, 0, { 2.1787, 1, 1.5332, 0 } }, + { "Canon", "EOS REBEL T4i", Cloudy, 3, { 2.2705, 1, 1.4668, 0 } }, + { "Canon", "EOS REBEL T4i", Tungsten, -3, { 1.3975, 1, 2.5928, 0 } }, + { "Canon", "EOS REBEL T4i", Tungsten, 0, { 1.4541, 1, 2.4561, 0 } }, + { "Canon", "EOS REBEL T4i", Tungsten, 3, { 1.5127, 1, 2.3428, 0 } }, + { "Canon", "EOS REBEL T4i", WhiteFluorescent, -3, { 1.6982, 1, 2.4268, 0 } }, + { "Canon", "EOS REBEL T4i", WhiteFluorescent, 0, { 1.7715, 1, 2.3066, 0 } }, + { "Canon", "EOS REBEL T4i", WhiteFluorescent, 3, { 1.8486, 1, 2.1973, 0 } }, + { "Canon", "EOS REBEL T4i", Flash, -3, { 2.1699, 1, 1.5879, 0 } }, + { "Canon", "EOS REBEL T4i", Flash, 0, { 2.2607, 1, 1.5166, 0 } }, + { "Canon", "EOS REBEL T4i", Flash, 3, { 2.3701, 1, 1.4502, 0 } }, + + { "Canon", "EOS Kiss X6i", Daylight, -3, { 1.9502, 1, 1.7539, 0 } }, + { "Canon", "EOS Kiss X6i", Daylight, 0, { 2.0322, 1, 1.6572, 0 } }, + { "Canon", "EOS Kiss X6i", Daylight, 3, { 2.1152, 1, 1.5850, 0 } }, + { "Canon", "EOS Kiss X6i", Shade, -3, { 2.2305, 1, 1.4951, 0 } }, + { "Canon", "EOS Kiss X6i", Shade, 0, { 2.3379, 1, 1.4238, 0 } }, + { "Canon", "EOS Kiss X6i", Shade, 3, { 2.4443, 1, 1.3604, 0 } }, + { "Canon", "EOS Kiss X6i", Cloudy, -3, { 2.0898, 1, 1.6074, 0 } }, + { "Canon", "EOS Kiss X6i", Cloudy, 0, { 2.1787, 1, 1.5332, 0 } }, + { "Canon", "EOS Kiss X6i", Cloudy, 3, { 2.2705, 1, 1.4668, 0 } }, + { "Canon", "EOS Kiss X6i", Tungsten, -3, { 1.3975, 1, 2.5928, 0 } }, + { "Canon", "EOS Kiss X6i", Tungsten, 0, { 1.4541, 1, 2.4561, 0 } }, + { "Canon", "EOS Kiss X6i", Tungsten, 3, { 1.5127, 1, 2.3428, 0 } }, + { "Canon", "EOS Kiss X6i", WhiteFluorescent, -3, { 1.6982, 1, 2.4268, 0 } }, + { "Canon", "EOS Kiss X6i", WhiteFluorescent, 0, { 1.7715, 1, 2.3066, 0 } }, + { "Canon", "EOS Kiss X6i", WhiteFluorescent, 3, { 1.8486, 1, 2.1973, 0 } }, + { "Canon", "EOS Kiss X6i", Flash, -3, { 2.1699, 1, 1.5879, 0 } }, + { "Canon", "EOS Kiss X6i", Flash, 0, { 2.2607, 1, 1.5166, 0 } }, + { "Canon", "EOS Kiss X6i", Flash, 3, { 2.3701, 1, 1.4502, 0 } }, + + // Canon EOS 700D firmware Version 1.1.4 + { "Canon", "EOS 700D", Daylight, 0, { 2.089844, 1, 1.540039, 0 } }, + { "Canon", "EOS 700D", Shade, 0, { 2.403320, 1, 1.302734, 0 } }, + { "Canon", "EOS 700D", Cloudy, 0, { 2.240234, 1, 1.412109, 0 } }, + { "Canon", "EOS 700D", Tungsten, 0, { 1.501953, 1, 2.365234, 0 } }, + { "Canon", "EOS 700D", WhiteFluorescent, 0, { 1.832031, 1, 2.250977, 0 } }, + { "Canon", "EOS 700D", Flash, 0, { 2.327148, 1, 1.398438, 0 } }, + + { "Canon", "EOS REBEL T5i", Daylight, 0, { 2.089844, 1, 1.540039, 0 } }, + { "Canon", "EOS REBEL T5i", Shade, 0, { 2.403320, 1, 1.302734, 0 } }, + { "Canon", "EOS REBEL T5i", Cloudy, 0, { 2.240234, 1, 1.412109, 0 } }, + { "Canon", "EOS REBEL T5i", Tungsten, 0, { 1.501953, 1, 2.365234, 0 } }, + { "Canon", "EOS REBEL T5i", WhiteFluorescent, 0, { 1.832031, 1, 2.250977, 0 } }, + { "Canon", "EOS REBEL T5i", Flash, 0, { 2.327148, 1, 1.398438, 0 } }, + + { "Canon", "EOS Kiss X7i", Daylight, 0, { 2.089844, 1, 1.540039, 0 } }, + { "Canon", "EOS Kiss X7i", Shade, 0, { 2.403320, 1, 1.302734, 0 } }, + { "Canon", "EOS Kiss X7i", Cloudy, 0, { 2.240234, 1, 1.412109, 0 } }, + { "Canon", "EOS Kiss X7i", Tungsten, 0, { 1.501953, 1, 2.365234, 0 } }, + { "Canon", "EOS Kiss X7i", WhiteFluorescent, 0, { 1.832031, 1, 2.250977, 0 } }, + { "Canon", "EOS Kiss X7i", Flash, 0, { 2.327148, 1, 1.398438, 0 } }, + + { "Canon", "EOS 750D", Daylight, 0, { 2.115234, 1, 1.701172, 0 } }, + { "Canon", "EOS 750D", Shade, 0, { 2.461914, 1, 1.458984, 0 } }, + { "Canon", "EOS 750D", Cloudy, 0, { 2.286133, 1, 1.570312, 0 } }, + { "Canon", "EOS 750D", Tungsten, 0, { 1.473633, 1, 2.467773, 0 } }, + { "Canon", "EOS 750D", WhiteFluorescent, 0, { 1.784180, 1, 2.300781, 0 } }, + { "Canon", "EOS 750D", Flash, 0, { 2.359375, 1, 1.548828, 0 } }, + + { "Canon", "EOS REBEL T6i", Daylight, 0, { 2.115234, 1, 1.701172, 0 } }, + { "Canon", "EOS REBEL T6i", Shade, 0, { 2.461914, 1, 1.458984, 0 } }, + { "Canon", "EOS REBEL T6i", Cloudy, 0, { 2.286133, 1, 1.570312, 0 } }, + { "Canon", "EOS REBEL T6i", Tungsten, 0, { 1.473633, 1, 2.467773, 0 } }, + { "Canon", "EOS REBEL T6i", WhiteFluorescent, 0, { 1.784180, 1, 2.300781, 0 } }, + { "Canon", "EOS REBEL T6i", Flash, 0, { 2.359375, 1, 1.548828, 0 } }, + + { "Canon", "EOS Kiss X8i", Daylight, 0, { 2.115234, 1, 1.701172, 0 } }, + { "Canon", "EOS Kiss X8i", Shade, 0, { 2.461914, 1, 1.458984, 0 } }, + { "Canon", "EOS Kiss X8i", Cloudy, 0, { 2.286133, 1, 1.570312, 0 } }, + { "Canon", "EOS Kiss X8i", Tungsten, 0, { 1.473633, 1, 2.467773, 0 } }, + { "Canon", "EOS Kiss X8i", WhiteFluorescent, 0, { 1.784180, 1, 2.300781, 0 } }, + { "Canon", "EOS Kiss X8i", Flash, 0, { 2.359375, 1, 1.548828, 0 } }, + + // Firmware version 1.0.0 + { "Canon", "EOS 760D", Daylight, 0, { 2.169922, 1, 1.709961, 0 } }, + { "Canon", "EOS 760D", Shade, 0, { 2.528320, 1, 1.466797, 0 } }, + { "Canon", "EOS 760D", Cloudy, 0, { 2.342773, 1, 1.578125, 0 } }, + { "Canon", "EOS 760D", Tungsten, 0, { 1.510742, 1, 2.479492, 0 } }, + { "Canon", "EOS 760D", WhiteFluorescent, 0, { 1.825195, 1, 2.311523, 0 } }, + { "Canon", "EOS 760D", Flash, 0, { 2.420898, 1, 1.556641, 0 } }, + + // Firmware version 1.0.0 + { "Canon", "EOS REBEL T6s", Daylight, 0, { 2.169922, 1, 1.709961, 0 } }, + { "Canon", "EOS REBEL T6s", Shade, 0, { 2.528320, 1, 1.466797, 0 } }, + { "Canon", "EOS REBEL T6s", Cloudy, 0, { 2.342773, 1, 1.578125, 0 } }, + { "Canon", "EOS REBEL T6s", Tungsten, 0, { 1.510742, 1, 2.479492, 0 } }, + { "Canon", "EOS REBEL T6s", WhiteFluorescent, 0, { 1.825195, 1, 2.311523, 0 } }, + { "Canon", "EOS REBEL T6s", Flash, 0, { 2.420898, 1, 1.556641, 0 } }, + + // Firmware version 1.0.0 + { "Canon", "EOS 8000D", Daylight, 0, { 2.169922, 1, 1.709961, 0 } }, + { "Canon", "EOS 8000D", Shade, 0, { 2.528320, 1, 1.466797, 0 } }, + { "Canon", "EOS 8000D", Cloudy, 0, { 2.342773, 1, 1.578125, 0 } }, + { "Canon", "EOS 8000D", Tungsten, 0, { 1.510742, 1, 2.479492, 0 } }, + { "Canon", "EOS 8000D", WhiteFluorescent, 0, { 1.825195, 1, 2.311523, 0 } }, + { "Canon", "EOS 8000D", Flash, 0, { 2.420898, 1, 1.556641, 0 } }, + + { "Canon", "EOS 1000D", Daylight, 0, { 2.183594, 1, 1.526367, 0 } }, + { "Canon", "EOS 1000D", Shade, 0, { 2.553711, 1, 1.262695, 0 } }, + { "Canon", "EOS 1000D", Cloudy, 0, { 2.365234, 1, 1.375977, 0 } }, + { "Canon", "EOS 1000D", Tungsten, 0, { 1.470328, 1, 2.402126, 0 } }, + { "Canon", "EOS 1000D", WhiteFluorescent, 0, { 1.889648, 1, 2.133789, 0 } }, + { "Canon", "EOS 1000D", Flash, 0, { 2.541830, 1, 1.769099, 0 } }, + + { "Canon", "EOS DIGITAL REBEL XS", Daylight, 0, { 2.183594, 1, 1.526367, 0 } }, + { "Canon", "EOS DIGITAL REBEL XS", Shade, 0, { 2.553711, 1, 1.262695, 0 } }, + { "Canon", "EOS DIGITAL REBEL XS", Cloudy, 0, { 2.365234, 1, 1.375977, 0 } }, + { "Canon", "EOS DIGITAL REBEL XS", Tungsten, 0, { 1.470328, 1, 2.402126, 0 } }, + { "Canon", "EOS DIGITAL REBEL XS", WhiteFluorescent, 0, { 1.889648, 1, 2.133789, 0 } }, + { "Canon", "EOS DIGITAL REBEL XS", Flash, 0, { 2.541830, 1, 1.769099, 0 } }, + + { "Canon", "EOS Kiss Digital F", Daylight, 0, { 2.183594, 1, 1.526367, 0 } }, + { "Canon", "EOS Kiss Digital F", Shade, 0, { 2.553711, 1, 1.262695, 0 } }, + { "Canon", "EOS Kiss Digital F", Cloudy, 0, { 2.365234, 1, 1.375977, 0 } }, + { "Canon", "EOS Kiss Digital F", Tungsten, 0, { 1.470328, 1, 2.402126, 0 } }, + { "Canon", "EOS Kiss Digital F", WhiteFluorescent, 0, { 1.889648, 1, 2.133789, 0 } }, + { "Canon", "EOS Kiss Digital F", Flash, 0, { 2.541830, 1, 1.769099, 0 } }, + + { "Canon", "EOS 1100D", Daylight, 0, { 2.2559, 1, 1.4844, 0 } }, + { "Canon", "EOS 1100D", Shade, 0, { 2.6455, 1, 1.2725, 0 } }, + { "Canon", "EOS 1100D", Cloudy, 0, { 2.4443, 1, 1.3652, 0 } }, + { "Canon", "EOS 1100D", Tungsten, 0, { 1.5654, 1, 2.2402, 0 } }, + { "Canon", "EOS 1100D", WhiteFluorescent, 0, { 1.9541, 1, 2.0732, 0 } }, + { "Canon", "EOS 1100D", Flash, 0, { 2.5283, 1, 1.3584, 0 } }, + + { "Canon", "EOS REBEL T3", Daylight, 0, { 2.2559, 1, 1.4844, 0 } }, + { "Canon", "EOS REBEL T3", Shade, 0, { 2.6455, 1, 1.2725, 0 } }, + { "Canon", "EOS REBEL T3", Cloudy, 0, { 2.4443, 1, 1.3652, 0 } }, + { "Canon", "EOS REBEL T3", Tungsten, 0, { 1.5654, 1, 2.2402, 0 } }, + { "Canon", "EOS REBEL T3", WhiteFluorescent, 0, { 1.9541, 1, 2.0732, 0 } }, + { "Canon", "EOS REBEL T3", Flash, 0, { 2.5283, 1, 1.3584, 0 } }, + + { "Canon", "EOS Kiss Digital X50", Daylight, 0, { 2.2559, 1, 1.4844, 0 } }, + { "Canon", "EOS Kiss Digital X50", Shade, 0, { 2.6455, 1, 1.2725, 0 } }, + { "Canon", "EOS Kiss Digital X50", Cloudy, 0, { 2.4443, 1, 1.3652, 0 } }, + { "Canon", "EOS Kiss Digital X50", Tungsten, 0, { 1.5654, 1, 2.2402, 0 } }, + { "Canon", "EOS Kiss Digital X50", WhiteFluorescent, 0, { 1.9541, 1, 2.0732, 0 } }, + { "Canon", "EOS Kiss Digital X50", Flash, 0, { 2.5283, 1, 1.3584, 0 } }, + + { "Canon", "EOS 1200D", Daylight, 0, { 2.007812, 1, 1.599609, 0 } }, + { "Canon", "EOS 1200D", Shade, 0, { 2.322266, 1, 1.361328, 0 } }, + { "Canon", "EOS 1200D", Cloudy, 0, { 2.160156, 1, 1.471680, 0 } }, + { "Canon", "EOS 1200D", Tungsten, 0, { 1.444336, 1, 2.392578, 0 } }, + { "Canon", "EOS 1200D", WhiteFluorescent, 0, { 1.759766, 1, 2.275391, 0 } }, + { "Canon", "EOS 1200D", Flash, 0, { 2.246094, 1, 1.452148, 0 } }, + + { "Canon", "EOS REBEL T5", Daylight, 0, { 2.007812, 1, 1.599609, 0 } }, + { "Canon", "EOS REBEL T5", Shade, 0, { 2.322266, 1, 1.361328, 0 } }, + { "Canon", "EOS REBEL T5", Cloudy, 0, { 2.160156, 1, 1.471680, 0 } }, + { "Canon", "EOS REBEL T5", Tungsten, 0, { 1.444336, 1, 2.392578, 0 } }, + { "Canon", "EOS REBEL T5", WhiteFluorescent, 0, { 1.759766, 1, 2.275391, 0 } }, + { "Canon", "EOS REBEL T5", Flash, 0, { 2.246094, 1, 1.452148, 0 } }, + + { "Canon", "EOS Kiss Digital X70", Daylight, 0, { 2.007812, 1, 1.599609, 0 } }, + { "Canon", "EOS Kiss Digital X70", Shade, 0, { 2.322266, 1, 1.361328, 0 } }, + { "Canon", "EOS Kiss Digital X70", Cloudy, 0, { 2.160156, 1, 1.471680, 0 } }, + { "Canon", "EOS Kiss Digital X70", Tungsten, 0, { 1.444336, 1, 2.392578, 0 } }, + { "Canon", "EOS Kiss Digital X70", WhiteFluorescent, 0, { 1.759766, 1, 2.275391, 0 } }, + { "Canon", "EOS Kiss Digital X70", Flash, 0, { 2.246094, 1, 1.452148, 0 } }, + + { "Canon", "EOS 1300D", Daylight, 0, { 1.988281, 1, 1.530273, 0 } }, + { "Canon", "EOS 1300D", Shade, 0, { 2.295898, 1, 1.300781, 0 } }, + { "Canon", "EOS 1300D", Cloudy, 0, { 2.137695, 1, 1.406250, 0 } }, + { "Canon", "EOS 1300D", Tungsten, 0, { 1.432617, 1, 2.300781, 0 } }, + { "Canon", "EOS 1300D", WhiteFluorescent, 0, { 1.747070, 1, 2.188477, 0 } }, + { "Canon", "EOS 1300D", Flash, 0, { 2.221680, 1, 1.387695, 0 } }, + + { "Canon", "EOS REBEL T6", Daylight, 0, { 1.988281, 1, 1.530273, 0 } }, + { "Canon", "EOS REBEL T6", Shade, 0, { 2.295898, 1, 1.300781, 0 } }, + { "Canon", "EOS REBEL T6", Cloudy, 0, { 2.137695, 1, 1.406250, 0 } }, + { "Canon", "EOS REBEL T6", Tungsten, 0, { 1.432617, 1, 2.300781, 0 } }, + { "Canon", "EOS REBEL T6", WhiteFluorescent, 0, { 1.747070, 1, 2.188477, 0 } }, + { "Canon", "EOS REBEL T6", Flash, 0, { 2.221680, 1, 1.387695, 0 } }, + + { "Canon", "EOS Kiss Digital X80", Daylight, 0, { 1.988281, 1, 1.530273, 0 } }, + { "Canon", "EOS Kiss Digital X80", Shade, 0, { 2.295898, 1, 1.300781, 0 } }, + { "Canon", "EOS Kiss Digital X80", Cloudy, 0, { 2.137695, 1, 1.406250, 0 } }, + { "Canon", "EOS Kiss Digital X80", Tungsten, 0, { 1.432617, 1, 2.300781, 0 } }, + { "Canon", "EOS Kiss Digital X80", WhiteFluorescent, 0, { 1.747070, 1, 2.188477, 0 } }, + { "Canon", "EOS Kiss Digital X80", Flash, 0, { 2.221680, 1, 1.387695, 0 } }, + + { "Canon", "EOS-1DS", Daylight, 0, { 1.6133, 1, 1.2500, 0 } }, /* 5302K */ + { "Canon", "EOS-1DS", Shade, 0, { 1.8477, 1, 1.0684, 0 } }, /* 6685K */ + { "Canon", "EOS-1DS", Cloudy, 0, { 1.7285, 1, 1.1504, 0 } }, /* 5940K */ + { "Canon", "EOS-1DS", Tungsten, 0, { 1.1270, 1, 1.9199, 0 } }, /* 3334K */ + { "Canon", "EOS-1DS", WhiteFluorescent, 0, { 1.2012, 1, 1.7168, 0 } }, /* 3643K */ + { "Canon", "EOS-1DS", Flash, 0, { 1.7793, 1, 1.1445, 0 } }, /* 6184K */ + + // Firmware Version 1.1.6 + { "Canon", "EOS-1Ds Mark II", Daylight, 0, { 1.992188, 1, 1.503906, 0 } }, + { "Canon", "EOS-1Ds Mark II", Shade, 0, { 2.300781, 1, 1.243164, 0 } }, + { "Canon", "EOS-1Ds Mark II", Cloudy, 0, { 2.146484, 1, 1.363281, 0 } }, + { "Canon", "EOS-1Ds Mark II", Tungsten, 0, { 1.395018, 1, 2.370107, 0 } }, + { "Canon", "EOS-1Ds Mark II", WhiteFluorescent, 0, { 1.854792, 1, 2.067764, 0 } }, + { "Canon", "EOS-1Ds Mark II", Flash, 0, { 2.235352, 1, 1.297852, 0 } }, + + { "Canon", "EOS-1D Mark II", Cloudy, 0, { 2.093750, 1, 1.166016, 0 } }, + { "Canon", "EOS-1D Mark II", Daylight, 0, { 1.957031, 1, 1.295898, 0 } }, + { "Canon", "EOS-1D Mark II", Flash, 0, { 2.225586, 1, 1.172852, 0 } }, + { "Canon", "EOS-1D Mark II", WhiteFluorescent, 0, { 1.785853, 1, 1.785853, 0 } }, + { "Canon", "EOS-1D Mark II", Shade, 0, { 2.220703, 1, 1.069336, 0 } }, + { "Canon", "EOS-1D Mark II", Tungsten, 0, { 1.415480, 1, 2.160142, 0 } }, + + { "Canon", "EOS-1D Mark II N", Cloudy, 0, { 2.183594, 1, 1.220703, 0 } }, + { "Canon", "EOS-1D Mark II N", Daylight, 0, { 2.019531, 1, 1.349609, 0 } }, + { "Canon", "EOS-1D Mark II N", Flash, 0, { 2.291016, 1, 1.149414, 0 } }, + { "Canon", "EOS-1D Mark II N", WhiteFluorescent, 0, { 1.802899, 1, 1.990338, 0 } }, + { "Canon", "EOS-1D Mark II N", Shade, 0, { 2.337891, 1, 1.112305, 0 } }, + { "Canon", "EOS-1D Mark II N", Tungsten, 0, { 1.408514, 1, 2.147645, 0 } }, + + { "Canon", "EOS-1D Mark III", Daylight, 0, { 1.980469, 1, 1.471680, 0 } }, + { "Canon", "EOS-1D Mark III", Shade, 0, { 2.291016, 1, 1.205078, 0 } }, + { "Canon", "EOS-1D Mark III", Cloudy, 0, { 2.142578, 1, 1.325195, 0 } }, + { "Canon", "EOS-1D Mark III", Tungsten, 0, { 1.363470, 1, 2.380822, 0 } }, + { "Canon", "EOS-1D Mark III", WhiteFluorescent, 0, { 1.742612, 1, 2.222116, 0 } }, + { "Canon", "EOS-1D Mark III", Flash, 0, { 2.173828, 1, 1.288086, 0 } }, + + { "Canon", "EOS-1Ds Mark III", Daylight, 0, { 2.093750, 1, 1.521484, 0 } }, + { "Canon", "EOS-1Ds Mark III", Shade, 0, { 2.420898, 1, 1.238281, 0 } }, + { "Canon", "EOS-1Ds Mark III", Cloudy, 0, { 2.250977, 1, 1.361328, 0 } }, + { "Canon", "EOS-1Ds Mark III", Tungsten, 0, { 1.455382, 1, 2.404784, 0 } }, + { "Canon", "EOS-1Ds Mark III", WhiteFluorescent, 0, { 1.842718, 1, 2.330097, 0 } }, + { "Canon", "EOS-1Ds Mark III", Flash, 0, { 2.311523, 1, 1.316406, 0 } }, + + // Firmware Version 1.0.6 (Temporary) + { "Canon", "EOS-1D Mark IV", Daylight, 0, { 2.040039, 1, 1.558594, 0 } }, + { "Canon", "EOS-1D Mark IV", Shade, 0, { 2.342773, 1, 1.333008, 0 } }, + { "Canon", "EOS-1D Mark IV", Cloudy, 0, { 2.188477, 1, 1.440430, 0 } }, + { "Canon", "EOS-1D Mark IV", Tungsten, 0, { 1.458333, 1, 2.305254, 0 } }, + { "Canon", "EOS-1D Mark IV", WhiteFluorescent, 0, { 1.767892, 1, 2.205029, 0 } }, + { "Canon", "EOS-1D Mark IV", Flash, 0, { 2.230469, 1, 1.423828, 0 } }, + + /* Canon EOS-1D X Firmware Version 1.0.6 */ + { "Canon", "EOS-1D X", Daylight, 0, { 1.943359, 1, 1.374023, 0 } }, + { "Canon", "EOS-1D X", Shade, 0, { 2.230469, 1, 1.175781, 0 } }, + { "Canon", "EOS-1D X", Cloudy, 0, { 2.085938, 1, 1.268555, 0 } }, + { "Canon", "EOS-1D X", Tungsten, 0, { 1.385742, 1, 2.068359, 0 } }, + { "Canon", "EOS-1D X", WhiteFluorescent, 0, { 1.726563, 1, 1.950195, 0 } }, + { "Canon", "EOS-1D X", Flash, 0, { 2.173828, 1, 1.239258, 0 } }, + + { "Canon", "EOS-1D X Mark II", Daylight, 0, { 1.822266, 1, 1.584961, 0 } }, + { "Canon", "EOS-1D X Mark II", Shade, 0, { 2.081055, 1, 1.381836, 0 } }, + { "Canon", "EOS-1D X Mark II", Cloudy, 0, { 1.954102, 1, 1.481445, 0 } }, + { "Canon", "EOS-1D X Mark II", Tungsten, 0, { 1.300781, 1, 2.275391, 0 } }, + { "Canon", "EOS-1D X Mark II", WhiteFluorescent, 0, { 1.540039, 1, 2.169922, 0 } }, + { "Canon", "EOS-1D X Mark II", Flash, 0, { 2.011719, 1, 1.454102, 0 } }, + + // Canon EOS M Firmware 1.0.6 + { "Canon", "EOS M", Cloudy, 0, { 2.156250, 1, 1.448242, 0 } }, + { "Canon", "EOS M", Daylight, 0, { 2.007813, 1, 1.575195, 0 } }, + { "Canon", "EOS M", Flash, 0, { 2.230469, 1, 1.429688, 0 } }, + { "Canon", "EOS M", Tungsten, 0, { 1.448242, 1, 2.386719, 0 } }, + { "Canon", "EOS M", Shade, 0, { 2.300781, 1, 1.334961, 0 } }, + { "Canon", "EOS M", WhiteFluorescent, 0, { 1.784180, 1, 2.275391, 0 } }, + + { "Canon", "EOS M2", Cloudy, 0, { 2.085938, 1, 1.493164, 0 } }, + { "Canon", "EOS M2", Daylight, 0, { 1.943359, 1, 1.615234, 0 } }, + { "Canon", "EOS M2", Flash, 0, { 2.165039, 1, 1.475586, 0 } }, + { "Canon", "EOS M2", Tungsten, 0, { 1.391602, 1, 2.392578, 0 } }, + { "Canon", "EOS M2", Shade, 0, { 2.226563, 1, 1.381836, 0 } }, + { "Canon", "EOS M2", WhiteFluorescent, 0, { 1.735352, 1, 2.280273, 0 } }, + + { "Canon", "EOS M3", Cloudy, 0, { 2.316032, 1, 1.585928, 0 } }, + { "Canon", "EOS M3", Daylight, 0, { 2.140411, 1, 1.702055, 0 } }, + { "Canon", "EOS M3", Flash, 0, { 2.787515, 1, 1.357743, 0 } }, + { "Canon", "EOS M3", Tungsten, 0, { 1.488650, 1, 2.624851, 0 } }, + { "Canon", "EOS M3", Shade, 0, { 2.477855, 1, 1.488345, 0 } }, + { "Canon", "EOS M3", WhiteFluorescent, 0, { 1.870460, 1, 2.325666, 0 } }, + + { "Canon", "EOS M10", Cloudy, 0, { 2.171053, 1, 1.438596, 0 } }, + { "Canon", "EOS M10", Daylight, 0, { 1.992408, 1, 1.556399, 0 } }, + { "Canon", "EOS M10", Flash, 0, { 2.557562, 1, 1.220090, 0 } }, + { "Canon", "EOS M10", Tungsten, 0, { 1.399530, 1, 2.615746, 0 } }, + { "Canon", "EOS M10", Shade, 0, { 2.334441, 1, 1.330011, 0 } }, + { "Canon", "EOS M10", WhiteFluorescent, 0, { 1.809693, 1, 2.239953, 0 } }, + + { "FUJIFILM", "E900", Daylight, 0, { 1.571875, 1, 1.128125, 0 } }, + { "FUJIFILM", "E900", Shade, 0, { 1.668750, 1, 1.006250, 0 } }, + { "FUJIFILM", "E900", DaylightFluorescent, 0, { 1.907609, 1, 1.016304, 0 } }, + { "FUJIFILM", "E900", WarmWhiteFluorescent, 0, { 1.654891, 1, 1.241848, 0 } }, + { "FUJIFILM", "E900", CoolWhiteFluorescent, 0, { 1.554348, 1, 1.519022, 0 } }, + { "FUJIFILM", "E900", Incandescent, 0, { 1.037611, 1, 1.842920, 0 } }, + + { "FUJIFILM", "F700", Daylight, 0, { 1.725000, 1, 1.500000, 0 } }, + { "FUJIFILM", "F700", Shade, 0, { 1.950000, 1, 1.325000, 0 } }, + { "FUJIFILM", "F700", DaylightFluorescent, 0, { 2.032609, 1, 1.336957, 0 } }, + { "FUJIFILM", "F700", WarmWhiteFluorescent, 0, { 1.706522, 1, 1.663043, 0 } }, + { "FUJIFILM", "F700", CoolWhiteFluorescent, 0, { 1.684783, 1, 2.152174, 0 } }, + { "FUJIFILM", "F700", Incandescent, 0, { 1.168142, 1, 2.477876, 0 } }, + + { "FUJIFILM", "HS20EXR", Daylight, 0, { 1.4107, 1, 1.9702, 0 } }, + { "FUJIFILM", "HS20EXR", Shade, 0, { 1.5804, 1, 1.7440, 0 } }, + { "FUJIFILM", "HS20EXR", DaylightFluorescent, 0, { 1.7292, 1, 1.7470, 0 } }, + { "FUJIFILM", "HS20EXR", WarmWhiteFluorescent, 0, { 1.4821, 1, 2.0476, 0 } }, + { "FUJIFILM", "HS20EXR", CoolWhiteFluorescent, 0, { 1.5625, 1, 2.5714, 0 } }, + { "FUJIFILM", "HS20EXR", Incandescent, 0, { 1, 1.0633, 2.9430, 0 } }, + + { "FUJIFILM", "HS50EXR", Daylight, 0, { 1.589286, 1, 1.892857, 0 } }, + { "FUJIFILM", "HS50EXR", Cloudy, 0, { 1.705357, 1, 1.663690, 0 } }, + { "FUJIFILM", "HS50EXR", DaylightFluorescent, 0, { 1.875000, 1, 1.648810, 0 } }, + { "FUJIFILM", "HS50EXR", DayWhiteFluorescent, 0, { 1.619048, 1, 1.946429, 0 } }, + { "FUJIFILM", "HS50EXR", WhiteFluorescent, 0, { 1.651786, 1, 2.464286, 0 } }, + { "FUJIFILM", "HS50EXR", Incandescent, 0, { 1.041667, 1, 2.601190, 0 } }, + + { "FUJIFILM", "S100FS", Daylight, 0, { 1.702381, 1, 1.845238, 0 } }, + { "FUJIFILM", "S100FS", Shade, 0, { 1.830357, 1, 1.601190, 0 } }, + { "FUJIFILM", "S100FS", DaylightFluorescent, 0, { 1.895833, 1, 1.461309, 0 } }, + { "FUJIFILM", "S100FS", WarmWhiteFluorescent, 0, { 1.574405, 1, 1.818452, 0 } }, + { "FUJIFILM", "S100FS", CoolWhiteFluorescent, 0, { 1.663690, 1, 2.309524, 0 } }, + { "FUJIFILM", "S100FS", Incandescent, 0, { 1.107143, 1, 2.815476, 0 } }, + + { "FUJIFILM", "S20Pro", Daylight, 0, { 1.712500, 1, 1.500000, 0 } }, + { "FUJIFILM", "S20Pro", Cloudy, 0, { 1.887500, 1, 1.262500, 0 } }, + { "FUJIFILM", "S20Pro", DaylightFluorescent, 0, { 2.097826, 1, 1.304348, 0 } }, + { "FUJIFILM", "S20Pro", WarmWhiteFluorescent, 0, { 1.782609, 1, 1.619565, 0 } }, + { "FUJIFILM", "S20Pro", CoolWhiteFluorescent, 0, { 1.670213, 1, 2.063830, 0 } }, + { "FUJIFILM", "S20Pro", Incandescent, 0, { 1.069565, 1, 2.486957, 0 } }, + + { "FUJIFILM", "S2Pro", Daylight, 0, { 1.509804, 1, 1.401961, 0 } }, + { "FUJIFILM", "S2Pro", Cloudy, 0, { 1.666667, 1, 1.166667, 0 } }, + { "FUJIFILM", "S2Pro", Flash, 0, { 1, 1.014084, 2.542253, 0 } }, + { "FUJIFILM", "S2Pro", DaylightFluorescent, 0, { 1.948718, 1, 1.230769, 0 } }, + { "FUJIFILM", "S2Pro", WarmWhiteFluorescent, 0, { 1.675214, 1, 1.572650, 0 } }, + { "FUJIFILM", "S2Pro", CoolWhiteFluorescent, 0, { 1.649573, 1, 2.094017, 0 } }, + + { "FUJIFILM", "S5000", Incandescent, 0, { 1.212081, 1, 2.672364, 0 } }, + { "FUJIFILM", "S5000", Fluorescent, 0, { 1.772316, 1, 2.349902, 0 } }, + { "FUJIFILM", "S5000", Daylight, 0, { 1.860403, 1, 1.515946, 0 } }, + { "FUJIFILM", "S5000", Flash, 0, { 2.202181, 1, 1.423284, 0 } }, + { "FUJIFILM", "S5000", Cloudy, 0, { 2.036578, 1, 1.382513, 0 } }, + { "FUJIFILM", "S5000", Shade, 0, { 2.357215, 1, 1.212016, 0 } }, + + { "FUJIFILM", "S5200", Daylight, 0, { 1.587500, 1, 1.381250, 0 } }, + { "FUJIFILM", "S5200", Shade, 0, { 1.946875, 1, 1.175000, 0 } }, + { "FUJIFILM", "S5200", DaylightFluorescent, 0, { 1.948370, 1, 1.187500, 0 } }, + { "FUJIFILM", "S5200", WarmWhiteFluorescent, 0, { 1.682065, 1, 1.437500, 0 } }, + { "FUJIFILM", "S5200", CoolWhiteFluorescent, 0, { 1.595109, 1, 1.839674, 0 } }, + { "FUJIFILM", "S5200", Incandescent, 0, { 1.077434, 1, 2.170354, 0 } }, + + { "FUJIFILM", "S5500", Daylight, 0, { 1.712500, 1, 1.550000, 0 } }, + { "FUJIFILM", "S5500", Shade, 0, { 1.912500, 1, 1.375000, 0 } }, + { "FUJIFILM", "S5500", DaylightFluorescent, 0, { 1.978261, 1, 1.380435, 0 } }, + { "FUJIFILM", "S5500", WarmWhiteFluorescent, 0, { 1.673913, 1, 1.673913, 0 } }, + { "FUJIFILM", "S5500", CoolWhiteFluorescent, 0, { 1.663043, 1, 2.163043, 0 } }, + { "FUJIFILM", "S5500", Incandescent, 0, { 1.115044, 1, 2.566372, 0 } }, + + { "FUJIFILM", "S5600", Daylight, 0, { 1.587500, 1, 1.381250, 0 } }, + { "FUJIFILM", "S5600", Shade, 0, { 1.946875, 1, 1.175000, 0 } }, + { "FUJIFILM", "S5600", DaylightFluorescent, 0, { 1.948370, 1, 1.187500, 0 } }, + { "FUJIFILM", "S5600", WarmWhiteFluorescent, 0, { 1.682065, 1, 1.437500, 0 } }, + { "FUJIFILM", "S5600", CoolWhiteFluorescent, 0, { 1.595109, 1, 1.839674, 0 } }, + { "FUJIFILM", "S5600", Incandescent, 0, { 1.077434, 1, 2.170354, 0 } }, + + { "FUJIFILM", "S6000fd", Daylight, 0, { 1.511905, 1, 1.431548, 0 } }, + { "FUJIFILM", "S6000fd", Shade, 0, { 1.699405, 1, 1.232143, 0 } }, + { "FUJIFILM", "S6000fd", DaylightFluorescent, 0, { 1.866071, 1, 1.309524, 0 } }, + { "FUJIFILM", "S6000fd", WarmWhiteFluorescent, 0, { 1.568452, 1, 1.627976, 0 } }, + { "FUJIFILM", "S6000fd", CoolWhiteFluorescent, 0, { 1.598214, 1, 2.038691, 0 } }, + { "FUJIFILM", "S6000fd", Incandescent, 0, { 1, 1.024390, 2.466463, 0 } }, + + { "FUJIFILM", "S6500fd", Daylight, 0, { 1.398810, 1, 1.470238, 0 } }, + { "FUJIFILM", "S6500fd", Shade, 0, { 1.580357, 1, 1.270833, 0 } }, + { "FUJIFILM", "S6500fd", DaylightFluorescent, 0, { 1.735119, 1, 1.348214, 0 } }, + { "FUJIFILM", "S6500fd", WarmWhiteFluorescent, 0, { 1.455357, 1, 1.672619, 0 } }, + { "FUJIFILM", "S6500fd", CoolWhiteFluorescent, 0, { 1.482143, 1, 2.089286, 0 } }, + { "FUJIFILM", "S6500fd", Incandescent, 0, { 1, 1.123746, 2.769231, 0 } }, + + { "FUJIFILM", "S7000", Daylight, 0, { 1.900000, 1, 1.525000, 0 } }, + { "FUJIFILM", "S7000", Shade, 0, { 2.137500, 1, 1.350000, 0 } }, + { "FUJIFILM", "S7000", DaylightFluorescent, 0, { 2.315217, 1, 1.347826, 0 } }, + { "FUJIFILM", "S7000", WarmWhiteFluorescent, 0, { 1.902174, 1, 1.663043, 0 } }, + { "FUJIFILM", "S7000", CoolWhiteFluorescent, 0, { 1.836957, 1, 2.130435, 0 } }, + { "FUJIFILM", "S7000", Incandescent, 0, { 1.221239, 1, 2.548673, 0 } }, + + /* The S9000 and S9500 are the same camera */ + { "FUJIFILM", "S9000", Daylight, 0, { 1.618750, 1, 1.231250, 0 } }, + { "FUJIFILM", "S9000", Shade, 0, { 1.700000, 1, 1.046875, 0 } }, + { "FUJIFILM", "S9000", DaylightFluorescent, 0, { 1.902174, 1, 1.057065, 0 } }, + { "FUJIFILM", "S9000", WarmWhiteFluorescent, 0, { 1.633152, 1, 1.293478, 0 } }, + { "FUJIFILM", "S9000", CoolWhiteFluorescent, 0, { 1.546196, 1, 1.622283, 0 } }, + { "FUJIFILM", "S9000", Incandescent, 0, { 1.064159, 1, 1.960177, 0 } }, + + { "FUJIFILM", "S9100", Daylight, 0, { 1.506250, 1, 1.318750, 0 } }, + { "FUJIFILM", "S9100", Shade, 0, { 1.587500, 1, 1.128125, 0 } }, + { "FUJIFILM", "S9100", DaylightFluorescent, 0, { 1.777174, 1, 1.138587, 0 } }, + { "FUJIFILM", "S9100", WarmWhiteFluorescent, 0, { 1.521739, 1, 1.380435, 0 } }, + { "FUJIFILM", "S9100", CoolWhiteFluorescent, 0, { 1.437500, 1, 1.720109, 0 } }, + { "FUJIFILM", "S9100", Incandescent, 0, { 1, 1.024943, 2.113379, 0 } }, + + /* The S9000 and S9500 are the same camera */ + { "FUJIFILM", "S9500", Daylight, 0, { 1.618750, 1, 1.231250, 0 } }, + { "FUJIFILM", "S9500", Shade, 0, { 1.700000, 1, 1.046875, 0 } }, + { "FUJIFILM", "S9500", DaylightFluorescent, 0, { 1.902174, 1, 1.057065, 0 } }, + { "FUJIFILM", "S9500", WarmWhiteFluorescent, 0, { 1.633152, 1, 1.293478, 0 } }, + { "FUJIFILM", "S9500", CoolWhiteFluorescent, 0, { 1.546196, 1, 1.622283, 0 } }, + { "FUJIFILM", "S9500", Incandescent, 0, { 1.064159, 1, 1.960177, 0 } }, + + { "FUJIFILM", "S9600", Daylight, 0, { 1.534375, 1, 1.300000, 0 } }, + { "FUJIFILM", "S9600", Shade, 0, { 1.615625, 1, 1.112500, 0 } }, + { "FUJIFILM", "S9600", DaylightFluorescent, 0, { 1.809783, 1, 1.122283, 0 } }, + { "FUJIFILM", "S9600", WarmWhiteFluorescent, 0, { 1.551630, 1, 1.361413, 0 } }, + { "FUJIFILM", "S9600", CoolWhiteFluorescent, 0, { 1.467391, 1, 1.692935, 0 } }, + { "FUJIFILM", "S9600", Incandescent, 0, { 1, 1.004444, 2.040000, 0 } }, + + { "FUJIFILM", "X20", Daylight, 0, { 1.688742, 1, 1.850993, 0 } }, + { "FUJIFILM", "X20", Shade, 0, { 1.827815, 1, 1.622517, 0 } }, + { "FUJIFILM", "X20", DayWhiteFluorescent, 0, { 1.754967, 1, 1.864238, 0 } }, + { "FUJIFILM", "X20", DaylightFluorescent, 0, { 2.052980, 1, 1.625828, 0 } }, + { "FUJIFILM", "X20", WhiteFluorescent, 0, { 1.754967, 1, 2.341060, 0 } }, + { "FUJIFILM", "X20", Incandescent, 0, { 1.066225, 1, 2.605960, 0 } }, + { "FUJIFILM", "X20", Underwater, 0, { 1.688742, 1, 1.850993, 0 } }, + + { "FUJIFILM", "X70", Daylight, 0, { 2.009934, 1, 1.513245, 0 } }, + { "FUJIFILM", "X70", Shade, 0, { 2.211921, 1, 1.311258, 0 } }, + { "FUJIFILM", "X70", DayWhiteFluorescent, 0, { 2.188742, 1, 1.566225, 0 } }, + { "FUJIFILM", "X70", DaylightFluorescent, 0, { 2.619205, 1, 1.311258, 0 } }, + { "FUJIFILM", "X70", WhiteFluorescent, 0, { 2.056291, 1, 2.013245, 0 } }, + { "FUJIFILM", "X70", Incandescent, 0, { 1.314570, 1, 2.251656, 0 } }, + { "FUJIFILM", "X70", Underwater, 0, { 2.006623, 1, 1.533113, 0 } }, + + { "FUJIFILM", "X100", Daylight, 0, { 1.4503, 1, 1.5033, 0 } }, + { "FUJIFILM", "X100", Shade, 0, { 1.5861, 1, 1.2947, 0 } }, + { "FUJIFILM", "X100", DaylightFluorescent, 0, { 1.8841, 1, 1.3179, 0 } }, + { "FUJIFILM", "X100", WarmWhiteFluorescent, 0, { 1.6291, 1, 1.5927, 0 } }, + { "FUJIFILM", "X100", CoolWhiteFluorescent, 0, { 1.5662, 1, 2.0265, 0 } }, + { "FUJIFILM", "X100", Incandescent, 0, { 1, 1.0272, 2.4966, 0 } }, + { "FUJIFILM", "X100", Underwater, 0, { 1.4603, 1, 1.5662, 0 } }, + { "FUJIFILM", "X100", "2500K", 0, { 1, 1.6503, 5.1858, 0 } }, + { "FUJIFILM", "X100", "2550K", 0, { 1, 1.5729, 4.7917, 0 } }, + { "FUJIFILM", "X100", "2650K", 0, { 1, 1.4313, 4.1090, 0 } }, + { "FUJIFILM", "X100", "2700K", 0, { 1, 1.3790, 3.8447, 0 } }, + { "FUJIFILM", "X100", "2800K", 0, { 1, 1.2797, 3.3814, 0 } }, + { "FUJIFILM", "X100", "2850K", 0, { 1, 1.2377, 3.1844, 0 } }, + { "FUJIFILM", "X100", "2950K", 0, { 1, 1.1660, 2.8571, 0 } }, + { "FUJIFILM", "X100", "3000K", 0, { 1, 1.1353, 2.7180, 0 } }, + { "FUJIFILM", "X100", "3100K", 0, { 1, 1.0824, 2.4731, 0 } }, + { "FUJIFILM", "X100", "3200K", 0, { 1, 1.0342, 2.2671, 0 } }, + { "FUJIFILM", "X100", "3300K", 0, { 1.0066, 1, 2.1060, 0 } }, + { "FUJIFILM", "X100", "3400K", 0, { 1.0430, 1, 2.0265, 0 } }, + { "FUJIFILM", "X100", "3600K", 0, { 1.1159, 1, 1.8907, 0 } }, + { "FUJIFILM", "X100", "3700K", 0, { 1.1457, 1, 1.8311, 0 } }, + { "FUJIFILM", "X100", "3800K", 0, { 1.1755, 1, 1.7781, 0 } }, + { "FUJIFILM", "X100", "4000K", 0, { 1.2351, 1, 1.6821, 0 } }, + { "FUJIFILM", "X100", "4200K", 0, { 1.2848, 1, 1.5993, 0 } }, + { "FUJIFILM", "X100", "4300K", 0, { 1.3079, 1, 1.5662, 0 } }, + { "FUJIFILM", "X100", "4500K", 0, { 1.3543, 1, 1.5000, 0 } }, + { "FUJIFILM", "X100", "4800K", 0, { 1.4172, 1, 1.4205, 0 } }, + { "FUJIFILM", "X100", "5000K", 0, { 1.4536, 1, 1.3742, 0 } }, + { "FUJIFILM", "X100", "5300K", 0, { 1.5033, 1, 1.3179, 0 } }, + { "FUJIFILM", "X100", "5600K", 0, { 1.5530, 1, 1.2715, 0 } }, + { "FUJIFILM", "X100", "5900K", 0, { 1.5927, 1, 1.2318, 0 } }, + { "FUJIFILM", "X100", "6300K", 0, { 1.6457, 1, 1.1887, 0 } }, + { "FUJIFILM", "X100", "6700K", 0, { 1.6921, 1, 1.1556, 0 } }, + { "FUJIFILM", "X100", "7100K", 0, { 1.7318, 1, 1.1291, 0 } }, + { "FUJIFILM", "X100", "7700K", 0, { 1.7881, 1, 1.0960, 0 } }, + { "FUJIFILM", "X100", "8300K", 0, { 1.8377, 1, 1.0728, 0 } }, + { "FUJIFILM", "X100", "9100K", 0, { 1.8940, 1, 1.0464, 0 } }, + { "FUJIFILM", "X100", "10000K", 0, { 1.9503, 1, 1.0298, 0 } }, + + /* FUJIFILM X100S firmware 1.20 */ + { "FUJIFILM", "X100S", Daylight, 0, { 1.874172, 1, 1.490066, 0 } }, + { "FUJIFILM", "X100S", Shade, 0, { 2.049669, 1, 1.271523, 0 } }, + { "FUJIFILM", "X100S", DaylightFluorescent, 0, { 2.344371, 1, 1.264901, 0 } }, + { "FUJIFILM", "X100S", WarmWhiteFluorescent, 0, { 2.000000, 1, 1.509934, 0 } }, + { "FUJIFILM", "X100S", CoolWhiteFluorescent, 0, { 1.874172, 1, 1.913907, 0 } }, + { "FUJIFILM", "X100S", Incandescent, 0, { 1.198675, 1, 2.341060, 0 } }, + { "FUJIFILM", "X100S", Underwater, 0, { 1.874172, 1, 1.490066, 0 } }, + { "FUJIFILM", "X100S", "2500K", 0, { 1, 1.074733, 3.597865, 0 } }, + { "FUJIFILM", "X100S", "2550K", 0, { 1, 1.059649, 3.428070, 0 } }, + { "FUJIFILM", "X100S", "2650K", 0, { 1, 1.020270, 3.091216, 0 } }, + { "FUJIFILM", "X100S", "2700K", 0, { 1, 1.003322, 2.950166, 0 } }, + { "FUJIFILM", "X100S", "2800K", 0, { 1.036424, 1, 2.774834, 0 } }, + { "FUJIFILM", "X100S", "2850K", 0, { 1.056291, 1, 2.701987, 0 } }, + { "FUJIFILM", "X100S", "2950K", 0, { 1.096026, 1, 2.569536, 0 } }, + { "FUJIFILM", "X100S", "3000K", 0, { 1.119205, 1, 2.509934, 0 } }, + { "FUJIFILM", "X100S", "3100K", 0, { 1.158940, 1, 2.400662, 0 } }, + { "FUJIFILM", "X100S", "3200K", 0, { 1.198676, 1, 2.304636, 0 } }, + { "FUJIFILM", "X100S", "3300K", 0, { 1.241722, 1, 2.218543, 0 } }, + { "FUJIFILM", "X100S", "3400K", 0, { 1.278146, 1, 2.142384, 0 } }, + { "FUJIFILM", "X100S", "3600K", 0, { 1.357616, 1, 2.013245, 0 } }, + { "FUJIFILM", "X100S", "3700K", 0, { 1.394040, 1, 1.956954, 0 } }, + { "FUJIFILM", "X100S", "3800K", 0, { 1.430464, 1, 1.907285, 0 } }, + { "FUJIFILM", "X100S", "4000K", 0, { 1.496689, 1, 1.817881, 0 } }, + { "FUJIFILM", "X100S", "4200K", 0, { 1.559603, 1, 1.741722, 0 } }, + { "FUJIFILM", "X100S", "4300K", 0, { 1.592715, 1, 1.708609, 0 } }, + { "FUJIFILM", "X100S", "4500K", 0, { 1.649007, 1, 1.649007, 0 } }, + { "FUJIFILM", "X100S", "4800K", 0, { 1.728477, 1, 1.572848, 0 } }, + { "FUJIFILM", "X100S", "5000K", 0, { 1.774835, 1, 1.529801, 0 } }, + { "FUJIFILM", "X100S", "5300K", 0, { 1.841060, 1, 1.473510, 0 } }, + { "FUJIFILM", "X100S", "5600K", 0, { 1.900662, 1, 1.423841, 0 } }, + { "FUJIFILM", "X100S", "5900K", 0, { 1.953642, 1, 1.380795, 0 } }, + { "FUJIFILM", "X100S", "6300K", 0, { 2.019868, 1, 1.334437, 0 } }, + { "FUJIFILM", "X100S", "6700K", 0, { 2.076159, 1, 1.291391, 0 } }, + { "FUJIFILM", "X100S", "7100K", 0, { 2.125828, 1, 1.254967, 0 } }, + { "FUJIFILM", "X100S", "7700K", 0, { 2.192053, 1, 1.208609, 0 } }, + { "FUJIFILM", "X100S", "8300K", 0, { 2.245033, 1, 1.168874, 0 } }, + { "FUJIFILM", "X100S", "9100K", 0, { 2.304636, 1, 1.122517, 0 } }, + { "FUJIFILM", "X100S", "10000K", 0, { 2.360927, 1, 1.079470, 0 } }, + + { "FUJIFILM", "X100T", Daylight, 0, { 1.930464, 1, 1.539735, 0 } }, + { "FUJIFILM", "X100T", Shade, 0, { 2.109272, 1, 1.324503, 0 } }, + { "FUJIFILM", "X100T", DaylightFluorescent, 0, { 2.456954, 1, 1.334437, 0 } }, + { "FUJIFILM", "X100T", WarmWhiteFluorescent, 0, { 2.102649, 1, 1.589404, 0 } }, + { "FUJIFILM", "X100T", CoolWhiteFluorescent, 0, { 2.013245, 1, 1.970199, 0 } }, + { "FUJIFILM", "X100T", Incandescent, 0, { 1.238411, 1, 2.307947, 0 } }, + { "FUJIFILM", "X100T", Underwater, 0, { 1.927152, 1, 1.549669, 0 } }, + + { "FUJIFILM", "X-A2", Daylight, 0, { 1.824503, 1, 1.758278, 0 } }, + { "FUJIFILM", "X-A2", Shade, 0, { 2.033113, 1, 1.496689, 0 } }, + { "FUJIFILM", "X-A2", DaylightFluorescent, 0, { 2.327815, 1, 1.500000, 0 } }, + { "FUJIFILM", "X-A2", WarmWhiteFluorescent, 0, { 1.986755, 1, 1.804636, 0 } }, + { "FUJIFILM", "X-A2", CoolWhiteFluorescent, 0, { 1.900662, 1, 2.284768, 0 } }, + { "FUJIFILM", "X-A2", Incandescent, 0, { 1.162252, 1, 2.864238, 0 } }, + + /* FUJIFILM X-E1 Firmware Version 1.01 */ + // The manual calls it "Direct sunlight". + { "FUJIFILM", "X-E1", Daylight, 0, { 1.821192, 1, 1.804636, 0 } }, + // The manual calls it "Shade", but exiftool shows it as "Cloudy". + { "FUJIFILM", "X-E1", Shade, 0, { 2.039735, 1, 1.572848, 0 } }, + { "FUJIFILM", "X-E1", DaylightFluorescent, 0, { 2.321192, 1, 1.566225, 0 } }, + { "FUJIFILM", "X-E1", WarmWhiteFluorescent, 0, { 1.966887, 1, 1.837748, 0 } }, + { "FUJIFILM", "X-E1", CoolWhiteFluorescent, 0, { 1.847682, 1, 2.317881, 0 } }, + { "FUJIFILM", "X-E1", Incandescent, 0, { 1.165563, 1, 2.920530, 0 } }, + { "FUJIFILM", "X-E1", Underwater, 0, { 1.821192, 1, 1.804636, 0 } }, + { "FUJIFILM", "X-E1", "2500K", 0, { 0.980132, 1, 3.427152, 0 } }, + { "FUJIFILM", "X-E1", "2550K", 0, { 1.009934, 1, 3.334437, 0 } }, + { "FUJIFILM", "X-E1", "2650K", 0, { 1.059603, 1, 3.165563, 0 } }, + { "FUJIFILM", "X-E1", "2700K", 0, { 1.082781, 1, 3.086093, 0 } }, + { "FUJIFILM", "X-E1", "2800K", 0, { 1.125828, 1, 2.950331, 0 } }, + { "FUJIFILM", "X-E1", "2850K", 0, { 1.145695, 1, 2.887417, 0 } }, + { "FUJIFILM", "X-E1", "2950K", 0, { 1.182119, 1, 2.771523, 0 } }, + { "FUJIFILM", "X-E1", "3000K", 0, { 1.201987, 1, 2.718543, 0 } }, + { "FUJIFILM", "X-E1", "3100K", 0, { 1.235099, 1, 2.622517, 0 } }, + { "FUJIFILM", "X-E1", "3200K", 0, { 1.271523, 1, 2.536424, 0 } }, + { "FUJIFILM", "X-E1", "3300K", 0, { 1.304636, 1, 2.456954, 0 } }, + { "FUJIFILM", "X-E1", "3400K", 0, { 1.334437, 1, 2.387417, 0 } }, + { "FUJIFILM", "X-E1", "3600K", 0, { 1.397351, 1, 2.261589, 0 } }, + { "FUJIFILM", "X-E1", "3700K", 0, { 1.430464, 1, 2.205298, 0 } }, + { "FUJIFILM", "X-E1", "3800K", 0, { 1.460265, 1, 2.152318, 0 } }, + { "FUJIFILM", "X-E1", "4000K", 0, { 1.523179, 1, 2.062914, 0 } }, + { "FUJIFILM", "X-E1", "4200K", 0, { 1.582781, 1, 1.980132, 0 } }, + { "FUJIFILM", "X-E1", "4300K", 0, { 1.612583, 1, 1.943709, 0 } }, + { "FUJIFILM", "X-E1", "4500K", 0, { 1.672185, 1, 1.874172, 0 } }, + { "FUJIFILM", "X-E1", "4800K", 0, { 1.758278, 1, 1.784768, 0 } }, + { "FUJIFILM", "X-E1", "5000K", 0, { 1.814570, 1, 1.731788, 0 } }, + { "FUJIFILM", "X-E1", "5300K", 0, { 1.897351, 1, 1.658940, 0 } }, + { "FUJIFILM", "X-E1", "5600K", 0, { 1.973510, 1, 1.596026, 0 } }, + { "FUJIFILM", "X-E1", "5900K", 0, { 2.049669, 1, 1.536424, 0 } }, + { "FUJIFILM", "X-E1", "6300K", 0, { 2.149007, 1, 1.466887, 0 } }, + { "FUJIFILM", "X-E1", "6700K", 0, { 2.238411, 1, 1.403974, 0 } }, + { "FUJIFILM", "X-E1", "7100K", 0, { 2.324503, 1, 1.350993, 0 } }, + { "FUJIFILM", "X-E1", "7700K", 0, { 2.447020, 1, 1.274834, 0 } }, + { "FUJIFILM", "X-E1", "8300K", 0, { 2.556291, 1, 1.211921, 0 } }, + { "FUJIFILM", "X-E1", "9100K", 0, { 2.688742, 1, 1.135762, 0 } }, + { "FUJIFILM", "X-E1", "10000K", 0, { 2.821192, 1, 1.062914, 0 } }, + + { "FUJIFILM", "X-E2", Daylight, 0, { 1.870861, 1, 1.582781, 0 } }, + { "FUJIFILM", "X-E2", Shade, 0, { 2.066225, 1, 1.374172, 0 } }, + { "FUJIFILM", "X-E2", DaylightFluorescent, 0, { 2.394040, 1, 1.370861, 0 } }, + { "FUJIFILM", "X-E2", WarmWhiteFluorescent, 0, { 2.039735, 1, 1.612583, 0 } }, + { "FUJIFILM", "X-E2", CoolWhiteFluorescent, 0, { 1.917219, 1, 2.006623, 0 } }, + { "FUJIFILM", "X-E2", Incandescent, 0, { 1.215232, 1, 2.400662, 0 } }, + { "FUJIFILM", "X-E2", Underwater, 0, { 1.864238, 1, 1.559603, 0 } }, + + { "FUJIFILM", "X-M1", Daylight, 0, { 1.943709, 1, 1.824503, 0 } }, + { "FUJIFILM", "X-M1", Shade, 0, { 2.139073, 1, 1.599338, 0 } }, + { "FUJIFILM", "X-M1", DaylightFluorescent, 0, { 2.440397, 1, 1.592715, 0 } }, + { "FUJIFILM", "X-M1", WarmWhiteFluorescent, 0, { 2.066225, 1, 1.870861, 0 } }, + { "FUJIFILM", "X-M1", CoolWhiteFluorescent, 0, { 1.937086, 1, 2.360927, 0 } }, + { "FUJIFILM", "X-M1", Incandescent, 0, { 1.225166, 1, 2.976821, 0 } }, + + /* FUJIFILM X-T1 Firmware Version 1.10 */ + { "FUJIFILM", "X-T1", Daylight, 0, { 1.894040, 1, 1.569536, 0 } }, + // The manual calls it "Shade", but exiftool shows it as "Cloudy". + { "FUJIFILM", "X-T1", Shade, 0, { 2.092715, 1, 1.347682, 0 } }, + { "FUJIFILM", "X-T1", DaylightFluorescent, 0, { 2.394040, 1, 1.377483, 0 } }, + { "FUJIFILM", "X-T1", WarmWhiteFluorescent, 0, { 2.023179, 1, 1.622517, 0 } }, + { "FUJIFILM", "X-T1", CoolWhiteFluorescent, 0, { 1.947020, 1, 2.066225, 0 } }, + { "FUJIFILM", "X-T1", Incandescent, 0, { 1.268212, 1, 2.284768, 0 } }, + { "FUJIFILM", "X-T1", Underwater, 0, { 1.894040, 1, 1.569536, 0 } }, + { "FUJIFILM", "X-T1", "5000K", 0, { 1.847682, 1, 1.546358, 0 } }, + + { "FUJIFILM", "X-T2", Daylight, 0, { 1.877483, 1, 1.940397, 0 } }, + { "FUJIFILM", "X-T2", Shade, 0, { 2.086093, 1, 1.672185, 0 } }, + { "FUJIFILM", "X-T2", DaylightFluorescent, 0, { 2.360927, 1, 1.668874, 0 } }, + { "FUJIFILM", "X-T2", DayWhiteFluorescent, 0, { 1.976821, 1, 2.052980, 0 } }, + { "FUJIFILM", "X-T2", WhiteFluorescent, 0, { 1.867550, 1, 2.639073, 0 } }, + { "FUJIFILM", "X-T2", Incandescent, 0, { 1.248344, 1, 2.907285, 0 } }, + { "FUJIFILM", "X-T2", Underwater, 0, { 1.877483, 1, 1.940397, 0 } }, + + /* FUJIFILM X-T10 Firmware Version 1.21 */ + { "FUJIFILM", "X-T10", Daylight, 0, { 1.884106, 1, 1.526490, 0 } }, + // The manual calls it "Shade", but exiftool shows it as "Cloudy". + { "FUJIFILM", "X-T10", Shade, 0, { 2.072848, 1, 1.324503, 0 } }, + { "FUJIFILM", "X-T10", DaylightFluorescent, 0, { 2.423841, 1, 1.334437, 0 } }, + { "FUJIFILM", "X-T10", WarmWhiteFluorescent, 0, { 2.026490, 1, 1.599338, 0 } }, + { "FUJIFILM", "X-T10", CoolWhiteFluorescent, 0, { 1.890728, 1, 2.046358, 0 } }, + { "FUJIFILM", "X-T10", Incandescent, 0, { 1.211921, 1, 2.321192, 0 } }, + { "FUJIFILM", "X-T10", Underwater, 0, { 1.990066, 1, 1.440397, 0 } }, + + /* FUJIFILM X-Pro1 Firmware Version v3.30 */ + // The manual calls it "Fine". + { "FUJIFILM", "X-Pro1", Daylight, 0, { 1.860927, 1, 1.708609, 0 } }, + // The manual calls it "Shade", but exiftool shows it as "Cloudy". + { "FUJIFILM", "X-Pro1", Shade, 0, { 2.105960, 1, 1.460265, 0 } }, + { "FUJIFILM", "X-Pro1", DaylightFluorescent, 0, { 2.390728, 1, 1.500000, 0 } }, + { "FUJIFILM", "X-Pro1", WarmWhiteFluorescent, 0, { 2.059603, 1, 1.794702, 0 } }, + { "FUJIFILM", "X-Pro1", CoolWhiteFluorescent, 0, { 1.966887, 1, 2.254967, 0 } }, + { "FUJIFILM", "X-Pro1", Incandescent, 0, { 1.225166, 1, 2.708609, 0 } }, + { "FUJIFILM", "X-Pro1", Underwater, 0, { 1.860927, 1, 1.708609, 0 } }, + { "FUJIFILM", "X-Pro1", "2500K", 0, { 1.009934, 1, 3.423841, 0 } }, + { "FUJIFILM", "X-Pro1", "2550K", 0, { 1.039735, 1, 3.327815, 0 } }, + { "FUJIFILM", "X-Pro1", "2650K", 0, { 1.092715, 1, 3.155629, 0 } }, + { "FUJIFILM", "X-Pro1", "2700K", 0, { 1.115894, 1, 3.079470, 0 } }, + { "FUJIFILM", "X-Pro1", "2800K", 0, { 1.158940, 1, 2.937086, 0 } }, + { "FUJIFILM", "X-Pro1", "2850K", 0, { 1.178808, 1, 2.874172, 0 } }, + { "FUJIFILM", "X-Pro1", "2950K", 0, { 1.218543, 1, 2.758278, 0 } }, + { "FUJIFILM", "X-Pro1", "3000K", 0, { 1.235099, 1, 2.705298, 0 } }, + { "FUJIFILM", "X-Pro1", "3100K", 0, { 1.271523, 1, 2.605960, 0 } }, + { "FUJIFILM", "X-Pro1", "3200K", 0, { 1.307947, 1, 2.519868, 0 } }, + { "FUJIFILM", "X-Pro1", "3300K", 0, { 1.341060, 1, 2.440397, 0 } }, + { "FUJIFILM", "X-Pro1", "3400K", 0, { 1.374172, 1, 2.367550, 0 } }, + { "FUJIFILM", "X-Pro1", "3600K", 0, { 1.437086, 1, 2.238411, 0 } }, + { "FUJIFILM", "X-Pro1", "3700K", 0, { 1.470199, 1, 2.182119, 0 } }, + { "FUJIFILM", "X-Pro1", "3800K", 0, { 1.500000, 1, 2.132450, 0 } }, + { "FUJIFILM", "X-Pro1", "4000K", 0, { 1.562914, 1, 2.036424, 0 } }, + { "FUJIFILM", "X-Pro1", "4200K", 0, { 1.622517, 1, 1.953642, 0 } }, + { "FUJIFILM", "X-Pro1", "4300K", 0, { 1.652318, 1, 1.917219, 0 } }, + { "FUJIFILM", "X-Pro1", "4500K", 0, { 1.711921, 1, 1.847682, 0 } }, + { "FUJIFILM", "X-Pro1", "4800K", 0, { 1.801325, 1, 1.754967, 0 } }, + { "FUJIFILM", "X-Pro1", "5000K", 0, { 1.857616, 1, 1.701987, 0 } }, + { "FUJIFILM", "X-Pro1", "5300K", 0, { 1.940397, 1, 1.629139, 0 } }, + { "FUJIFILM", "X-Pro1", "5600K", 0, { 2.019868, 1, 1.562914, 0 } }, + { "FUJIFILM", "X-Pro1", "5900K", 0, { 2.096026, 1, 1.503311, 0 } }, + { "FUJIFILM", "X-Pro1", "6300K", 0, { 2.192053, 1, 1.433775, 0 } }, + { "FUJIFILM", "X-Pro1", "6700K", 0, { 2.281457, 1, 1.370861, 0 } }, + { "FUJIFILM", "X-Pro1", "7100K", 0, { 2.367550, 1, 1.311258, 0 } }, + { "FUJIFILM", "X-Pro1", "7700K", 0, { 2.486755, 1, 1.238411, 0 } }, + { "FUJIFILM", "X-Pro1", "8300K", 0, { 2.592715, 1, 1.172185, 0 } }, + { "FUJIFILM", "X-Pro1", "9100K", 0, { 2.721854, 1, 1.096026, 0 } }, + { "FUJIFILM", "X-Pro1", "10000K", 0, { 2.847682, 1, 1.023179, 0 } }, + + { "FUJIFILM", "X-Pro2", Daylight, 0, { 1.947020, 1, 1.831126, 0 } }, + { "FUJIFILM", "X-Pro2", Cloudy, 0, { 2.145695, 1, 1.582781, 0 } }, + { "FUJIFILM", "X-Pro2", Incandescent, 0, { 1.264901, 1, 2.754967, 0 } }, + { "FUJIFILM", "X-Pro2", DayWhiteFluorescent, 0, { 2.069536, 1, 1.950331, 0 } }, + { "FUJIFILM", "X-Pro2", DaylightFluorescent, 0, { 2.463576, 1, 1.602649, 0 } }, + { "FUJIFILM", "X-Pro2", WhiteFluorescent, 0, { 1.973510, 1, 2.513245, 0 } }, + { "FUJIFILM", "X-Pro2", Underwater, 0, { 1.943709, 1, 1.827815, 0 } }, + + { "KODAK", "DCS Pro 14N", Daylight, 0, { 1, 1.055126, 1.353602, 0 } }, + { "KODAK", "DCS Pro 14N", Tungsten, 0, { 1, 1.337688, 2.218852, 0 } }, + { "KODAK", "DCS Pro 14N", Fluorescent, 0, { 1, 1.102854, 1.513673, 0 } }, + { "KODAK", "DCS Pro 14N", Flash, 0, { 1, 1.055670, 1.353602, 0 } }, + + /* Median of 3 DCS Pro SLR/n cameras. */ + { "KODAK", "DCS Pro SLR/n", Daylight, 0, { 1, 0.816913, 1.267327, 0 } }, + { "KODAK", "DCS Pro SLR/n", Tungsten, 0, { 1, 1.045431, 1.948620, 0 } }, + { "KODAK", "DCS Pro SLR/n", Fluorescent, 0, { 1, 0.778411, 1.244228, 0 } }, + { "KODAK", "DCS Pro SLR/n", Flash, 0, { 1, 0.789819, 1.224880, 0 } }, + + { "KODAK", "DCS560C", Daylight, 0, { 1.238959, 1.057305, 2.133333, 0 } }, + { "KODAK", "DCS560C", Tungsten, 0, { 1.061690, 1.043833, 2.612245, 0 } }, + { "KODAK", "DCS560C", Fluorescent, 0, { 1.463903, 0.994658, 2.081301, 0 } }, + { "KODAK", "DCS560C", Flash, 0, { 1.238956, 1.057305, 2.133333, 0 } }, + + { "KODAK", "ProBack645", Daylight, 0, { 1.122807, 1.001467, 1.368984, 0 } }, + { "KODAK", "ProBack645", Tungsten, 0, { 1.000000, 1.204706, 2.409412, 0 } }, + { "KODAK", "ProBack645", Fluorescent, 0, { 1.099893, 1.000000, 1.699585, 0 } }, + { "KODAK", "ProBack645", Flash, 0, { 1.134626, 1.011858, 1.382849, 0 } }, + + { "KODAK", "P850 ZOOM", Daylight, 0, { 1.859375, 1, 1.566406, 0 } }, + { "KODAK", "P850 ZOOM", Cloudy, 0, { 1.960938, 1, 1.570313, 0 } }, + { "KODAK", "P850 ZOOM", Shade, 0, { 2.027344, 1, 1.519531, 0 } }, + { "KODAK", "P850 ZOOM", EveningSun, 0, { 1.679688, 1, 1.812500, 0 } }, + { "KODAK", "P850 ZOOM", Tungsten, 0, { 1.140625, 1, 2.726563, 0 } }, + { "KODAK", "P850 ZOOM", Fluorescent, 0, { 1.113281, 1, 2.949219, 0 } }, + + { "KODAK", "EASYSHARE Z1015 IS", Daylight, 0, { 1.546875, 1, 2.082031, 0 } }, + { "KODAK", "EASYSHARE Z1015 IS", Tungsten, 0, { 1, 1.024000, 3.384000, 0 } }, + { "KODAK", "EASYSHARE Z1015 IS", Fluorescent, 0, { 1.562500, 1, 2.515625, 0 } }, + { "KODAK", "EASYSHARE Z1015 IS", Shade, 0, { 1.820313, 1, 1.789062, 0 } }, + + { "LEICA", "M8", Cloudy, 0, { 2.136719, 1, 1.168213, 0 } }, + { "LEICA", "M8", Daylight, 0, { 2.007996, 1, 1.268982, 0 } }, + { "LEICA", "M8", Flash, 0, { 2.164490, 1, 1.177795, 0 } }, + { "LEICA", "M8", Fluorescent, 0, { 1.655579, 1, 2.070374, 0 } }, + { "LEICA", "M8", Shade, 0, { 2.197754, 1, 1.111084, 0 } }, + { "LEICA", "M8", Tungsten, 0, { 1.160034, 1, 2.028381, 0 } }, + + { "LEICA", "M9", Tungsten, 0, { 1.321288, 1, 2.077024, 0 } }, + { "LEICA", "M9", Fluorescent, 0, { 1.673827, 1, 1.855043, 0 } }, + { "LEICA", "M9", DaylightFluorescent, 0, { 2.224852, 1, 1.388000, 0 } }, + { "LEICA", "M9", Daylight, 0, { 2.013733, 1, 1.364869, 0 } }, + { "LEICA", "M9", Flash, 0, { 1.980652, 1, 1.331111, 0 } }, + { "LEICA", "M9", Cloudy, 0, { 2.146728, 1, 1.252197, 0 } }, + { "LEICA", "M9", Shade, 0, { 2.249268, 1, 1.179015, 0 } }, + + { "LEICA", "R8 - Digital Back DMR", Incandescent, 0, { 1, 1.109985, 2.430664, 0 } }, + { "LEICA", "R8 - Digital Back DMR", Fluorescent, 0, { 1.234985, 1, 1.791138, 0 } }, + { "LEICA", "R8 - Digital Back DMR", Daylight, 0, { 1.459961, 1, 1.184937, 0 } }, + { "LEICA", "R8 - Digital Back DMR", Flash, 0, { 1.395020, 1, 1.144897, 0 } }, + { "LEICA", "R8 - Digital Back DMR", Cloudy, 0, { 1.541992, 1, 1.052856, 0 } }, + { "LEICA", "R8 - Digital Back DMR", Shade, 0, { 1.644897, 1.033936, 1, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "2600K", 0, { 1, 1.220825, 2.999390, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "2700K", 0, { 1, 1.172607, 2.747192, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "2800K", 0, { 1, 1.129639, 2.527710, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "2900K", 0, { 1, 1.088867, 2.333130, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "3000K", 0, { 1, 1.049438, 2.156494, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "3100K", 0, { 1, 1.015503, 2.008423, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "3200K", 0, { 1.008789, 1, 1.904663, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "3300K", 0, { 1.032349, 1, 1.841187, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "3400K", 0, { 1.056763, 1, 1.780273, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "3500K", 0, { 1.081543, 1, 1.723755, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "3600K", 0, { 1.105591, 1, 1.673828, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "3700K", 0, { 1.128052, 1, 1.625732, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "3800K", 0, { 1.149536, 1, 1.580688, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "3900K", 0, { 1.170532, 1, 1.540527, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "4000K", 0, { 1.191040, 1, 1.504150, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "4100K", 0, { 1.209106, 1, 1.466919, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "4200K", 0, { 1.226807, 1, 1.433228, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "4300K", 0, { 1.244019, 1, 1.402466, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "4400K", 0, { 1.261108, 1, 1.374268, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "4500K", 0, { 1.276611, 1, 1.346924, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "4600K", 0, { 1.290771, 1, 1.320435, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "4700K", 0, { 1.304565, 1, 1.295898, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "4800K", 0, { 1.318115, 1, 1.273315, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "4900K", 0, { 1.331543, 1, 1.252441, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "5000K", 0, { 1.344360, 1, 1.233032, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "5200K", 0, { 1.365479, 1, 1.193970, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "5400K", 0, { 1.385498, 1, 1.160034, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "5600K", 0, { 1.404663, 1, 1.130127, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "5800K", 0, { 1.421387, 1, 1.102661, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "6000K", 0, { 1.435303, 1, 1.076782, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "6200K", 0, { 1.448608, 1, 1.053833, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "6400K", 0, { 1.461304, 1, 1.032959, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "6600K", 0, { 1.473511, 1, 1.014160, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "6800K", 0, { 1.488647, 1.003906, 1, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "7000K", 0, { 1.522705, 1.021118, 1, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "7200K", 0, { 1.555176, 1.037476, 1, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "7400K", 0, { 1.586182, 1.052979, 1, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "7600K", 0, { 1.615967, 1.067627, 1, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "7800K", 0, { 1.644409, 1.081665, 1, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "8000K", 0, { 1.671875, 1.094849, 1, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "8300K", 0, { 1.708740, 1.114624, 1, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "8600K", 0, { 1.743286, 1.133057, 1, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "8900K", 0, { 1.775879, 1.150269, 1, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "9200K", 0, { 1.806274, 1.166382, 1, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "9500K", 0, { 1.835449, 1.181519, 1, 0 } }, + { "LEICA", "R8 - Digital Back DMR", "9800K", 0, { 1.862793, 1.195801, 1, 0 } }, + + { "LEICA", "R9 - Digital Back DMR", Incandescent, 0, { 1, 1.109985, 2.430664, 0 } }, + { "LEICA", "R9 - Digital Back DMR", Fluorescent, 0, { 1.234985, 1, 1.791138, 0 } }, + { "LEICA", "R9 - Digital Back DMR", Daylight, 0, { 1.459961, 1, 1.184937, 0 } }, + { "LEICA", "R9 - Digital Back DMR", Flash, 0, { 1.395020, 1, 1.144897, 0 } }, + { "LEICA", "R9 - Digital Back DMR", Cloudy, 0, { 1.541992, 1, 1.052856, 0 } }, + { "LEICA", "R9 - Digital Back DMR", Shade, 0, { 1.644897, 1.033936, 1, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "2600K", 0, { 1, 1.220825, 2.999390, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "2700K", 0, { 1, 1.172607, 2.747192, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "2800K", 0, { 1, 1.129639, 2.527710, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "2900K", 0, { 1, 1.088867, 2.333130, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "3000K", 0, { 1, 1.049438, 2.156494, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "3100K", 0, { 1, 1.015503, 2.008423, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "3200K", 0, { 1.008789, 1, 1.904663, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "3300K", 0, { 1.032349, 1, 1.841187, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "3400K", 0, { 1.056763, 1, 1.780273, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "3500K", 0, { 1.081543, 1, 1.723755, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "3600K", 0, { 1.105591, 1, 1.673828, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "3700K", 0, { 1.128052, 1, 1.625732, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "3800K", 0, { 1.149536, 1, 1.580688, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "3900K", 0, { 1.170532, 1, 1.540527, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "4000K", 0, { 1.191040, 1, 1.504150, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "4100K", 0, { 1.209106, 1, 1.466919, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "4200K", 0, { 1.226807, 1, 1.433228, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "4300K", 0, { 1.244019, 1, 1.402466, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "4400K", 0, { 1.261108, 1, 1.374268, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "4500K", 0, { 1.276611, 1, 1.346924, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "4600K", 0, { 1.290771, 1, 1.320435, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "4700K", 0, { 1.304565, 1, 1.295898, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "4800K", 0, { 1.318115, 1, 1.273315, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "4900K", 0, { 1.331543, 1, 1.252441, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "5000K", 0, { 1.344360, 1, 1.233032, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "5200K", 0, { 1.365479, 1, 1.193970, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "5400K", 0, { 1.385498, 1, 1.160034, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "5600K", 0, { 1.404663, 1, 1.130127, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "5800K", 0, { 1.421387, 1, 1.102661, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "6000K", 0, { 1.435303, 1, 1.076782, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "6200K", 0, { 1.448608, 1, 1.053833, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "6400K", 0, { 1.461304, 1, 1.032959, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "6600K", 0, { 1.473511, 1, 1.014160, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "6800K", 0, { 1.488647, 1.003906, 1, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "7000K", 0, { 1.522705, 1.021118, 1, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "7200K", 0, { 1.555176, 1.037476, 1, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "7400K", 0, { 1.586182, 1.052979, 1, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "7600K", 0, { 1.615967, 1.067627, 1, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "7800K", 0, { 1.644409, 1.081665, 1, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "8000K", 0, { 1.671875, 1.094849, 1, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "8300K", 0, { 1.708740, 1.114624, 1, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "8600K", 0, { 1.743286, 1.133057, 1, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "8900K", 0, { 1.775879, 1.150269, 1, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "9200K", 0, { 1.806274, 1.166382, 1, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "9500K", 0, { 1.835449, 1.181519, 1, 0 } }, + { "LEICA", "R9 - Digital Back DMR", "9800K", 0, { 1.862793, 1.195801, 1, 0 } }, + + { "LEICA", "DIGILUX 2", Daylight, 0, { 1.628906, 1, 1.488281, 0 } }, + { "LEICA", "DIGILUX 2", Cloudy, 0, { 1.835938, 1, 1.343750, 0 } }, + { "LEICA", "DIGILUX 2", Incandescent, 0, { 1.078125, 1, 2.203125, 0 } }, + { "LEICA", "DIGILUX 2", Flash, 0, { 2.074219, 1, 1.304688, 0 } }, + { "LEICA", "DIGILUX 2", BlackNWhite, 0, { 1.632812, 1, 1.550781, 0 } }, + + { "LEICA", "DIGILUX 3", Daylight, 0, { 1.942966, 1, 1.399240, 0 } }, + { "LEICA", "DIGILUX 3", Cloudy, 0, { 2.083650, 1, 1.247148, 0 } }, + { "LEICA", "DIGILUX 3", Shade, 0, { 2.296578, 1, 1.110266, 0 } }, + { "LEICA", "DIGILUX 3", Incandescent, 0, { 1.372624, 1, 2.079848, 0 } }, + /* Flash multipliers are variable */ + { "LEICA", "DIGILUX 3", Flash, 0, { 2.095057, 1, 1.091255, 0 } }, + + /* Digilux 3 Kelvin presets */ + { "LEICA", "DIGILUX 3", "2500K", 0, { 1.178707, 1, 2.756654, 0 } }, + { "LEICA", "DIGILUX 3", "2600K", 0, { 1.212928, 1, 2.650190, 0 } }, + { "LEICA", "DIGILUX 3", "2700K", 0, { 1.250951, 1, 2.539924, 0 } }, + { "LEICA", "DIGILUX 3", "2800K", 0, { 1.285171, 1, 2.433460, 0 } }, + { "LEICA", "DIGILUX 3", "2900K", 0, { 1.323194, 1, 2.326996, 0 } }, + { "LEICA", "DIGILUX 3", "3000K", 0, { 1.361217, 1, 2.212928, 0 } }, + { "LEICA", "DIGILUX 3", "3100K", 0, { 1.391635, 1, 2.197719, 0 } }, + { "LEICA", "DIGILUX 3", "3200K", 0, { 1.429658, 1, 2.178707, 0 } }, + { "LEICA", "DIGILUX 3", "3300K", 0, { 1.471483, 1, 2.167300, 0 } }, + { "LEICA", "DIGILUX 3", "3400K", 0, { 1.509506, 1, 2.148289, 0 } }, + { "LEICA", "DIGILUX 3", "3500K", 0, { 1.547529, 1, 2.133080, 0 } }, + { "LEICA", "DIGILUX 3", "3600K", 0, { 1.574145, 1, 2.087453, 0 } }, + { "LEICA", "DIGILUX 3", "3800K", 0, { 1.631179, 1, 1.992395, 0 } }, + { "LEICA", "DIGILUX 3", "4000K", 0, { 1.684411, 1, 1.882129, 0 } }, + { "LEICA", "DIGILUX 3", "4200K", 0, { 1.733840, 1, 1.790875, 0 } }, + { "LEICA", "DIGILUX 3", "4400K", 0, { 1.790875, 1, 1.699620, 0 } }, + { "LEICA", "DIGILUX 3", "4600K", 0, { 1.821293, 1, 1.615970, 0 } }, + { "LEICA", "DIGILUX 3", "4800K", 0, { 1.832700, 1, 1.551331, 0 } }, + { "LEICA", "DIGILUX 3", "5000K", 0, { 1.851711, 1, 1.490494, 0 } }, + { "LEICA", "DIGILUX 3", "5300K", 0, { 1.889734, 1, 1.414449, 0 } }, + { "LEICA", "DIGILUX 3", "5500K", 0, { 1.923954, 1, 1.361217, 0 } }, + { "LEICA", "DIGILUX 3", "5800K", 0, { 1.954373, 1, 1.315589, 0 } }, + { "LEICA", "DIGILUX 3", "6000K", 0, { 1.977186, 1, 1.277567, 0 } }, + { "LEICA", "DIGILUX 3", "6300K", 0, { 2.049430, 1, 1.231939, 0 } }, + { "LEICA", "DIGILUX 3", "6500K", 0, { 2.102662, 1, 1.193916, 0 } }, + { "LEICA", "DIGILUX 3", "6800K", 0, { 2.155893, 1, 1.178707, 0 } }, + { "LEICA", "DIGILUX 3", "7300K", 0, { 2.254753, 1, 1.133080, 0 } }, + { "LEICA", "DIGILUX 3", "7800K", 0, { 2.319392, 1, 1.087452, 0 } }, + { "LEICA", "DIGILUX 3", "8300K", 0, { 2.365019, 1, 1.045627, 0 } }, + { "LEICA", "DIGILUX 3", "9000K", 0, { 2.429658, 1, 1.007605, 0 } }, + { "LEICA", "DIGILUX 3", "10000K", 0, { 2.680608, 1.057034, 1, 0 } }, + + { "LEICA", "D-LUX 6", Daylight, 0, { 1.992453, 1, 1.750943, 0 } }, + { "LEICA", "D-LUX 6", Cloudy, 0, { 2.143396, 1, 1.603774, 0 } }, + { "LEICA", "D-LUX 6", Shade, 0, { 2.286792, 1, 1.498113, 0 } }, + { "LEICA", "D-LUX 6", Flash, 0, { 2.219697, 1, 1.659091, 0 } }, + { "LEICA", "D-LUX 6", Incandescent, 0, { 1.335849, 1, 2.762264, 0 } }, + + { "MINOLTA", "DiMAGE 5", Daylight, 0, { 2.023438, 1, 1.371094, 0 } }, + { "MINOLTA", "DiMAGE 5", Incandescent, 0, { 1.113281, 1, 2.480469, 0 } }, + { "MINOLTA", "DiMAGE 5", Fluorescent, 0, { 1.957031, 1, 2.058594, 0 } }, + { "MINOLTA", "DiMAGE 5", Cloudy, 0, { 2.199219, 1, 1.300781, 0 } }, + + { "MINOLTA", "DiMAGE 7", Cloudy, 0, { 2.082031, 1, 1.226562, 0 } }, + { "MINOLTA", "DiMAGE 7", Daylight, 0, { 1.914062, 1, 1.527344, 0 } }, + { "MINOLTA", "DiMAGE 7", Fluorescent, 0, { 1.917969, 1, 2.007812, 0 } }, + { "MINOLTA", "DiMAGE 7", Tungsten, 0, { 1.050781, 1, 2.437500, 0 } }, + + { "MINOLTA", "DiMAGE 7i", Daylight, 0, { 1.441406, 1, 1.457031, 0 } }, + { "MINOLTA", "DiMAGE 7i", Tungsten, 0, { 1, 1.333333, 3.572917, 0 } }, + { "MINOLTA", "DiMAGE 7i", Fluorescent, 0, { 1.554688, 1, 2.230469, 0 } }, + { "MINOLTA", "DiMAGE 7i", Cloudy, 0, { 1.550781, 1, 1.402344, 0 } }, + + { "MINOLTA", "DiMAGE 7Hi", Daylight, 0, { 1.609375, 1, 1.328125, 0 } }, /*5500K*/ + { "MINOLTA", "DiMAGE 7Hi", Tungsten, 0, { 1, 1.137778, 2.768889, 0 } }, /*2800K*/ + { "MINOLTA", "DiMAGE 7Hi", WhiteFluorescent, 0, { 1.664062, 1, 2.105469, 0 } }, /*4060K*/ + { "MINOLTA", "DiMAGE 7Hi", CoolWhiteFluorescent, 0, { 1.796875, 1, 1.734375, 0 } }, /*4938K*/ + { "MINOLTA", "DiMAGE 7Hi", Cloudy, 0, { 1.730469, 1, 1.269531, 0 } }, /*5823K*/ + + { "MINOLTA", "DiMAGE A1", Daylight, 0, { 1.808594, 1, 1.304688, 0 } }, + { "MINOLTA", "DiMAGE A1", Tungsten, 0, { 1.062500, 1, 2.675781, 0 } }, + { "MINOLTA", "DiMAGE A1", Fluorescent, 0, { 1.707031, 1, 2.039063, 0 } }, + { "MINOLTA", "DiMAGE A1", Cloudy, 0, { 1.960938, 1, 1.339844, 0 } }, + { "MINOLTA", "DiMAGE A1", Shade, 0, { 2.253906, 1, 1.199219, 0 } }, + { "MINOLTA", "DiMAGE A1", Shade, 2, { 2.000000, 1, 1.183594, 0 } }, + { "MINOLTA", "DiMAGE A1", Flash, 0, { 1.972656, 1, 1.265625, 0 } }, + + { "MINOLTA", "DiMAGE A2", Cloudy, -3, { 2.109375, 1, 1.578125, 0 } }, + { "MINOLTA", "DiMAGE A2", Cloudy, 0, { 2.203125, 1, 1.296875, 0 } }, + { "MINOLTA", "DiMAGE A2", Cloudy, 3, { 2.296875, 1, 1.015625, 0 } }, + { "MINOLTA", "DiMAGE A2", Daylight, -3, { 1.867188, 1, 1.683594, 0 } }, + { "MINOLTA", "DiMAGE A2", Daylight, 0, { 1.960938, 1, 1.402344, 0 } }, + { "MINOLTA", "DiMAGE A2", Daylight, 3, { 2.054688, 1, 1.121094, 0 } }, + { "MINOLTA", "DiMAGE A2", Flash, -3, { 1.945312, 1, 1.613281, 0 } }, + { "MINOLTA", "DiMAGE A2", Flash, 0, { 2.039062, 1, 1.332031, 0 } }, + { "MINOLTA", "DiMAGE A2", Flash, 3, { 2.132812, 1, 1.050781, 0 } }, + { "MINOLTA", "DiMAGE A2", Fluorescent, -2, { 1.136719, 1, 2.746094, 0 } }, + { "MINOLTA", "DiMAGE A2", Fluorescent, 0, { 1.722656, 1, 2.132812, 0 } }, + { "MINOLTA", "DiMAGE A2", Fluorescent, 4, { 2.347656, 1, 1.535156, 0 } }, + { "MINOLTA", "DiMAGE A2", Shade, -3, { 2.273438, 1, 1.546875, 0 } }, + { "MINOLTA", "DiMAGE A2", Shade, 0, { 2.367188, 1, 1.265625, 0 } }, + { "MINOLTA", "DiMAGE A2", Shade, 3, { 2.500000, 1.015873, 1, 0 } }, + { "MINOLTA", "DiMAGE A2", Tungsten, -3, { 1.003906, 1, 3.164062, 0 } }, + { "MINOLTA", "DiMAGE A2", Tungsten, 0, { 1.097656, 1, 2.882812, 0 } }, + { "MINOLTA", "DiMAGE A2", Tungsten, 3, { 1.191406, 1, 2.601562, 0 } }, + + { "MINOLTA", "DiMAGE Z2", Daylight, 0, { 1.843749, 1, 1.664062, 0 } }, + { "MINOLTA", "DiMAGE Z2", Cloudy, 0, { 2.195312, 1, 1.449218, 0 } }, + { "MINOLTA", "DiMAGE Z2", Tungsten, 0, { 1.097656, 1, 3.050780, 0 } }, + { "MINOLTA", "DiMAGE Z2", Fluorescent, 0, { 1.796874, 1, 2.257810, 0 } }, + { "MINOLTA", "DiMAGE Z2", Flash, 0, { 2.117186, 1, 1.472656, 0 } }, + + { "MINOLTA", "DiMAGE G500", Daylight, 0, { 1.496094, 1, 1.121094, 0 } }, + { "MINOLTA", "DiMAGE G500", Cloudy, 0, { 1.527344, 1, 1.105469, 0 } }, + { "MINOLTA", "DiMAGE G500", Fluorescent, 0, { 1.382813, 1, 1.347656, 0 } }, + { "MINOLTA", "DiMAGE G500", Tungsten, 0, { 1.042969, 1, 1.859375, 0 } }, + { "MINOLTA", "DiMAGE G500", Flash, 0, { 1.647078, 1, 1.218159, 0 } }, + + { "MINOLTA", "DYNAX 5D", Daylight, -3, { 1.593750, 1, 1.875000, 0 } }, + { "MINOLTA", "DYNAX 5D", Daylight, -2, { 1.644531, 1, 1.792969, 0 } }, + { "MINOLTA", "DYNAX 5D", Daylight, -1, { 1.699219, 1, 1.718750, 0 } }, + { "MINOLTA", "DYNAX 5D", Daylight, 0, { 1.757812, 1, 1.636719, 0 } }, + { "MINOLTA", "DYNAX 5D", Daylight, 1, { 1.804688, 1, 1.566406, 0 } }, + { "MINOLTA", "DYNAX 5D", Daylight, 2, { 1.863281, 1, 1.500000, 0 } }, + { "MINOLTA", "DYNAX 5D", Daylight, 3, { 1.925781, 1, 1.437500, 0 } }, + { "MINOLTA", "DYNAX 5D", Shade, -3, { 1.835938, 1, 1.644531, 0 } }, + { "MINOLTA", "DYNAX 5D", Shade, -2, { 1.894531, 1, 1.574219, 0 } }, + { "MINOLTA", "DYNAX 5D", Shade, -1, { 1.957031, 1, 1.507812, 0 } }, + { "MINOLTA", "DYNAX 5D", Shade, 0, { 2.011719, 1, 1.433594, 0 } }, + { "MINOLTA", "DYNAX 5D", Shade, 1, { 2.078125, 1, 1.375000, 0 } }, + { "MINOLTA", "DYNAX 5D", Shade, 2, { 2.148438, 1, 1.316406, 0 } }, + { "MINOLTA", "DYNAX 5D", Shade, 3, { 2.218750, 1, 1.261719, 0 } }, + { "MINOLTA", "DYNAX 5D", Cloudy, -3, { 1.718750, 1, 1.738281, 0 } }, + { "MINOLTA", "DYNAX 5D", Cloudy, -2, { 1.773438, 1, 1.664062, 0 } }, + { "MINOLTA", "DYNAX 5D", Cloudy, -1, { 1.835938, 1, 1.593750, 0 } }, + { "MINOLTA", "DYNAX 5D", Cloudy, 0, { 1.886719, 1, 1.500000, 0 } }, + { "MINOLTA", "DYNAX 5D", Cloudy, 1, { 1.945312, 1, 1.460938, 0 } }, + { "MINOLTA", "DYNAX 5D", Cloudy, 2, { 2.007812, 1, 1.390625, 0 } }, + { "MINOLTA", "DYNAX 5D", Cloudy, 3, { 2.078125, 1, 1.332031, 0 } }, + { "MINOLTA", "DYNAX 5D", Tungsten, -3, { 1, 1.066667, 4.262500, 0 } }, + { "MINOLTA", "DYNAX 5D", Tungsten, -2, { 1, 1.032258, 3.951613, 0 } }, + { "MINOLTA", "DYNAX 5D", Tungsten, -1, { 1, 1.000000, 3.671875, 0 } }, + { "MINOLTA", "DYNAX 5D", Tungsten, 0, { 1.023438, 1, 3.496094, 0 } }, + { "MINOLTA", "DYNAX 5D", Tungsten, 1, { 1.062500, 1, 3.367188, 0 } }, + { "MINOLTA", "DYNAX 5D", Tungsten, 2, { 1.097656, 1, 3.203125, 0 } }, + { "MINOLTA", "DYNAX 5D", Tungsten, 3, { 1.132812, 1, 3.070312, 0 } }, + { "MINOLTA", "DYNAX 5D", Fluorescent, -2, { 1.148438, 1, 3.429688, 0 } }, + { "MINOLTA", "DYNAX 5D", Fluorescent, -1, { 1.285156, 1, 3.250000, 0 } }, + { "MINOLTA", "DYNAX 5D", Fluorescent, 0, { 1.703125, 1, 2.582031, 0 } }, + { "MINOLTA", "DYNAX 5D", Fluorescent, 1, { 1.761719, 1, 2.335938, 0 } }, + { "MINOLTA", "DYNAX 5D", Fluorescent, 2, { 1.730469, 1, 1.878906, 0 } }, + { "MINOLTA", "DYNAX 5D", Fluorescent, 3, { 1.996094, 1, 1.527344, 0 } }, + { "MINOLTA", "DYNAX 5D", Fluorescent, 4, { 2.218750, 1, 1.714844, 0 } }, + { "MINOLTA", "DYNAX 5D", Flash, -3, { 1.738281, 1, 1.683594, 0 } }, + { "MINOLTA", "DYNAX 5D", Flash, -2, { 1.792969, 1, 1.609375, 0 } }, + { "MINOLTA", "DYNAX 5D", Flash, -1, { 1.855469, 1, 1.542969, 0 } }, + { "MINOLTA", "DYNAX 5D", Flash, 0, { 1.917969, 1, 1.457031, 0 } }, + { "MINOLTA", "DYNAX 5D", Flash, 1, { 1.968750, 1, 1.406250, 0 } }, + { "MINOLTA", "DYNAX 5D", Flash, 2, { 2.031250, 1, 1.347656, 0 } }, + { "MINOLTA", "DYNAX 5D", Flash, 3, { 2.101562, 1, 1.289062, 0 } }, + + { "MINOLTA", "DYNAX 7D", Daylight, -3, { 1.476562, 1, 1.824219, 0 } }, + { "MINOLTA", "DYNAX 7D", Daylight, 0, { 1.621094, 1, 1.601562, 0 } }, + { "MINOLTA", "DYNAX 7D", Daylight, 3, { 1.785156, 1, 1.414062, 0 } }, + { "MINOLTA", "DYNAX 7D", Shade, -3, { 1.683594, 1, 1.585938, 0 } }, + { "MINOLTA", "DYNAX 7D", Shade, 0, { 1.855469, 1, 1.402344, 0 } }, + { "MINOLTA", "DYNAX 7D", Shade, 3, { 2.031250, 1, 1.226562, 0 } }, + { "MINOLTA", "DYNAX 7D", Cloudy, -3, { 1.593750, 1, 1.671875, 0 } }, + { "MINOLTA", "DYNAX 7D", Cloudy, 0, { 1.738281, 1, 1.464844, 0 } }, + { "MINOLTA", "DYNAX 7D", Cloudy, 3, { 1.925781, 1, 1.296875, 0 } }, + { "MINOLTA", "DYNAX 7D", Tungsten, -3, { 0.867188, 1, 3.765625, 0 } }, + { "MINOLTA", "DYNAX 7D", Tungsten, 0, { 0.945312, 1, 3.292969, 0 } }, + { "MINOLTA", "DYNAX 7D", Tungsten, 3, { 1.050781, 1, 2.921875, 0 } }, + { "MINOLTA", "DYNAX 7D", Fluorescent, -2, { 1.058594, 1, 3.230469, 0 } }, + { "MINOLTA", "DYNAX 7D", Fluorescent, 0, { 1.570312, 1, 2.453125, 0 } }, + { "MINOLTA", "DYNAX 7D", Fluorescent, 1, { 1.625000, 1, 2.226562, 0 } }, + { "MINOLTA", "DYNAX 7D", Fluorescent, 4, { 2.046875, 1, 1.675781, 0 } }, + { "MINOLTA", "DYNAX 7D", Flash, -3, { 1.738281, 1, 1.656250, 0 } }, + { "MINOLTA", "DYNAX 7D", Flash, 0, { 1.890625, 1, 1.445312, 0 } }, + { "MINOLTA", "DYNAX 7D", Flash, 3, { 2.101562, 1, 1.281250, 0 } }, + { "MINOLTA", "DYNAX 7D", "2500K", 0, { 1, 1.207547, 4.801887, 0 } }, + { "MINOLTA", "DYNAX 7D", "2600K", 0, { 1, 1.153153, 4.297297, 0 } }, + { "MINOLTA", "DYNAX 7D", "2700K", 0, { 1, 1.089362, 3.829787, 0 } }, + { "MINOLTA", "DYNAX 7D", "2800K", 0, { 1, 1.044898, 3.477551, 0 } }, + { "MINOLTA", "DYNAX 7D", "2900K", 0, { 1, 1.007874, 3.173228, 0 } }, + { "MINOLTA", "DYNAX 7D", "3000K", 0, { 1.031250, 1, 3.000000, 0 } }, + { "MINOLTA", "DYNAX 7D", "3100K", 0, { 1.066406, 1, 2.875000, 0 } }, + { "MINOLTA", "DYNAX 7D", "3200K", 0, { 1.109375, 1, 2.765625, 0 } }, + { "MINOLTA", "DYNAX 7D", "3300K", 0, { 1.144531, 1, 2.648438, 0 } }, + { "MINOLTA", "DYNAX 7D", "3400K", 0, { 1.175781, 1, 2.554688, 0 } }, + { "MINOLTA", "DYNAX 7D", "3500K", 0, { 1.207031, 1, 2.468750, 0 } }, + { "MINOLTA", "DYNAX 7D", "3600K", 0, { 1.242188, 1, 2.390625, 0 } }, + { "MINOLTA", "DYNAX 7D", "3700K", 0, { 1.277344, 1, 2.312500, 0 } }, + { "MINOLTA", "DYNAX 7D", "3800K", 0, { 1.304688, 1, 2.242188, 0 } }, + { "MINOLTA", "DYNAX 7D", "3900K", 0, { 1.339844, 1, 2.179688, 0 } }, + { "MINOLTA", "DYNAX 7D", "4000K", 0, { 1.363281, 1, 2.125000, 0 } }, + { "MINOLTA", "DYNAX 7D", "4100K", 0, { 1.390625, 1, 2.078125, 0 } }, + { "MINOLTA", "DYNAX 7D", "4200K", 0, { 1.421875, 1, 2.023438, 0 } }, + { "MINOLTA", "DYNAX 7D", "4300K", 0, { 1.445312, 1, 1.976562, 0 } }, + { "MINOLTA", "DYNAX 7D", "4400K", 0, { 1.476562, 1, 1.937500, 0 } }, + { "MINOLTA", "DYNAX 7D", "4500K", 0, { 1.500000, 1, 1.894531, 0 } }, + { "MINOLTA", "DYNAX 7D", "4600K", 0, { 1.527344, 1, 1.855469, 0 } }, + { "MINOLTA", "DYNAX 7D", "4700K", 0, { 1.542969, 1, 1.824219, 0 } }, + { "MINOLTA", "DYNAX 7D", "4800K", 0, { 1.566406, 1, 1.785156, 0 } }, + { "MINOLTA", "DYNAX 7D", "4900K", 0, { 1.593750, 1, 1.757812, 0 } }, + { "MINOLTA", "DYNAX 7D", "5000K", 0, { 1.609375, 1, 1.726562, 0 } }, + { "MINOLTA", "DYNAX 7D", "5100K", 0, { 1.636719, 1, 1.699219, 0 } }, + { "MINOLTA", "DYNAX 7D", "5200K", 0, { 1.656250, 1, 1.671875, 0 } }, + { "MINOLTA", "DYNAX 7D", "5300K", 0, { 1.671875, 1, 1.644531, 0 } }, + { "MINOLTA", "DYNAX 7D", "5400K", 0, { 1.691406, 1, 1.621094, 0 } }, + { "MINOLTA", "DYNAX 7D", "5500K", 0, { 1.710938, 1, 1.601562, 0 } }, + { "MINOLTA", "DYNAX 7D", "5600K", 0, { 1.726562, 1, 1.585938, 0 } }, + { "MINOLTA", "DYNAX 7D", "5700K", 0, { 1.757812, 1, 1.558594, 0 } }, + { "MINOLTA", "DYNAX 7D", "5800K", 0, { 1.765625, 1, 1.535156, 0 } }, + { "MINOLTA", "DYNAX 7D", "5900K", 0, { 1.785156, 1, 1.515625, 0 } }, + { "MINOLTA", "DYNAX 7D", "6000K", 0, { 1.792969, 1, 1.500000, 0 } }, + { "MINOLTA", "DYNAX 7D", "6100K", 0, { 1.812500, 1, 1.484375, 0 } }, + { "MINOLTA", "DYNAX 7D", "6200K", 0, { 1.835938, 1, 1.468750, 0 } }, + { "MINOLTA", "DYNAX 7D", "6300K", 0, { 1.843750, 1, 1.453125, 0 } }, + { "MINOLTA", "DYNAX 7D", "6400K", 0, { 1.863281, 1, 1.437500, 0 } }, + { "MINOLTA", "DYNAX 7D", "6500K", 0, { 1.875000, 1, 1.421875, 0 } }, + { "MINOLTA", "DYNAX 7D", "6600K", 0, { 1.894531, 1, 1.414062, 0 } }, + { "MINOLTA", "DYNAX 7D", "6700K", 0, { 1.914062, 1, 1.398438, 0 } }, + { "MINOLTA", "DYNAX 7D", "6800K", 0, { 1.925781, 1, 1.382812, 0 } }, + { "MINOLTA", "DYNAX 7D", "6900K", 0, { 1.937500, 1, 1.375000, 0 } }, + { "MINOLTA", "DYNAX 7D", "7000K", 0, { 1.945312, 1, 1.363281, 0 } }, + { "MINOLTA", "DYNAX 7D", "7100K", 0, { 1.957031, 1, 1.347656, 0 } }, + { "MINOLTA", "DYNAX 7D", "7200K", 0, { 1.976562, 1, 1.339844, 0 } }, + { "MINOLTA", "DYNAX 7D", "7300K", 0, { 1.988281, 1, 1.324219, 0 } }, + { "MINOLTA", "DYNAX 7D", "7400K", 0, { 2.000000, 1, 1.316406, 0 } }, + { "MINOLTA", "DYNAX 7D", "7500K", 0, { 2.007812, 1, 1.304688, 0 } }, + { "MINOLTA", "DYNAX 7D", "7600K", 0, { 2.023438, 1, 1.304688, 0 } }, + { "MINOLTA", "DYNAX 7D", "7700K", 0, { 2.031250, 1, 1.289062, 0 } }, + { "MINOLTA", "DYNAX 7D", "7800K", 0, { 2.046875, 1, 1.277344, 0 } }, + { "MINOLTA", "DYNAX 7D", "7900K", 0, { 2.054688, 1, 1.277344, 0 } }, + { "MINOLTA", "DYNAX 7D", "8000K", 0, { 2.062500, 1, 1.261719, 0 } }, + { "MINOLTA", "DYNAX 7D", "8100K", 0, { 2.085938, 1, 1.253906, 0 } }, + { "MINOLTA", "DYNAX 7D", "8200K", 0, { 2.085938, 1, 1.250000, 0 } }, + { "MINOLTA", "DYNAX 7D", "8300K", 0, { 2.101562, 1, 1.234375, 0 } }, + { "MINOLTA", "DYNAX 7D", "8400K", 0, { 2.109375, 1, 1.234375, 0 } }, + { "MINOLTA", "DYNAX 7D", "8500K", 0, { 2.125000, 1, 1.226562, 0 } }, + { "MINOLTA", "DYNAX 7D", "8600K", 0, { 2.132812, 1, 1.214844, 0 } }, + { "MINOLTA", "DYNAX 7D", "8700K", 0, { 2.132812, 1, 1.207031, 0 } }, + { "MINOLTA", "DYNAX 7D", "8800K", 0, { 2.148438, 1, 1.207031, 0 } }, + { "MINOLTA", "DYNAX 7D", "8900K", 0, { 2.156250, 1, 1.195312, 0 } }, + { "MINOLTA", "DYNAX 7D", "9000K", 0, { 2.171875, 1, 1.187500, 0 } }, + { "MINOLTA", "DYNAX 7D", "9100K", 0, { 2.179688, 1, 1.187500, 0 } }, + { "MINOLTA", "DYNAX 7D", "9200K", 0, { 2.179688, 1, 1.183594, 0 } }, + { "MINOLTA", "DYNAX 7D", "9300K", 0, { 2.195312, 1, 1.175781, 0 } }, + { "MINOLTA", "DYNAX 7D", "9400K", 0, { 2.203125, 1, 1.171875, 0 } }, + { "MINOLTA", "DYNAX 7D", "9500K", 0, { 2.218750, 1, 1.164062, 0 } }, + { "MINOLTA", "DYNAX 7D", "9600K", 0, { 2.218750, 1, 1.156250, 0 } }, + { "MINOLTA", "DYNAX 7D", "9700K", 0, { 2.226562, 1, 1.152344, 0 } }, + { "MINOLTA", "DYNAX 7D", "9800K", 0, { 2.226562, 1, 1.144531, 0 } }, + { "MINOLTA", "DYNAX 7D", "9900K", 0, { 2.242188, 1, 1.144531, 0 } }, + + // copied from NIKON 1 V1 + { "NIKON", "1 J1", Incandescent, 0, { 1.210938, 1, 2.308594, 0 } }, + { "NIKON", "1 J1", CoolWhiteFluorescent, 0, { 1.687500, 1, 2.199219, 0 } }, + { "NIKON", "1 J1", DirectSunlight, 0, { 1.828125, 1, 1.550781, 0 } }, + { "NIKON", "1 J1", Flash, 0, { 2.101563, 1, 1.335938, 0 } }, + { "NIKON", "1 J1", Cloudy, 0, { 1.960938, 1, 1.406250, 0 } }, + { "NIKON", "1 J1", Shade, 0, { 2.257813, 1, 1.277344, 0 } }, + + { "NIKON", "1 J3", Incandescent, 0, { 1.484375, 1, 2.308594, 0 } }, + { "NIKON", "1 J3", CoolWhiteFluorescent, 0, { 2.003906, 1, 2.160156, 0 } }, + { "NIKON", "1 J3", DirectSunlight, 0, { 2.269531, 1, 1.621094, 0 } }, + { "NIKON", "1 J3", Flash, 0, { 2.648438, 1, 1.390625, 0 } }, + { "NIKON", "1 J3", Cloudy, 0, { 2.394531, 1, 1.519531, 0 } }, + { "NIKON", "1 J3", Shade, 0, { 2.718750, 1, 1.382813, 0 } }, + { "NIKON", "1 J3", Underwater, 0, { 2.144531, 1, 1.660156, 0 } }, + + { "NIKON", "1 J5", Incandescent, 0, { 1.546875, 1, 2.171875, 0 } }, + { "NIKON", "1 J5", CoolWhiteFluorescent, 0, { 2.156250, 1, 1.949219, 0 } }, + { "NIKON", "1 J5", DirectSunlight, 0, { 2.316406, 1, 1.378906, 0 } }, + { "NIKON", "1 J5", Flash, 0, { 2.621094, 1, 1.167969, 0 } }, + { "NIKON", "1 J5", Cloudy, 0, { 2.460938, 1, 1.257813, 0 } }, + { "NIKON", "1 J5", Shade, 0, { 2.785156, 1, 1.125000, 0 } }, + + { "NIKON", "1 V1", Incandescent, 0, { 1.210938, 1, 2.308594, 0 } }, + { "NIKON", "1 V1", CoolWhiteFluorescent, 0, { 1.687500, 1, 2.199219, 0 } }, + { "NIKON", "1 V1", DirectSunlight, 0, { 1.828125, 1, 1.550781, 0 } }, + { "NIKON", "1 V1", Flash, 0, { 2.101563, 1, 1.335938, 0 } }, + { "NIKON", "1 V1", Cloudy, 0, { 1.960938, 1, 1.406250, 0 } }, + { "NIKON", "1 V1", Shade, 0, { 2.257813, 1, 1.277344, 0 } }, + + { "NIKON", "1 V3", Incandescent, 0, { 1.738281, 1, 2.679688, 0 } }, + { "NIKON", "1 V3", CoolWhiteFluorescent, 0, { 2.429688, 1, 2.406250, 0 } }, + { "NIKON", "1 V3", DirectSunlight, 0, { 2.722656, 1, 1.796875, 0 } }, + { "NIKON", "1 V3", Flash, 0, { 3.152344, 1, 1.562500, 0 } }, + { "NIKON", "1 V3", Cloudy, 0, { 2.910156, 1, 1.644531, 0 } }, + { "NIKON", "1 V3", Shade, 0, { 3.359375, 1, 1.507812, 0 } }, + + // NIKON COOLPIX P330 firmware 1.0 + { "NIKON", "COOLPIX P330", DirectSunlight, 0, { 1.792969, 1, 1.656250, 0 } }, + { "NIKON", "COOLPIX P330", Incandescent, 0, { 1.171875, 1, 2.730469, 0 } }, + { "NIKON", "COOLPIX P330", CoolWhiteFluorescent, 0, { 1.867188, 1, 2.421875, 0 } }, + { "NIKON", "COOLPIX P330", DayWhiteFluorescent, 0, { 1.812500, 1, 1.742188, 0 } }, + { "NIKON", "COOLPIX P330", DaylightFluorescent, 0, { 2.046875, 1, 1.390625, 0 } }, + { "NIKON", "COOLPIX P330", Cloudy, 0, { 1.929688, 1, 1.480469, 0 } }, + { "NIKON", "COOLPIX P330", Flash, 0, { 2.039063, 1, 1.578125, 0 } }, + + { "NIKON", "COOLPIX P340", DirectSunlight, 0, { 1.835938, 1, 1.632813, 0 } }, + { "NIKON", "COOLPIX P340", Incandescent, 0, { 1.199219, 1, 2.691406, 0 } }, + { "NIKON", "COOLPIX P340", CoolWhiteFluorescent, 0, { 1.914063, 1, 2.386719, 0 } }, + { "NIKON", "COOLPIX P340", DayWhiteFluorescent, 0, { 1.855469, 1, 1.718750, 0 } }, + { "NIKON", "COOLPIX P340", DaylightFluorescent, 0, { 2.093750, 1, 1.371094, 0 } }, + { "NIKON", "COOLPIX P340", Cloudy, 0, { 1.976563, 1, 1.457031, 0 } }, + { "NIKON", "COOLPIX P340", Flash, 0, { 2.085938, 1, 1.554688, 0 } }, + + // Fine tuning is from A6 to B6 on amber-blue. + { "NIKON", "COOLPIX P7100", DirectSunlight, -6, { 1.7908, 1, 1.9042, 0 } }, + { "NIKON", "COOLPIX P7100", DirectSunlight, 0, { 1.6500, 1, 2.1349, 0 } }, + { "NIKON", "COOLPIX P7100", DirectSunlight, 6, { 1.5171, 1, 2.3891, 0 } }, + { "NIKON", "COOLPIX P7100", Incandescent, -6, { 1.2708, 1, 3.0068, 0 } }, + { "NIKON", "COOLPIX P7100", Incandescent, 0, { 1.1730, 1, 3.3705, 0 } }, + { "NIKON", "COOLPIX P7100", Incandescent, 6, { 1.0753, 1, 3.7693, 0 } }, + { "NIKON", "COOLPIX P7100", CoolWhiteFluorescent, -6, { 2.0020, 1, 2.6158, 0 } }, + { "NIKON", "COOLPIX P7100", CoolWhiteFluorescent, 0, { 1.8456, 1, 2.9326, 0 } }, + { "NIKON", "COOLPIX P7100", CoolWhiteFluorescent, 6, { 1.6970, 1, 3.2805, 0 } }, + { "NIKON", "COOLPIX P7100", DayWhiteFluorescent, -6, { 1.9707, 1, 1.9003, 0 } }, + { "NIKON", "COOLPIX P7100", DayWhiteFluorescent, 0, { 1.8182, 1, 2.1310, 0 } }, + { "NIKON", "COOLPIX P7100", DayWhiteFluorescent, 6, { 1.6696, 1, 2.3812, 0 } }, + { "NIKON", "COOLPIX P7100", DaylightFluorescent, -6, { 2.3069, 1, 1.5601, 0 } }, + { "NIKON", "COOLPIX P7100", DaylightFluorescent, 0, { 2.1271, 1, 1.7517, 0 } }, + { "NIKON", "COOLPIX P7100", DaylightFluorescent, 6, { 1.9550, 1, 1.9589, 0 } }, + { "NIKON", "COOLPIX P7100", Cloudy, -6, { 1.9707, 1, 1.6540, 0 } }, + { "NIKON", "COOLPIX P7100", Cloudy, 0, { 1.8182, 1, 1.8534, 0 } }, + { "NIKON", "COOLPIX P7100", Cloudy, 6, { 1.6696, 1, 2.0723, 0 } }, + { "NIKON", "COOLPIX P7100", Flash, -6, { 2.3148, 1, 1.4780, 0 } }, + { "NIKON", "COOLPIX P7100", Flash, 0, { 2.1349, 1, 1.6579, 0 } }, + { "NIKON", "COOLPIX P7100", Flash, 6, { 1.9629, 1, 1.8534, 0 } }, + + { "NIKON", "D1", Incandescent, -3, { 1, 1.439891, 2.125769, 0 } }, + { "NIKON", "D1", Incandescent, 0, { 1, 1.582583, 2.556096, 0 } }, + { "NIKON", "D1", Incandescent, 3, { 1, 1.745033, 3.044175, 0 } }, + { "NIKON", "D1", Fluorescent, -3, { 1, 1.013461, 1.489820, 0 } }, + { "NIKON", "D1", Fluorescent, 0, { 1, 1.077710, 1.672660, 0 } }, + { "NIKON", "D1", Fluorescent, 3, { 1, 1.143167, 1.875227, 0 } }, + { "NIKON", "D1", DirectSunlight, -3, { 1.084705, 1.039344, 1, 0 } }, + { "NIKON", "D1", DirectSunlight, 0, { 1.000000, 1.000000, 1, 0 } }, + { "NIKON", "D1", DirectSunlight, 3, { 1, 1.049801, 1.109411, 0 } }, + { "NIKON", "D1", Flash, -3, { 1.317409, 1.116197, 1, 0 } }, + { "NIKON", "D1", Flash, 0, { 1.235772, 1.078231, 1, 0 } }, + { "NIKON", "D1", Flash, 3, { 1.100855, 1.016026, 1, 0 } }, + { "NIKON", "D1", Cloudy, -3, { 1.241160, 1.116197, 1, 0 } }, + { "NIKON", "D1", Cloudy, 0, { 1.162116, 1.078231, 1, 0 } }, + { "NIKON", "D1", Cloudy, 3, { 1.063923, 1.032573, 1, 0 } }, + { "NIKON", "D1", Shade, -3, { 1.361330, 1.191729, 1, 0 } }, + { "NIKON", "D1", Shade, 0, { 1.284963, 1.136201, 1, 0 } }, + { "NIKON", "D1", Shade, 3, { 1.205117, 1.096886, 1, 0 } }, + + { "NIKON", "D1H", Incandescent, -3, { 1.503906, 1, 1.832031, 0 } }, + { "NIKON", "D1H", Incandescent, 0, { 1.363281, 1, 1.996094, 0 } }, + { "NIKON", "D1H", Incandescent, 3, { 1.246094, 1, 2.148438, 0 } }, + { "NIKON", "D1H", Fluorescent, -3, { 2.546875, 1, 1.175781, 0 } }, + { "NIKON", "D1H", Fluorescent, 0, { 1.925781, 1, 2.054688, 0 } }, + { "NIKON", "D1H", Fluorescent, 3, { 1.234375, 1, 2.171875, 0 } }, + { "NIKON", "D1H", DirectSunlight, -3, { 2.230469, 1, 1.187500, 0 } }, + { "NIKON", "D1H", DirectSunlight, 0, { 2.148438, 1, 1.246094, 0 } }, + { "NIKON", "D1H", DirectSunlight, 3, { 2.066406, 1, 1.316406, 0 } }, + { "NIKON", "D1H", Flash, -3, { 2.453125, 1, 1.117188, 0 } }, + { "NIKON", "D1H", Flash, 0, { 2.347656, 1, 1.140625, 0 } }, + { "NIKON", "D1H", Flash, 3, { 2.242188, 1, 1.164062, 0 } }, + { "NIKON", "D1H", Cloudy, -3, { 2.441406, 1, 1.046875, 0 } }, + { "NIKON", "D1H", Cloudy, 0, { 2.300781, 1, 1.128906, 0 } }, + { "NIKON", "D1H", Cloudy, 3, { 2.207031, 1, 1.199219, 0 } }, + { "NIKON", "D1H", Shade, -3, { 2.839844, 1, 1.000000, 0 } }, + { "NIKON", "D1H", Shade, 0, { 2.628906, 1, 1.011719, 0 } }, + { "NIKON", "D1H", Shade, 3, { 2.441406, 1, 1.046875, 0 } }, + + { "NIKON", "D1X", Incandescent, -3, { 1.503906, 1, 1.832031, 0 } }, /*3250K*/ + { "NIKON", "D1X", Incandescent, -2, { 1.445312, 1, 1.890625, 0 } }, /*3150K*/ + { "NIKON", "D1X", Incandescent, -1, { 1.410156, 1, 1.937500, 0 } }, /*3100K*/ + { "NIKON", "D1X", Incandescent, 0, { 1.363281, 1, 1.996094, 0 } }, /*3000K*/ + { "NIKON", "D1X", Incandescent, 1, { 1.316406, 1, 2.042969, 0 } }, /*2900K*/ + { "NIKON", "D1X", Incandescent, 2, { 1.281250, 1, 2.101562, 0 } }, /*2800K*/ + { "NIKON", "D1X", Incandescent, 3, { 1.246094, 1, 2.148438, 0 } }, /*2700K*/ + { "NIKON", "D1X", Fluorescent, -3, { 2.546875, 1, 1.175781, 0 } }, /*7200K*/ + { "NIKON", "D1X", Fluorescent, -2, { 2.464844, 1, 1.210938, 0 } }, /*6500K*/ + { "NIKON", "D1X", Fluorescent, -1, { 2.160156, 1, 1.386719, 0 } }, /*5000K*/ + { "NIKON", "D1X", Fluorescent, 0, { 1.925781, 1, 2.054688, 0 } }, /*4200K*/ + { "NIKON", "D1X", Fluorescent, 1, { 1.703125, 1, 2.277344, 0 } }, /*3700K*/ + { "NIKON", "D1X", Fluorescent, 2, { 1.328125, 1, 2.394531, 0 } }, /*3000K*/ + { "NIKON", "D1X", Fluorescent, 3, { 1.234375, 1, 2.171875, 0 } }, /*2700K*/ + { "NIKON", "D1X", DirectSunlight, -3, { 2.230469, 1, 1.187500, 0 } }, /*5600K*/ + { "NIKON", "D1X", DirectSunlight, -2, { 2.207031, 1, 1.210938, 0 } }, /*5400K*/ + { "NIKON", "D1X", DirectSunlight, -1, { 2.171875, 1, 1.222656, 0 } }, /*5300K*/ + { "NIKON", "D1X", DirectSunlight, 0, { 2.148438, 1, 1.246094, 0 } }, /*5200K*/ + { "NIKON", "D1X", DirectSunlight, 1, { 2.113281, 1, 1.269531, 0 } }, /*5000K*/ + { "NIKON", "D1X", DirectSunlight, 2, { 2.089844, 1, 1.292969, 0 } }, /*4900K*/ + { "NIKON", "D1X", DirectSunlight, 3, { 2.066406, 1, 1.316406, 0 } }, /*4800K*/ + { "NIKON", "D1X", Flash, -3, { 2.453125, 1, 1.117188, 0 } }, /*6000K*/ + { "NIKON", "D1X", Flash, -2, { 2.417969, 1, 1.128906, 0 } }, /*5800K*/ + { "NIKON", "D1X", Flash, -1, { 2.382812, 1, 1.128906, 0 } }, /*5600K*/ + { "NIKON", "D1X", Flash, 0, { 2.347656, 1, 1.140625, 0 } }, /*5400K*/ + { "NIKON", "D1X", Flash, 1, { 2.312500, 1, 1.152344, 0 } }, /*5200K*/ + { "NIKON", "D1X", Flash, 2, { 2.277344, 1, 1.164062, 0 } }, /*5000K*/ + { "NIKON", "D1X", Flash, 3, { 2.242188, 1, 1.164062, 0 } }, /*4800K*/ + { "NIKON", "D1X", Cloudy, -3, { 2.441406, 1, 1.046875, 0 } }, /*6600K*/ + { "NIKON", "D1X", Cloudy, -2, { 2.394531, 1, 1.082031, 0 } }, /*6400K*/ + { "NIKON", "D1X", Cloudy, -1, { 2.347656, 1, 1.105469, 0 } }, /*6200K*/ + { "NIKON", "D1X", Cloudy, 0, { 2.300781, 1, 1.128906, 0 } }, /*6000K*/ + { "NIKON", "D1X", Cloudy, 1, { 2.253906, 1, 1.164062, 0 } }, /*5800K*/ + { "NIKON", "D1X", Cloudy, 2, { 2.230469, 1, 1.187500, 0 } }, /*5600K*/ + { "NIKON", "D1X", Cloudy, 3, { 2.207031, 1, 1.199219, 0 } }, /*5400K*/ + { "NIKON", "D1X", Shade, -3, { 2.839844, 1, 1.000000, 0 } }, /*9200K*/ + { "NIKON", "D1X", Shade, -2, { 2.769531, 1, 1.000000, 0 } }, /*8800K*/ + { "NIKON", "D1X", Shade, -1, { 2.699219, 1, 1.000000, 0 } }, /*8400K*/ + { "NIKON", "D1X", Shade, 0, { 2.628906, 1, 1.011719, 0 } }, /*8000K*/ + { "NIKON", "D1X", Shade, 1, { 2.558594, 1, 1.023438, 0 } }, /*7500K*/ + { "NIKON", "D1X", Shade, 2, { 2.500000, 1, 1.035156, 0 } }, /*7100K*/ + { "NIKON", "D1X", Shade, 3, { 2.441406, 1, 1.046875, 0 } }, /*6700K*/ + + /* + * D2X with firmware A 1.01 and B 1.01 + */ + + /* D2X basic + fine tune presets */ + { "NIKON", "D2X", Incandescent, -3, { 0.98462, 1, 2.61154, 0 } }, /*3300K*/ + { "NIKON", "D2X", Incandescent, -2, { 0.95880, 1, 2.71536, 0 } }, /*3200K*/ + { "NIKON", "D2X", Incandescent, -1, { 0.94465, 1, 2.77122, 0 } }, /*3100K*/ + { "NIKON", "D2X", Incandescent, 0, { 0.92086, 1, 2.89928, 0 } }, /*3000K*/ + { "NIKON", "D2X", Incandescent, 1, { 0.89510, 1, 3.03846, 0 } }, /*2900K*/ + { "NIKON", "D2X", Incandescent, 2, { 0.86486, 1, 3.17905, 0 } }, /*2800K*/ + { "NIKON", "D2X", Incandescent, 3, { 0.83388, 1, 3.34528, 0 } }, /*2700K*/ + { "NIKON", "D2X", Fluorescent, -3, { 2.01562, 1, 1.72266, 0 } }, /*7200K*/ + { "NIKON", "D2X", Fluorescent, -2, { 1.67969, 1, 1.42578, 0 } }, /*6500K*/ + { "NIKON", "D2X", Fluorescent, -1, { 1.42969, 1, 1.80078, 0 } }, /*5000K*/ + { "NIKON", "D2X", Fluorescent, 0, { 1.42969, 1, 2.62891, 0 } }, /*4200K*/ + { "NIKON", "D2X", Fluorescent, 1, { 1.13672, 1, 3.02734, 0 } }, /*3700K*/ + { "NIKON", "D2X", Fluorescent, 2, { 0.94118, 1, 2.68498, 0 } }, /*3000K*/ + { "NIKON", "D2X", Fluorescent, 3, { 0.83388, 1, 3.51140, 0 } }, /*2700K*/ + { "NIKON", "D2X", DirectSunlight, -3, { 1.61328, 1, 1.61328, 0 } }, /*5600K*/ + { "NIKON", "D2X", DirectSunlight, -2, { 1.57031, 1, 1.65234, 0 } }, /*5400K*/ + { "NIKON", "D2X", DirectSunlight, -1, { 1.55078, 1, 1.67578, 0 } }, /*5300K*/ + { "NIKON", "D2X", DirectSunlight, 0, { 1.52734, 1, 1.69531, 0 } }, /*5200K*/ + { "NIKON", "D2X", DirectSunlight, 1, { 1.48438, 1, 1.74609, 0 } }, /*5000K*/ + { "NIKON", "D2X", DirectSunlight, 2, { 1.45312, 1, 1.76953, 0 } }, /*4900K*/ + { "NIKON", "D2X", DirectSunlight, 3, { 1.42578, 1, 1.78906, 0 } }, /*4800K*/ + { "NIKON", "D2X", Flash, -3, { 1.71484, 1, 1.48438, 0 } }, /*6000K*/ + { "NIKON", "D2X", Flash, -2, { 1.67578, 1, 1.48438, 0 } }, /*5800K*/ + { "NIKON", "D2X", Flash, -1, { 1.66797, 1, 1.50781, 0 } }, /*5600K*/ + { "NIKON", "D2X", Flash, 0, { 1.66016, 1, 1.53125, 0 } }, /*5400K*/ + { "NIKON", "D2X", Flash, 1, { 1.64453, 1, 1.54297, 0 } }, /*5200K*/ + { "NIKON", "D2X", Flash, 2, { 1.62891, 1, 1.54297, 0 } }, /*5000K*/ + { "NIKON", "D2X", Flash, 3, { 1.57031, 1, 1.56641, 0 } }, /*4800K*/ + { "NIKON", "D2X", Cloudy, -3, { 1.79297, 1, 1.46875, 0 } }, /*6600K*/ + { "NIKON", "D2X", Cloudy, -2, { 1.76172, 1, 1.49219, 0 } }, /*6400K*/ + { "NIKON", "D2X", Cloudy, -1, { 1.72656, 1, 1.51953, 0 } }, /*6200K*/ + { "NIKON", "D2X", Cloudy, 0, { 1.69141, 1, 1.54688, 0 } }, /*6000K*/ + { "NIKON", "D2X", Cloudy, 1, { 1.65234, 1, 1.57812, 0 } }, /*5800K*/ + { "NIKON", "D2X", Cloudy, 2, { 1.61328, 1, 1.61328, 0 } }, /*5600K*/ + { "NIKON", "D2X", Cloudy, 3, { 1.57031, 1, 1.65234, 0 } }, /*5400K*/ + { "NIKON", "D2X", Shade, -3, { 2.10938, 1, 1.23828, 0 } }, /*9200K*/ + { "NIKON", "D2X", Shade, -2, { 2.07031, 1, 1.26562, 0 } }, /*8800K*/ + { "NIKON", "D2X", Shade, -1, { 2.02734, 1, 1.29688, 0 } }, /*8400K*/ + { "NIKON", "D2X", Shade, 0, { 1.98047, 1, 1.32812, 0 } }, /*8000K*/ + { "NIKON", "D2X", Shade, 1, { 1.92188, 1, 1.37109, 0 } }, /*7500K*/ + { "NIKON", "D2X", Shade, 2, { 1.86719, 1, 1.41406, 0 } }, /*7100K*/ + { "NIKON", "D2X", Shade, 3, { 1.80859, 1, 1.45703, 0 } }, /*6700K*/ + + /* D2X Kelvin presets */ + { "NIKON", "D2X", "2500K", 0, { 0.74203, 1, 3.67536, 0 } }, + { "NIKON", "D2X", "2550K", 0, { 0.76877, 1, 3.58859, 0 } }, + { "NIKON", "D2X", "2650K", 0, { 0.81529, 1, 3.42675, 0 } }, + { "NIKON", "D2X", "2700K", 0, { 0.83388, 1, 3.34528, 0 } }, + { "NIKON", "D2X", "2800K", 0, { 0.86486, 1, 3.17905, 0 } }, + { "NIKON", "D2X", "2850K", 0, { 0.87973, 1, 3.10309, 0 } }, + { "NIKON", "D2X", "2950K", 0, { 0.90780, 1, 2.96454, 0 } }, + { "NIKON", "D2X", "3000K", 0, { 0.92086, 1, 2.89928, 0 } }, + { "NIKON", "D2X", "3100K", 0, { 0.94465, 1, 2.77122, 0 } }, + { "NIKON", "D2X", "3200K", 0, { 0.96970, 1, 2.65530, 0 } }, + { "NIKON", "D2X", "3300K", 0, { 0.99611, 1, 2.55642, 0 } }, + { "NIKON", "D2X", "3400K", 0, { 1.01953, 1, 2.46484, 0 } }, + { "NIKON", "D2X", "3600K", 0, { 1.07422, 1, 2.34375, 0 } }, + { "NIKON", "D2X", "3700K", 0, { 1.09766, 1, 2.26172, 0 } }, + { "NIKON", "D2X", "3800K", 0, { 1.12500, 1, 2.18750, 0 } }, + { "NIKON", "D2X", "4000K", 0, { 1.17969, 1, 2.06250, 0 } }, + { "NIKON", "D2X", "4200K", 0, { 1.24219, 1, 1.96094, 0 } }, + { "NIKON", "D2X", "4300K", 0, { 1.27344, 1, 1.91797, 0 } }, + { "NIKON", "D2X", "4500K", 0, { 1.33594, 1, 1.83984, 0 } }, + { "NIKON", "D2X", "4800K", 0, { 1.42578, 1, 1.78906, 0 } }, + { "NIKON", "D2X", "5000K", 0, { 1.48438, 1, 1.74609, 0 } }, + { "NIKON", "D2X", "5300K", 0, { 1.55078, 1, 1.67578, 0 } }, + { "NIKON", "D2X", "5600K", 0, { 1.61328, 1, 1.61328, 0 } }, + { "NIKON", "D2X", "5900K", 0, { 1.67188, 1, 1.56250, 0 } }, + { "NIKON", "D2X", "6300K", 0, { 1.74219, 1, 1.50391, 0 } }, + { "NIKON", "D2X", "6700K", 0, { 1.80859, 1, 1.45703, 0 } }, + { "NIKON", "D2X", "7100K", 0, { 1.86719, 1, 1.41406, 0 } }, + { "NIKON", "D2X", "7700K", 0, { 1.94531, 1, 1.35547, 0 } }, + { "NIKON", "D2X", "8300K", 0, { 2.01562, 1, 1.30469, 0 } }, + { "NIKON", "D2X", "9100K", 0, { 2.09766, 1, 1.24609, 0 } }, + { "NIKON", "D2X", "10000K", 0, { 2.17578, 1, 1.18359, 0 } }, + + { "NIKON", "D3", Daylight, 0, { 1.81640, 1, 1.35546, 0 } }, + { "NIKON", "D3", Flash, 0, { 2.03906, 1, 1.17187, 0 } }, + { "NIKON", "D3", Cloudy, 0, { 1.94921, 1, 1.22265, 0 } }, + { "NIKON", "D3", Shade, 0, { 2.24609, 1, 1.08593, 0 } }, + { "NIKON", "D3", Incandescent, 0, { 1.16796, 1, 2.31640, 0 } }, + { "NIKON", "D3", Fluorescent, 0, { 1.68750, 1, 2.10156, 0 } }, + { "NIKON", "D3", "2500K", 0, { 1.00390, 1, 3.00000, 0 } }, + { "NIKON", "D3", "2560K", 0, { 1.02343, 1, 2.89062, 0 } }, + { "NIKON", "D3", "2630K", 0, { 1.04296, 1, 2.78125, 0 } }, + { "NIKON", "D3", "2700K", 0, { 1.06640, 1, 2.67968, 0 } }, + { "NIKON", "D3", "2780K", 0, { 1.09375, 1, 2.57812, 0 } }, + { "NIKON", "D3", "2860K", 0, { 1.11718, 1, 2.47656, 0 } }, + { "NIKON", "D3", "2940K", 0, { 1.14843, 1, 2.38281, 0 } }, + { "NIKON", "D3", "3000K", 0, { 1.16796, 1, 2.31640, 0 } }, + { "NIKON", "D3", "3030K", 0, { 1.17578, 1, 2.28906, 0 } }, + { "NIKON", "D3", "3130K", 0, { 1.20703, 1, 2.19921, 0 } }, + { "NIKON", "D3", "3230K", 0, { 1.24218, 1, 2.10937, 0 } }, + { "NIKON", "D3", "3330K", 0, { 1.27734, 1, 2.02343, 0 } }, + { "NIKON", "D3", "3450K", 0, { 1.31350, 1, 1.94140, 0 } }, + { "NIKON", "D3", "3570K", 0, { 1.35156, 1, 1.85937, 0 } }, + { "NIKON", "D3", "3700K", 0, { 1.39062, 1, 1.78125, 0 } }, + { "NIKON", "D3", "3850K", 0, { 1.43359, 1, 1.70703, 0 } }, + { "NIKON", "D3", "4000K", 0, { 1.47656, 1, 1.63281, 0 } }, + { "NIKON", "D3", "4170K", 0, { 1.52343, 1, 1.56640, 0 } }, + { "NIKON", "D3", "4350K", 0, { 1.60156, 1, 1.55078, 0 } }, + { "NIKON", "D3", "4550K", 0, { 1.66406, 1, 1.51562, 0 } }, + { "NIKON", "D3", "4760K", 0, { 1.72265, 1, 1.46093, 0 } }, + { "NIKON", "D3", "5000K", 0, { 1.77734, 1, 1.40234, 0 } }, + { "NIKON", "D3", "5200K", 0, { 1.81640, 1, 1.35546, 0 } }, + { "NIKON", "D3", "5260K", 0, { 1.82812, 1, 1.34375, 0 } }, + { "NIKON", "D3", "5560K", 0, { 1.87890, 1, 1.28515, 0 } }, + { "NIKON", "D3", "5880K", 0, { 1.93359, 1, 1.23437, 0 } }, + { "NIKON", "D3", "6000K", 0, { 1.94921, 1, 1.22265, 0 } }, + { "NIKON", "D3", "6250K", 0, { 1.99218, 1, 1.19140, 0 } }, + { "NIKON", "D3", "6400K", 0, { 2.03906, 1, 1.17187, 0 } }, + { "NIKON", "D3", "6670K", 0, { 2.05468, 1, 1.15625, 0 } }, + { "NIKON", "D3", "7140K", 0, { 2.12500, 1, 1.12500, 0 } }, + { "NIKON", "D3", "7690K", 0, { 2.20312, 1, 1.09765, 0 } }, + { "NIKON", "D3", "8000K", 0, { 2.24609, 1, 1.08593, 0 } }, + { "NIKON", "D3", "8330K", 0, { 2.28906, 1, 1.07031, 0 } }, + { "NIKON", "D3", "9090K", 0, { 2.38281, 1, 1.03515, 0 } }, + { "NIKON", "D3", "10000K", 0, { 2.48046, 1, 1.00000, 0 } }, + + { "NIKON", "D3S", Incandescent, 0, { 1.191406, 1, 2.242188, 0 } }, + { "NIKON", "D3S", SodiumVaporFluorescent, 0, { 1.132812, 1, 2.511719, 0 } }, + { "NIKON", "D3S", WarmWhiteFluorescent, 0, { 1.179688, 1, 1.996094, 0 } }, + { "NIKON", "D3S", WhiteFluorescent, 0, { 1.394531, 1, 2.402344, 0 } }, + { "NIKON", "D3S", CoolWhiteFluorescent, 0, { 1.703125, 1, 2.066406, 0 } }, + { "NIKON", "D3S", DayWhiteFluorescent, 0, { 1.710938, 1, 1.390625, 0 } }, + { "NIKON", "D3S", DaylightFluorescent, 0, { 1.941406, 1, 1.113281, 0 } }, + { "NIKON", "D3S", HighTempMercuryVaporFluorescent, 0, { 2.289062, 1, 1.355469, 0 } }, + { "NIKON", "D3S", DirectSunlight, 0, { 1.835938, 1, 1.359375, 0 } }, + { "NIKON", "D3S", Flash, 0, { 2.035156, 1, 1.183594, 0 } }, + { "NIKON", "D3S", Cloudy, 0, { 1.964844, 1, 1.226562, 0 } }, + { "NIKON", "D3S", Shade, 0, { 2.253906, 1, 1.089844, 0 } }, + { "NIKON", "D3S", "2500K", 0, { 1.031250, 1, 2.851562, 0 } }, + { "NIKON", "D3S", "2560K", 0, { 1.050781, 1, 2.753906, 0 } }, + { "NIKON", "D3S", "2630K", 0, { 1.070312, 1, 2.656250, 0 } }, + { "NIKON", "D3S", "2700K", 0, { 1.093750, 1, 2.558594, 0 } }, + { "NIKON", "D3S", "2780K", 0, { 1.117188, 1, 2.468750, 0 } }, + { "NIKON", "D3S", "2860K", 0, { 1.144531, 1, 2.382812, 0 } }, + { "NIKON", "D3S", "2940K", 0, { 1.171875, 1, 2.300781, 0 } }, + { "NIKON", "D3S", "3030K", 0, { 1.199219, 1, 2.214844, 0 } }, + { "NIKON", "D3S", "3130K", 0, { 1.230469, 1, 2.125000, 0 } }, + { "NIKON", "D3S", "3230K", 0, { 1.265625, 1, 2.050781, 0 } }, + { "NIKON", "D3S", "3330K", 0, { 1.296875, 1, 1.984375, 0 } }, + { "NIKON", "D3S", "3450K", 0, { 1.335938, 1, 1.921875, 0 } }, + { "NIKON", "D3S", "3570K", 0, { 1.375000, 1, 1.843750, 0 } }, + { "NIKON", "D3S", "3700K", 0, { 1.414062, 1, 1.769531, 0 } }, + { "NIKON", "D3S", "3850K", 0, { 1.453125, 1, 1.695312, 0 } }, + { "NIKON", "D3S", "4000K", 0, { 1.500000, 1, 1.628906, 0 } }, + { "NIKON", "D3S", "4170K", 0, { 1.542969, 1, 1.562500, 0 } }, + { "NIKON", "D3S", "4350K", 0, { 1.621094, 1, 1.550781, 0 } }, + { "NIKON", "D3S", "4550K", 0, { 1.687500, 1, 1.511719, 0 } }, + { "NIKON", "D3S", "4760K", 0, { 1.742188, 1, 1.460938, 0 } }, + { "NIKON", "D3S", "5000K", 0, { 1.796875, 1, 1.402344, 0 } }, + { "NIKON", "D3S", "5260K", 0, { 1.847656, 1, 1.343750, 0 } }, + { "NIKON", "D3S", "5560K", 0, { 1.894531, 1, 1.292969, 0 } }, + { "NIKON", "D3S", "5880K", 0, { 1.949219, 1, 1.242188, 0 } }, + { "NIKON", "D3S", "6250K", 0, { 2.003906, 1, 1.199219, 0 } }, + { "NIKON", "D3S", "6670K", 0, { 2.066406, 1, 1.160156, 0 } }, + { "NIKON", "D3S", "7140K", 0, { 2.140625, 1, 1.132812, 0 } }, + { "NIKON", "D3S", "7690K", 0, { 2.214844, 1, 1.101562, 0 } }, + { "NIKON", "D3S", "8330K", 0, { 2.292969, 1, 1.070312, 0 } }, + { "NIKON", "D3S", "9090K", 0, { 2.390625, 1, 1.046875, 0 } }, + { "NIKON", "D3S", "10000K", 0, { 2.492188, 1, 1.003906, 0 } }, + + /* D3X with firmware A 1.00 and B 1.01 */ + { "NIKON", "D3X", Incandescent, -4, { 1.441406, 1, 2.125000, 0 } }, + { "NIKON", "D3X", Incandescent, -3, { 1.421875, 1, 2.167969, 0 } }, + { "NIKON", "D3X", Incandescent, -2, { 1.402344, 1, 2.210938, 0 } }, + { "NIKON", "D3X", Incandescent, -1, { 1.382813, 1, 2.250000, 0 } }, + { "NIKON", "D3X", Incandescent, 0, { 1.367188, 1, 2.292969, 0 } }, + { "NIKON", "D3X", Incandescent, 1, { 1.351563, 1, 2.332031, 0 } }, + { "NIKON", "D3X", Incandescent, 2, { 1.332031, 1, 2.371093, 0 } }, + { "NIKON", "D3X", Incandescent, 3, { 1.316406, 1, 2.414063, 0 } }, + { "NIKON", "D3X", Incandescent, 4, { 1.300781, 1, 2.457031, 0 } }, + { "NIKON", "D3X", Fluorescent, -4, { 2.183594, 1, 1.980469, 0 } }, + { "NIKON", "D3X", Fluorescent, -3, { 2.136719, 1, 2.015625, 0 } }, + { "NIKON", "D3X", Fluorescent, -2, { 2.089844, 1, 2.054688, 0 } }, + { "NIKON", "D3X", Fluorescent, -1, { 2.039064, 1, 2.089844, 0 } }, + { "NIKON", "D3X", Fluorescent, 0, { 1.984375, 1, 2.128906, 0 } }, + { "NIKON", "D3X", Fluorescent, 1, { 1.929688, 1, 2.167969, 0 } }, + { "NIKON", "D3X", Fluorescent, 2, { 1.875000, 1, 2.207031, 0 } }, + { "NIKON", "D3X", Fluorescent, 3, { 1.816406, 1, 2.246094, 0 } }, + { "NIKON", "D3X", Fluorescent, 4, { 1.753906, 1, 2.292969, 0 } }, + { "NIKON", "D3X", DirectSunlight, -4, { 2.289063, 1, 1.308594, 0 } }, + { "NIKON", "D3X", DirectSunlight, -3, { 2.253906, 1, 1.335938, 0 } }, + { "NIKON", "D3X", DirectSunlight, -2, { 2.222656, 1, 1.359375, 0 } }, + { "NIKON", "D3X", DirectSunlight, -1, { 2.187500, 1, 1.386719, 0 } }, + { "NIKON", "D3X", DirectSunlight, 0, { 2.156250, 1, 1.417969, 0 } }, + { "NIKON", "D3X", DirectSunlight, 1, { 2.125000, 1, 1.445313, 0 } }, + { "NIKON", "D3X", DirectSunlight, 2, { 2.093750, 1, 1.472656, 0 } }, + { "NIKON", "D3X", DirectSunlight, 3, { 2.062500, 1, 1.496094, 0 } }, + { "NIKON", "D3X", DirectSunlight, 4, { 2.027344, 1, 1.519531, 0 } }, + { "NIKON", "D3X", Flash, -4, { 2.566406, 1, 1.183594, 0 } }, + { "NIKON", "D3X", Flash, -3, { 2.523438, 1, 1.199219, 0 } }, + { "NIKON", "D3X", Flash, -2, { 2.484375, 1, 1.214844, 0 } }, + { "NIKON", "D3X", Flash, -1, { 2.445313, 1, 1.226563, 0 } }, + { "NIKON", "D3X", Flash, 0, { 2.402344, 1, 1.242187, 0 } }, + { "NIKON", "D3X", Flash, 1, { 2.371094, 1, 1.257813, 0 } }, + { "NIKON", "D3X", Flash, 2, { 2.343750, 1, 1.273438, 0 } }, + { "NIKON", "D3X", Flash, 3, { 2.320313, 1, 1.292969, 0 } }, + { "NIKON", "D3X", Flash, 4, { 2.289063, 1, 1.308594, 0 } }, + { "NIKON", "D3X", Cloudy, -4, { 2.488281, 1, 1.214844, 0 } }, + { "NIKON", "D3X", Cloudy, -3, { 2.445313, 1, 1.230469, 0 } }, + { "NIKON", "D3X", Cloudy, -2, { 2.406250, 1, 1.250000, 0 } }, + { "NIKON", "D3X", Cloudy, -1, { 2.363281, 1, 1.265625, 0 } }, + { "NIKON", "D3X", Cloudy, 0, { 2.328125, 1, 1.289062, 0 } }, + { "NIKON", "D3X", Cloudy, 1, { 2.289063, 1, 1.308594, 0 } }, + { "NIKON", "D3X", Cloudy, 2, { 2.253906, 1, 1.335938, 0 } }, + { "NIKON", "D3X", Cloudy, 3, { 2.222656, 1, 1.359375, 0 } }, + { "NIKON", "D3X", Cloudy, 4, { 2.187500, 1, 1.386719, 0 } }, + { "NIKON", "D3X", Shade, -4, { 2.937500, 1, 1.089844, 0 } }, + { "NIKON", "D3X", Shade, -3, { 2.878906, 1, 1.113281, 0 } }, + { "NIKON", "D3X", Shade, -2, { 2.820313, 1, 1.128906, 0 } }, + { "NIKON", "D3X", Shade, -1, { 2.761719, 1, 1.144531, 0 } }, + { "NIKON", "D3X", Shade, 0, { 2.707031, 1, 1.160156, 0 } }, + { "NIKON", "D3X", Shade, 1, { 2.652344, 1, 1.171875, 0 } }, + { "NIKON", "D3X", Shade, 2, { 2.601563, 1, 1.183594, 0 } }, + { "NIKON", "D3X", Shade, 3, { 2.554688, 1, 1.199219, 0 } }, + { "NIKON", "D3X", Shade, 4, { 2.507813, 1, 1.210938, 0 } }, + + /* D3X Kelvin presets */ + { "NIKON", "D3X", "2500K", 0, { 1.179688, 1, 2.898438, 0 } }, + { "NIKON", "D3X", "2560K", 0, { 1.203125, 1, 2.796875, 0 } }, + { "NIKON", "D3X", "2630K", 0, { 1.226563, 1, 2.699219, 0 } }, + { "NIKON", "D3X", "2700K", 0, { 1.253906, 1, 2.605469, 0 } }, + { "NIKON", "D3X", "2780K", 0, { 1.281250, 1, 2.519531, 0 } }, + { "NIKON", "D3X", "2860K", 0, { 1.312500, 1, 2.429688, 0 } }, + { "NIKON", "D3X", "2940K", 0, { 1.343750, 1, 2.347656, 0 } }, + { "NIKON", "D3X", "3030K", 0, { 1.378906, 1, 2.269531, 0 } }, + { "NIKON", "D3X", "3130K", 0, { 1.414063, 1, 2.187500, 0 } }, + { "NIKON", "D3X", "3230K", 0, { 1.453125, 1, 2.097656, 0 } }, + { "NIKON", "D3X", "3330K", 0, { 1.492187, 1, 2.015625, 0 } }, + { "NIKON", "D3X", "3450K", 0, { 1.539062, 1, 1.933594, 0 } }, + { "NIKON", "D3X", "3570K", 0, { 1.585937, 1, 1.859375, 0 } }, + { "NIKON", "D3X", "3700K", 0, { 1.636719, 1, 1.792969, 0 } }, + { "NIKON", "D3X", "3850K", 0, { 1.695312, 1, 1.734375, 0 } }, + { "NIKON", "D3X", "4000K", 0, { 1.753906, 1, 1.683594, 0 } }, + { "NIKON", "D3X", "4170K", 0, { 1.824219, 1, 1.636719, 0 } }, + { "NIKON", "D3X", "4350K", 0, { 1.902344, 1, 1.593750, 0 } }, + { "NIKON", "D3X", "4550K", 0, { 1.976562, 1, 1.554687, 0 } }, + { "NIKON", "D3X", "4760K", 0, { 2.042969, 1, 1.511719, 0 } }, + { "NIKON", "D3X", "5000K", 0, { 2.105469, 1, 1.460938, 0 } }, + { "NIKON", "D3X", "5260K", 0, { 2.167969, 1, 1.406250, 0 } }, + { "NIKON", "D3X", "5560K", 0, { 2.234375, 1, 1.351563, 0 } }, + { "NIKON", "D3X", "5880K", 0, { 2.304688, 1, 1.300781, 0 } }, + { "NIKON", "D3X", "6250K", 0, { 2.378906, 1, 1.257813, 0 } }, + { "NIKON", "D3X", "6670K", 0, { 2.464844, 1, 1.226562, 0 } }, + { "NIKON", "D3X", "7140K", 0, { 2.554687, 1, 1.199219, 0 } }, + { "NIKON", "D3X", "7690K", 0, { 2.652344, 1, 1.171875, 0 } }, + { "NIKON", "D3X", "8330K", 0, { 2.761719, 1, 1.144531, 0 } }, + { "NIKON", "D3X", "9090K", 0, { 2.878906, 1, 1.113281, 0 } }, + { "NIKON", "D3X", "10000K", 0, { 3.000000, 1, 1.062500, 0 } }, + + { "NIKON", "D4", Incandescent, 0, { 1.281250, 1, 2.371094, 0 } }, + { "NIKON", "D4", SodiumVaporFluorescent, 0, { 1.195313, 1, 2.589844, 0 } }, + { "NIKON", "D4", WarmWhiteFluorescent, 0, { 1.277344, 1, 2.109375, 0 } }, + { "NIKON", "D4", WhiteFluorescent, 0, { 1.488281, 1, 2.476563, 0 } }, + { "NIKON", "D4", CoolWhiteFluorescent, 0, { 1.855469, 1, 2.156250, 0 } }, + { "NIKON", "D4", DayWhiteFluorescent, 0, { 1.867188, 1, 1.476563, 0 } }, + { "NIKON", "D4", DaylightFluorescent, 0, { 2.132813, 1, 1.156250, 0 } }, + { "NIKON", "D4", HighTempMercuryVaporFluorescent, 0, { 2.546875, 1, 1.425781, 0 } }, + { "NIKON", "D4", DirectSunlight, 0, { 2.019531, 1, 1.437500, 0 } }, + { "NIKON", "D4", Flash, 0, { 2.300781, 1, 1.253906, 0 } }, + { "NIKON", "D4", Cloudy, 0, { 2.175781, 1, 1.300781, 0 } }, + { "NIKON", "D4", Shade, 0, { 2.511719, 1, 1.164063, 0 } }, + { "NIKON", "D4", "2500K", 0, { 1.097656, 1, 3.027344, 0 } }, + { "NIKON", "D4", "2600K", 0, { 1.132813, 1, 2.859375, 0 } }, + { "NIKON", "D4", "2700K", 0, { 1.167969, 1, 2.710938, 0 } }, + { "NIKON", "D4", "2800K", 0, { 1.207031, 1, 2.582031, 0 } }, + { "NIKON", "D4", "2900K", 0, { 1.246094, 1, 2.464844, 0 } }, + { "NIKON", "D4", "3000K", 0, { 1.281250, 1, 2.363281, 0 } }, + { "NIKON", "D4", "3200K", 0, { 1.355469, 1, 2.195313, 0 } }, + { "NIKON", "D4", "3400K", 0, { 1.425781, 1, 2.054688, 0 } }, + { "NIKON", "D4", "3600K", 0, { 1.496094, 1, 1.929688, 0 } }, + { "NIKON", "D4", "3800K", 0, { 1.558594, 1, 1.812500, 0 } }, + { "NIKON", "D4", "4000K", 0, { 1.628906, 1, 1.718750, 0 } }, + { "NIKON", "D4", "4200K", 0, { 1.703125, 1, 1.660156, 0 } }, + { "NIKON", "D4", "4400K", 0, { 1.781250, 1, 1.621094, 0 } }, + { "NIKON", "D4", "4600K", 0, { 1.859375, 1, 1.589844, 0 } }, + { "NIKON", "D4", "4800K", 0, { 1.921875, 1, 1.539063, 0 } }, + { "NIKON", "D4", "5000K", 0, { 1.972656, 1, 1.488281, 0 } }, + { "NIKON", "D4", "5300K", 0, { 2.039063, 1, 1.417969, 0 } }, + { "NIKON", "D4", "5600K", 0, { 2.097656, 1, 1.359375, 0 } }, + { "NIKON", "D4", "5900K", 0, { 2.152344, 1, 1.308594, 0 } }, + { "NIKON", "D4", "6200K", 0, { 2.207031, 1, 1.273438, 0 } }, + { "NIKON", "D4", "6500K", 0, { 2.261719, 1, 1.242188, 0 } }, + { "NIKON", "D4", "6800K", 0, { 2.312500, 1, 1.222656, 0 } }, + { "NIKON", "D4", "7100K", 0, { 2.363281, 1, 1.203125, 0 } }, + { "NIKON", "D4", "7500K", 0, { 2.433594, 1, 1.183594, 0 } }, + { "NIKON", "D4", "8000K", 0, { 2.511719, 1, 1.160156, 0 } }, + { "NIKON", "D4", "8500K", 0, { 2.589844, 1, 1.140625, 0 } }, + { "NIKON", "D4", "9000K", 0, { 2.660156, 1, 1.117188, 0 } }, + { "NIKON", "D4", "9500K", 0, { 2.730469, 1, 1.093750, 0 } }, + { "NIKON", "D4", "10000K", 0, { 2.792969, 1, 1.066406, 0 } }, + + { "NIKON", "D100", Incandescent, -3, { 1.527344, 1, 2.539062, 0 } }, /*3300K*/ + { "NIKON", "D100", Incandescent, -2, { 1.476562, 1, 2.656250, 0 } }, /*3200K*/ + { "NIKON", "D100", Incandescent, -1, { 1.457031, 1, 2.707031, 0 } }, /*3100K*/ + { "NIKON", "D100", Incandescent, 0, { 1.406250, 1, 2.828125, 0 } }, /*3000K*/ + { "NIKON", "D100", Incandescent, 1, { 1.367188, 1, 2.937500, 0 } }, /*2900K*/ + { "NIKON", "D100", Incandescent, 2, { 1.316406, 1, 3.046875, 0 } }, /*2800K*/ + { "NIKON", "D100", Incandescent, 3, { 1.269531, 1, 3.167969, 0 } }, /*2700K*/ + { "NIKON", "D100", Fluorescent, -3, { 3.148438, 1, 1.847656, 0 } }, /*7200K*/ + { "NIKON", "D100", Fluorescent, -2, { 2.609375, 1, 1.617187, 0 } }, /*6500K*/ + { "NIKON", "D100", Fluorescent, -1, { 2.250000, 1, 2.039062, 0 } }, /*5000K*/ + { "NIKON", "D100", Fluorescent, 0, { 2.058594, 1, 2.617187, 0 } }, /*4200K*/ + { "NIKON", "D100", Fluorescent, 1, { 1.886719, 1, 2.726562, 0 } }, /*3700K*/ + { "NIKON", "D100", Fluorescent, 2, { 1.429688, 1, 3.359375, 0 } }, /*3000K*/ + { "NIKON", "D100", Fluorescent, 3, { 1.250000, 1, 2.699219, 0 } }, /*2700K*/ + { "NIKON", "D100", DirectSunlight, -3, { 2.386719, 1, 1.687500, 0 } }, /*5600K*/ + { "NIKON", "D100", DirectSunlight, -2, { 2.316406, 1, 1.726563, 0 } }, /*5400K*/ + { "NIKON", "D100", DirectSunlight, -1, { 2.296875, 1, 1.738281, 0 } }, /*5300K*/ + { "NIKON", "D100", DirectSunlight, 0, { 2.257812, 1, 1.757812, 0 } }, /*5200K*/ + { "NIKON", "D100", DirectSunlight, 1, { 2.187500, 1, 1.796875, 0 } }, /*5000K*/ + { "NIKON", "D100", DirectSunlight, 2, { 2.156250, 1, 1.816406, 0 } }, /*4900K*/ + { "NIKON", "D100", DirectSunlight, 3, { 2.117187, 1, 1.847656, 0 } }, /*4800K*/ + { "NIKON", "D100", Flash, -3, { 2.718750, 1, 1.519531, 0 } }, /*6000K*/ + { "NIKON", "D100", Flash, -2, { 2.656250, 1, 1.527344, 0 } }, /*5800K*/ + { "NIKON", "D100", Flash, -1, { 2.597656, 1, 1.527344, 0 } }, /*5600K*/ + { "NIKON", "D100", Flash, 0, { 2.539062, 1, 1.539062, 0 } }, /*5400K*/ + { "NIKON", "D100", Flash, 1, { 2.476562, 1, 1.539062, 0 } }, /*5200K*/ + { "NIKON", "D100", Flash, 2, { 2.437500, 1, 1.546875, 0 } }, /*5000K*/ + { "NIKON", "D100", Flash, 3, { 2.398438, 1, 1.546875, 0 } }, /*4800K*/ + { "NIKON", "D100", Cloudy, -3, { 2.648438, 1, 1.558594, 0 } }, /*6600K*/ + { "NIKON", "D100", Cloudy, -2, { 2.609375, 1, 1.578125, 0 } }, /*6400K*/ + { "NIKON", "D100", Cloudy, -1, { 2.558594, 1, 1.597656, 0 } }, /*6200K*/ + { "NIKON", "D100", Cloudy, 0, { 2.507813, 1, 1.628906, 0 } }, /*6000K*/ + { "NIKON", "D100", Cloudy, 1, { 2.449219, 1, 1.656250, 0 } }, /*5800K*/ + { "NIKON", "D100", Cloudy, 2, { 2.398438, 1, 1.687500, 0 } }, /*5600K*/ + { "NIKON", "D100", Cloudy, 3, { 2.316406, 1, 1.726563, 0 } }, /*5400K*/ + { "NIKON", "D100", Shade, -3, { 3.046875, 1, 1.386719, 0 } }, /*9200K*/ + { "NIKON", "D100", Shade, -2, { 3.000000, 1, 1.406250, 0 } }, /*8800K*/ + { "NIKON", "D100", Shade, -1, { 2.957031, 1, 1.417969, 0 } }, /*8400K*/ + { "NIKON", "D100", Shade, 0, { 2.906250, 1, 1.437500, 0 } }, /*8000K*/ + { "NIKON", "D100", Shade, 1, { 2.816406, 1, 1.476562, 0 } }, /*7500K*/ + { "NIKON", "D100", Shade, 2, { 2.750000, 1, 1.519531, 0 } }, /*7100K*/ + { "NIKON", "D100", Shade, 3, { 2.667969, 1, 1.546875, 0 } }, /*6700K*/ + + { "NIKON", "D200", Incandescent, -3, { 1.234375, 1, 2.136719, 0 } }, + { "NIKON", "D200", Incandescent, -2, { 1.199219, 1, 2.238281, 0 } }, + { "NIKON", "D200", Incandescent, -1, { 1.183594, 1, 2.289063, 0 } }, + { "NIKON", "D200", Incandescent, 0, { 1.148434, 1, 2.398438, 0 } }, + { "NIKON", "D200", Incandescent, 1, { 1.113281, 1, 2.519531, 0 } }, + { "NIKON", "D200", Incandescent, 2, { 1.074219, 1, 2.648438, 0 } }, + { "NIKON", "D200", Incandescent, 3, { 1.031250, 1, 2.804688, 0 } }, + { "NIKON", "D200", Fluorescent, -3, { 2.273438, 1, 1.410156, 0 } }, + { "NIKON", "D200", Fluorescent, -2, { 1.933594, 1, 1.152344, 0 } }, + { "NIKON", "D200", Fluorescent, -1, { 1.675781, 1, 1.453125, 0 } }, + { "NIKON", "D200", Fluorescent, 0, { 1.664063, 1, 2.148438, 0 } }, + { "NIKON", "D200", Fluorescent, 1, { 1.335938, 1, 2.453125, 0 } }, + { "NIKON", "D200", Fluorescent, 2, { 1.140625, 1, 2.214844, 0 } }, + { "NIKON", "D200", Fluorescent, 3, { 1.035156, 1, 2.410156, 0 } }, + { "NIKON", "D200", DirectSunlight, -3, { 1.863281, 1, 1.320313, 0 } }, + { "NIKON", "D200", DirectSunlight, -2, { 1.835938, 1, 1.355469, 0 } }, + { "NIKON", "D200", DirectSunlight, -1, { 1.820313, 1, 1.375000, 0 } }, + { "NIKON", "D200", DirectSunlight, 0, { 1.804688, 1, 1.398438, 0 } }, + { "NIKON", "D200", DirectSunlight, 1, { 1.746094, 1, 1.425781, 0 } }, + { "NIKON", "D200", DirectSunlight, 2, { 1.714844, 1, 1.437500, 0 } }, + { "NIKON", "D200", DirectSunlight, 3, { 1.687500, 1, 1.449219, 0 } }, + { "NIKON", "D200", Flash, -3, { 2.066406, 1, 1.183594, 0 } }, + { "NIKON", "D200", Flash, -2, { 2.046875, 1, 1.191406, 0 } }, + { "NIKON", "D200", Flash, -1, { 2.027344, 1, 1.199219, 0 } }, + { "NIKON", "D200", Flash, 0, { 2.007813, 1, 1.171875, 0 } }, + { "NIKON", "D200", Flash, 1, { 1.984375, 1, 1.207031, 0 } }, + { "NIKON", "D200", Flash, 2, { 1.964844, 1, 1.214844, 0 } }, + { "NIKON", "D200", Flash, 3, { 1.945313, 1, 1.222656, 0 } }, + { "NIKON", "D200", Cloudy, -3, { 2.027344, 1, 1.210938, 0 } }, + { "NIKON", "D200", Cloudy, -2, { 1.992188, 1, 1.226563, 0 } }, + { "NIKON", "D200", Cloudy, -1, { 1.953125, 1, 1.242188, 0 } }, + { "NIKON", "D200", Cloudy, 0, { 1.917969, 1, 1.261719, 0 } }, + { "NIKON", "D200", Cloudy, 1, { 1.890625, 1, 1.285156, 0 } }, + { "NIKON", "D200", Cloudy, 2, { 1.863281, 1, 1.320313, 0 } }, + { "NIKON", "D200", Cloudy, 3, { 1.835938, 1, 1.355469, 0 } }, + { "NIKON", "D200", Shade, -3, { 2.378906, 1, 1.066406, 0 } }, + { "NIKON", "D200", Shade, -2, { 2.332031, 1, 1.085938, 0 } }, + { "NIKON", "D200", Shade, -1, { 2.289063, 1, 1.105469, 0 } }, + { "NIKON", "D200", Shade, 0, { 2.234375, 1, 1.125000, 0 } }, + { "NIKON", "D200", Shade, 1, { 2.167969, 1, 1.152344, 0 } }, + { "NIKON", "D200", Shade, 2, { 2.105469, 1, 1.175781, 0 } }, + { "NIKON", "D200", Shade, 3, { 2.046875, 1, 1.199219, 0 } }, + { "NIKON", "D200", "2500K", 0, { 1.000000, 1, 3.121094, 0 } }, + { "NIKON", "D200", "2550K", 0, { 1.000000, 1, 3.035156, 0 } }, + { "NIKON", "D200", "2650K", 0, { 1.011719, 1, 2.878906, 0 } }, + { "NIKON", "D200", "2700K", 0, { 1.031250, 1, 2.804688, 0 } }, + { "NIKON", "D200", "2800K", 0, { 1.074219, 1, 2.648438, 0 } }, + { "NIKON", "D200", "2850K", 0, { 1.089844, 1, 2.589844, 0 } }, + { "NIKON", "D200", "2950K", 0, { 1.132813, 1, 2.453125, 0 } }, + { "NIKON", "D200", "3000K", 0, { 1.148438, 1, 2.398438, 0 } }, + { "NIKON", "D200", "3100K", 0, { 1.183594, 1, 2.289063, 0 } }, + { "NIKON", "D200", "3200K", 0, { 1.218750, 1, 2.187500, 0 } }, + { "NIKON", "D200", "3300K", 0, { 1.250000, 1, 2.097656, 0 } }, + { "NIKON", "D200", "3400K", 0, { 1.281250, 1, 2.015625, 0 } }, + { "NIKON", "D200", "3600K", 0, { 1.343750, 1, 1.871094, 0 } }, + { "NIKON", "D200", "3700K", 0, { 1.371094, 1, 1.820313, 0 } }, + { "NIKON", "D200", "3800K", 0, { 1.402344, 1, 1.761719, 0 } }, + { "NIKON", "D200", "4000K", 0, { 1.457031, 1, 1.667969, 0 } }, + { "NIKON", "D200", "4200K", 0, { 1.511719, 1, 1.593750, 0 } }, + { "NIKON", "D200", "4300K", 0, { 1.535156, 1, 1.558594, 0 } }, + { "NIKON", "D200", "4500K", 0, { 1.589844, 1, 1.500000, 0 } }, + { "NIKON", "D200", "4800K", 0, { 1.687500, 1, 1.449219, 0 } }, + { "NIKON", "D200", "5000K", 0, { 1.746094, 1, 1.425781, 0 } }, + { "NIKON", "D200", "5300K", 0, { 1.820313, 1, 1.375000, 0 } }, + { "NIKON", "D200", "5600K", 0, { 1.863281, 1, 1.320313, 0 } }, + { "NIKON", "D200", "5900K", 0, { 1.902344, 1, 1.273438, 0 } }, + { "NIKON", "D200", "6300K", 0, { 1.972656, 1, 1.234375, 0 } }, + { "NIKON", "D200", "6700K", 0, { 2.046875, 1, 1.199219, 0 } }, + { "NIKON", "D200", "7100K", 0, { 2.105469, 1, 1.175781, 0 } }, + { "NIKON", "D200", "7700K", 0, { 2.191406, 1, 1.144531, 0 } }, + { "NIKON", "D200", "8300K", 0, { 2.277344, 1, 1.109375, 0 } }, + { "NIKON", "D200", "9100K", 0, { 2.367188, 1, 1.070313, 0 } }, + { "NIKON", "D200", "10000K", 0, { 2.453125, 1, 1.035156, 0 } }, + + { "NIKON", "D300", Incandescent, -6, { 1.097656, 1, 1.898438, 0 } }, + { "NIKON", "D300", Incandescent, -5, { 1.085938, 1, 1.929688, 0 } }, + { "NIKON", "D300", Incandescent, -4, { 1.070313, 1, 1.964844, 0 } }, + { "NIKON", "D300", Incandescent, -3, { 1.058594, 1, 2.000000, 0 } }, + { "NIKON", "D300", Incandescent, -2, { 1.042969, 1, 2.035156, 0 } }, + { "NIKON", "D300", Incandescent, -1, { 1.031250, 1, 2.074219, 0 } }, + { "NIKON", "D300", Incandescent, 0, { 1.019531, 1, 2.109375, 0 } }, + { "NIKON", "D300", Incandescent, 1, { 1.007813, 1, 2.144531, 0 } }, + { "NIKON", "D300", Incandescent, 2, { 0.996094, 1, 2.183594, 0 } }, + { "NIKON", "D300", Incandescent, 3, { 0.984375, 1, 2.218750, 0 } }, + { "NIKON", "D300", Incandescent, 4, { 0.972656, 1, 2.257813, 0 } }, + { "NIKON", "D300", Incandescent, 5, { 0.964844, 1, 2.296875, 0 } }, + { "NIKON", "D300", Incandescent, 6, { 0.953125, 1, 2.335938, 0 } }, + { "NIKON", "D300", SodiumVaporFluorescent, -6, { 1.031250, 1, 2.101563, 0 } }, + { "NIKON", "D300", SodiumVaporFluorescent, -5, { 1.015625, 1, 2.136719, 0 } }, + { "NIKON", "D300", SodiumVaporFluorescent, -4, { 1.003906, 1, 2.167969, 0 } }, + { "NIKON", "D300", SodiumVaporFluorescent, -3, { 0.988281, 1, 2.207031, 0 } }, + { "NIKON", "D300", SodiumVaporFluorescent, -2, { 0.976563, 1, 2.242188, 0 } }, + { "NIKON", "D300", SodiumVaporFluorescent, -1, { 0.960938, 1, 2.281250, 0 } }, + { "NIKON", "D300", SodiumVaporFluorescent, 0, { 0.949219, 1, 2.320313, 0 } }, + { "NIKON", "D300", SodiumVaporFluorescent, 1, { 0.937500, 1, 2.363281, 0 } }, + { "NIKON", "D300", SodiumVaporFluorescent, 2, { 0.925781, 1, 2.410156, 0 } }, + { "NIKON", "D300", SodiumVaporFluorescent, 3, { 0.914063, 1, 2.457031, 0 } }, + { "NIKON", "D300", SodiumVaporFluorescent, 4, { 0.902344, 1, 2.503906, 0 } }, + { "NIKON", "D300", SodiumVaporFluorescent, 5, { 0.890625, 1, 2.558594, 0 } }, + { "NIKON", "D300", SodiumVaporFluorescent, 6, { 0.878906, 1, 2.613281, 0 } }, + { "NIKON", "D300", WarmWhiteFluorescent, -6, { 1.128906, 1, 1.847656, 0 } }, + { "NIKON", "D300", WarmWhiteFluorescent, -5, { 1.113281, 1, 1.867188, 0 } }, + { "NIKON", "D300", WarmWhiteFluorescent, -4, { 1.097656, 1, 1.886719, 0 } }, + { "NIKON", "D300", WarmWhiteFluorescent, -3, { 1.085938, 1, 1.906250, 0 } }, + { "NIKON", "D300", WarmWhiteFluorescent, -2, { 1.070313, 1, 1.925781, 0 } }, + { "NIKON", "D300", WarmWhiteFluorescent, -1, { 1.058594, 1, 1.945313, 0 } }, + { "NIKON", "D300", WarmWhiteFluorescent, 0, { 1.046875, 1, 1.960938, 0 } }, + { "NIKON", "D300", WarmWhiteFluorescent, 1, { 1.035156, 1, 1.980469, 0 } }, + { "NIKON", "D300", WarmWhiteFluorescent, 2, { 1.023438, 1, 1.996094, 0 } }, + { "NIKON", "D300", WarmWhiteFluorescent, 3, { 1.007813, 1, 2.015625, 0 } }, + { "NIKON", "D300", WarmWhiteFluorescent, 4, { 1.000000, 1, 2.031250, 0 } }, + { "NIKON", "D300", WarmWhiteFluorescent, 5, { 0.988281, 1, 2.046875, 0 } }, + { "NIKON", "D300", WarmWhiteFluorescent, 6, { 0.976563, 1, 2.062500, 0 } }, + { "NIKON", "D300", WhiteFluorescent, -6, { 1.453125, 1, 2.050781, 0 } }, + { "NIKON", "D300", WhiteFluorescent, -5, { 1.414063, 1, 2.093750, 0 } }, + { "NIKON", "D300", WhiteFluorescent, -4, { 1.371094, 1, 2.132813, 0 } }, + { "NIKON", "D300", WhiteFluorescent, -3, { 1.328125, 1, 2.175781, 0 } }, + { "NIKON", "D300", WhiteFluorescent, -2, { 1.285156, 1, 2.218750, 0 } }, + { "NIKON", "D300", WhiteFluorescent, -1, { 1.238281, 1, 2.261719, 0 } }, + { "NIKON", "D300", WhiteFluorescent, 0, { 1.191406, 1, 2.304688, 0 } }, + { "NIKON", "D300", WhiteFluorescent, 1, { 1.140625, 1, 2.351563, 0 } }, + { "NIKON", "D300", WhiteFluorescent, 2, { 1.089844, 1, 2.394531, 0 } }, + { "NIKON", "D300", WhiteFluorescent, 3, { 1.039063, 1, 2.441406, 0 } }, + { "NIKON", "D300", WhiteFluorescent, 4, { 0.984375, 1, 2.488281, 0 } }, + { "NIKON", "D300", WhiteFluorescent, 5, { 0.925781, 1, 2.535156, 0 } }, + { "NIKON", "D300", WhiteFluorescent, 6, { 0.867188, 1, 2.582031, 0 } }, + { "NIKON", "D300", CoolWhiteFluorescent, -6, { 1.667969, 1, 1.800781, 0 } }, + { "NIKON", "D300", CoolWhiteFluorescent, -5, { 1.636719, 1, 1.835938, 0 } }, + { "NIKON", "D300", CoolWhiteFluorescent, -4, { 1.605469, 1, 1.875000, 0 } }, + { "NIKON", "D300", CoolWhiteFluorescent, -3, { 1.574219, 1, 1.914063, 0 } }, + { "NIKON", "D300", CoolWhiteFluorescent, -2, { 1.539063, 1, 1.953125, 0 } }, + { "NIKON", "D300", CoolWhiteFluorescent, -1, { 1.503906, 1, 1.996094, 0 } }, + { "NIKON", "D300", CoolWhiteFluorescent, 0, { 1.468750, 1, 2.035156, 0 } }, + { "NIKON", "D300", CoolWhiteFluorescent, 1, { 1.429688, 1, 2.074219, 0 } }, + { "NIKON", "D300", CoolWhiteFluorescent, 2, { 1.386719, 1, 2.117188, 0 } }, + { "NIKON", "D300", CoolWhiteFluorescent, 3, { 1.347656, 1, 2.160156, 0 } }, + { "NIKON", "D300", CoolWhiteFluorescent, 4, { 1.304688, 1, 2.203125, 0 } }, + { "NIKON", "D300", CoolWhiteFluorescent, 5, { 1.257813, 1, 2.246094, 0 } }, + { "NIKON", "D300", CoolWhiteFluorescent, 6, { 1.210938, 1, 2.289063, 0 } }, + { "NIKON", "D300", DayWhiteFluorescent, -6, { 1.625000, 1, 1.195313, 0 } }, + { "NIKON", "D300", DayWhiteFluorescent, -5, { 1.601563, 1, 1.222656, 0 } }, + { "NIKON", "D300", DayWhiteFluorescent, -4, { 1.582031, 1, 1.253906, 0 } }, + { "NIKON", "D300", DayWhiteFluorescent, -3, { 1.558594, 1, 1.281250, 0 } }, + { "NIKON", "D300", DayWhiteFluorescent, -2, { 1.535156, 1, 1.308594, 0 } }, + { "NIKON", "D300", DayWhiteFluorescent, -1, { 1.515625, 1, 1.335938, 0 } }, + { "NIKON", "D300", DayWhiteFluorescent, 0, { 1.492188, 1, 1.363281, 0 } }, + { "NIKON", "D300", DayWhiteFluorescent, 1, { 1.472656, 1, 1.390625, 0 } }, + { "NIKON", "D300", DayWhiteFluorescent, 2, { 1.453125, 1, 1.417969, 0 } }, + { "NIKON", "D300", DayWhiteFluorescent, 3, { 1.433594, 1, 1.441406, 0 } }, + { "NIKON", "D300", DayWhiteFluorescent, 4, { 1.410156, 1, 1.468750, 0 } }, + { "NIKON", "D300", DayWhiteFluorescent, 5, { 1.390625, 1, 1.492188, 0 } }, + { "NIKON", "D300", DayWhiteFluorescent, 6, { 1.375000, 1, 1.519531, 0 } }, + { "NIKON", "D300", DaylightFluorescent, -6, { 1.851563, 1, 1.000000, 0 } }, + { "NIKON", "D300", DaylightFluorescent, -5, { 1.824219, 1, 1.000000, 0 } }, + { "NIKON", "D300", DaylightFluorescent, -4, { 1.796875, 1, 1.000000, 0 } }, + { "NIKON", "D300", DaylightFluorescent, -3, { 1.773438, 1, 1.007813, 0 } }, + { "NIKON", "D300", DaylightFluorescent, -2, { 1.750000, 1, 1.039063, 0 } }, + { "NIKON", "D300", DaylightFluorescent, -1, { 1.722656, 1, 1.070313, 0 } }, + { "NIKON", "D300", DaylightFluorescent, 0, { 1.699219, 1, 1.101563, 0 } }, + { "NIKON", "D300", DaylightFluorescent, 1, { 1.675781, 1, 1.128906, 0 } }, + { "NIKON", "D300", DaylightFluorescent, 2, { 1.652344, 1, 1.160156, 0 } }, + { "NIKON", "D300", DaylightFluorescent, 3, { 1.628906, 1, 1.187500, 0 } }, + { "NIKON", "D300", DaylightFluorescent, 4, { 1.605469, 1, 1.218750, 0 } }, + { "NIKON", "D300", DaylightFluorescent, 5, { 1.585938, 1, 1.246094, 0 } }, + { "NIKON", "D300", DaylightFluorescent, 6, { 1.562500, 1, 1.273438, 0 } }, + { "NIKON", "D300", HighTempMercuryVaporFluorescent, -6, { 2.039063, 1, 1.156250, 0 } }, + { "NIKON", "D300", HighTempMercuryVaporFluorescent, -5, { 2.027344, 1, 1.183594, 0 } }, + { "NIKON", "D300", HighTempMercuryVaporFluorescent, -4, { 2.015625, 1, 1.210938, 0 } }, + { "NIKON", "D300", HighTempMercuryVaporFluorescent, -3, { 2.003906, 1, 1.238281, 0 } }, + { "NIKON", "D300", HighTempMercuryVaporFluorescent, -2, { 1.992188, 1, 1.269531, 0 } }, + { "NIKON", "D300", HighTempMercuryVaporFluorescent, -1, { 1.976563, 1, 1.300781, 0 } }, + { "NIKON", "D300", HighTempMercuryVaporFluorescent, 0, { 1.960938, 1, 1.328125, 0 } }, + { "NIKON", "D300", HighTempMercuryVaporFluorescent, 1, { 1.945313, 1, 1.359375, 0 } }, + { "NIKON", "D300", HighTempMercuryVaporFluorescent, 2, { 1.929688, 1, 1.390625, 0 } }, + { "NIKON", "D300", HighTempMercuryVaporFluorescent, 3, { 1.914063, 1, 1.421875, 0 } }, + { "NIKON", "D300", HighTempMercuryVaporFluorescent, 4, { 1.894531, 1, 1.457031, 0 } }, + { "NIKON", "D300", HighTempMercuryVaporFluorescent, 5, { 1.875000, 1, 1.488281, 0 } }, + { "NIKON", "D300", HighTempMercuryVaporFluorescent, 6, { 1.855469, 1, 1.523438, 0 } }, + { "NIKON", "D300", DirectSunlight, -6, { 1.687500, 1, 1.167969, 0 } }, + { "NIKON", "D300", DirectSunlight, -5, { 1.664063, 1, 1.187500, 0 } }, + { "NIKON", "D300", DirectSunlight, -4, { 1.644531, 1, 1.207031, 0 } }, + { "NIKON", "D300", DirectSunlight, -3, { 1.625000, 1, 1.230469, 0 } }, + { "NIKON", "D300", DirectSunlight, -2, { 1.601563, 1, 1.253906, 0 } }, + { "NIKON", "D300", DirectSunlight, -1, { 1.582031, 1, 1.281250, 0 } }, + { "NIKON", "D300", DirectSunlight, 0, { 1.562500, 1, 1.308594, 0 } }, + { "NIKON", "D300", DirectSunlight, 1, { 1.542969, 1, 1.335938, 0 } }, + { "NIKON", "D300", DirectSunlight, 2, { 1.523438, 1, 1.359375, 0 } }, + { "NIKON", "D300", DirectSunlight, 3, { 1.503906, 1, 1.386719, 0 } }, + { "NIKON", "D300", DirectSunlight, 4, { 1.480469, 1, 1.414063, 0 } }, + { "NIKON", "D300", DirectSunlight, 5, { 1.457031, 1, 1.437500, 0 } }, + { "NIKON", "D300", DirectSunlight, 6, { 1.429688, 1, 1.457031, 0 } }, + { "NIKON", "D300", Flash, -6, { 1.910156, 1, 1.058594, 0 } }, + { "NIKON", "D300", Flash, -5, { 1.863281, 1, 1.078125, 0 } }, + { "NIKON", "D300", Flash, -4, { 1.820313, 1, 1.093750, 0 } }, + { "NIKON", "D300", Flash, -3, { 1.781250, 1, 1.105469, 0 } }, + { "NIKON", "D300", Flash, -2, { 1.746094, 1, 1.121094, 0 } }, + { "NIKON", "D300", Flash, -1, { 1.714844, 1, 1.136719, 0 } }, + { "NIKON", "D300", Flash, 0, { 1.687500, 1, 1.152344, 0 } }, + { "NIKON", "D300", Flash, 1, { 1.660156, 1, 1.164063, 0 } }, + { "NIKON", "D300", Flash, 2, { 1.636719, 1, 1.179688, 0 } }, + { "NIKON", "D300", Flash, 3, { 1.613281, 1, 1.195313, 0 } }, + { "NIKON", "D300", Flash, 4, { 1.593750, 1, 1.210938, 0 } }, + { "NIKON", "D300", Flash, 5, { 1.574219, 1, 1.230469, 0 } }, + { "NIKON", "D300", Flash, 6, { 1.554688, 1, 1.246094, 0 } }, + { "NIKON", "D300", Cloudy, -6, { 1.820313, 1, 1.093750, 0 } }, + { "NIKON", "D300", Cloudy, -5, { 1.789063, 1, 1.105469, 0 } }, + { "NIKON", "D300", Cloudy, -4, { 1.761719, 1, 1.117188, 0 } }, + { "NIKON", "D300", Cloudy, -3, { 1.734375, 1, 1.132813, 0 } }, + { "NIKON", "D300", Cloudy, -2, { 1.710938, 1, 1.148438, 0 } }, + { "NIKON", "D300", Cloudy, -1, { 1.687500, 1, 1.167969, 0 } }, + { "NIKON", "D300", Cloudy, 0, { 1.664063, 1, 1.187500, 0 } }, + { "NIKON", "D300", Cloudy, 1, { 1.644531, 1, 1.207031, 0 } }, + { "NIKON", "D300", Cloudy, 2, { 1.625000, 1, 1.230469, 0 } }, + { "NIKON", "D300", Cloudy, 3, { 1.601563, 1, 1.253906, 0 } }, + { "NIKON", "D300", Cloudy, 4, { 1.582031, 1, 1.281250, 0 } }, + { "NIKON", "D300", Cloudy, 5, { 1.562500, 1, 1.308594, 0 } }, + { "NIKON", "D300", Cloudy, 6, { 1.542969, 1, 1.335938, 0 } }, + { "NIKON", "D300", Shade, -6, { 2.156250, 1, 1.000000, 0 } }, + { "NIKON", "D300", Shade, -5, { 2.109375, 1, 1.000000, 0 } }, + { "NIKON", "D300", Shade, -4, { 2.062500, 1, 1.011719, 0 } }, + { "NIKON", "D300", Shade, -3, { 2.019531, 1, 1.027344, 0 } }, + { "NIKON", "D300", Shade, -2, { 1.976563, 1, 1.042969, 0 } }, + { "NIKON", "D300", Shade, -1, { 1.937500, 1, 1.054688, 0 } }, + { "NIKON", "D300", Shade, 0, { 1.902344, 1, 1.066406, 0 } }, + { "NIKON", "D300", Shade, 1, { 1.867188, 1, 1.074219, 0 } }, + { "NIKON", "D300", Shade, 2, { 1.832031, 1, 1.085938, 0 } }, + { "NIKON", "D300", Shade, 3, { 1.804688, 1, 1.097656, 0 } }, + { "NIKON", "D300", Shade, 4, { 1.773438, 1, 1.113281, 0 } }, + { "NIKON", "D300", Shade, 5, { 1.746094, 1, 1.125000, 0 } }, + { "NIKON", "D300", Shade, 6, { 1.722656, 1, 1.140625, 0 } }, + { "NIKON", "D300", "2500K", 0, { 0.894531, 1, 2.632813, 0 } }, + { "NIKON", "D300", "2560K", 0, { 0.906250, 1, 2.550781, 0 } }, + { "NIKON", "D300", "2630K", 0, { 0.921875, 1, 2.468750, 0 } }, + { "NIKON", "D300", "2700K", 0, { 0.941406, 1, 2.390625, 0 } }, + { "NIKON", "D300", "2780K", 0, { 0.960938, 1, 2.312500, 0 } }, + { "NIKON", "D300", "2860K", 0, { 0.980469, 1, 2.234375, 0 } }, + { "NIKON", "D300", "2940K", 0, { 1.003906, 1, 2.160156, 0 } }, + { "NIKON", "D300", "3030K", 0, { 1.027344, 1, 2.085938, 0 } }, + { "NIKON", "D300", "3130K", 0, { 1.050781, 1, 2.015625, 0 } }, + { "NIKON", "D300", "3230K", 0, { 1.078125, 1, 1.945313, 0 } }, + { "NIKON", "D300", "3330K", 0, { 1.109375, 1, 1.875000, 0 } }, + { "NIKON", "D300", "3450K", 0, { 1.136719, 1, 1.808594, 0 } }, + { "NIKON", "D300", "3570K", 0, { 1.167969, 1, 1.742188, 0 } }, + { "NIKON", "D300", "3700K", 0, { 1.203125, 1, 1.679688, 0 } }, + { "NIKON", "D300", "3850K", 0, { 1.238281, 1, 1.617188, 0 } }, + { "NIKON", "D300", "4000K", 0, { 1.277344, 1, 1.554688, 0 } }, + { "NIKON", "D300", "4170K", 0, { 1.316406, 1, 1.500000, 0 } }, + { "NIKON", "D300", "4350K", 0, { 1.386719, 1, 1.484375, 0 } }, + { "NIKON", "D300", "4550K", 0, { 1.441406, 1, 1.449219, 0 } }, + { "NIKON", "D300", "4760K", 0, { 1.488281, 1, 1.402344, 0 } }, + { "NIKON", "D300", "5000K", 0, { 1.531250, 1, 1.351563, 0 } }, + { "NIKON", "D300", "5260K", 0, { 1.570313, 1, 1.296875, 0 } }, + { "NIKON", "D300", "5560K", 0, { 1.613281, 1, 1.246094, 0 } }, + { "NIKON", "D300", "5880K", 0, { 1.652344, 1, 1.199219, 0 } }, + { "NIKON", "D300", "6250K", 0, { 1.695313, 1, 1.160156, 0 } }, + { "NIKON", "D300", "6670K", 0, { 1.746094, 1, 1.125000, 0 } }, + { "NIKON", "D300", "7140K", 0, { 1.804688, 1, 1.097656, 0 } }, + { "NIKON", "D300", "7690K", 0, { 1.867188, 1, 1.074219, 0 } }, + { "NIKON", "D300", "8330K", 0, { 1.937500, 1, 1.054688, 0 } }, + { "NIKON", "D300", "9090K", 0, { 2.019531, 1, 1.027344, 0 } }, + { "NIKON", "D300", "10000K", 0, { 2.109375, 1, 1.000000, 0 } }, + + { "NIKON", "D300S", DirectSunlight, -6, { 1.687, 1, 1.168, 0 } }, + { "NIKON", "D300S", DirectSunlight, 0, { 1.563, 1, 1.309, 0 } }, + { "NIKON", "D300S", DirectSunlight, 6, { 1.430, 1, 1.457, 0 } }, + { "NIKON", "D300S", Flash, -6, { 1.910, 1, 1.059, 0 } }, + { "NIKON", "D300S", Flash, 0, { 1.687, 1, 1.152, 0 } }, + { "NIKON", "D300S", Flash, 6, { 1.555, 1, 1.246, 0 } }, + { "NIKON", "D300S", Cloudy, -6, { 1.820, 1, 1.094, 0 } }, + { "NIKON", "D300S", Cloudy, 0, { 1.664, 1, 1.187, 0 } }, + { "NIKON", "D300S", Cloudy, 6, { 1.543, 1, 1.336, 0 } }, + { "NIKON", "D300S", Shade, -6, { 2.156, 1, 1.000, 0 } }, + { "NIKON", "D300S", Shade, 0, { 1.902, 1, 1.066, 0 } }, + { "NIKON", "D300S", Shade, 6, { 1.723, 1, 1.141, 0 } }, + { "NIKON", "D300S", Incandescent, -6, { 1.098, 1, 1.898, 0 } }, + { "NIKON", "D300S", Incandescent, 0, { 1.020, 1, 2.109, 0 } }, + { "NIKON", "D300S", Incandescent, 6, { 1, 1.049, 2.451, 0 } }, + { "NIKON", "D300S", SodiumVaporFluorescent, -6, { 1.031, 1, 2.102, 0 } }, + { "NIKON", "D300S", SodiumVaporFluorescent, 0, { 1, 1.053, 2.444, 0 } }, + { "NIKON", "D300S", SodiumVaporFluorescent, 6, { 1, 1.138, 2.973, 0 } }, + { "NIKON", "D300S", WarmWhiteFluorescent, -6, { 1.129, 1, 1.848, 0 } }, + { "NIKON", "D300S", WarmWhiteFluorescent, 0, { 1.047, 1, 1.961, 0 } }, + { "NIKON", "D300S", WarmWhiteFluorescent, 6, { 1, 1.024, 2.112, 0 } }, + { "NIKON", "D300S", WhiteFluorescent, -6, { 1.453, 1, 2.051, 0 } }, + { "NIKON", "D300S", WhiteFluorescent, 0, { 1.191, 1, 2.305, 0 } }, + { "NIKON", "D300S", WhiteFluorescent, 6, { 1, 1.153, 2.977, 0 } }, + { "NIKON", "D300S", CoolWhiteFluorescent, -6, { 1.668, 1, 1.801, 0 } }, + { "NIKON", "D300S", CoolWhiteFluorescent, 0, { 1.469, 1, 2.035, 0 } }, + { "NIKON", "D300S", CoolWhiteFluorescent, 6, { 1.211, 1, 2.289, 0 } }, + { "NIKON", "D300S", DayWhiteFluorescent, -6, { 1.625, 1, 1.195, 0 } }, + { "NIKON", "D300S", DayWhiteFluorescent, 0, { 1.492, 1, 1.363, 0 } }, + { "NIKON", "D300S", DayWhiteFluorescent, 6, { 1.375, 1, 1.520, 0 } }, + { "NIKON", "D300S", DaylightFluorescent, -6, { 1.852, 1, 1.000, 0 } }, + { "NIKON", "D300S", DaylightFluorescent, 0, { 1.699, 1, 1.102, 0 } }, + { "NIKON", "D300S", DaylightFluorescent, 6, { 1.563, 1, 1.273, 0 } }, + { "NIKON", "D300S", HighTempMercuryVaporFluorescent, -6, { 2.039, 1, 1.156, 0 } }, + { "NIKON", "D300S", HighTempMercuryVaporFluorescent, 0, { 1.961, 1, 1.328, 0 } }, + { "NIKON", "D300S", HighTempMercuryVaporFluorescent, 6, { 1.855, 1, 1.523, 0 } }, + + { "NIKON", "D600", DirectSunlight, 0, { 1.906250, 1, 1.390625, 0 } }, + { "NIKON", "D600", Flash, 0, { 2.136719, 1, 1.214844, 0 } }, + { "NIKON", "D600", Cloudy, 0, { 2.039063, 1, 1.261719, 0 } }, + { "NIKON", "D600", Shade, 0, { 2.328125, 1, 1.136719, 0 } }, + { "NIKON", "D600", Incandescent, 0, { 1.226563, 1, 2.214844, 0 } }, + { "NIKON", "D600", SodiumVaporFluorescent, 0, { 1.148438, 1, 2.433594, 0 } }, + { "NIKON", "D600", WarmWhiteFluorescent, 0, { 1.230469, 1, 1.953125, 0 } }, + { "NIKON", "D600", WhiteFluorescent, 0, { 1.421875, 1, 2.281250, 0 } }, + { "NIKON", "D600", CoolWhiteFluorescent, 0, { 1.730469, 1, 2.003906, 0 } }, + { "NIKON", "D600", DayWhiteFluorescent, 0, { 1.777344, 1, 1.375000, 0 } }, + { "NIKON", "D600", DaylightFluorescent, 0, { 2.039063, 1, 1.117188, 0 } }, + { "NIKON", "D600", HighTempMercuryVaporFluorescent, 0, { 2.332031, 1, 1.355469, 0 } }, + + /* D610 with firmware C1.00 L1.009 */ + { "NIKON", "D610", DirectSunlight, 0, { 1.906250, 1, 1.390625, 0 } }, + { "NIKON", "D610", Flash, 0, { 2.136719, 1, 1.214844, 0 } }, + { "NIKON", "D610", Cloudy, 0, { 2.039063, 1, 1.261719, 0 } }, + { "NIKON", "D610", Shade, 0, { 2.328125, 1, 1.136719, 0 } }, + { "NIKON", "D610", Incandescent, 0, { 1.226563, 1, 2.214844, 0 } }, + { "NIKON", "D610", SodiumVaporFluorescent, 0, { 1.148438, 1, 2.433594, 0 } }, + { "NIKON", "D610", WarmWhiteFluorescent, 0, { 1.230469, 1, 1.953125, 0 } }, + { "NIKON", "D610", WhiteFluorescent, 0, { 1.421875, 1, 2.281250, 0 } }, + { "NIKON", "D610", CoolWhiteFluorescent, 0, { 1.730469, 1, 2.003906, 0 } }, + { "NIKON", "D610", DayWhiteFluorescent, 0, { 1.777344, 1, 1.375000, 0 } }, + { "NIKON", "D610", DaylightFluorescent, 0, { 2.039063, 1, 1.117188, 0 } }, + { "NIKON", "D610", HighTempMercuryVaporFluorescent, 0, { 2.332031, 1, 1.355469, 0 } }, + + { "NIKON", "D700", DirectSunlight, -6, { 1.980469, 1, 1.199219, 0 } }, + { "NIKON", "D700", DirectSunlight, 0, { 1.816406, 1, 1.355469, 0 } }, + { "NIKON", "D700", DirectSunlight, 6, { 1.652344, 1, 1.523437, 0 } }, + { "NIKON", "D700", Flash, -6, { 2.261719, 1, 1.082031, 0 } }, + { "NIKON", "D700", Flash, 0, { 2.039063, 1, 1.171875, 0 } }, + { "NIKON", "D700", Flash, 6, { 1.871094, 1, 1.281250, 0 } }, + { "NIKON", "D700", Cloudy, -6, { 2.148437, 1, 1.117187, 0 } }, + { "NIKON", "D700", Cloudy, 0, { 1.949219, 1, 1.222656, 0 } }, + { "NIKON", "D700", Cloudy, 6, { 1.792969, 1, 1.386719, 0 } }, + { "NIKON", "D700", Shade, -6, { 2.535156, 1, 1.000000, 0 } }, + { "NIKON", "D700", Shade, 0, { 2.246094, 1, 1.085937, 0 } }, + { "NIKON", "D700", Shade, 6, { 2.023438, 1, 1.171875, 0 } }, + { "NIKON", "D700", Incandescent , -6, { 1.265625, 1, 2.050781, 0 } }, + { "NIKON", "D700", Incandescent , 0, { 1.167969, 1, 2.316406, 0 } }, + { "NIKON", "D700", Incandescent , 6, { 1.085938, 1, 2.605469, 0 } }, + { "NIKON", "D700", SodiumVaporFluorescent, -6, { 1.175781, 1, 2.191406, 0 } }, + { "NIKON", "D700", SodiumVaporFluorescent, 0, { 1.062500, 1, 2.464844, 0 } }, + { "NIKON", "D700", SodiumVaporFluorescent, 6, { 1.000000, 1, 2.789062, 0 } }, + { "NIKON", "D700", WarmWhiteFluorescent, -6, { 1.269531, 1, 1.968750, 0 } }, + { "NIKON", "D700", WarmWhiteFluorescent, 0, { 1.167969, 1, 2.109375, 0 } }, + { "NIKON", "D700", WarmWhiteFluorescent, 6, { 1.078125, 1, 2.230469, 0 } }, + { "NIKON", "D700", WhiteFluorescent, -6, { 1.671875, 1, 2.121094, 0 } }, + { "NIKON", "D700", WhiteFluorescent, 0, { 1.363281, 1, 2.425781, 0 } }, + { "NIKON", "D700", WhiteFluorescent, 6, { 1, 1.015873, 2.813492, 0 } }, + { "NIKON", "D700", CoolWhiteFluorescent, -6, { 1.929687, 1, 1.835938, 0 } }, + { "NIKON", "D700", CoolWhiteFluorescent, 0, { 1.687500, 1, 2.101563, 0 } }, + { "NIKON", "D700", CoolWhiteFluorescent, 6, { 1.386719, 1, 2.406250, 0 } }, + { "NIKON", "D700", DayWhiteFluorescent, -6, { 1.867188, 1, 1.218750, 0 } }, + { "NIKON", "D700", DayWhiteFluorescent, 0, { 1.710938, 1, 1.410156, 0 } }, + { "NIKON", "D700", DayWhiteFluorescent, 6, { 1.570313, 1, 1.585938, 0 } }, + { "NIKON", "D700", DaylightFluorescent, -6, { 2.128906, 1, 1.000000, 0 } }, + { "NIKON", "D700", DaylightFluorescent, 0, { 1.953125, 1, 1.113281, 0 } }, + { "NIKON", "D700", DaylightFluorescent, 6, { 1.792969, 1, 1.308594, 0 } }, + { "NIKON", "D700", HighTempMercuryVaporFluorescent, -6, { 2.378906, 1, 1.218750, 0 } }, + { "NIKON", "D700", HighTempMercuryVaporFluorescent, 0, { 2.289063, 1, 1.363281, 0 } }, + { "NIKON", "D700", HighTempMercuryVaporFluorescent, 6, { 2.164063, 1, 1.542969, 0 } }, + { "NIKON", "D700", "2500K", 0, { 1.003906, 1, 3.000000, 0 } }, + { "NIKON", "D700", "2560K", 0, { 1.023438, 1, 2.890625, 0 } }, + { "NIKON", "D700", "2630K", 0, { 1.042969, 1, 2.781250, 0 } }, + { "NIKON", "D700", "2700K", 0, { 1.066406, 1, 2.679687, 0 } }, + { "NIKON", "D700", "2780K", 0, { 1.093750, 1, 2.578125, 0 } }, + { "NIKON", "D700", "2860K", 0, { 1.117187, 1, 2.476562, 0 } }, + { "NIKON", "D700", "2940K", 0, { 1.148437, 1, 2.382812, 0 } }, + { "NIKON", "D700", "3030K", 0, { 1.175781, 1, 2.289063, 0 } }, + { "NIKON", "D700", "3130K", 0, { 1.207031, 1, 2.199219, 0 } }, + { "NIKON", "D700", "3230K", 0, { 1.242188, 1, 2.109375, 0 } }, + { "NIKON", "D700", "3330K", 0, { 1.277344, 1, 2.023438, 0 } }, + { "NIKON", "D700", "3450K", 0, { 1.312500, 1, 1.941406, 0 } }, + { "NIKON", "D700", "3570K", 0, { 1.351562, 1, 1.859375, 0 } }, + { "NIKON", "D700", "3700K", 0, { 1.390625, 1, 1.781250, 0 } }, + { "NIKON", "D700", "3850K", 0, { 1.433594, 1, 1.707031, 0 } }, + { "NIKON", "D700", "4000K", 0, { 1.476563, 1, 1.632813, 0 } }, + { "NIKON", "D700", "4170K", 0, { 1.523437, 1, 1.566406, 0 } }, + { "NIKON", "D700", "4350K", 0, { 1.601562, 1, 1.550781, 0 } }, + { "NIKON", "D700", "4760K", 0, { 1.722656, 1, 1.460938, 0 } }, + { "NIKON", "D700", "5000K", 0, { 1.777344, 1, 1.402344, 0 } }, + { "NIKON", "D700", "5260K", 0, { 1.828125, 1, 1.343750, 0 } }, + { "NIKON", "D700", "5560K", 0, { 1.878906, 1, 1.285156, 0 } }, + { "NIKON", "D700", "5880K", 0, { 1.933594, 1, 1.234375, 0 } }, + { "NIKON", "D700", "6250K", 0, { 1.992187, 1, 1.191406, 0 } }, + { "NIKON", "D700", "6670K", 0, { 2.054688, 1, 1.156250, 0 } }, + { "NIKON", "D700", "7140K", 0, { 2.125000, 1, 1.125000, 0 } }, + { "NIKON", "D700", "7690K", 0, { 2.203125, 1, 1.097656, 0 } }, + { "NIKON", "D700", "8330K", 0, { 2.289063, 1, 1.070313, 0 } }, + { "NIKON", "D700", "9090K", 0, { 2.382812, 1, 1.035156, 0 } }, + { "NIKON", "D700", "10000K", 0, { 2.480469, 1, 1.000000, 0 } }, + + { "NIKON", "D750", DirectSunlight, -6, { 2.113281, 1, 1.203125, 0 } }, + { "NIKON", "D750", DirectSunlight, 0, { 1.949219, 1, 1.343750, 0 } }, + { "NIKON", "D750", DirectSunlight, 6, { 1.777344, 1, 1.492188, 0 } }, + { "NIKON", "D750", Flash, -6, { 2.386719, 1, 1.109375, 0 } }, + { "NIKON", "D750", Flash, 0, { 2.156250, 1, 1.183594, 0 } }, + { "NIKON", "D750", Flash, 6, { 1.980469, 1, 1.273438, 0 } }, + { "NIKON", "D750", Cloudy, -6, { 2.289063, 1, 1.132813, 0 } }, + { "NIKON", "D750", Cloudy, 0, { 2.082031, 1, 1.222656, 0 } }, + { "NIKON", "D750", Cloudy, 6, { 1.921875, 1, 1.371094, 0 } }, + { "NIKON", "D750", Shade, -6, { 2.695313, 1, 1.000000, 0 } }, + { "NIKON", "D750", Shade, 0, { 2.390625, 1, 1.105469, 0 } }, + { "NIKON", "D750", Shade, 6, { 2.156250, 1, 1.179688, 0 } }, + { "NIKON", "D750", Incandescent, -6, { 1.367188, 1, 1.910156, 0 } }, + { "NIKON", "D750", Incandescent, 0, { 1.257813, 1, 2.097656, 0 } }, + { "NIKON", "D750", Incandescent, 6, { 1.171875, 1, 2.304688, 0 } }, + { "NIKON", "D750", SodiumVaporFluorescent, -6, { 1.312500, 1, 2.082031, 0 } }, + { "NIKON", "D750", SodiumVaporFluorescent, 0, { 1.187500, 1, 2.304688, 0 } }, + { "NIKON", "D750", SodiumVaporFluorescent, 6, { 1.105469, 1, 2.554688, 0 } }, + { "NIKON", "D750", WarmWhiteFluorescent, -6, { 1.375000, 1, 1.773438, 0 } }, + { "NIKON", "D750", WarmWhiteFluorescent, 0, { 1.265625, 1, 1.863281, 0 } }, + { "NIKON", "D750", WarmWhiteFluorescent, 6, { 1.171875, 1, 1.968750, 0 } }, + { "NIKON", "D750", WhiteFluorescent, -6, { 1.769531, 1, 1.976563, 0 } }, + { "NIKON", "D750", WhiteFluorescent, 0, { 1.468750, 1, 2.226563, 0 } }, + { "NIKON", "D750", WhiteFluorescent, 6, { 1.062500, 1, 2.531250, 0 } }, + { "NIKON", "D750", CoolWhiteFluorescent, -6, { 2.054688, 1, 1.757813, 0 } }, + { "NIKON", "D750", CoolWhiteFluorescent, 0, { 1.789063, 1, 1.964844, 0 } }, + { "NIKON", "D750", CoolWhiteFluorescent, 6, { 1.492188, 1, 2.207031, 0 } }, + { "NIKON", "D750", DayWhiteFluorescent, -6, { 1.996094, 1, 1.199219, 0 } }, + { "NIKON", "D750", DayWhiteFluorescent, 0, { 1.835938, 1, 1.359375, 0 } }, + { "NIKON", "D750", DayWhiteFluorescent, 6, { 1.683594, 1, 1.500000, 0 } }, + { "NIKON", "D750", DaylightFluorescent, -6, { 2.269531, 1, 1.000000, 0 } }, + { "NIKON", "D750", DaylightFluorescent, 0, { 2.089844, 1, 1.105469, 0 } }, + { "NIKON", "D750", DaylightFluorescent, 6, { 1.917969, 1, 1.277344, 0 } }, + { "NIKON", "D750", HighTempMercuryVaporFluorescent, -6, { 2.503906, 1, 1.183594, 0 } }, + { "NIKON", "D750", HighTempMercuryVaporFluorescent, 0, { 2.414063, 1, 1.324219, 0 } }, + { "NIKON", "D750", HighTempMercuryVaporFluorescent, 6, { 2.289063, 1, 1.492188, 0 } }, + { "NIKON", "D750", "2700K", 0, { 1.156250, 1, 2.359375, 0 } }, + { "NIKON", "D750", "3300K", 0, { 1.367188, 1, 1.914063, 0 } }, + { "NIKON", "D750", "5000K", 0, { 1.906250, 1, 1.386719, 0 } }, + { "NIKON", "D750", "6500K", 0, { 2.164063, 1, 1.175781, 0 } }, + + { "NIKON", "D800", Incandescent, -6, { 1.390625, 1, 1.984375, 0 } }, + { "NIKON", "D800", Incandescent, 0, { 1.289063, 1, 2.175781, 0 } }, + { "NIKON", "D800", Incandescent, 6, { 1.199219, 1, 2.429688, 0 } }, + { "NIKON", "D800", CoolWhiteFluorescent, -6, { 2.003906, 1, 1.769531, 0 } }, + { "NIKON", "D800", CoolWhiteFluorescent, 0, { 1.765625, 1, 2.003906, 0 } }, + { "NIKON", "D800", CoolWhiteFluorescent, 6, { 1.480469, 1, 2.257813, 0 } }, + { "NIKON", "D800", DirectSunlight, -6, { 2.128906, 1, 1.230469, 0 } }, + { "NIKON", "D800", DirectSunlight, 0, { 1.972656, 1, 1.375000, 0 } }, + { "NIKON", "D800", DirectSunlight, 6, { 1.804688, 1, 1.531250, 0 } }, + { "NIKON", "D800", Flash, -6, { 2.398438, 1, 1.125000, 0 } }, + { "NIKON", "D800", Flash, 0, { 2.187500, 1, 1.207031, 0 } }, + { "NIKON", "D800", Flash, 6, { 2.027344, 1, 1.300781, 0 } }, + { "NIKON", "D800", Cloudy, -6, { 2.292969, 1, 1.156250, 0 } }, + { "NIKON", "D800", Cloudy, 0, { 2.101563, 1, 1.253906, 0 } }, + { "NIKON", "D800", Cloudy, 6, { 1.945313, 1, 1.402344, 0 } }, + { "NIKON", "D800", Shade, -6, { 2.687500, 1, 1.015625, 0 } }, + { "NIKON", "D800", Shade, 0, { 2.378906, 1, 1.128906, 0 } }, + { "NIKON", "D800", Shade, 6, { 2.167969, 1, 1.207031, 0 } }, + { "NIKON", "D800", "2700K", 0, { 1.179688, 1, 2.488281, 0 } }, + { "NIKON", "D800", "5000K", 0, { 1.929688, 1, 1.417969, 0 } }, + + { "NIKON", "D800E", Incandescent, -6, { 1.390625, 1, 1.984375, 0 } }, + { "NIKON", "D800E", Incandescent, 0, { 1.289063, 1, 2.175781, 0 } }, + { "NIKON", "D800E", Incandescent, 6, { 1.199219, 1, 2.429688, 0 } }, + { "NIKON", "D800E", CoolWhiteFluorescent, -6, { 2.003906, 1, 1.769531, 0 } }, + { "NIKON", "D800E", CoolWhiteFluorescent, 0, { 1.765625, 1, 2.003906, 0 } }, + { "NIKON", "D800E", CoolWhiteFluorescent, 6, { 1.480469, 1, 2.257813, 0 } }, + { "NIKON", "D800E", DirectSunlight, -6, { 2.128906, 1, 1.230469, 0 } }, + { "NIKON", "D800E", DirectSunlight, 0, { 1.972656, 1, 1.375000, 0 } }, + { "NIKON", "D800E", DirectSunlight, 6, { 1.804688, 1, 1.531250, 0 } }, + { "NIKON", "D800E", Flash, -6, { 2.398438, 1, 1.125000, 0 } }, + { "NIKON", "D800E", Flash, 0, { 2.187500, 1, 1.207031, 0 } }, + { "NIKON", "D800E", Flash, 6, { 2.027344, 1, 1.300781, 0 } }, + { "NIKON", "D800E", Cloudy, -6, { 2.292969, 1, 1.156250, 0 } }, + { "NIKON", "D800E", Cloudy, 0, { 2.101563, 1, 1.253906, 0 } }, + { "NIKON", "D800E", Cloudy, 6, { 1.945313, 1, 1.402344, 0 } }, + { "NIKON", "D800E", Shade, -6, { 2.687500, 1, 1.015625, 0 } }, + { "NIKON", "D800E", Shade, 0, { 2.378906, 1, 1.128906, 0 } }, + { "NIKON", "D800E", Shade, 6, { 2.167969, 1, 1.207031, 0 } }, + { "NIKON", "D800E", "2700K", 0, { 1.179688, 1, 2.488281, 0 } }, + { "NIKON", "D800E", "5000K", 0, { 1.929688, 1, 1.417969, 0 } }, + + /* D810 with firmware C: 1.10 L: 2.009 */ + { "NIKON", "D810", DirectSunlight, 0, { 1.953125, 1, 1.335938, 0 } }, + { "NIKON", "D810", Flash, 0, { 2.183594, 1, 1.171875, 0 } }, + { "NIKON", "D810", Cloudy, 0, { 2.089844, 1, 1.210938, 0 } }, + { "NIKON", "D810", Shade, 0, { 2.410156, 1, 1.089844, 0 } }, + { "NIKON", "D810", Incandescent, 0, { 1.253906, 1, 2.136719, 0 } }, + { "NIKON", "D810", SodiumVaporFluorescent, 0, { 1.164062, 1, 2.320312, 0 } }, + { "NIKON", "D810", WhiteFluorescent, 0, { 1.445312, 1, 2.210938, 0 } }, + { "NIKON", "D810", WarmWhiteFluorescent, 0, { 1.253906, 1, 1.917969, 0 } }, + { "NIKON", "D810", CoolWhiteFluorescent, 0, { 1.789062, 1, 1.968750, 0 } }, + { "NIKON", "D810", DayWhiteFluorescent, 0, { 1.820312, 1, 1.355469, 0 } }, + { "NIKON", "D810", DaylightFluorescent, 0, { 2.074219, 1, 1.093750, 0 } }, + { "NIKON", "D810", HighTempMercuryVaporFluorescent, 0, { 2.414062, 1, 1.320312, 0 } }, + + { "NIKON", "D40", Incandescent, -3, { 1.492188, 1, 2.164063, 0 } }, + { "NIKON", "D40", Incandescent, -2, { 1.437500, 1, 2.367188, 0 } }, + { "NIKON", "D40", Incandescent, -1, { 1.417969, 1, 2.414062, 0 } }, + { "NIKON", "D40", Incandescent, 0, { 1.375000, 1, 2.511719, 0 } }, + { "NIKON", "D40", Incandescent, 1, { 1.324219, 1, 2.628906, 0 } }, + { "NIKON", "D40", Incandescent, 2, { 1.277344, 1, 2.753906, 0 } }, + { "NIKON", "D40", Incandescent, 3, { 1.222656, 1, 2.914063, 0 } }, + { "NIKON", "D40", Fluorescent, -3, { 2.738281, 1, 1.492188, 0 } }, + { "NIKON", "D40", Fluorescent, -2, { 2.417969, 1, 1.246094, 0 } }, + { "NIKON", "D40", Fluorescent, -1, { 2.093750, 1, 1.570312, 0 } }, + { "NIKON", "D40", Fluorescent, 0, { 2.007813, 1, 2.269531, 0 } }, + { "NIKON", "D40", Fluorescent, 1, { 1.613281, 1, 2.593750, 0 } }, + { "NIKON", "D40", Fluorescent, 2, { 1.394531, 1, 2.343750, 0 } }, + { "NIKON", "D40", Fluorescent, 3, { 1.210938, 1, 2.621094, 0 } }, + { "NIKON", "D40", DirectSunlight, -3, { 2.328125, 1, 1.371094, 0 } }, + { "NIKON", "D40", DirectSunlight, -2, { 2.269531, 1, 1.394531, 0 } }, + { "NIKON", "D40", DirectSunlight, -1, { 2.230469, 1, 1.410156, 0 } }, + { "NIKON", "D40", DirectSunlight, 0, { 2.195313, 1, 1.421875, 0 } }, + { "NIKON", "D40", DirectSunlight, 1, { 2.113281, 1, 1.445312, 0 } }, + { "NIKON", "D40", DirectSunlight, 2, { 2.070312, 1, 1.453125, 0 } }, + { "NIKON", "D40", DirectSunlight, 3, { 2.039063, 1, 1.457031, 0 } }, + { "NIKON", "D40", Flash, -3, { 2.667969, 1, 1.214844, 0 } }, + { "NIKON", "D40", Flash, -2, { 2.605469, 1, 1.234375, 0 } }, + { "NIKON", "D40", Flash, -1, { 2.539062, 1, 1.257812, 0 } }, + { "NIKON", "D40", Flash, 0, { 2.464844, 1, 1.281250, 0 } }, + { "NIKON", "D40", Flash, 1, { 2.390625, 1, 1.312500, 0 } }, + { "NIKON", "D40", Flash, 2, { 2.308594, 1, 1.343750, 0 } }, + { "NIKON", "D40", Flash, 3, { 2.222656, 1, 1.386719, 0 } }, + { "NIKON", "D40", Cloudy, -3, { 2.570313, 1, 1.246094, 0 } }, + { "NIKON", "D40", Cloudy, -2, { 2.523438, 1, 1.269531, 0 } }, + { "NIKON", "D40", Cloudy, -1, { 2.476562, 1, 1.296875, 0 } }, + { "NIKON", "D40", Cloudy, 0, { 2.429688, 1, 1.320313, 0 } }, + { "NIKON", "D40", Cloudy, 1, { 2.382812, 1, 1.343750, 0 } }, + { "NIKON", "D40", Cloudy, 2, { 2.328125, 1, 1.371094, 0 } }, + { "NIKON", "D40", Cloudy, 3, { 2.269531, 1, 1.394531, 0 } }, + { "NIKON", "D40", Shade, -3, { 2.957031, 1, 1.054688, 0 } }, + { "NIKON", "D40", Shade, -2, { 2.921875, 1, 1.074219, 0 } }, + { "NIKON", "D40", Shade, -1, { 2.878906, 1, 1.097656, 0 } }, + { "NIKON", "D40", Shade, 0, { 2.820313, 1, 1.125000, 0 } }, + { "NIKON", "D40", Shade, 1, { 2.746094, 1, 1.160156, 0 } }, + { "NIKON", "D40", Shade, 2, { 2.671875, 1, 1.195312, 0 } }, + { "NIKON", "D40", Shade, 3, { 2.597656, 1, 1.234375, 0 } }, + + { "NIKON", "D40X", Incandescent, -3, { 1.234375, 1, 2.140625, 0 } }, + { "NIKON", "D40X", Incandescent, 0, { 1.148438, 1, 2.386719, 0 } }, + { "NIKON", "D40X", Incandescent, 3, { 1.039062, 1, 2.734375, 0 } }, + { "NIKON", "D40X", Fluorescent, -3, { 2.296875, 1, 1.398438, 0 } }, + { "NIKON", "D40X", Fluorescent, 0, { 1.683594, 1, 2.117188, 0 } }, + { "NIKON", "D40X", Fluorescent, 3, { 1.000000, 1, 2.527344, 0 } }, + { "NIKON", "D40X", DirectSunlight, -3, { 1.882812, 1, 1.300781, 0 } }, + { "NIKON", "D40X", DirectSunlight, 0, { 1.792969, 1, 1.371094, 0 } }, + { "NIKON", "D40X", DirectSunlight, 3, { 1.695312, 1, 1.437500, 0 } }, + { "NIKON", "D40X", Flash, -3, { 2.089844, 1, 1.132812, 0 } }, + { "NIKON", "D40X", Flash, 0, { 1.949219, 1, 1.187500, 0 } }, + { "NIKON", "D40X", Flash, 3, { 1.769531, 1, 1.269531, 0 } }, + { "NIKON", "D40X", Cloudy, -3, { 2.070312, 1, 1.191406, 0 } }, + { "NIKON", "D40X", Cloudy, 0, { 1.960938, 1, 1.253906, 0 } }, + { "NIKON", "D40X", Cloudy, 3, { 1.835938, 1, 1.332031, 0 } }, + { "NIKON", "D40X", Shade, -3, { 2.414062, 1, 1.042969, 0 } }, + { "NIKON", "D40X", Shade, 0, { 2.277344, 1, 1.089844, 0 } }, + { "NIKON", "D40X", Shade, 3, { 2.085938, 1, 1.183594, 0 } }, + + { "NIKON", "D50", Incandescent, 0, { 1.328125, 1, 2.500000, 0 } }, + { "NIKON", "D50", Fluorescent, 0, { 1.945312, 1, 2.191406, 0 } }, + { "NIKON", "D50", DirectSunlight, 0, { 2.140625, 1, 1.398438, 0 } }, + { "NIKON", "D50", Flash, 0, { 2.398438, 1, 1.339844, 0 } }, + { "NIKON", "D50", Cloudy, 0, { 2.360269, 1, 1.282828, 0 } }, + { "NIKON", "D50", Shade, 0, { 2.746094, 1, 1.156250, 0 } }, + + { "NIKON", "D60", DirectSunlight, 0, { 1.792969, 1, 1.371094, 0 } }, + { "NIKON", "D60", Flash, 0, { 2.007813, 1, 1.187500, 0 } }, + { "NIKON", "D60", Cloudy, 0, { 1.960937, 1, 1.253906, 0 } }, + { "NIKON", "D60", Shade, 0, { 2.277344, 1, 1.089844, 0 } }, + { "NIKON", "D60", Incandescent, 0, { 1.148437, 1, 2.382812, 0 } }, + { "NIKON", "D60", SodiumVaporFluorescent, 0, { 1.035156, 1, 2.468750, 0 } }, + { "NIKON", "D60", WarmWhiteFluorescent, 0, { 1.136719, 1, 2.167969, 0 } }, + { "NIKON", "D60", WhiteFluorescent, 0, { 1.343750, 1, 2.480469, 0 } }, + { "NIKON", "D60", CoolWhiteFluorescent, 0, { 1.683594, 1, 2.117187, 0 } }, + { "NIKON", "D60", DayWhiteFluorescent, 0, { 1.679688, 1, 1.414063, 0 } }, + { "NIKON", "D60", DaylightFluorescent, 0, { 1.953125, 1, 1.121094, 0 } }, + { "NIKON", "D60", HighTempMercuryVaporFluorescent, 0, { 2.296875, 1, 1.398438, 0 } }, + + { "NIKON", "D70", Incandescent, -3, { 1.429688, 1, 2.539063, 0 } }, /*3300K*/ + { "NIKON", "D70", Incandescent, -2, { 1.398438, 1, 2.632813, 0 } }, /*3200K*/ + { "NIKON", "D70", Incandescent, -1, { 1.378906, 1, 2.687500, 0 } }, /*3100K*/ + { "NIKON", "D70", Incandescent, 0, { 1.343750, 1, 2.816406, 0 } }, /*3000K*/ + { "NIKON", "D70", Incandescent, 1, { 1.312500, 1, 2.937500, 0 } }, /*2900K*/ + { "NIKON", "D70", Incandescent, 2, { 1.281250, 1, 3.089844, 0 } }, /*2800K*/ + { "NIKON", "D70", Incandescent, 3, { 1.253906, 1, 3.250000, 0 } }, /*2700K*/ + { "NIKON", "D70", Fluorescent, -3, { 2.734375, 1, 1.621094, 0 } }, /*7200K*/ + { "NIKON", "D70", Fluorescent, -2, { 2.417969, 1, 1.343750, 0 } }, /*6500K*/ + { "NIKON", "D70", Fluorescent, -1, { 2.078125, 1, 1.691406, 0 } }, /*5000K*/ + { "NIKON", "D70", Fluorescent, 0, { 1.964844, 1, 2.476563, 0 } }, /*4200K*/ + { "NIKON", "D70", Fluorescent, 1, { 1.566406, 1, 2.753906, 0 } }, /*3700K*/ + { "NIKON", "D70", Fluorescent, 2, { 1.406250, 1, 2.550781, 0 } }, /*3000K*/ + { "NIKON", "D70", Fluorescent, 3, { 1.312500, 1, 2.562500, 0 } }, /*2700K*/ + { "NIKON", "D70", DirectSunlight, -3, { 2.156250, 1, 1.523438, 0 } }, /*5600K*/ + { "NIKON", "D70", DirectSunlight, -2, { 2.109375, 1, 1.562500, 0 } }, /*5400K*/ + { "NIKON", "D70", DirectSunlight, -1, { 2.089844, 1, 1.574219, 0 } }, /*5300K*/ + { "NIKON", "D70", DirectSunlight, 0, { 2.062500, 1, 1.597656, 0 } }, /*5200K*/ + { "NIKON", "D70", DirectSunlight, 1, { 2.007813, 1, 1.648438, 0 } }, /*5000K*/ + { "NIKON", "D70", DirectSunlight, 2, { 1.980469, 1, 1.671875, 0 } }, /*4900K*/ + { "NIKON", "D70", DirectSunlight, 3, { 1.953125, 1, 1.695313, 0 } }, /*4800K*/ + { "NIKON", "D70", Flash, -3, { 2.578125, 1, 1.476563, 0 } }, /*6000K*/ + { "NIKON", "D70", Flash, -2, { 2.535156, 1, 1.484375, 0 } }, /*5800K*/ + { "NIKON", "D70", Flash, -1, { 2.488281, 1, 1.492188, 0 } }, /*5600K*/ + { "NIKON", "D70", Flash, 0, { 2.441406, 1, 1.500000, 0 } }, /*5400K*/ + { "NIKON", "D70", Flash, 1, { 2.421875, 1, 1.507813, 0 } }, /*5200K*/ + { "NIKON", "D70", Flash, 2, { 2.398438, 1, 1.515625, 0 } }, /*5000K*/ + { "NIKON", "D70", Flash, 3, { 2.378906, 1, 1.523438, 0 } }, /*4800K*/ + { "NIKON", "D70", Cloudy, -3, { 2.375000, 1, 1.386719, 0 } }, /*6600K*/ + { "NIKON", "D70", Cloudy, -2, { 2.343750, 1, 1.406250, 0 } }, /*6400K*/ + { "NIKON", "D70", Cloudy, -1, { 2.300781, 1, 1.429688, 0 } }, /*6200K*/ + { "NIKON", "D70", Cloudy, 0, { 2.257813, 1, 1.457031, 0 } }, /*6000K*/ + { "NIKON", "D70", Cloudy, 1, { 2.207031, 1, 1.488281, 0 } }, /*5800K*/ + { "NIKON", "D70", Cloudy, 2, { 2.156250, 1, 1.523438, 0 } }, /*5600K*/ + { "NIKON", "D70", Cloudy, 3, { 2.109375, 1, 1.562500, 0 } }, /*5400K*/ + { "NIKON", "D70", Shade, -3, { 2.757813, 1, 1.226563, 0 } }, /*9200K*/ + { "NIKON", "D70", Shade, -2, { 2.710938, 1, 1.242188, 0 } }, /*8800K*/ + { "NIKON", "D70", Shade, -1, { 2.660156, 1, 1.257813, 0 } }, /*8400K*/ + { "NIKON", "D70", Shade, 0, { 2.613281, 1, 1.277344, 0 } }, /*8000K*/ + { "NIKON", "D70", Shade, 1, { 2.531250, 1, 1.308594, 0 } }, /*7500K*/ + { "NIKON", "D70", Shade, 2, { 2.472656, 1, 1.335938, 0 } }, /*7100K*/ + { "NIKON", "D70", Shade, 3, { 2.394531, 1, 1.375000, 0 } }, /*6700K*/ + + { "NIKON", "D70s", Incandescent, -3, { 1.429688, 1, 2.539063, 0 } }, /*3300K*/ + { "NIKON", "D70s", Incandescent, -2, { 1.398438, 1, 2.632813, 0 } }, /*3200K*/ + { "NIKON", "D70s", Incandescent, -1, { 1.378906, 1, 2.687500, 0 } }, /*3100K*/ + { "NIKON", "D70s", Incandescent, 0, { 1.343750, 1, 2.816406, 0 } }, /*3000K*/ + { "NIKON", "D70s", Incandescent, 1, { 1.312500, 1, 2.937500, 0 } }, /*2900K*/ + { "NIKON", "D70s", Incandescent, 2, { 1.281250, 1, 3.089844, 0 } }, /*2800K*/ + { "NIKON", "D70s", Incandescent, 3, { 1.253906, 1, 3.250000, 0 } }, /*2700K*/ + { "NIKON", "D70s", Fluorescent, -3, { 2.734375, 1, 1.621094, 0 } }, /*7200K*/ + { "NIKON", "D70s", Fluorescent, -2, { 2.417969, 1, 1.343750, 0 } }, /*6500K*/ + { "NIKON", "D70s", Fluorescent, -1, { 2.078125, 1, 1.691406, 0 } }, /*5000K*/ + { "NIKON", "D70s", Fluorescent, 0, { 1.964844, 1, 2.476563, 0 } }, /*4200K*/ + { "NIKON", "D70s", Fluorescent, 1, { 1.566406, 1, 2.753906, 0 } }, /*3700K*/ + { "NIKON", "D70s", Fluorescent, 2, { 1.406250, 1, 2.550781, 0 } }, /*3000K*/ + { "NIKON", "D70s", Fluorescent, 3, { 1.312500, 1, 2.562500, 0 } }, /*2700K*/ + { "NIKON", "D70s", DirectSunlight, -3, { 2.156250, 1, 1.523438, 0 } }, /*5600K*/ + { "NIKON", "D70s", DirectSunlight, -2, { 2.109375, 1, 1.562500, 0 } }, /*5400K*/ + { "NIKON", "D70s", DirectSunlight, -1, { 2.089844, 1, 1.574219, 0 } }, /*5300K*/ + { "NIKON", "D70s", DirectSunlight, 0, { 2.062500, 1, 1.597656, 0 } }, /*5200K*/ + { "NIKON", "D70s", DirectSunlight, 1, { 2.007813, 1, 1.648438, 0 } }, /*5000K*/ + { "NIKON", "D70s", DirectSunlight, 2, { 1.980469, 1, 1.671875, 0 } }, /*4900K*/ + { "NIKON", "D70s", DirectSunlight, 3, { 1.953125, 1, 1.695313, 0 } }, /*4800K*/ + { "NIKON", "D70s", Flash, -3, { 2.578125, 1, 1.476563, 0 } }, /*6000K*/ + { "NIKON", "D70s", Flash, -2, { 2.535156, 1, 1.484375, 0 } }, /*5800K*/ + { "NIKON", "D70s", Flash, -1, { 2.488281, 1, 1.492188, 0 } }, /*5600K*/ + { "NIKON", "D70s", Flash, 0, { 2.441406, 1, 1.500000, 0 } }, /*5400K*/ + { "NIKON", "D70s", Flash, 1, { 2.421875, 1, 1.507813, 0 } }, /*5200K*/ + { "NIKON", "D70s", Flash, 2, { 2.398438, 1, 1.515625, 0 } }, /*5000K*/ + { "NIKON", "D70s", Flash, 3, { 2.378906, 1, 1.523438, 0 } }, /*4800K*/ + { "NIKON", "D70s", Cloudy, -3, { 2.375000, 1, 1.386719, 0 } }, /*6600K*/ + { "NIKON", "D70s", Cloudy, -2, { 2.343750, 1, 1.406250, 0 } }, /*6400K*/ + { "NIKON", "D70s", Cloudy, -1, { 2.300781, 1, 1.429688, 0 } }, /*6200K*/ + { "NIKON", "D70s", Cloudy, 0, { 2.257813, 1, 1.457031, 0 } }, /*6000K*/ + { "NIKON", "D70s", Cloudy, 1, { 2.207031, 1, 1.488281, 0 } }, /*5800K*/ + { "NIKON", "D70s", Cloudy, 2, { 2.156250, 1, 1.523438, 0 } }, /*5600K*/ + { "NIKON", "D70s", Cloudy, 3, { 2.109375, 1, 1.562500, 0 } }, /*5400K*/ + { "NIKON", "D70s", Shade, -3, { 2.757813, 1, 1.226563, 0 } }, /*9200K*/ + { "NIKON", "D70s", Shade, -2, { 2.710938, 1, 1.242188, 0 } }, /*8800K*/ + { "NIKON", "D70s", Shade, -1, { 2.660156, 1, 1.257813, 0 } }, /*8400K*/ + { "NIKON", "D70s", Shade, 0, { 2.613281, 1, 1.277344, 0 } }, /*8000K*/ + { "NIKON", "D70s", Shade, 1, { 2.531250, 1, 1.308594, 0 } }, /*7500K*/ + { "NIKON", "D70s", Shade, 2, { 2.472656, 1, 1.335938, 0 } }, /*7100K*/ + { "NIKON", "D70s", Shade, 3, { 2.394531, 1, 1.375000, 0 } }, /*6700K*/ + + { "NIKON", "D80", Incandescent, -3, { 1.234375, 1, 2.140625, 0 } }, + { "NIKON", "D80", Incandescent, 0, { 1.148438, 1, 2.386719, 0 } }, + { "NIKON", "D80", Incandescent, 3, { 1.039062, 1, 2.734375, 0 } }, + { "NIKON", "D80", Fluorescent, -3, { 2.296875, 1, 1.398438, 0 } }, + { "NIKON", "D80", Fluorescent, 0, { 1.683594, 1, 2.117188, 0 } }, + { "NIKON", "D80", Fluorescent, 3, { 1.000000, 1, 2.527344, 0 } }, + { "NIKON", "D80", Daylight, -3, { 1.882812, 1, 1.300781, 0 } }, + { "NIKON", "D80", Daylight, 0, { 1.792969, 1, 1.371094, 0 } }, + { "NIKON", "D80", Daylight, 3, { 1.695312, 1, 1.437500, 0 } }, + { "NIKON", "D80", Flash, -3, { 2.070312, 1, 1.144531, 0 } }, + { "NIKON", "D80", Flash, 0, { 2.007812, 1, 1.242188, 0 } }, + { "NIKON", "D80", Flash, 3, { 1.972656, 1, 1.156250, 0 } }, + { "NIKON", "D80", Cloudy, -3, { 2.070312, 1, 1.191406, 0 } }, + { "NIKON", "D80", Cloudy, 0, { 1.960938, 1, 1.253906, 0 } }, + { "NIKON", "D80", Cloudy, 3, { 1.835938, 1, 1.332031, 0 } }, + { "NIKON", "D80", Shade, -3, { 2.414062, 1, 1.042969, 0 } }, + { "NIKON", "D80", Shade, 0, { 2.277344, 1, 1.089844, 0 } }, + { "NIKON", "D80", Shade, 3, { 2.085938, 1, 1.183594, 0 } }, + { "NIKON", "D80", "4300K", 0, { 1.562500, 1, 1.523438, 0 } }, + { "NIKON", "D80", "5000K", 0, { 1.746094, 1, 1.410156, 0 } }, + { "NIKON", "D80", "5900K", 0, { 1.941406, 1, 1.265625, 0 } }, + + { "NIKON", "D90", Incandescent, -6, { 1.273438, 1, 1.906250, 0 } }, + { "NIKON", "D90", Incandescent, 0, { 1.179688, 1, 2.097656, 0 } }, + { "NIKON", "D90", Incandescent, 6, { 1.113281, 1, 2.320313, 0 } }, + { "NIKON", "D90", SodiumVaporFluorescent, -6, { 1.164063, 1, 2.058594, 0 } }, + { "NIKON", "D90", SodiumVaporFluorescent, 0, { 1.062500, 1, 2.289063, 0 } }, + { "NIKON", "D90", SodiumVaporFluorescent, 6, { 1.000000, 1, 2.554688, 0 } }, + { "NIKON", "D90", WarmWhiteFluorescent, -6, { 1.285156, 1, 1.761719, 0 } }, + { "NIKON", "D90", WarmWhiteFluorescent, 0, { 1.191406, 1, 1.871094, 0 } }, + { "NIKON", "D90", WarmWhiteFluorescent, 6, { 1.105469, 1, 1.968750, 0 } }, + { "NIKON", "D90", WhiteFluorescent, -6, { 1.628906, 1, 1.953125, 0 } }, + { "NIKON", "D90", WhiteFluorescent, 0, { 1.343750, 1, 2.183594, 0 } }, + { "NIKON", "D90", WhiteFluorescent, 6, { 1.000000, 1, 2.429688, 0 } }, + { "NIKON", "D90", CoolWhiteFluorescent, -6, { 1.867188, 1, 1.722656, 0 } }, + { "NIKON", "D90", CoolWhiteFluorescent, 0, { 1.644531, 1, 1.937500, 0 } }, + { "NIKON", "D90", CoolWhiteFluorescent, 6, { 1.363281, 1, 2.167969, 0 } }, + { "NIKON", "D90", DayWhiteFluorescent, -6, { 1.843750, 1, 1.160156, 0 } }, + { "NIKON", "D90", DayWhiteFluorescent, 0, { 1.695313, 1, 1.312500, 0 } }, + { "NIKON", "D90", DayWhiteFluorescent, 6, { 1.562500, 1, 1.457031, 0 } }, + { "NIKON", "D90", DaylightFluorescent, -6, { 2.089844, 1, 1.000000, 0 } }, + { "NIKON", "D90", DaylightFluorescent, 0, { 1.925781, 1, 1.074219, 0 } }, + { "NIKON", "D90", DaylightFluorescent, 6, { 1.773438, 1, 1.234375, 0 } }, + { "NIKON", "D90", HighTempMercuryVaporFluorescent, -6, { 2.308594, 1, 1.132813, 0 } }, + { "NIKON", "D90", HighTempMercuryVaporFluorescent, 0, { 2.207031, 1, 1.292969, 0 } }, + { "NIKON", "D90", HighTempMercuryVaporFluorescent, 6, { 2.085938, 1, 1.468750, 0 } }, + { "NIKON", "D90", DirectSunlight, -6, { 1.949219, 1, 1.171875, 0 } }, + { "NIKON", "D90", DirectSunlight, 0, { 1.800781, 1, 1.308594, 0 } }, + { "NIKON", "D90", DirectSunlight, 6, { 1.640625, 1, 1.457031, 0 } }, + { "NIKON", "D90", Flash, -6, { 2.218750, 1, 1.062500, 0 } }, + { "NIKON", "D90", Flash, 0, { 1.976563, 1, 1.152344, 0 } }, + { "NIKON", "D90", Flash, 6, { 1.789063, 1, 1.253906, 0 } }, + { "NIKON", "D90", Cloudy, -6, { 2.093750, 1, 1.093750, 0 } }, + { "NIKON", "D90", Cloudy, 0, { 1.917969, 1, 1.187500, 0 } }, + { "NIKON", "D90", Cloudy, 6, { 1.765625, 1, 1.332031, 0 } }, + { "NIKON", "D90", Shade, -6, { 2.453125, 1, 1.000000, 0 } }, + { "NIKON", "D90", Shade, 0, { 2.183594, 1, 1.062500, 0 } }, + { "NIKON", "D90", Shade, 6, { 1.984375, 1, 1.140625, 0 } }, + { "NIKON", "D90", "2500K", 0, { 1.023438, 1, 2.644531, 0 } }, + { "NIKON", "D90", "2560K", 0, { 1.046875, 1, 2.554688, 0 } }, + { "NIKON", "D90", "2630K", 0, { 1.070313, 1, 2.464844, 0 } }, + { "NIKON", "D90", "2700K", 0, { 1.093750, 1, 2.378906, 0 } }, + { "NIKON", "D90", "2780K", 0, { 1.117188, 1, 2.296875, 0 } }, + { "NIKON", "D90", "2860K", 0, { 1.140625, 1, 2.218750, 0 } }, + { "NIKON", "D90", "2940K", 0, { 1.164063, 1, 2.144531, 0 } }, + { "NIKON", "D90", "3030K", 0, { 1.187500, 1, 2.078125, 0 } }, + { "NIKON", "D90", "3130K", 0, { 1.218750, 1, 2.011719, 0 } }, + { "NIKON", "D90", "3230K", 0, { 1.250000, 1, 1.949219, 0 } }, + { "NIKON", "D90", "3330K", 0, { 1.285156, 1, 1.886719, 0 } }, + { "NIKON", "D90", "3450K", 0, { 1.324219, 1, 1.828125, 0 } }, + { "NIKON", "D90", "3570K", 0, { 1.359375, 1, 1.769531, 0 } }, + { "NIKON", "D90", "3700K", 0, { 1.398438, 1, 1.707031, 0 } }, + { "NIKON", "D90", "3850K", 0, { 1.437500, 1, 1.636719, 0 } }, + { "NIKON", "D90", "4000K", 0, { 1.480469, 1, 1.562500, 0 } }, + { "NIKON", "D90", "4170K", 0, { 1.535156, 1, 1.519531, 0 } }, + { "NIKON", "D90", "4350K", 0, { 1.593750, 1, 1.488281, 0 } }, + { "NIKON", "D90", "4550K", 0, { 1.652344, 1, 1.445313, 0 } }, + { "NIKON", "D90", "4760K", 0, { 1.707031, 1, 1.398438, 0 } }, + { "NIKON", "D90", "5000K", 0, { 1.761719, 1, 1.347656, 0 } }, + { "NIKON", "D90", "5260K", 0, { 1.808594, 1, 1.296875, 0 } }, + { "NIKON", "D90", "5560K", 0, { 1.859375, 1, 1.250000, 0 } }, + { "NIKON", "D90", "5880K", 0, { 1.910156, 1, 1.207031, 0 } }, + { "NIKON", "D90", "6250K", 0, { 1.960938, 1, 1.164063, 0 } }, + { "NIKON", "D90", "6670K", 0, { 2.011719, 1, 1.128906, 0 } }, + { "NIKON", "D90", "7140K", 0, { 2.074219, 1, 1.097656, 0 } }, + { "NIKON", "D90", "7690K", 0, { 2.140625, 1, 1.074219, 0 } }, + { "NIKON", "D90", "8330K", 0, { 2.218750, 1, 1.050781, 0 } }, + { "NIKON", "D90", "9090K", 0, { 2.308594, 1, 1.027344, 0 } }, + { "NIKON", "D90", "10000K", 0, { 2.414063, 1, 1.007813, 0 } }, + + { "NIKON", "D3000", DirectSunlight, 0, { 1.851563, 1, 1.347656, 0 } }, + { "NIKON", "D3000", Flash, 0, { 2.113281, 1, 1.164062, 0 } }, + { "NIKON", "D3000", Cloudy, 0, { 2.019531, 1, 1.214844, 0 } }, + { "NIKON", "D3000", Shade, 0, { 2.355469, 1, 1.082031, 0 } }, + { "NIKON", "D3000", Incandescent, 0, { 1.171875, 1, 2.316406, 0 } }, + { "NIKON", "D3000", SodiumVaporFluorescent, 0, { 1.023438, 1, 2.371094, 0 } }, + { "NIKON", "D3000", WarmWhiteFluorescent, 0, { 1.179688, 1, 2.074219, 0 } }, + { "NIKON", "D3000", WhiteFluorescent, 0, { 1.355469, 1, 2.328125, 0 } }, + { "NIKON", "D3000", CoolWhiteFluorescent, 0, { 1.703125, 1, 2.019531, 0 } }, + { "NIKON", "D3000", DayWhiteFluorescent, 0, { 1.750000, 1, 1.386719, 0 } }, + { "NIKON", "D3000", DaylightFluorescent, 0, { 1.960937, 1, 1.105469, 0 } }, + { "NIKON", "D3000", HighTempMercuryVaporFluorescent, 0, { 2.351563, 1, 1.328125, 0 } }, + + { "NIKON", "D3100", DirectSunlight, 0, { 2.109375, 1, 1.257813, 0 } }, + { "NIKON", "D3100", Flash, 0, { 2.386719, 1, 1.097656, 0 } }, + { "NIKON", "D3100", Cloudy, 0, { 2.257812, 1, 1.140625, 0 } }, + { "NIKON", "D3100", Shade, 0, { 2.609375, 1, 1.015625, 0 } }, + { "NIKON", "D3100", Incandescent, 0, { 1.320313, 1, 2.039063, 0 } }, + { "NIKON", "D3100", SodiumVaporFluorescent, 0, { 1.222656, 1, 2.238281, 0 } }, + { "NIKON", "D3100", WarmWhiteFluorescent, 0, { 1.312500, 1, 1.847656, 0 } }, + { "NIKON", "D3100", WhiteFluorescent, 0, { 1.531250, 1, 2.152344, 0 } }, + { "NIKON", "D3100", CoolWhiteFluorescent, 0, { 1.894531, 1, 1.875000, 0 } }, + { "NIKON", "D3100", DayWhiteFluorescent, 0, { 1.941406, 1, 1.281250, 0 } }, + { "NIKON", "D3100", DaylightFluorescent, 0, { 2.214844, 1, 1.015625, 0 } }, + { "NIKON", "D3100", HighTempMercuryVaporFluorescent, 0, { 2.589844, 1, 1.250000, 0 } }, + + /* Firmware version 1.01 */ + /* -6/+6 fine tuning is A6/B6 in amber-blue and zero in green-magenta */ + { "NIKON", "D3200", DirectSunlight, -6, { 2.199219, 1, 1.140625, 0 } }, + { "NIKON", "D3200", DirectSunlight, 0, { 2.050781, 1, 1.273438, 0 } }, + { "NIKON", "D3200", DirectSunlight, 6, { 1.882813, 1, 1.406250, 0 } }, + { "NIKON", "D3200", Flash, -6, { 2.515625, 1, 1.062500, 0 } }, + { "NIKON", "D3200", Flash, 0, { 2.320313, 1, 1.148438, 0 } }, + { "NIKON", "D3200", Flash, 6, { 2.121094, 1, 1.218750, 0 } }, + { "NIKON", "D3200", Cloudy, -6, { 2.355469, 1, 1.078125, 0 } }, + { "NIKON", "D3200", Cloudy, 0, { 2.171875, 1, 1.164063, 0 } }, + { "NIKON", "D3200", Cloudy, 6, { 2.031250, 1, 1.300781, 0 } }, + { "NIKON", "D3200", Shade, -6, { 2.750000, 1, 1.000000, 0 } }, + { "NIKON", "D3200", Shade, 0, { 2.449219, 1, 1.050781, 0 } }, + { "NIKON", "D3200", Shade, 6, { 2.242188, 1, 1.121094, 0 } }, + { "NIKON", "D3200", Incandescent, -6, { 1.468750, 1, 1.796875, 0 } }, + { "NIKON", "D3200", Incandescent, 0, { 1.359375, 1, 1.964844, 0 } }, + { "NIKON", "D3200", Incandescent, 6, { 1.269531, 1, 2.144531, 0 } }, + { "NIKON", "D3200", SodiumVaporFluorescent, -6, { 1.390625, 1, 1.917969, 0 } }, + { "NIKON", "D3200", SodiumVaporFluorescent, 0, { 1.277344, 1, 2.093750, 0 } }, + { "NIKON", "D3200", SodiumVaporFluorescent, 6, { 1.203125, 1, 2.281250, 0 } }, + { "NIKON", "D3200", WarmWhiteFluorescent, -6, { 1.453125, 1, 1.679688, 0 } }, + { "NIKON", "D3200", WarmWhiteFluorescent, 0, { 1.351563, 1, 1.773438, 0 } }, + { "NIKON", "D3200", WarmWhiteFluorescent, 6, { 1.246094, 1, 1.878906, 0 } }, + { "NIKON", "D3200", WhiteFluorescent, -6, { 1.800781, 1, 1.812500, 0 } }, + { "NIKON", "D3200", WhiteFluorescent, 0, { 1.503906, 1, 1.972656, 0 } }, + { "NIKON", "D3200", WhiteFluorescent, 6, { 1.085938, 1, 2.253906, 0 } }, + { "NIKON", "D3200", CoolWhiteFluorescent, -6, { 2.085938, 1, 1.628906, 0 } }, + { "NIKON", "D3200", CoolWhiteFluorescent, 0, { 1.820313, 1, 1.796875, 0 } }, + { "NIKON", "D3200", CoolWhiteFluorescent, 6, { 1.531250, 1, 1.957031, 0 } }, + { "NIKON", "D3200", DayWhiteFluorescent, -6, { 2.027344, 1, 1.117188, 0 } }, + { "NIKON", "D3200", DayWhiteFluorescent, 0, { 1.878906, 1, 1.261719, 0 } }, + { "NIKON", "D3200", DayWhiteFluorescent, 6, { 1.742188, 1, 1.398438, 0 } }, + { "NIKON", "D3200", DaylightFluorescent, -6, { 2.296875, 1, 1.000000, 0 } }, + { "NIKON", "D3200", DaylightFluorescent, 0, { 2.109375, 1, 1.031250, 0 } }, + { "NIKON", "D3200", DaylightFluorescent, 6, { 1.957031, 1, 1.183594, 0 } }, + { "NIKON", "D3200", HighTempMercuryVaporFluorescent, -6, { 2.542969, 1, 1.117188, 0 } }, + { "NIKON", "D3200", HighTempMercuryVaporFluorescent, 0, { 2.445313, 1, 1.250000, 0 } }, + { "NIKON", "D3200", HighTempMercuryVaporFluorescent, 6, { 2.324219, 1, 1.394531, 0 } }, + + { "NIKON", "D3300", DirectSunlight, 0, { 2.054688, 1, 1.394531, 0 } }, + { "NIKON", "D3300", Flash, 0, { 2.289063, 1, 1.230469, 0 } }, + { "NIKON", "D3300", Cloudy, 0, { 2.199219, 1, 1.277344, 0 } }, + { "NIKON", "D3300", Shade, 0, { 2.527344, 1, 1.152344, 0 } }, + { "NIKON", "D3300", Incandescent, 0, { 1.312500, 1, 2.214844, 0 } }, + { "NIKON", "D3300", CoolWhiteFluorescent, 0, { 1.855469, 1, 2.023438, 0 } }, + + { "NIKON", "D5000", DirectSunlight, 0, { 1.800781, 1, 1.308594, 0 } }, + { "NIKON", "D5000", Flash, 0, { 1.976562, 1, 1.152344, 0 } }, + { "NIKON", "D5000", Cloudy, 0, { 1.917969, 1, 1.187500, 0 } }, + { "NIKON", "D5000", Shade, 0, { 2.183594, 1, 1.062500, 0 } }, + { "NIKON", "D5000", Incandescent, 0, { 1.179687, 1, 2.097656, 0 } }, + { "NIKON", "D5000", SodiumVaporFluorescent, 0, { 1.062500, 1, 2.289063, 0 } }, + { "NIKON", "D5000", WarmWhiteFluorescent, 0, { 1.191406, 1, 1.871094, 0 } }, + { "NIKON", "D5000", WhiteFluorescent, 0, { 1.343750, 1, 2.183594, 0 } }, + { "NIKON", "D5000", CoolWhiteFluorescent, 0, { 1.644531, 1, 1.937500, 0 } }, + { "NIKON", "D5000", DayWhiteFluorescent, 0, { 1.695313, 1, 1.312500, 0 } }, + { "NIKON", "D5000", DaylightFluorescent, 0, { 1.925781, 1, 1.074219, 0 } }, + { "NIKON", "D5000", HighTempMercuryVaporFluorescent, 0, { 2.207031, 1, 1.292969, 0 } }, + + { "NIKON", "D5100", DirectSunlight, -6, { 2.199219, 1, 1.242188, 0 } }, + { "NIKON", "D5100", DirectSunlight, -5, { 2.167969, 1, 1.265625, 0 } }, + { "NIKON", "D5100", DirectSunlight, -4, { 2.140625, 1, 1.285156, 0 } }, + { "NIKON", "D5100", DirectSunlight, -3, { 2.117188, 1, 1.308594, 0 } }, + { "NIKON", "D5100", DirectSunlight, -2, { 2.085938, 1, 1.335938, 0 } }, + { "NIKON", "D5100", DirectSunlight, -1, { 2.058594, 1, 1.363281, 0 } }, + { "NIKON", "D5100", DirectSunlight, 0, { 2.027344, 1, 1.390625, 0 } }, + { "NIKON", "D5100", DirectSunlight, 1, { 2.000000, 1, 1.421875, 0 } }, + { "NIKON", "D5100", DirectSunlight, 2, { 1.972656, 1, 1.449219, 0 } }, + { "NIKON", "D5100", DirectSunlight, 3, { 1.941406, 1, 1.472656, 0 } }, + { "NIKON", "D5100", DirectSunlight, 4, { 1.910156, 1, 1.500000, 0 } }, + { "NIKON", "D5100", DirectSunlight, 5, { 1.882813, 1, 1.523438, 0 } }, + { "NIKON", "D5100", DirectSunlight, 6, { 1.847656, 1, 1.542969, 0 } }, + { "NIKON", "D5100", Flash, -6, { 2.511719, 1, 1.132813, 0 } }, + { "NIKON", "D5100", Flash, -5, { 2.460938, 1, 1.144531, 0 } }, + { "NIKON", "D5100", Flash, -4, { 2.414063, 1, 1.160156, 0 } }, + { "NIKON", "D5100", Flash, -3, { 2.375000, 1, 1.171875, 0 } }, + { "NIKON", "D5100", Flash, -2, { 2.339844, 1, 1.183594, 0 } }, + { "NIKON", "D5100", Flash, -1, { 2.308594, 1, 1.199219, 0 } }, + { "NIKON", "D5100", Flash, 0, { 2.281250, 1, 1.210938, 0 } }, + { "NIKON", "D5100", Flash, 1, { 2.250000, 1, 1.226563, 0 } }, + { "NIKON", "D5100", Flash, 2, { 2.222656, 1, 1.238281, 0 } }, + { "NIKON", "D5100", Flash, 3, { 2.191406, 1, 1.253906, 0 } }, + { "NIKON", "D5100", Flash, 4, { 2.160156, 1, 1.273438, 0 } }, + { "NIKON", "D5100", Flash, 5, { 2.125000, 1, 1.289063, 0 } }, + { "NIKON", "D5100", Flash, 6, { 2.089844, 1, 1.308594, 0 } }, + { "NIKON", "D5100", Cloudy, -6, { 2.386719, 1, 1.164063, 0 } }, + { "NIKON", "D5100", Cloudy, -5, { 2.343750, 1, 1.175781, 0 } }, + { "NIKON", "D5100", Cloudy, -4, { 2.300781, 1, 1.195313, 0 } }, + { "NIKON", "D5100", Cloudy, -3, { 2.261719, 1, 1.210938, 0 } }, + { "NIKON", "D5100", Cloudy, -2, { 2.230469, 1, 1.226563, 0 } }, + { "NIKON", "D5100", Cloudy, -1, { 2.199219, 1, 1.242188, 0 } }, + { "NIKON", "D5100", Cloudy, 0, { 2.167969, 1, 1.265625, 0 } }, + { "NIKON", "D5100", Cloudy, 1, { 2.140625, 1, 1.285156, 0 } }, + { "NIKON", "D5100", Cloudy, 2, { 2.117188, 1, 1.308594, 0 } }, + { "NIKON", "D5100", Cloudy, 3, { 2.085938, 1, 1.335938, 0 } }, + { "NIKON", "D5100", Cloudy, 4, { 2.058594, 1, 1.363281, 0 } }, + { "NIKON", "D5100", Cloudy, 5, { 2.027344, 1, 1.390625, 0 } }, + { "NIKON", "D5100", Cloudy, 6, { 2.000000, 1, 1.421875, 0 } }, + { "NIKON", "D5100", Shade, -6, { 2.828125, 1, 1.023438, 0 } }, + { "NIKON", "D5100", Shade, -5, { 2.769531, 1, 1.050781, 0 } }, + { "NIKON", "D5100", Shade, -4, { 2.703125, 1, 1.074219, 0 } }, + { "NIKON", "D5100", Shade, -3, { 2.644531, 1, 1.093750, 0 } }, + { "NIKON", "D5100", Shade, -2, { 2.585938, 1, 1.109375, 0 } }, + { "NIKON", "D5100", Shade, -1, { 2.539063, 1, 1.121094, 0 } }, + { "NIKON", "D5100", Shade, 0, { 2.492188, 1, 1.136719, 0 } }, + { "NIKON", "D5100", Shade, 1, { 2.445313, 1, 1.148438, 0 } }, + { "NIKON", "D5100", Shade, 2, { 2.406250, 1, 1.156250, 0 } }, + { "NIKON", "D5100", Shade, 3, { 2.359375, 1, 1.171875, 0 } }, + { "NIKON", "D5100", Shade, 4, { 2.316406, 1, 1.187500, 0 } }, + { "NIKON", "D5100", Shade, 5, { 2.277344, 1, 1.203125, 0 } }, + { "NIKON", "D5100", Shade, 6, { 2.246094, 1, 1.218750, 0 } }, + { "NIKON", "D5100", Incandescent, -6, { 1.417969, 1, 2.003906, 0 } }, + { "NIKON", "D5100", Incandescent, -5, { 1.394531, 1, 2.035156, 0 } }, + { "NIKON", "D5100", Incandescent, -4, { 1.375000, 1, 2.066406, 0 } }, + { "NIKON", "D5100", Incandescent, -3, { 1.355469, 1, 2.101563, 0 } }, + { "NIKON", "D5100", Incandescent, -2, { 1.339844, 1, 2.140625, 0 } }, + { "NIKON", "D5100", Incandescent, -1, { 1.324219, 1, 2.179688, 0 } }, + { "NIKON", "D5100", Incandescent, 0, { 1.304688, 1, 2.214844, 0 } }, + { "NIKON", "D5100", Incandescent, 1, { 1.289063, 1, 2.257813, 0 } }, + { "NIKON", "D5100", Incandescent, 2, { 1.273438, 1, 2.296875, 0 } }, + { "NIKON", "D5100", Incandescent, 3, { 1.261719, 1, 2.335938, 0 } }, + { "NIKON", "D5100", Incandescent, 4, { 1.246094, 1, 2.378906, 0 } }, + { "NIKON", "D5100", Incandescent, 5, { 1.230469, 1, 2.421875, 0 } }, + { "NIKON", "D5100", Incandescent, 6, { 1.218750, 1, 2.464844, 0 } }, + { "NIKON", "D5100", SodiumVaporFluorescent, -6, { 1.324219, 1, 2.187500, 0 } }, + { "NIKON", "D5100", SodiumVaporFluorescent, -5, { 1.296875, 1, 2.230469, 0 } }, + { "NIKON", "D5100", SodiumVaporFluorescent, -4, { 1.273438, 1, 2.277344, 0 } }, + { "NIKON", "D5100", SodiumVaporFluorescent, -3, { 1.253906, 1, 2.316406, 0 } }, + { "NIKON", "D5100", SodiumVaporFluorescent, -2, { 1.238281, 1, 2.355469, 0 } }, + { "NIKON", "D5100", SodiumVaporFluorescent, -1, { 1.218750, 1, 2.398438, 0 } }, + { "NIKON", "D5100", SodiumVaporFluorescent, 0, { 1.203125, 1, 2.437500, 0 } }, + { "NIKON", "D5100", SodiumVaporFluorescent, 1, { 1.187500, 1, 2.480469, 0 } }, + { "NIKON", "D5100", SodiumVaporFluorescent, 2, { 1.175781, 1, 2.523438, 0 } }, + { "NIKON", "D5100", SodiumVaporFluorescent, 3, { 1.164063, 1, 2.566406, 0 } }, + { "NIKON", "D5100", SodiumVaporFluorescent, 4, { 1.152344, 1, 2.609375, 0 } }, + { "NIKON", "D5100", SodiumVaporFluorescent, 5, { 1.140625, 1, 2.664063, 0 } }, + { "NIKON", "D5100", SodiumVaporFluorescent, 6, { 1.128906, 1, 2.718750, 0 } }, + { "NIKON", "D5100", WarmWhiteFluorescent, -6, { 1.414063, 1, 1.859375, 0 } }, + { "NIKON", "D5100", WarmWhiteFluorescent, -5, { 1.394531, 1, 1.878906, 0 } }, + { "NIKON", "D5100", WarmWhiteFluorescent, -4, { 1.375000, 1, 1.894531, 0 } }, + { "NIKON", "D5100", WarmWhiteFluorescent, -3, { 1.355469, 1, 1.914063, 0 } }, + { "NIKON", "D5100", WarmWhiteFluorescent, -2, { 1.335938, 1, 1.929688, 0 } }, + { "NIKON", "D5100", WarmWhiteFluorescent, -1, { 1.316406, 1, 1.949219, 0 } }, + { "NIKON", "D5100", WarmWhiteFluorescent, 0, { 1.300781, 1, 1.964844, 0 } }, + { "NIKON", "D5100", WarmWhiteFluorescent, 1, { 1.281250, 1, 1.984375, 0 } }, + { "NIKON", "D5100", WarmWhiteFluorescent, 2, { 1.261719, 1, 2.003906, 0 } }, + { "NIKON", "D5100", WarmWhiteFluorescent, 3, { 1.246094, 1, 2.023438, 0 } }, + { "NIKON", "D5100", WarmWhiteFluorescent, 4, { 1.230469, 1, 2.042969, 0 } }, + { "NIKON", "D5100", WarmWhiteFluorescent, 5, { 1.214844, 1, 2.062500, 0 } }, + { "NIKON", "D5100", WarmWhiteFluorescent, 6, { 1.199219, 1, 2.082031, 0 } }, + { "NIKON", "D5100", WhiteFluorescent, -6, { 1.812500, 1, 2.042969, 0 } }, + { "NIKON", "D5100", WhiteFluorescent, -5, { 1.765625, 1, 2.085938, 0 } }, + { "NIKON", "D5100", WhiteFluorescent, -4, { 1.714844, 1, 2.128906, 0 } }, + { "NIKON", "D5100", WhiteFluorescent, -3, { 1.664063, 1, 2.171875, 0 } }, + { "NIKON", "D5100", WhiteFluorescent, -2, { 1.609375, 1, 2.214844, 0 } }, + { "NIKON", "D5100", WhiteFluorescent, -1, { 1.550781, 1, 2.261719, 0 } }, + { "NIKON", "D5100", WhiteFluorescent, 0, { 1.496094, 1, 2.304688, 0 } }, + { "NIKON", "D5100", WhiteFluorescent, 1, { 1.429688, 1, 2.355469, 0 } }, + { "NIKON", "D5100", WhiteFluorescent, 2, { 1.363281, 1, 2.406250, 0 } }, + { "NIKON", "D5100", WhiteFluorescent, 3, { 1.296875, 1, 2.460938, 0 } }, + { "NIKON", "D5100", WhiteFluorescent, 4, { 1.226563, 1, 2.515625, 0 } }, + { "NIKON", "D5100", WhiteFluorescent, 5, { 1.156250, 1, 2.570313, 0 } }, + { "NIKON", "D5100", WhiteFluorescent, 6, { 1.078125, 1, 2.628906, 0 } }, + { "NIKON", "D5100", CoolWhiteFluorescent, -6, { 2.105469, 1, 1.808594, 0 } }, + { "NIKON", "D5100", CoolWhiteFluorescent, -5, { 2.062500, 1, 1.843750, 0 } }, + { "NIKON", "D5100", CoolWhiteFluorescent, -4, { 2.019531, 1, 1.878906, 0 } }, + { "NIKON", "D5100", CoolWhiteFluorescent, -3, { 1.976563, 1, 1.917969, 0 } }, + { "NIKON", "D5100", CoolWhiteFluorescent, -2, { 1.933594, 1, 1.953125, 0 } }, + { "NIKON", "D5100", CoolWhiteFluorescent, -1, { 1.882813, 1, 1.988281, 0 } }, + { "NIKON", "D5100", CoolWhiteFluorescent, 0, { 1.832031, 1, 2.027344, 0 } }, + { "NIKON", "D5100", CoolWhiteFluorescent, 1, { 1.789063, 1, 2.070313, 0 } }, + { "NIKON", "D5100", CoolWhiteFluorescent, 2, { 1.738281, 1, 2.109375, 0 } }, + { "NIKON", "D5100", CoolWhiteFluorescent, 3, { 1.687500, 1, 2.152344, 0 } }, + { "NIKON", "D5100", CoolWhiteFluorescent, 4, { 1.632813, 1, 2.195313, 0 } }, + { "NIKON", "D5100", CoolWhiteFluorescent, 5, { 1.574219, 1, 2.238281, 0 } }, + { "NIKON", "D5100", CoolWhiteFluorescent, 6, { 1.519531, 1, 2.281250, 0 } }, + { "NIKON", "D5100", DayWhiteFluorescent, -6, { 2.070313, 1, 1.214844, 0 } }, + { "NIKON", "D5100", DayWhiteFluorescent, -5, { 2.042969, 1, 1.246094, 0 } }, + { "NIKON", "D5100", DayWhiteFluorescent, -4, { 2.011719, 1, 1.277344, 0 } }, + { "NIKON", "D5100", DayWhiteFluorescent, -3, { 1.984375, 1, 1.304688, 0 } }, + { "NIKON", "D5100", DayWhiteFluorescent, -2, { 1.953125, 1, 1.332031, 0 } }, + { "NIKON", "D5100", DayWhiteFluorescent, -1, { 1.925781, 1, 1.363281, 0 } }, + { "NIKON", "D5100", DayWhiteFluorescent, 0, { 1.898438, 1, 1.390625, 0 } }, + { "NIKON", "D5100", DayWhiteFluorescent, 1, { 1.871094, 1, 1.417969, 0 } }, + { "NIKON", "D5100", DayWhiteFluorescent, 2, { 1.843750, 1, 1.441406, 0 } }, + { "NIKON", "D5100", DayWhiteFluorescent, 3, { 1.816406, 1, 1.472656, 0 } }, + { "NIKON", "D5100", DayWhiteFluorescent, 4, { 1.792969, 1, 1.496094, 0 } }, + { "NIKON", "D5100", DayWhiteFluorescent, 5, { 1.765625, 1, 1.523438, 0 } }, + { "NIKON", "D5100", DayWhiteFluorescent, 6, { 1.742188, 1, 1.546875, 0 } }, + { "NIKON", "D5100", DaylightFluorescent, -6, { 2.359375, 1, 1.000000, 0 } }, + { "NIKON", "D5100", DaylightFluorescent, -5, { 2.328125, 1, 1.000000, 0 } }, + { "NIKON", "D5100", DaylightFluorescent, -4, { 2.296875, 1, 1.000000, 0 } }, + { "NIKON", "D5100", DaylightFluorescent, -3, { 2.261719, 1, 1.015625, 0 } }, + { "NIKON", "D5100", DaylightFluorescent, -2, { 2.230469, 1, 1.050781, 0 } }, + { "NIKON", "D5100", DaylightFluorescent, -1, { 2.199219, 1, 1.082031, 0 } }, + { "NIKON", "D5100", DaylightFluorescent, 0, { 2.167969, 1, 1.117188, 0 } }, + { "NIKON", "D5100", DaylightFluorescent, 1, { 2.136719, 1, 1.148438, 0 } }, + { "NIKON", "D5100", DaylightFluorescent, 2, { 2.109375, 1, 1.179688, 0 } }, + { "NIKON", "D5100", DaylightFluorescent, 3, { 2.078125, 1, 1.210938, 0 } }, + { "NIKON", "D5100", DaylightFluorescent, 4, { 2.046875, 1, 1.242188, 0 } }, + { "NIKON", "D5100", DaylightFluorescent, 5, { 2.019531, 1, 1.269531, 0 } }, + { "NIKON", "D5100", DaylightFluorescent, 6, { 1.988281, 1, 1.300781, 0 } }, + { "NIKON", "D5100", HighTempMercuryVaporFluorescent, -6, { 2.578125, 1, 1.222656, 0 } }, + { "NIKON", "D5100", HighTempMercuryVaporFluorescent, -5, { 2.566406, 1, 1.246094, 0 } }, + { "NIKON", "D5100", HighTempMercuryVaporFluorescent, -4, { 2.550781, 1, 1.265625, 0 } }, + { "NIKON", "D5100", HighTempMercuryVaporFluorescent, -3, { 2.535156, 1, 1.292969, 0 } }, + { "NIKON", "D5100", HighTempMercuryVaporFluorescent, -2, { 2.519531, 1, 1.316406, 0 } }, + { "NIKON", "D5100", HighTempMercuryVaporFluorescent, -1, { 2.503906, 1, 1.343750, 0 } }, + { "NIKON", "D5100", HighTempMercuryVaporFluorescent, 0, { 2.484375, 1, 1.367188, 0 } }, + { "NIKON", "D5100", HighTempMercuryVaporFluorescent, 1, { 2.464844, 1, 1.394531, 0 } }, + { "NIKON", "D5100", HighTempMercuryVaporFluorescent, 2, { 2.441406, 1, 1.421875, 0 } }, + { "NIKON", "D5100", HighTempMercuryVaporFluorescent, 3, { 2.425781, 1, 1.453125, 0 } }, + { "NIKON", "D5100", HighTempMercuryVaporFluorescent, 4, { 2.402344, 1, 1.476563, 0 } }, + { "NIKON", "D5100", HighTempMercuryVaporFluorescent, 5, { 2.375000, 1, 1.511719, 0 } }, + { "NIKON", "D5100", HighTempMercuryVaporFluorescent, 6, { 2.375000, 1, 1.511719, 0 } }, + + /* NIKON D5200 firmware version 1.01 */ + { "NIKON", "D5200", DirectSunlight, 0, { 2.386719, 1, 1.597656, 0 } }, + { "NIKON", "D5200", Flash, 0, { 2.753906, 1, 1.371094, 0 } }, + { "NIKON", "D5200", Cloudy, 0, { 2.656250, 1, 1.453125, 0 } }, + { "NIKON", "D5200", Shade, 0, { 3.183594, 1, 1.292969, 0 } }, + { "NIKON", "D5200", Incandescent, 0, { 1.445313, 1, 2.667969, 0 } }, + { "NIKON", "D5200", CoolWhiteFluorescent, 0, { 2.222656, 1, 2.417969, 0 } }, + + { "NIKON", "D5300", DirectSunlight, 0, { 2.054688, 1, 1.394531, 0 } }, + { "NIKON", "D5300", Flash, 0, { 2.289063, 1, 1.230469, 0 } }, + { "NIKON", "D5300", Cloudy, 0, { 2.199219, 1, 1.277344, 0 } }, + { "NIKON", "D5300", Shade, 0, { 2.527344, 1, 1.152344, 0 } }, + { "NIKON", "D5300", Incandescent, 0, { 1.312500, 1, 2.214844, 0 } }, + { "NIKON", "D5300", CoolWhiteFluorescent, 0, { 1.855469, 1, 2.023438, 0 } }, + + { "NIKON", "D5500", DirectSunlight, 0, { 2.050781, 1, 1.402344, 0 } }, + { "NIKON", "D5500", Shade, 0, { 2.527344, 1, 1.144531, 0 } }, + { "NIKON", "D5500", Cloudy, 0, { 2.191406, 1, 1.281250, 0 } }, + { "NIKON", "D5500", Incandescent, 0, { 1.308594, 1, 2.214844, 0 } }, + { "NIKON", "D5500", WarmWhiteFluorescent, 0, { 1.289062, 1, 1.984375, 0 } }, + { "NIKON", "D5500", CoolWhiteFluorescent, 0, { 1.863281, 1, 2.046875, 0 } }, + { "NIKON", "D5500", DayWhiteFluorescent, 0, { 1.890625, 1, 1.406250, 0 } }, + { "NIKON", "D5500", DaylightFluorescent, 0, { 2.148438, 1, 1.140625, 0 } }, + { "NIKON", "D5500", WhiteFluorescent, 0, { 1.511719, 1, 2.332031, 0 } }, + { "NIKON", "D5500", HighTempMercuryVaporFluorescent, 0, { 2.519531, 1, 1.378906, 0 } }, + { "NIKON", "D5500", SodiumVaporFluorescent, 0, { 1.210938, 1, 2.437500, 0 } }, + { "NIKON", "D5500", Flash, 0, { 2.285156, 1, 1.226562, 0 } }, + + { "NIKON", "D7000", DirectSunlight, -6, { 2.199219, 1, 1.242187, 0 } }, + { "NIKON", "D7000", DirectSunlight, 0, { 2.027344, 1, 1.390625, 0 } }, + { "NIKON", "D7000", DirectSunlight, 6, { 1.847656, 1, 1.542969, 0 } }, + { "NIKON", "D7000", Flash, -6, { 2.511719, 1, 1.132812, 0 } }, + { "NIKON", "D7000", Flash, 0, { 2.281250, 1, 1.210938, 0 } }, + { "NIKON", "D7000", Flash, 6, { 2.089844, 1, 1.308594, 0 } }, + { "NIKON", "D7000", Cloudy, -6, { 2.386719, 1, 1.164062, 0 } }, + { "NIKON", "D7000", Cloudy, 0, { 2.167969, 1, 1.265625, 0 } }, + { "NIKON", "D7000", Cloudy, 6, { 2.000000, 1, 1.421875, 0 } }, + { "NIKON", "D7000", Shade, -6, { 2.828125, 1, 1.023437, 0 } }, + { "NIKON", "D7000", Shade, 0, { 2.492188, 1, 1.136719, 0 } }, + { "NIKON", "D7000", Shade, 6, { 2.246094, 1, 1.218750, 0 } }, + { "NIKON", "D7000", Incandescent, -6, { 1.417969, 1, 2.003906, 0 } }, + { "NIKON", "D7000", Incandescent, 0, { 1.304688, 1, 2.214844, 0 } }, + { "NIKON", "D7000", Incandescent, 6, { 1.218750, 1, 2.464844, 0 } }, + { "NIKON", "D7000", SodiumVaporFluorescent, -6, { 1.324219, 1, 2.187500, 0 } }, + { "NIKON", "D7000", SodiumVaporFluorescent, 0, { 1.203125, 1, 2.437500, 0 } }, + { "NIKON", "D7000", SodiumVaporFluorescent, 6, { 1.128906, 1, 2.718750, 0 } }, + { "NIKON", "D7000", WarmWhiteFluorescent, -6, { 1.414062, 1, 1.859375, 0 } }, + { "NIKON", "D7000", WarmWhiteFluorescent, 0, { 1.300781, 1, 1.964844, 0 } }, + { "NIKON", "D7000", WarmWhiteFluorescent, 6, { 1.199219, 1, 2.082031, 0 } }, + { "NIKON", "D7000", WhiteFluorescent, -6, { 1.812500, 1, 2.042969, 0 } }, + { "NIKON", "D7000", WhiteFluorescent, 0, { 1.496094, 1, 2.304688, 0 } }, + { "NIKON", "D7000", WhiteFluorescent, 6, { 1.078125, 1, 2.628906, 0 } }, + { "NIKON", "D7000", CoolWhiteFluorescent, -6, { 2.105469, 1, 1.808594, 0 } }, + { "NIKON", "D7000", CoolWhiteFluorescent, 0, { 1.832031, 1, 2.027344, 0 } }, + { "NIKON", "D7000", CoolWhiteFluorescent, 6, { 1.519531, 1, 2.281250, 0 } }, + { "NIKON", "D7000", DayWhiteFluorescent, -6, { 2.070312, 1, 1.214844, 0 } }, + { "NIKON", "D7000", DayWhiteFluorescent, 0, { 1.898438, 1, 1.390625, 0 } }, + { "NIKON", "D7000", DayWhiteFluorescent, 6, { 1.742187, 1, 1.546875, 0 } }, + { "NIKON", "D7000", DaylightFluorescent, -6, { 2.359375, 1, 1.000000, 0 } }, + { "NIKON", "D7000", DaylightFluorescent, 0, { 2.167969, 1, 1.117187, 0 } }, + { "NIKON", "D7000", DaylightFluorescent, 6, { 1.988281, 1, 1.300781, 0 } }, + { "NIKON", "D7000", HighTempMercuryVaporFluorescent, -6, { 2.578125, 1, 1.222656, 0 } }, + { "NIKON", "D7000", HighTempMercuryVaporFluorescent, 0, { 2.484375, 1, 1.367188, 0 } }, + { "NIKON", "D7000", HighTempMercuryVaporFluorescent, 6, { 2.351563, 1, 1.539063, 0 } }, + + /* NIKON D7100 / Firmware C 1.03 / L 2.008 */ + { "NIKON", "D7100", DirectSunlight, -6, { 2.675781, 1, 1.425781, 0 } }, + { "NIKON", "D7100", DirectSunlight, -5, { 2.628906, 1, 1.449219, 0 } }, + { "NIKON", "D7100", DirectSunlight, -4, { 2.582031, 1, 1.476563, 0 } }, + { "NIKON", "D7100", DirectSunlight, -3, { 2.535156, 1, 1.503906, 0 } }, + { "NIKON", "D7100", DirectSunlight, -2, { 2.492188, 1, 1.535156, 0 } }, + { "NIKON", "D7100", DirectSunlight, -1, { 2.441406, 1, 1.566406, 0 } }, + { "NIKON", "D7100", DirectSunlight, 0, { 2.386719, 1, 1.597656, 0 } }, + { "NIKON", "D7100", DirectSunlight, 1, { 2.351563, 1, 1.632813, 0 } }, + { "NIKON", "D7100", DirectSunlight, 2, { 2.312500, 1, 1.671875, 0 } }, + { "NIKON", "D7100", DirectSunlight, 3, { 2.273438, 1, 1.703125, 0 } }, + { "NIKON", "D7100", DirectSunlight, 4, { 2.230469, 1, 1.734375, 0 } }, + { "NIKON", "D7100", DirectSunlight, 5, { 2.187500, 1, 1.761719, 0 } }, + { "NIKON", "D7100", DirectSunlight, 6, { 2.144531, 1, 1.789063, 0 } }, + { "NIKON", "D7100", Flash, -6, { 3.132813, 1, 1.281250, 0 } }, + { "NIKON", "D7100", Flash, -5, { 3.050781, 1, 1.296875, 0 } }, + { "NIKON", "D7100", Flash, -4, { 2.976563, 1, 1.312500, 0 } }, + { "NIKON", "D7100", Flash, -3, { 2.914063, 1, 1.328125, 0 } }, + { "NIKON", "D7100", Flash, -2, { 2.855469, 1, 1.343750, 0 } }, + { "NIKON", "D7100", Flash, -1, { 2.800781, 1, 1.355469, 0 } }, + { "NIKON", "D7100", Flash, 0, { 2.753906, 1, 1.371094, 0 } }, + { "NIKON", "D7100", Flash, 1, { 2.710938, 1, 1.386719, 0 } }, + { "NIKON", "D7100", Flash, 2, { 2.671875, 1, 1.406250, 0 } }, + { "NIKON", "D7100", Flash, 3, { 2.628906, 1, 1.425781, 0 } }, + { "NIKON", "D7100", Flash, 4, { 2.585938, 1, 1.449219, 0 } }, + { "NIKON", "D7100", Flash, 5, { 2.539063, 1, 1.472656, 0 } }, + { "NIKON", "D7100", Flash, 6, { 2.488281, 1, 1.500000, 0 } }, + { "NIKON", "D7100", Cloudy, -6, { 2.972656, 1, 1.328125, 0 } }, + { "NIKON", "D7100", Cloudy, -5, { 2.902344, 1, 1.347656, 0 } }, + { "NIKON", "D7100", Cloudy, -4, { 2.839844, 1, 1.363281, 0 } }, + { "NIKON", "D7100", Cloudy, -3, { 2.781250, 1, 1.382813, 0 } }, + { "NIKON", "D7100", Cloudy, -2, { 2.734375, 1, 1.402344, 0 } }, + { "NIKON", "D7100", Cloudy, -1, { 2.695313, 1, 1.425781, 0 } }, + { "NIKON", "D7100", Cloudy, 0, { 2.656250, 1, 1.453125, 0 } }, + { "NIKON", "D7100", Cloudy, 1, { 2.597656, 1, 1.476563, 0 } }, + { "NIKON", "D7100", Cloudy, 2, { 2.542969, 1, 1.507813, 0 } }, + { "NIKON", "D7100", Cloudy, 3, { 2.492188, 1, 1.535156, 0 } }, + { "NIKON", "D7100", Cloudy, 4, { 2.445313, 1, 1.566406, 0 } }, + { "NIKON", "D7100", Cloudy, 5, { 2.398438, 1, 1.601563, 0 } }, + { "NIKON", "D7100", Cloudy, 6, { 2.351563, 1, 1.632813, 0 } }, + { "NIKON", "D7100", Shade, -6, { 3.644531, 1, 1.148438, 0 } }, + { "NIKON", "D7100", Shade, -5, { 3.554688, 1, 1.183594, 0 } }, + { "NIKON", "D7100", Shade, -4, { 3.472656, 1, 1.214844, 0 } }, + { "NIKON", "D7100", Shade, -3, { 3.386719, 1, 1.234375, 0 } }, + { "NIKON", "D7100", Shade, -2, { 3.308594, 1, 1.257813, 0 } }, + { "NIKON", "D7100", Shade, -1, { 3.242188, 1, 1.277344, 0 } }, + { "NIKON", "D7100", Shade, 0, { 3.183594, 1, 1.292969, 0 } }, + { "NIKON", "D7100", Shade, 1, { 3.085938, 1, 1.308594, 0 } }, + { "NIKON", "D7100", Shade, 2, { 2.992188, 1, 1.324219, 0 } }, + { "NIKON", "D7100", Shade, 3, { 2.925781, 1, 1.339844, 0 } }, + { "NIKON", "D7100", Shade, 4, { 2.859375, 1, 1.355469, 0 } }, + { "NIKON", "D7100", Shade, 5, { 2.796875, 1, 1.371094, 0 } }, + { "NIKON", "D7100", Shade, 6, { 2.746094, 1, 1.394531, 0 } }, + { "NIKON", "D7100", Incandescent, -6, { 1.589844, 1, 2.371094, 0 } }, + { "NIKON", "D7100", Incandescent, -5, { 1.562500, 1, 2.417969, 0 } }, + { "NIKON", "D7100", Incandescent, -4, { 1.542969, 1, 2.468750, 0 } }, + { "NIKON", "D7100", Incandescent, -3, { 1.519531, 1, 2.519531, 0 } }, + { "NIKON", "D7100", Incandescent, -2, { 1.492188, 1, 2.566406, 0 } }, + { "NIKON", "D7100", Incandescent, -1, { 1.468750, 1, 2.617188, 0 } }, + { "NIKON", "D7100", Incandescent, 0, { 1.445313, 1, 2.667969, 0 } }, + { "NIKON", "D7100", Incandescent, 1, { 1.425781, 1, 2.718750, 0 } }, + { "NIKON", "D7100", Incandescent, 2, { 1.410156, 1, 2.769531, 0 } }, + { "NIKON", "D7100", Incandescent, 3, { 1.390625, 1, 2.820313, 0 } }, + { "NIKON", "D7100", Incandescent, 4, { 1.371094, 1, 2.875000, 0 } }, + { "NIKON", "D7100", Incandescent, 5, { 1.355469, 1, 2.925781, 0 } }, + { "NIKON", "D7100", Incandescent, 6, { 1.335938, 1, 2.980469, 0 } }, + { "NIKON", "D7100", SodiumVaporFluorescent, -6, { 1.488281, 1, 2.589844, 0 } }, + { "NIKON", "D7100", SodiumVaporFluorescent, -5, { 1.457031, 1, 2.644531, 0 } }, + { "NIKON", "D7100", SodiumVaporFluorescent, -4, { 1.425781, 1, 2.695313, 0 } }, + { "NIKON", "D7100", SodiumVaporFluorescent, -3, { 1.398438, 1, 2.746094, 0 } }, + { "NIKON", "D7100", SodiumVaporFluorescent, -2, { 1.375000, 1, 2.792969, 0 } }, + { "NIKON", "D7100", SodiumVaporFluorescent, -1, { 1.355469, 1, 2.847656, 0 } }, + { "NIKON", "D7100", SodiumVaporFluorescent, 0, { 1.332031, 1, 2.894531, 0 } }, + { "NIKON", "D7100", SodiumVaporFluorescent, 1, { 1.312500, 1, 2.949219, 0 } }, + { "NIKON", "D7100", SodiumVaporFluorescent, 2, { 1.296875, 1, 3.000000, 0 } }, + { "NIKON", "D7100", SodiumVaporFluorescent, 3, { 1.281250, 1, 3.058594, 0 } }, + { "NIKON", "D7100", SodiumVaporFluorescent, 4, { 1.261719, 1, 3.113281, 0 } }, + { "NIKON", "D7100", SodiumVaporFluorescent, 5, { 1.250000, 1, 3.179688, 0 } }, + { "NIKON", "D7100", SodiumVaporFluorescent, 6, { 1.234375, 1, 3.246094, 0 } }, + { "NIKON", "D7100", WarmWhiteFluorescent, -6, { 1.621094, 1, 2.281250, 0 } }, + { "NIKON", "D7100", WarmWhiteFluorescent, -5, { 1.597656, 1, 2.304688, 0 } }, + { "NIKON", "D7100", WarmWhiteFluorescent, -4, { 1.574219, 1, 2.328125, 0 } }, + { "NIKON", "D7100", WarmWhiteFluorescent, -3, { 1.546875, 1, 2.351563, 0 } }, + { "NIKON", "D7100", WarmWhiteFluorescent, -2, { 1.527344, 1, 2.378906, 0 } }, + { "NIKON", "D7100", WarmWhiteFluorescent, -1, { 1.500000, 1, 2.398438, 0 } }, + { "NIKON", "D7100", WarmWhiteFluorescent, 0, { 1.480469, 1, 2.425781, 0 } }, + { "NIKON", "D7100", WarmWhiteFluorescent, 1, { 1.460938, 1, 2.449219, 0 } }, + { "NIKON", "D7100", WarmWhiteFluorescent, 2, { 1.441406, 1, 2.476563, 0 } }, + { "NIKON", "D7100", WarmWhiteFluorescent, 3, { 1.421875, 1, 2.500000, 0 } }, + { "NIKON", "D7100", WarmWhiteFluorescent, 4, { 1.402344, 1, 2.523438, 0 } }, + { "NIKON", "D7100", WarmWhiteFluorescent, 5, { 1.382813, 1, 2.546875, 0 } }, + { "NIKON", "D7100", WarmWhiteFluorescent, 6, { 1.363281, 1, 2.570313, 0 } }, + { "NIKON", "D7100", WhiteFluorescent, -6, { 2.199219, 1, 2.437500, 0 } }, + { "NIKON", "D7100", WhiteFluorescent, -5, { 2.128906, 1, 2.492188, 0 } }, + { "NIKON", "D7100", WhiteFluorescent, -4, { 2.054688, 1, 2.546875, 0 } }, + { "NIKON", "D7100", WhiteFluorescent, -3, { 1.980469, 1, 2.605469, 0 } }, + { "NIKON", "D7100", WhiteFluorescent, -2, { 1.902344, 1, 2.660156, 0 } }, + { "NIKON", "D7100", WhiteFluorescent, -1, { 1.824219, 1, 2.718750, 0 } }, + { "NIKON", "D7100", WhiteFluorescent, 0, { 1.746094, 1, 2.777344, 0 } }, + { "NIKON", "D7100", WhiteFluorescent, 1, { 1.671875, 1, 2.839844, 0 } }, + { "NIKON", "D7100", WhiteFluorescent, 2, { 1.593750, 1, 2.902344, 0 } }, + { "NIKON", "D7100", WhiteFluorescent, 3, { 1.515625, 1, 2.968750, 0 } }, + { "NIKON", "D7100", WhiteFluorescent, 4, { 1.433594, 1, 3.031250, 0 } }, + { "NIKON", "D7100", WhiteFluorescent, 5, { 1.347656, 1, 3.101563, 0 } }, + { "NIKON", "D7100", WhiteFluorescent, 6, { 1.261719, 1, 3.167969, 0 } }, + { "NIKON", "D7100", CoolWhiteFluorescent, -6, { 2.601563, 1, 2.136719, 0 } }, + { "NIKON", "D7100", CoolWhiteFluorescent, -5, { 2.542969, 1, 2.179688, 0 } }, + { "NIKON", "D7100", CoolWhiteFluorescent, -4, { 2.484375, 1, 2.226563, 0 } }, + { "NIKON", "D7100", CoolWhiteFluorescent, -3, { 2.421875, 1, 2.273438, 0 } }, + { "NIKON", "D7100", CoolWhiteFluorescent, -2, { 2.359375, 1, 2.320313, 0 } }, + { "NIKON", "D7100", CoolWhiteFluorescent, -1, { 2.289063, 1, 2.367188, 0 } }, + { "NIKON", "D7100", CoolWhiteFluorescent, 0, { 2.222656, 1, 2.417969, 0 } }, + { "NIKON", "D7100", CoolWhiteFluorescent, 1, { 2.156250, 1, 2.472656, 0 } }, + { "NIKON", "D7100", CoolWhiteFluorescent, 2, { 2.082031, 1, 2.523438, 0 } }, + { "NIKON", "D7100", CoolWhiteFluorescent, 3, { 2.007813, 1, 2.582031, 0 } }, + { "NIKON", "D7100", CoolWhiteFluorescent, 4, { 1.933594, 1, 2.636719, 0 } }, + { "NIKON", "D7100", CoolWhiteFluorescent, 5, { 1.851563, 1, 2.695313, 0 } }, + { "NIKON", "D7100", CoolWhiteFluorescent, 6, { 1.773438, 1, 2.750000, 0 } }, + { "NIKON", "D7100", DayWhiteFluorescent, -6, { 2.488281, 1, 1.433594, 0 } }, + { "NIKON", "D7100", DayWhiteFluorescent, -5, { 2.445313, 1, 1.472656, 0 } }, + { "NIKON", "D7100", DayWhiteFluorescent, -4, { 2.402344, 1, 1.507813, 0 } }, + { "NIKON", "D7100", DayWhiteFluorescent, -3, { 2.363281, 1, 1.546875, 0 } }, + { "NIKON", "D7100", DayWhiteFluorescent, -2, { 2.324219, 1, 1.582031, 0 } }, + { "NIKON", "D7100", DayWhiteFluorescent, -1, { 2.285156, 1, 1.617188, 0 } }, + { "NIKON", "D7100", DayWhiteFluorescent, 0, { 2.242188, 1, 1.656250, 0 } }, + { "NIKON", "D7100", DayWhiteFluorescent, 1, { 2.207031, 1, 1.691406, 0 } }, + { "NIKON", "D7100", DayWhiteFluorescent, 2, { 2.175781, 1, 1.722656, 0 } }, + { "NIKON", "D7100", DayWhiteFluorescent, 3, { 2.140625, 1, 1.757813, 0 } }, + { "NIKON", "D7100", DayWhiteFluorescent, 4, { 2.105469, 1, 1.792969, 0 } }, + { "NIKON", "D7100", DayWhiteFluorescent, 5, { 2.074219, 1, 1.824219, 0 } }, + { "NIKON", "D7100", DayWhiteFluorescent, 6, { 2.039063, 1, 1.855469, 0 } }, + { "NIKON", "D7100", DaylightFluorescent, -6, { 2.859375, 1, 1.062500, 0 } }, + { "NIKON", "D7100", DaylightFluorescent, -5, { 2.820313, 1, 1.105469, 0 } }, + { "NIKON", "D7100", DaylightFluorescent, -4, { 2.781250, 1, 1.144531, 0 } }, + { "NIKON", "D7100", DaylightFluorescent, -3, { 2.742188, 1, 1.187500, 0 } }, + { "NIKON", "D7100", DaylightFluorescent, -2, { 2.703125, 1, 1.226563, 0 } }, + { "NIKON", "D7100", DaylightFluorescent, -1, { 2.664063, 1, 1.269531, 0 } }, + { "NIKON", "D7100", DaylightFluorescent, 0, { 2.628906, 1, 1.308594, 0 } }, + { "NIKON", "D7100", DaylightFluorescent, 1, { 2.582031, 1, 1.347656, 0 } }, + { "NIKON", "D7100", DaylightFluorescent, 2, { 2.539063, 1, 1.386719, 0 } }, + { "NIKON", "D7100", DaylightFluorescent, 3, { 2.496094, 1, 1.425781, 0 } }, + { "NIKON", "D7100", DaylightFluorescent, 4, { 2.453125, 1, 1.464844, 0 } }, + { "NIKON", "D7100", DaylightFluorescent, 5, { 2.410156, 1, 1.500000, 0 } }, + { "NIKON", "D7100", DaylightFluorescent, 6, { 2.367188, 1, 1.539063, 0 } }, + { "NIKON", "D7100", HighTempMercuryVaporFluorescent, -6, { 3.312500, 1, 1.417969, 0 } }, + { "NIKON", "D7100", HighTempMercuryVaporFluorescent, -5, { 3.296875, 1, 1.441406, 0 } }, + { "NIKON", "D7100", HighTempMercuryVaporFluorescent, -4, { 3.277344, 1, 1.468750, 0 } }, + { "NIKON", "D7100", HighTempMercuryVaporFluorescent, -3, { 3.257813, 1, 1.496094, 0 } }, + { "NIKON", "D7100", HighTempMercuryVaporFluorescent, -2, { 3.234375, 1, 1.527344, 0 } }, + { "NIKON", "D7100", HighTempMercuryVaporFluorescent, -1, { 3.214844, 1, 1.554688, 0 } }, + { "NIKON", "D7100", HighTempMercuryVaporFluorescent, 0, { 3.187500, 1, 1.585938, 0 } }, + { "NIKON", "D7100", HighTempMercuryVaporFluorescent, 1, { 3.156250, 1, 1.617188, 0 } }, + { "NIKON", "D7100", HighTempMercuryVaporFluorescent, 2, { 3.121094, 1, 1.652344, 0 } }, + { "NIKON", "D7100", HighTempMercuryVaporFluorescent, 3, { 3.085938, 1, 1.687500, 0 } }, + { "NIKON", "D7100", HighTempMercuryVaporFluorescent, 4, { 3.046875, 1, 1.722656, 0 } }, + { "NIKON", "D7100", HighTempMercuryVaporFluorescent, 5, { 3.007813, 1, 1.761719, 0 } }, + { "NIKON", "D7100", HighTempMercuryVaporFluorescent, 6, { 2.968750, 1, 1.796875, 0 } }, + { "NIKON", "D7100", "5000K", 0, { 2.332031, 1, 1.652344, 0 } }, + + // Firmware C 1.00 / L 2.008 + { "NIKON", "D7200", DirectSunlight, -6, { 2.671875, 1, 1.425781, 0 } }, + { "NIKON", "D7200", DirectSunlight, -5, { 2.617188, 1, 1.449219, 0 } }, + { "NIKON", "D7200", DirectSunlight, -4, { 2.570313, 1, 1.476563, 0 } }, + { "NIKON", "D7200", DirectSunlight, -3, { 2.523438, 1, 1.503906, 0 } }, + { "NIKON", "D7200", DirectSunlight, -2, { 2.480469, 1, 1.535156, 0 } }, + { "NIKON", "D7200", DirectSunlight, -1, { 2.437500, 1, 1.562500, 0 } }, + { "NIKON", "D7200", DirectSunlight, 0, { 2.394531, 1, 1.597656, 0 } }, + { "NIKON", "D7200", DirectSunlight, 1, { 2.351563, 1, 1.632813, 0 } }, + { "NIKON", "D7200", DirectSunlight, 2, { 2.308594, 1, 1.671875, 0 } }, + { "NIKON", "D7200", DirectSunlight, 3, { 2.269531, 1, 1.707031, 0 } }, + { "NIKON", "D7200", DirectSunlight, 4, { 2.226563, 1, 1.738281, 0 } }, + { "NIKON", "D7200", DirectSunlight, 5, { 2.183594, 1, 1.765625, 0 } }, + { "NIKON", "D7200", DirectSunlight, 6, { 2.136719, 1, 1.789063, 0 } }, + { "NIKON", "D7200", Flash, -6, { 3.113281, 1, 1.277344, 0 } }, + { "NIKON", "D7200", Flash, -5, { 3.027344, 1, 1.292969, 0 } }, + { "NIKON", "D7200", Flash, -4, { 2.957031, 1, 1.308594, 0 } }, + { "NIKON", "D7200", Flash, -3, { 2.890625, 1, 1.324219, 0 } }, + { "NIKON", "D7200", Flash, -2, { 2.835938, 1, 1.339844, 0 } }, + { "NIKON", "D7200", Flash, -1, { 2.785156, 1, 1.359375, 0 } }, + { "NIKON", "D7200", Flash, 0, { 2.738281, 1, 1.375000, 0 } }, + { "NIKON", "D7200", Flash, 1, { 2.695313, 1, 1.394531, 0 } }, + { "NIKON", "D7200", Flash, 2, { 2.656250, 1, 1.410156, 0 } }, + { "NIKON", "D7200", Flash, 3, { 2.613281, 1, 1.429688, 0 } }, + { "NIKON", "D7200", Flash, 4, { 2.570313, 1, 1.453125, 0 } }, + { "NIKON", "D7200", Flash, 5, { 2.523438, 1, 1.472656, 0 } }, + { "NIKON", "D7200", Flash, 6, { 2.472656, 1, 1.500000, 0 } }, + { "NIKON", "D7200", Cloudy, -6, { 2.972656, 1, 1.328125, 0 } }, + { "NIKON", "D7200", Cloudy, -5, { 2.906250, 1, 1.347656, 0 } }, + { "NIKON", "D7200", Cloudy, -4, { 2.843750, 1, 1.363281, 0 } }, + { "NIKON", "D7200", Cloudy, -3, { 2.785156, 1, 1.382813, 0 } }, + { "NIKON", "D7200", Cloudy, -2, { 2.726563, 1, 1.406250, 0 } }, + { "NIKON", "D7200", Cloudy, -1, { 2.671875, 1, 1.425781, 0 } }, + { "NIKON", "D7200", Cloudy, 0, { 2.617188, 1, 1.449219, 0 } }, + { "NIKON", "D7200", Cloudy, 1, { 2.570313, 1, 1.476563, 0 } }, + { "NIKON", "D7200", Cloudy, 2, { 2.523438, 1, 1.503906, 0 } }, + { "NIKON", "D7200", Cloudy, 3, { 2.480469, 1, 1.535156, 0 } }, + { "NIKON", "D7200", Cloudy, 4, { 2.437500, 1, 1.562500, 0 } }, + { "NIKON", "D7200", Cloudy, 5, { 2.394531, 1, 1.597656, 0 } }, + { "NIKON", "D7200", Cloudy, 6, { 2.351563, 1, 1.632813, 0 } }, + { "NIKON", "D7200", Shade, -6, { 3.664063, 1, 1.191406, 0 } }, + { "NIKON", "D7200", Shade, -5, { 3.570313, 1, 1.207031, 0 } }, + { "NIKON", "D7200", Shade, -4, { 3.480469, 1, 1.222656, 0 } }, + { "NIKON", "D7200", Shade, -3, { 3.390625, 1, 1.238281, 0 } }, + { "NIKON", "D7200", Shade, -2, { 3.304688, 1, 1.253906, 0 } }, + { "NIKON", "D7200", Shade, -1, { 3.226563, 1, 1.273438, 0 } }, + { "NIKON", "D7200", Shade, 0, { 3.148438, 1, 1.289063, 0 } }, + { "NIKON", "D7200", Shade, 1, { 3.074219, 1, 1.304688, 0 } }, + { "NIKON", "D7200", Shade, 2, { 3.003906, 1, 1.320313, 0 } }, + { "NIKON", "D7200", Shade, 3, { 2.933594, 1, 1.339844, 0 } }, + { "NIKON", "D7200", Shade, 4, { 2.871094, 1, 1.359375, 0 } }, + { "NIKON", "D7200", Shade, 5, { 2.808594, 1, 1.375000, 0 } }, + { "NIKON", "D7200", Shade, 6, { 2.750000, 1, 1.394531, 0 } }, + { "NIKON", "D7200", Incandescent, -6, { 1.582031, 1, 2.375000, 0 } }, + { "NIKON", "D7200", Incandescent, -5, { 1.558594, 1, 2.421875, 0 } }, + { "NIKON", "D7200", Incandescent, -4, { 1.535156, 1, 2.468750, 0 } }, + { "NIKON", "D7200", Incandescent, -3, { 1.511719, 1, 2.519531, 0 } }, + { "NIKON", "D7200", Incandescent, -2, { 1.488281, 1, 2.570313, 0 } }, + { "NIKON", "D7200", Incandescent, -1, { 1.464844, 1, 2.617188, 0 } }, + { "NIKON", "D7200", Incandescent, 0, { 1.445313, 1, 2.667969, 0 } }, + { "NIKON", "D7200", Incandescent, 1, { 1.425781, 1, 2.718750, 0 } }, + { "NIKON", "D7200", Incandescent, 2, { 1.406250, 1, 2.773438, 0 } }, + { "NIKON", "D7200", Incandescent, 3, { 1.386719, 1, 2.824219, 0 } }, + { "NIKON", "D7200", Incandescent, 4, { 1.367188, 1, 2.875000, 0 } }, + { "NIKON", "D7200", Incandescent, 5, { 1.351563, 1, 2.929688, 0 } }, + { "NIKON", "D7200", Incandescent, 6, { 1.332031, 1, 2.980469, 0 } }, + { "NIKON", "D7200", SodiumVaporFluorescent, -6, { 1.480469, 1, 2.597656, 0 } }, + { "NIKON", "D7200", SodiumVaporFluorescent, -5, { 1.449219, 1, 2.652344, 0 } }, + { "NIKON", "D7200", SodiumVaporFluorescent, -4, { 1.421875, 1, 2.707031, 0 } }, + { "NIKON", "D7200", SodiumVaporFluorescent, -3, { 1.394531, 1, 2.753906, 0 } }, + { "NIKON", "D7200", SodiumVaporFluorescent, -2, { 1.367188, 1, 2.804688, 0 } }, + { "NIKON", "D7200", SodiumVaporFluorescent, -1, { 1.347656, 1, 2.855469, 0 } }, + { "NIKON", "D7200", SodiumVaporFluorescent, 0, { 1.324219, 1, 2.906250, 0 } }, + { "NIKON", "D7200", SodiumVaporFluorescent, 1, { 1.304688, 1, 2.957031, 0 } }, + { "NIKON", "D7200", SodiumVaporFluorescent, 2, { 1.289063, 1, 3.007813, 0 } }, + { "NIKON", "D7200", SodiumVaporFluorescent, 3, { 1.273438, 1, 3.066406, 0 } }, + { "NIKON", "D7200", SodiumVaporFluorescent, 4, { 1.257813, 1, 3.125000, 0 } }, + { "NIKON", "D7200", SodiumVaporFluorescent, 5, { 1.242188, 1, 3.187500, 0 } }, + { "NIKON", "D7200", SodiumVaporFluorescent, 6, { 1.226563, 1, 3.253906, 0 } }, + { "NIKON", "D7200", WarmWhiteFluorescent, -6, { 1.613281, 1, 2.281250, 0 } }, + { "NIKON", "D7200", WarmWhiteFluorescent, -5, { 1.589844, 1, 2.308594, 0 } }, + { "NIKON", "D7200", WarmWhiteFluorescent, -4, { 1.566406, 1, 2.332031, 0 } }, + { "NIKON", "D7200", WarmWhiteFluorescent, -3, { 1.542969, 1, 2.359375, 0 } }, + { "NIKON", "D7200", WarmWhiteFluorescent, -2, { 1.519531, 1, 2.382813, 0 } }, + { "NIKON", "D7200", WarmWhiteFluorescent, -1, { 1.500000, 1, 2.410156, 0 } }, + { "NIKON", "D7200", WarmWhiteFluorescent, 0, { 1.476563, 1, 2.433594, 0 } }, + { "NIKON", "D7200", WarmWhiteFluorescent, 1, { 1.457031, 1, 2.457031, 0 } }, + { "NIKON", "D7200", WarmWhiteFluorescent, 2, { 1.437500, 1, 2.480469, 0 } }, + { "NIKON", "D7200", WarmWhiteFluorescent, 3, { 1.417969, 1, 2.503906, 0 } }, + { "NIKON", "D7200", WarmWhiteFluorescent, 4, { 1.398438, 1, 2.527344, 0 } }, + { "NIKON", "D7200", WarmWhiteFluorescent, 5, { 1.378906, 1, 2.550781, 0 } }, + { "NIKON", "D7200", WarmWhiteFluorescent, 6, { 1.363281, 1, 2.574219, 0 } }, + { "NIKON", "D7200", WhiteFluorescent, -6, { 2.191406, 1, 2.445313, 0 } }, + { "NIKON", "D7200", WhiteFluorescent, -5, { 2.121094, 1, 2.500000, 0 } }, + { "NIKON", "D7200", WhiteFluorescent, -4, { 2.050781, 1, 2.554688, 0 } }, + { "NIKON", "D7200", WhiteFluorescent, -3, { 1.976563, 1, 2.609375, 0 } }, + { "NIKON", "D7200", WhiteFluorescent, -2, { 1.902344, 1, 2.667969, 0 } }, + { "NIKON", "D7200", WhiteFluorescent, -1, { 1.824219, 1, 2.722656, 0 } }, + { "NIKON", "D7200", WhiteFluorescent, 0, { 1.746094, 1, 2.781250, 0 } }, + { "NIKON", "D7200", WhiteFluorescent, 1, { 1.667969, 1, 2.843750, 0 } }, + { "NIKON", "D7200", WhiteFluorescent, 2, { 1.585938, 1, 2.902344, 0 } }, + { "NIKON", "D7200", WhiteFluorescent, 3, { 1.503906, 1, 2.964844, 0 } }, + { "NIKON", "D7200", WhiteFluorescent, 4, { 1.421875, 1, 3.031250, 0 } }, + { "NIKON", "D7200", WhiteFluorescent, 5, { 1.339844, 1, 3.093750, 0 } }, + { "NIKON", "D7200", WhiteFluorescent, 6, { 1.253906, 1, 3.160156, 0 } }, + { "NIKON", "D7200", CoolWhiteFluorescent, -6, { 2.593750, 1, 2.128906, 0 } }, + { "NIKON", "D7200", CoolWhiteFluorescent, -5, { 2.535156, 1, 2.175781, 0 } }, + { "NIKON", "D7200", CoolWhiteFluorescent, -4, { 2.476563, 1, 2.222656, 0 } }, + { "NIKON", "D7200", CoolWhiteFluorescent, -3, { 2.414063, 1, 2.273438, 0 } }, + { "NIKON", "D7200", CoolWhiteFluorescent, -2, { 2.351563, 1, 2.324219, 0 } }, + { "NIKON", "D7200", CoolWhiteFluorescent, -1, { 2.289063, 1, 2.375000, 0 } }, + { "NIKON", "D7200", CoolWhiteFluorescent, 0, { 2.222656, 1, 2.425781, 0 } }, + { "NIKON", "D7200", CoolWhiteFluorescent, 1, { 2.152344, 1, 2.480469, 0 } }, + { "NIKON", "D7200", CoolWhiteFluorescent, 2, { 2.078125, 1, 2.531250, 0 } }, + { "NIKON", "D7200", CoolWhiteFluorescent, 3, { 2.007813, 1, 2.585938, 0 } }, + { "NIKON", "D7200", CoolWhiteFluorescent, 4, { 1.933594, 1, 2.644531, 0 } }, + { "NIKON", "D7200", CoolWhiteFluorescent, 5, { 1.855469, 1, 2.699219, 0 } }, + { "NIKON", "D7200", CoolWhiteFluorescent, 6, { 1.777344, 1, 2.757813, 0 } }, + { "NIKON", "D7200", DayWhiteFluorescent, -6, { 2.468750, 1, 1.433594, 0 } }, + { "NIKON", "D7200", DayWhiteFluorescent, -5, { 2.429688, 1, 1.472656, 0 } }, + { "NIKON", "D7200", DayWhiteFluorescent, -4, { 2.394531, 1, 1.507813, 0 } }, + { "NIKON", "D7200", DayWhiteFluorescent, -3, { 2.355469, 1, 1.546875, 0 } }, + { "NIKON", "D7200", DayWhiteFluorescent, -2, { 2.320313, 1, 1.582031, 0 } }, + { "NIKON", "D7200", DayWhiteFluorescent, -1, { 2.281250, 1, 1.617188, 0 } }, + { "NIKON", "D7200", DayWhiteFluorescent, 0, { 2.246094, 1, 1.652344, 0 } }, + { "NIKON", "D7200", DayWhiteFluorescent, 1, { 2.210938, 1, 1.687500, 0 } }, + { "NIKON", "D7200", DayWhiteFluorescent, 2, { 2.175781, 1, 1.722656, 0 } }, + { "NIKON", "D7200", DayWhiteFluorescent, 3, { 2.136719, 1, 1.757813, 0 } }, + { "NIKON", "D7200", DayWhiteFluorescent, 4, { 2.105469, 1, 1.789063, 0 } }, + { "NIKON", "D7200", DayWhiteFluorescent, 5, { 2.070313, 1, 1.824219, 0 } }, + { "NIKON", "D7200", DayWhiteFluorescent, 6, { 2.035156, 1, 1.855469, 0 } }, + { "NIKON", "D7200", DaylightFluorescent, -6, { 2.835938, 1, 1.062500, 0 } }, + { "NIKON", "D7200", DaylightFluorescent, -5, { 2.796875, 1, 1.105469, 0 } }, + { "NIKON", "D7200", DaylightFluorescent, -4, { 2.753906, 1, 1.144531, 0 } }, + { "NIKON", "D7200", DaylightFluorescent, -3, { 2.714844, 1, 1.187500, 0 } }, + { "NIKON", "D7200", DaylightFluorescent, -2, { 2.675781, 1, 1.230469, 0 } }, + { "NIKON", "D7200", DaylightFluorescent, -1, { 2.636719, 1, 1.269531, 0 } }, + { "NIKON", "D7200", DaylightFluorescent, 0, { 2.593750, 1, 1.308594, 0 } }, + { "NIKON", "D7200", DaylightFluorescent, 1, { 2.554688, 1, 1.347656, 0 } }, + { "NIKON", "D7200", DaylightFluorescent, 2, { 2.515625, 1, 1.386719, 0 } }, + { "NIKON", "D7200", DaylightFluorescent, 3, { 2.476563, 1, 1.425781, 0 } }, + { "NIKON", "D7200", DaylightFluorescent, 4, { 2.437500, 1, 1.464844, 0 } }, + { "NIKON", "D7200", DaylightFluorescent, 5, { 2.402344, 1, 1.503906, 0 } }, + { "NIKON", "D7200", DaylightFluorescent, 6, { 2.363281, 1, 1.539063, 0 } }, + { "NIKON", "D7200", HighTempMercuryVaporFluorescent, -6, { 3.308594, 1, 1.417969, 0 } }, + { "NIKON", "D7200", HighTempMercuryVaporFluorescent, -5, { 3.292969, 1, 1.445313, 0 } }, + { "NIKON", "D7200", HighTempMercuryVaporFluorescent, -4, { 3.269531, 1, 1.468750, 0 } }, + { "NIKON", "D7200", HighTempMercuryVaporFluorescent, -3, { 3.250000, 1, 1.500000, 0 } }, + { "NIKON", "D7200", HighTempMercuryVaporFluorescent, -2, { 3.226563, 1, 1.527344, 0 } }, + { "NIKON", "D7200", HighTempMercuryVaporFluorescent, -1, { 3.199219, 1, 1.558594, 0 } }, + { "NIKON", "D7200", HighTempMercuryVaporFluorescent, 0, { 3.171875, 1, 1.589844, 0 } }, + { "NIKON", "D7200", HighTempMercuryVaporFluorescent, 1, { 3.144531, 1, 1.621094, 0 } }, + { "NIKON", "D7200", HighTempMercuryVaporFluorescent, 2, { 3.113281, 1, 1.656250, 0 } }, + { "NIKON", "D7200", HighTempMercuryVaporFluorescent, 3, { 3.078125, 1, 1.691406, 0 } }, + { "NIKON", "D7200", HighTempMercuryVaporFluorescent, 4, { 3.042969, 1, 1.726563, 0 } }, + { "NIKON", "D7200", HighTempMercuryVaporFluorescent, 5, { 3.007813, 1, 1.761719, 0 } }, + { "NIKON", "D7200", HighTempMercuryVaporFluorescent, 6, { 2.968750, 1, 1.800781, 0 } }, + { "NIKON", "D7200", "2700K", 0, { 1.308594, 1, 3.062500, 0 } }, + { "NIKON", "D7200", "5000K", 0, { 2.328125, 1, 1.656250, 0 } }, + { "NIKON", "D7200", "5500K", 0, { 2.480469, 1, 1.531250, 0 } }, + { "NIKON", "D7200", "6500K", 0, { 2.761719, 1, 1.390625, 0 } }, + + { "NIKON", "E5400", Daylight, -3, { 2.046875, 1, 1.449219, 0 } }, + { "NIKON", "E5400", Daylight, 0, { 1.800781, 1, 1.636719, 0 } }, + { "NIKON", "E5400", Daylight, 3, { 1.539062, 1, 1.820312, 0 } }, + { "NIKON", "E5400", Incandescent, -3, { 1.218750, 1, 2.656250, 0 } }, + { "NIKON", "E5400", Incandescent, 0, { 1.218750, 1, 2.656250, 0 } }, + { "NIKON", "E5400", Incandescent, 3, { 1.382812, 1, 2.351562, 0 } }, + { "NIKON", "E5400", Fluorescent, -3, { 1.703125, 1, 2.460938, 0 } }, + { "NIKON", "E5400", Fluorescent, 0, { 1.218750, 1, 2.656250, 0 } }, + { "NIKON", "E5400", Fluorescent, 3, { 1.953125, 1, 1.906250, 0 } }, + { "NIKON", "E5400", Cloudy, -3, { 1.703125, 1, 2.460938, 0 } }, + { "NIKON", "E5400", Cloudy, 0, { 1.996094, 1, 1.421875, 0 } }, + { "NIKON", "E5400", Cloudy, 3, { 2.265625, 1, 1.261719, 0 } }, + { "NIKON", "E5400", Flash, -3, { 2.792969, 1, 1.152344, 0 } }, + { "NIKON", "E5400", Flash, 0, { 2.328125, 1, 1.386719, 0 } }, + { "NIKON", "E5400", Flash, 3, { 2.328125, 1, 1.386719, 0 } }, + { "NIKON", "E5400", Shade, -3, { 2.722656, 1, 1.011719, 0 } }, + { "NIKON", "E5400", Shade, 0, { 2.269531, 1, 1.218750, 0 } }, + { "NIKON", "E5400", Shade, 3, { 2.269531, 1, 1.218750, 0 } }, + + { "NIKON", "E8700", Daylight, 0, { 1.968750, 1, 1.582031, 0 } }, + { "NIKON", "E8700", Incandescent, 0, { 1.265625, 1, 2.765625, 0 } }, + { "NIKON", "E8700", Fluorescent, 0, { 1.863281, 1, 2.304688, 0 } }, + { "NIKON", "E8700", Cloudy, 0, { 2.218750, 1, 1.359375, 0 } }, + { "NIKON", "E8700", Flash, 0, { 2.535156, 1, 1.273438, 0 } }, + { "NIKON", "E8700", Shade, 0, { 2.527344, 1, 1.175781, 0 } }, + + { "OLYMPUS", "C5050Z", Shade, -7, { 3.887324, 1.201878, 1, 0 } }, + { "OLYMPUS", "C5050Z", Shade, 0, { 1.757812, 1, 1.437500, 0 } }, + { "OLYMPUS", "C5050Z", Shade, 7, { 1.019531, 1, 2.140625, 0 } }, + { "OLYMPUS", "C5050Z", Cloudy, -7, { 3.255507, 1.127753, 1, 0 } }, + { "OLYMPUS", "C5050Z", Cloudy, 0, { 1.570312, 1, 1.531250, 0 } }, + { "OLYMPUS", "C5050Z", Cloudy, 7, { 1, 1.098712, 2.506438, 0 } }, + { "OLYMPUS", "C5050Z", Daylight, -7, { 2.892116, 1.062241, 1, 0 } }, + { "OLYMPUS", "C5050Z", Daylight, 0, { 1.480469, 1, 1.628906, 0 } }, + { "OLYMPUS", "C5050Z", Daylight, 7, { 1, 1.168950, 2.835616, 0 } }, + { "OLYMPUS", "C5050Z", EveningSun, -7, { 3.072649, 1.094017, 1, 0 } }, + { "OLYMPUS", "C5050Z", EveningSun, 0, { 1.527344, 1, 1.578125, 0 } }, + { "OLYMPUS", "C5050Z", EveningSun, 7, { 1, 1.132743, 2.659292, 0 } }, + { "OLYMPUS", "C5050Z", DaylightFluorescent, -7, { 3.321267, 1.158371, 1, 0 } }, /*6700K*/ + { "OLYMPUS", "C5050Z", DaylightFluorescent, 0, { 1.558594, 1, 1.492188, 0 } }, /*6700K*/ + { "OLYMPUS", "C5050Z", DaylightFluorescent, 7, { 1, 1.108225, 2.463203, 0 } }, /*6700K*/ + { "OLYMPUS", "C5050Z", NeutralFluorescent, -7, { 2.606426, 1.028112, 1, 0 } }, /*5000K*/ + { "OLYMPUS", "C5050Z", NeutralFluorescent, 0, { 1.378906, 1, 1.679688, 0 } }, /*5000K*/ + { "OLYMPUS", "C5050Z", NeutralFluorescent, 7, { 1, 1.254902, 3.137255, 0 } }, /*5000K*/ + { "OLYMPUS", "C5050Z", CoolWhiteFluorescent, -7, { 2.519531, 1, 1.281250, 0 } }, /*4200K*/ + { "OLYMPUS", "C5050Z", CoolWhiteFluorescent, 0, { 1.371094, 1, 2.210938, 0 } }, /*4200K*/ + { "OLYMPUS", "C5050Z", CoolWhiteFluorescent, 7, { 1, 1.261084, 4.152709, 0 } }, /*4200K*/ + { "OLYMPUS", "C5050Z", WhiteFluorescent, -7, { 1.707031, 1, 1.699219, 0 } }, /*3500K*/ + { "OLYMPUS", "C5050Z", WhiteFluorescent, 0, { 1, 1.075630, 3.151261, 0 } }, /*3500K*/ + { "OLYMPUS", "C5050Z", WhiteFluorescent, 7, { 1, 1.855072, 8.094203, 0 } }, /*3500K*/ + { "OLYMPUS", "C5050Z", Incandescent, -7, { 1.679688, 1, 1.652344, 0 } }, /*3000K*/ + { "OLYMPUS", "C5050Z", Incandescent, 0, { 1, 1.094017, 3.123932, 0 } }, /*3000K*/ + { "OLYMPUS", "C5050Z", Incandescent, 7, { 1, 1.896296, 8.066667, 0 } }, /*3000K*/ + + { "OLYMPUS", "C5060WZ", Shade, 0, { 1.949219, 1, 1.195312, 0 } }, + { "OLYMPUS", "C5060WZ", Cloudy, 0, { 1.621094, 1, 1.410156, 0 } }, + { "OLYMPUS", "C5060WZ", DirectSunlight, 0, { 1.511719, 1, 1.500000, 0 } }, + { "OLYMPUS", "C5060WZ", EveningSun, 0, { 1.636719, 1, 1.496094, 0 } }, + { "OLYMPUS", "C5060WZ", DaylightFluorescent, 0, { 1.734375, 1, 1.343750, 0 } }, + { "OLYMPUS", "C5060WZ", NeutralFluorescent, 0, { 1.457031, 1, 1.691406, 0 } }, + { "OLYMPUS", "C5060WZ", CoolWhiteFluorescent, 0, { 1.417969, 1, 2.230469, 0 } }, + { "OLYMPUS", "C5060WZ", WhiteFluorescent, 0, { 1, 1.103448, 3.422414, 0 } }, + { "OLYMPUS", "C5060WZ", Incandescent, 0, { 1, 1.153153, 3.662162, 0 } }, + { "OLYMPUS", "C5060WZ", FlashAuto, 0, { 1.850000, 1, 1.308044, 0 } }, + + // OLYMPUS C8080WZ - firmware 757-78 + { "OLYMPUS", "C8080WZ", Shade, -7, { 1.515625, 1, 1.773438, 0 } }, + { "OLYMPUS", "C8080WZ", Shade, -6, { 1.671875, 1, 1.691406, 0 } }, + { "OLYMPUS", "C8080WZ", Shade, -5, { 1.832031, 1, 1.605469, 0 } }, + { "OLYMPUS", "C8080WZ", Shade, -4, { 1.988281, 1, 1.523438, 0 } }, + { "OLYMPUS", "C8080WZ", Shade, -3, { 2.144531, 1, 1.441406, 0 } }, + { "OLYMPUS", "C8080WZ", Shade, -2, { 2.300781, 1, 1.355469, 0 } }, + { "OLYMPUS", "C8080WZ", Shade, -1, { 2.457031, 1, 1.273438, 0 } }, + { "OLYMPUS", "C8080WZ", Shade, 0, { 2.617188, 1, 1.191406, 0 } }, + { "OLYMPUS", "C8080WZ", Shade, 1, { 2.929688, 1, 1.117188, 0 } }, + { "OLYMPUS", "C8080WZ", Shade, 2, { 3.242188, 1, 1.046875, 0 } }, + { "OLYMPUS", "C8080WZ", Shade, 3, { 3.644000, 1.024000, 1, 0 } }, + { "OLYMPUS", "C8080WZ", Shade, 4, { 4.290043, 1.108225, 1, 0 } }, + { "OLYMPUS", "C8080WZ", Shade, 5, { 5.032864, 1.201878, 1, 0 } }, + { "OLYMPUS", "C8080WZ", Shade, 6, { 5.907692, 1.312821, 1, 0 } }, + { "OLYMPUS", "C8080WZ", Shade, 7, { 7.000000, 1.454545, 1, 0 } }, + { "OLYMPUS", "C8080WZ", Cloudy, -7, { 1.277344, 1, 2.164062, 0 } }, + { "OLYMPUS", "C8080WZ", Cloudy, -6, { 1.406250, 1, 2.062500, 0 } }, + { "OLYMPUS", "C8080WZ", Cloudy, -5, { 1.539062, 1, 1.960938, 0 } }, + { "OLYMPUS", "C8080WZ", Cloudy, -4, { 1.671875, 1, 1.859375, 0 } }, + { "OLYMPUS", "C8080WZ", Cloudy, -3, { 1.804688, 1, 1.757812, 0 } }, + { "OLYMPUS", "C8080WZ", Cloudy, -2, { 1.937500, 1, 1.656250, 0 } }, + { "OLYMPUS", "C8080WZ", Cloudy, -1, { 2.070312, 1, 1.554688, 0 } }, + { "OLYMPUS", "C8080WZ", Cloudy, 0, { 2.203125, 1, 1.453125, 0 } }, + { "OLYMPUS", "C8080WZ", Cloudy, 1, { 2.464844, 1, 1.363281, 0 } }, + { "OLYMPUS", "C8080WZ", Cloudy, 2, { 2.730469, 1, 1.277344, 0 } }, + { "OLYMPUS", "C8080WZ", Cloudy, 3, { 2.996094, 1, 1.191406, 0 } }, + { "OLYMPUS", "C8080WZ", Cloudy, 4, { 3.257812, 1, 1.101562, 0 } }, + { "OLYMPUS", "C8080WZ", Cloudy, 5, { 3.523438, 1, 1.015625, 0 } }, + { "OLYMPUS", "C8080WZ", Cloudy, 6, { 4.075630, 1.075630, 1, 0 } }, + { "OLYMPUS", "C8080WZ", Cloudy, 7, { 4.823256, 1.190698, 1, 0 } }, + { "OLYMPUS", "C8080WZ", Daylight, -7, { 1.234375, 1, 2.343750, 0 } }, + { "OLYMPUS", "C8080WZ", Daylight, -6, { 1.359375, 1, 2.234375, 0 } }, + { "OLYMPUS", "C8080WZ", Daylight, -5, { 1.488281, 1, 2.125000, 0 } }, + { "OLYMPUS", "C8080WZ", Daylight, -4, { 1.617188, 1, 2.011719, 0 } }, + { "OLYMPUS", "C8080WZ", Daylight, -3, { 1.742188, 1, 1.902344, 0 } }, + { "OLYMPUS", "C8080WZ", Daylight, -2, { 1.871094, 1, 1.792969, 0 } }, + { "OLYMPUS", "C8080WZ", Daylight, -1, { 2.000000, 1, 1.683594, 0 } }, + { "OLYMPUS", "C8080WZ", Daylight, 0, { 2.128906, 1, 1.574219, 0 } }, + { "OLYMPUS", "C8080WZ", Daylight, 1, { 2.382812, 1, 1.476562, 0 } }, + { "OLYMPUS", "C8080WZ", Daylight, 2, { 2.636719, 1, 1.382812, 0 } }, + { "OLYMPUS", "C8080WZ", Daylight, 3, { 2.894531, 1, 1.289062, 0 } }, + { "OLYMPUS", "C8080WZ", Daylight, 4, { 3.148438, 1, 1.195312, 0 } }, + { "OLYMPUS", "C8080WZ", Daylight, 5, { 3.406250, 1, 1.101562, 0 } }, + { "OLYMPUS", "C8080WZ", Daylight, 6, { 3.660156, 1, 1.003906, 0 } }, + { "OLYMPUS", "C8080WZ", Daylight, 7, { 4.300429, 1.098712, 1, 0 } }, + { "OLYMPUS", "C8080WZ", EveningSun, -7, { 1.308594, 1, 2.199219, 0 } }, + { "OLYMPUS", "C8080WZ", EveningSun, -6, { 1.445312, 1, 2.093750, 0 } }, + { "OLYMPUS", "C8080WZ", EveningSun, -5, { 1.582031, 1, 1.992188, 0 } }, + { "OLYMPUS", "C8080WZ", EveningSun, -4, { 1.718750, 1, 1.886719, 0 } }, + { "OLYMPUS", "C8080WZ", EveningSun, -3, { 1.851562, 1, 1.785156, 0 } }, + { "OLYMPUS", "C8080WZ", EveningSun, -2, { 1.988281, 1, 1.679688, 0 } }, + { "OLYMPUS", "C8080WZ", EveningSun, -1, { 2.125000, 1, 1.578125, 0 } }, + { "OLYMPUS", "C8080WZ", EveningSun, 0, { 2.261719, 1, 1.476562, 0 } }, + { "OLYMPUS", "C8080WZ", EveningSun, 1, { 2.531250, 1, 1.386719, 0 } }, + { "OLYMPUS", "C8080WZ", EveningSun, 2, { 2.800781, 1, 1.296875, 0 } }, + { "OLYMPUS", "C8080WZ", EveningSun, 3, { 3.074219, 1, 1.207031, 0 } }, + { "OLYMPUS", "C8080WZ", EveningSun, 4, { 3.343750, 1, 1.121094, 0 } }, + { "OLYMPUS", "C8080WZ", EveningSun, 5, { 3.617188, 1, 1.031250, 0 } }, + { "OLYMPUS", "C8080WZ", EveningSun, 6, { 4.128631, 1.062241, 1, 0 } }, + { "OLYMPUS", "C8080WZ", EveningSun, 7, { 4.863014, 1.168950, 1, 0 } }, + { "OLYMPUS", "C8080WZ", FlashAuto, -7, { 1.488281, 1, 2.214844, 0 } }, + { "OLYMPUS", "C8080WZ", FlashAuto, -6, { 1.652344, 1, 2.105469, 0 } }, + { "OLYMPUS", "C8080WZ", FlashAuto, -5, { 1.812500, 1, 1.992188, 0 } }, + { "OLYMPUS", "C8080WZ", FlashAuto, -4, { 1.976562, 1, 1.882812, 0 } }, + { "OLYMPUS", "C8080WZ", FlashAuto, -3, { 2.117188, 1, 1.773438, 0 } }, + { "OLYMPUS", "C8080WZ", FlashAuto, -2, { 2.253906, 1, 1.675781, 0 } }, + { "OLYMPUS", "C8080WZ", FlashAuto, -1, { 2.425781, 1, 1.585938, 0 } }, + { "OLYMPUS", "C8080WZ", FlashAuto, 0, { 2.570312, 1, 1.468750, 0 } }, + { "OLYMPUS", "C8080WZ", FlashAuto, 1, { 2.890625, 1, 1.386719, 0 } }, + { "OLYMPUS", "C8080WZ", FlashAuto, 2, { 3.199219, 1, 1.308594, 0 } }, + { "OLYMPUS", "C8080WZ", FlashAuto, 3, { 3.500000, 1, 1.214844, 0 } }, + { "OLYMPUS", "C8080WZ", FlashAuto, 4, { 3.820312, 1, 1.125000, 0 } }, + { "OLYMPUS", "C8080WZ", FlashAuto, 5, { 4.128906, 1, 1.039062, 0 } }, + { "OLYMPUS", "C8080WZ", FlashAuto, 6, { 4.711934, 1.053498, 1, 0 } }, + { "OLYMPUS", "C8080WZ", FlashAuto, 7, { 5.450450, 1.153153, 1, 0 } }, + { "OLYMPUS", "C8080WZ", DaylightFluorescent, -7, { 1.425781, 1, 2.097656, 0 } }, /*6700K*/ + { "OLYMPUS", "C8080WZ", DaylightFluorescent, -6, { 1.574219, 1, 2.000000, 0 } }, /*6700K*/ + { "OLYMPUS", "C8080WZ", DaylightFluorescent, -5, { 1.722656, 1, 1.902344, 0 } }, /*6700K*/ + { "OLYMPUS", "C8080WZ", DaylightFluorescent, -4, { 1.867188, 1, 1.804688, 0 } }, /*6700K*/ + { "OLYMPUS", "C8080WZ", DaylightFluorescent, -3, { 2.015625, 1, 1.703125, 0 } }, /*6700K*/ + { "OLYMPUS", "C8080WZ", DaylightFluorescent, -2, { 2.164062, 1, 1.605469, 0 } }, /*6700K*/ + { "OLYMPUS", "C8080WZ", DaylightFluorescent, -1, { 2.312500, 1, 1.507812, 0 } }, /*6700K*/ + { "OLYMPUS", "C8080WZ", DaylightFluorescent, 0, { 2.460938, 1, 1.410156, 0 } }, /*6700K*/ + { "OLYMPUS", "C8080WZ", DaylightFluorescent, 1, { 2.753906, 1, 1.324219, 0 } }, /*6700K*/ + { "OLYMPUS", "C8080WZ", DaylightFluorescent, 2, { 3.050781, 1, 1.238281, 0 } }, /*6700K*/ + { "OLYMPUS", "C8080WZ", DaylightFluorescent, 3, { 3.343750, 1, 1.156250, 0 } }, /*6700K*/ + { "OLYMPUS", "C8080WZ", DaylightFluorescent, 4, { 3.640625, 1, 1.070312, 0 } }, /*6700K*/ + { "OLYMPUS", "C8080WZ", DaylightFluorescent, 5, { 4.000000, 1.015873, 1, 0 } }, /*6700K*/ + { "OLYMPUS", "C8080WZ", DaylightFluorescent, 6, { 4.688312, 1.108225, 1, 0 } }, /*6700K*/ + { "OLYMPUS", "C8080WZ", DaylightFluorescent, 7, { 5.545455, 1.224880, 1, 0 } }, /*6700K*/ + { "OLYMPUS", "C8080WZ", NeutralFluorescent, -7, { 1.195312, 1, 2.589844, 0 } }, /*5000K*/ + { "OLYMPUS", "C8080WZ", NeutralFluorescent, -6, { 1.316406, 1, 2.464844, 0 } }, /*5000K*/ + { "OLYMPUS", "C8080WZ", NeutralFluorescent, -5, { 1.441406, 1, 2.343750, 0 } }, /*5000K*/ + { "OLYMPUS", "C8080WZ", NeutralFluorescent, -4, { 1.566406, 1, 2.222656, 0 } }, /*5000K*/ + { "OLYMPUS", "C8080WZ", NeutralFluorescent, -3, { 1.687500, 1, 2.101562, 0 } }, /*5000K*/ + { "OLYMPUS", "C8080WZ", NeutralFluorescent, -2, { 1.812500, 1, 1.980469, 0 } }, /*5000K*/ + { "OLYMPUS", "C8080WZ", NeutralFluorescent, -1, { 1.937500, 1, 1.859375, 0 } }, /*5000K*/ + { "OLYMPUS", "C8080WZ", NeutralFluorescent, 0, { 2.062500, 1, 1.738281, 0 } }, /*5000K*/ + { "OLYMPUS", "C8080WZ", NeutralFluorescent, 1, { 2.308594, 1, 1.632812, 0 } }, /*5000K*/ + { "OLYMPUS", "C8080WZ", NeutralFluorescent, 2, { 2.554688, 1, 1.527344, 0 } }, /*5000K*/ + { "OLYMPUS", "C8080WZ", NeutralFluorescent, 3, { 2.804688, 1, 1.421875, 0 } }, /*5000K*/ + { "OLYMPUS", "C8080WZ", NeutralFluorescent, 4, { 3.050781, 1, 1.320312, 0 } }, /*5000K*/ + { "OLYMPUS", "C8080WZ", NeutralFluorescent, 5, { 3.296875, 1, 1.214844, 0 } }, /*5000K*/ + { "OLYMPUS", "C8080WZ", NeutralFluorescent, 6, { 3.546875, 1, 1.109375, 0 } }, /*5000K*/ + { "OLYMPUS", "C8080WZ", NeutralFluorescent, 7, { 3.792969, 1, 1.007812, 0 } }, /*5000K*/ + { "OLYMPUS", "C8080WZ", CoolWhiteFluorescent, -7, { 1.109375, 1, 3.257812, 0 } }, /*4200K*/ + { "OLYMPUS", "C8080WZ", CoolWhiteFluorescent, -6, { 1.226562, 1, 3.105469, 0 } }, /*4200K*/ + { "OLYMPUS", "C8080WZ", CoolWhiteFluorescent, -5, { 1.339844, 1, 2.953125, 0 } }, /*4200K*/ + { "OLYMPUS", "C8080WZ", CoolWhiteFluorescent, -4, { 1.457031, 1, 2.796875, 0 } }, /*4200K*/ + { "OLYMPUS", "C8080WZ", CoolWhiteFluorescent, -3, { 1.570312, 1, 2.644531, 0 } }, /*4200K*/ + { "OLYMPUS", "C8080WZ", CoolWhiteFluorescent, -2, { 1.687500, 1, 2.492188, 0 } }, /*4200K*/ + { "OLYMPUS", "C8080WZ", CoolWhiteFluorescent, -1, { 1.800781, 1, 2.339844, 0 } }, /*4200K*/ + { "OLYMPUS", "C8080WZ", CoolWhiteFluorescent, 0, { 1.917969, 1, 2.187500, 0 } }, /*4200K*/ + { "OLYMPUS", "C8080WZ", CoolWhiteFluorescent, 1, { 2.144531, 1, 2.054688, 0 } }, /*4200K*/ + { "OLYMPUS", "C8080WZ", CoolWhiteFluorescent, 2, { 2.375000, 1, 1.921875, 0 } }, /*4200K*/ + { "OLYMPUS", "C8080WZ", CoolWhiteFluorescent, 3, { 2.605469, 1, 1.792969, 0 } }, /*4200K*/ + { "OLYMPUS", "C8080WZ", CoolWhiteFluorescent, 4, { 2.835938, 1, 1.660156, 0 } }, /*4200K*/ + { "OLYMPUS", "C8080WZ", CoolWhiteFluorescent, 5, { 3.066406, 1, 1.531250, 0 } }, /*4200K*/ + { "OLYMPUS", "C8080WZ", CoolWhiteFluorescent, 6, { 3.296875, 1, 1.398438, 0 } }, /*4200K*/ + { "OLYMPUS", "C8080WZ", CoolWhiteFluorescent, 7, { 3.527344, 1, 1.265625, 0 } }, /*4200K*/ + { "OLYMPUS", "C8080WZ", WhiteFluorescent, -7, { 1, 1.347368, 5.963158, 0 } }, /*3500K*/ + { "OLYMPUS", "C8080WZ", WhiteFluorescent, -6, { 1, 1.224880, 5.167464, 0 } }, /*3500K*/ + { "OLYMPUS", "C8080WZ", WhiteFluorescent, -5, { 1, 1.117904, 4.484716, 0 } }, /*3500K*/ + { "OLYMPUS", "C8080WZ", WhiteFluorescent, -4, { 1, 1.028112, 3.911647, 0 } }, /*3500K*/ + { "OLYMPUS", "C8080WZ", WhiteFluorescent, -3, { 1.046875, 1, 3.593750, 0 } }, /*3500K*/ + { "OLYMPUS", "C8080WZ", WhiteFluorescent, -2, { 1.125000, 1, 3.386719, 0 } }, /*3500K*/ + { "OLYMPUS", "C8080WZ", WhiteFluorescent, -1, { 1.203125, 1, 3.179688, 0 } }, /*3500K*/ + { "OLYMPUS", "C8080WZ", WhiteFluorescent, 0, { 1.281250, 1, 2.972656, 0 } }, /*3500K*/ + { "OLYMPUS", "C8080WZ", WhiteFluorescent, 1, { 1.433594, 1, 2.792969, 0 } }, /*3500K*/ + { "OLYMPUS", "C8080WZ", WhiteFluorescent, 2, { 1.585938, 1, 2.613281, 0 } }, /*3500K*/ + { "OLYMPUS", "C8080WZ", WhiteFluorescent, 3, { 1.742188, 1, 2.437500, 0 } }, /*3500K*/ + { "OLYMPUS", "C8080WZ", WhiteFluorescent, 4, { 1.894531, 1, 2.257812, 0 } }, /*3500K*/ + { "OLYMPUS", "C8080WZ", WhiteFluorescent, 5, { 2.046875, 1, 2.078125, 0 } }, /*3500K*/ + { "OLYMPUS", "C8080WZ", WhiteFluorescent, 6, { 2.203125, 1, 1.902344, 0 } }, /*3500K*/ + { "OLYMPUS", "C8080WZ", WhiteFluorescent, 7, { 2.355469, 1, 1.722656, 0 } }, /*3500K*/ + { "OLYMPUS", "C8080WZ", Tungsten, -7, { 1, 1.488372, 6.988372, 0 } }, /*3000K*/ + { "OLYMPUS", "C8080WZ", Tungsten, -6, { 1, 1.347368, 6.026316, 0 } }, /*3000K*/ + { "OLYMPUS", "C8080WZ", Tungsten, -5, { 1, 1.230769, 5.235577, 0 } }, /*3000K*/ + { "OLYMPUS", "C8080WZ", Tungsten, -4, { 1, 1.132743, 4.566372, 0 } }, /*3000K*/ + { "OLYMPUS", "C8080WZ", Tungsten, -3, { 1, 1.049180, 4.000000, 0 } }, /*3000K*/ + { "OLYMPUS", "C8080WZ", Tungsten, -2, { 1.023438, 1, 3.589844, 0 } }, /*3000K*/ + { "OLYMPUS", "C8080WZ", Tungsten, -1, { 1.093750, 1, 3.371094, 0 } }, /*3000K*/ + { "OLYMPUS", "C8080WZ", Tungsten, 0, { 1.164062, 1, 3.152344, 0 } }, /*3000K*/ + { "OLYMPUS", "C8080WZ", Tungsten, 1, { 1.300781, 1, 2.960938, 0 } }, /*3000K*/ + { "OLYMPUS", "C8080WZ", Tungsten, 2, { 1.441406, 1, 2.773438, 0 } }, /*3000K*/ + { "OLYMPUS", "C8080WZ", Tungsten, 3, { 1.582031, 1, 2.582031, 0 } }, /*3000K*/ + { "OLYMPUS", "C8080WZ", Tungsten, 4, { 1.722656, 1, 2.394531, 0 } }, /*3000K*/ + { "OLYMPUS", "C8080WZ", Tungsten, 5, { 1.722656, 1, 2.394531, 0 } }, /*3000K*/ + { "OLYMPUS", "C8080WZ", Tungsten, 6, { 2.000000, 1, 2.015625, 0 } }, /*3000K*/ + { "OLYMPUS", "C8080WZ", Tungsten, 7, { 2.140625, 1, 1.828125, 0 } }, /*3000K*/ +// Fin ajout + + { "OLYMPUS", "E-1", Incandescent, -7, { 1.195312, 1, 1.562500, 0 } }, /*3600K*/ + { "OLYMPUS", "E-1", Incandescent, -6, { 1.187500, 1, 1.578125, 0 } }, /*3600K*/ + { "OLYMPUS", "E-1", Incandescent, -5, { 1.187500, 1, 1.585938, 0 } }, /*3600K*/ + { "OLYMPUS", "E-1", Incandescent, -4, { 1.179688, 1, 1.601562, 0 } }, /*3600K*/ + { "OLYMPUS", "E-1", Incandescent, -3, { 1.171875, 1, 1.609375, 0 } }, /*3600K*/ + { "OLYMPUS", "E-1", Incandescent, -2, { 1.164062, 1, 1.617188, 0 } }, /*3600K*/ + { "OLYMPUS", "E-1", Incandescent, -1, { 1.156250, 1, 1.632812, 0 } }, /*3600K*/ + { "OLYMPUS", "E-1", Incandescent, 0, { 1.156250, 1, 1.640625, 0 } }, /*3600K*/ + { "OLYMPUS", "E-1", Incandescent, 1, { 1.140625, 1, 1.648438, 0 } }, /*3600K*/ + { "OLYMPUS", "E-1", Incandescent, 2, { 1.132812, 1, 1.664062, 0 } }, /*3600K*/ + { "OLYMPUS", "E-1", Incandescent, 3, { 1.125000, 1, 1.671875, 0 } }, /*3600K*/ + { "OLYMPUS", "E-1", Incandescent, 4, { 1.117188, 1, 1.679688, 0 } }, /*3600K*/ + { "OLYMPUS", "E-1", Incandescent, 5, { 1.117188, 1, 1.695312, 0 } }, /*3600K*/ + { "OLYMPUS", "E-1", Incandescent, 6, { 1.109375, 1, 1.703125, 0 } }, /*3600K*/ + { "OLYMPUS", "E-1", Incandescent, 7, { 1.101562, 1, 1.718750, 0 } }, /*3600K*/ + { "OLYMPUS", "E-1", IncandescentWarm, -7, { 1.015625, 1, 1.867188, 0 } }, /*3000K*/ + { "OLYMPUS", "E-1", IncandescentWarm, -6, { 1.007812, 1, 1.875000, 0 } }, /*3000K*/ + { "OLYMPUS", "E-1", IncandescentWarm, -5, { 1.000000, 1, 1.890625, 0 } }, /*3000K*/ + { "OLYMPUS", "E-1", IncandescentWarm, -4, { 1, 1.007874, 1.913386, 0 } }, /*3000K*/ + { "OLYMPUS", "E-1", IncandescentWarm, -3, { 1, 1.015873, 1.944444, 0 } }, /*3000K*/ + { "OLYMPUS", "E-1", IncandescentWarm, -2, { 1, 1.015873, 1.952381, 0 } }, /*3000K*/ + { "OLYMPUS", "E-1", IncandescentWarm, -1, { 1, 1.024000, 1.984000, 0 } }, /*3000K*/ + { "OLYMPUS", "E-1", IncandescentWarm, 0, { 1, 1.024000, 1.992000, 0 } }, /*3000K*/ + { "OLYMPUS", "E-1", IncandescentWarm, 1, { 1, 1.032258, 2.008065, 0 } }, /*3000K*/ + { "OLYMPUS", "E-1", IncandescentWarm, 2, { 1, 1.040650, 2.040650, 0 } }, /*3000K*/ + { "OLYMPUS", "E-1", IncandescentWarm, 3, { 1, 1.040650, 2.048780, 0 } }, /*3000K*/ + { "OLYMPUS", "E-1", IncandescentWarm, 4, { 1, 1.049180, 2.081967, 0 } }, /*3000K*/ + { "OLYMPUS", "E-1", IncandescentWarm, 5, { 1, 1.057851, 2.107438, 0 } }, /*3000K*/ + { "OLYMPUS", "E-1", IncandescentWarm, 6, { 1, 1.066667, 2.141667, 0 } }, /*3000K*/ + { "OLYMPUS", "E-1", IncandescentWarm, 7, { 1, 1.075630, 2.168067, 0 } }, /*3000K*/ + { "OLYMPUS", "E-1", WhiteFluorescent, -7, { 2.296875, 1, 1.445312, 0 } }, /*4000K*/ + { "OLYMPUS", "E-1", WhiteFluorescent, -6, { 2.273438, 1, 1.468750, 0 } }, /*4000K*/ + { "OLYMPUS", "E-1", WhiteFluorescent, -5, { 2.242188, 1, 1.492188, 0 } }, /*4000K*/ + { "OLYMPUS", "E-1", WhiteFluorescent, -4, { 2.210938, 1, 1.523438, 0 } }, /*4000K*/ + { "OLYMPUS", "E-1", WhiteFluorescent, -3, { 2.171875, 1, 1.562500, 0 } }, /*4000K*/ + { "OLYMPUS", "E-1", WhiteFluorescent, -2, { 2.132812, 1, 1.601562, 0 } }, /*4000K*/ + { "OLYMPUS", "E-1", WhiteFluorescent, -1, { 2.093750, 1, 1.640625, 0 } }, /*4000K*/ + { "OLYMPUS", "E-1", WhiteFluorescent, 0, { 2.062500, 1, 1.679688, 0 } }, /*4000K*/ + { "OLYMPUS", "E-1", WhiteFluorescent, 1, { 2.039062, 1, 1.703125, 0 } }, /*4000K*/ + { "OLYMPUS", "E-1", WhiteFluorescent, 2, { 2.015625, 1, 1.734375, 0 } }, /*4000K*/ + { "OLYMPUS", "E-1", WhiteFluorescent, 3, { 2.000000, 1, 1.757812, 0 } }, /*4000K*/ + { "OLYMPUS", "E-1", WhiteFluorescent, 4, { 1.984375, 1, 1.789062, 0 } }, /*4000K*/ + { "OLYMPUS", "E-1", WhiteFluorescent, 5, { 1.968750, 1, 1.812500, 0 } }, /*4000K*/ + { "OLYMPUS", "E-1", WhiteFluorescent, 6, { 1.945312, 1, 1.835938, 0 } }, /*4000K*/ + { "OLYMPUS", "E-1", WhiteFluorescent, 7, { 1.929688, 1, 1.867188, 0 } }, /*4000K*/ + { "OLYMPUS", "E-1", NeutralFluorescent, -7, { 1.984375, 1, 1.203125, 0 } }, /*4500K*/ + { "OLYMPUS", "E-1", NeutralFluorescent, -6, { 1.960938, 1, 1.218750, 0 } }, /*4500K*/ + { "OLYMPUS", "E-1", NeutralFluorescent, -5, { 1.937500, 1, 1.234375, 0 } }, /*4500K*/ + { "OLYMPUS", "E-1", NeutralFluorescent, -4, { 1.921875, 1, 1.257812, 0 } }, /*4500K*/ + { "OLYMPUS", "E-1", NeutralFluorescent, -3, { 1.898438, 1, 1.273438, 0 } }, /*4500K*/ + { "OLYMPUS", "E-1", NeutralFluorescent, -2, { 1.875000, 1, 1.289062, 0 } }, /*4500K*/ + { "OLYMPUS", "E-1", NeutralFluorescent, -1, { 1.851562, 1, 1.304688, 0 } }, /*4500K*/ + { "OLYMPUS", "E-1", NeutralFluorescent, 0, { 1.835938, 1, 1.320312, 0 } }, /*4500K*/ + { "OLYMPUS", "E-1", NeutralFluorescent, 1, { 1.804688, 1, 1.343750, 0 } }, /*4500K*/ + { "OLYMPUS", "E-1", NeutralFluorescent, 2, { 1.773438, 1, 1.367188, 0 } }, /*4500K*/ + { "OLYMPUS", "E-1", NeutralFluorescent, 3, { 1.750000, 1, 1.390625, 0 } }, /*4500K*/ + { "OLYMPUS", "E-1", NeutralFluorescent, 4, { 1.718750, 1, 1.414062, 0 } }, /*4500K*/ + { "OLYMPUS", "E-1", NeutralFluorescent, 5, { 1.695312, 1, 1.437500, 0 } }, /*4500K*/ + { "OLYMPUS", "E-1", NeutralFluorescent, 6, { 1.656250, 1, 1.476562, 0 } }, /*4500K*/ + { "OLYMPUS", "E-1", NeutralFluorescent, 7, { 1.617188, 1, 1.515625, 0 } }, /*4500K*/ + { "OLYMPUS", "E-1", DaylightFluorescent, -7, { 2.819820, 1.153153, 1, 0 } }, /*6600K*/ + { "OLYMPUS", "E-1", DaylightFluorescent, -6, { 2.669565, 1.113043, 1, 0 } }, /*6600K*/ + { "OLYMPUS", "E-1", DaylightFluorescent, -5, { 2.521008, 1.075630, 1, 0 } }, /*6600K*/ + { "OLYMPUS", "E-1", DaylightFluorescent, -4, { 2.390244, 1.040650, 1, 0 } }, /*6600K*/ + { "OLYMPUS", "E-1", DaylightFluorescent, -3, { 2.259843, 1.007874, 1, 0 } }, /*6600K*/ + { "OLYMPUS", "E-1", DaylightFluorescent, -2, { 2.195312, 1, 1.023438, 0 } }, /*6600K*/ + { "OLYMPUS", "E-1", DaylightFluorescent, -1, { 2.140625, 1, 1.054688, 0 } }, /*6600K*/ + { "OLYMPUS", "E-1", DaylightFluorescent, 0, { 2.101562, 1, 1.085938, 0 } }, /*6600K*/ + { "OLYMPUS", "E-1", DaylightFluorescent, 1, { 2.070312, 1, 1.101562, 0 } }, /*6600K*/ + { "OLYMPUS", "E-1", DaylightFluorescent, 2, { 2.046875, 1, 1.117188, 0 } }, /*6600K*/ + { "OLYMPUS", "E-1", DaylightFluorescent, 3, { 2.023438, 1, 1.132812, 0 } }, /*6600K*/ + { "OLYMPUS", "E-1", DaylightFluorescent, 4, { 2.000000, 1, 1.156250, 0 } }, /*6600K*/ + { "OLYMPUS", "E-1", DaylightFluorescent, 5, { 1.976562, 1, 1.171875, 0 } }, /*6600K*/ + { "OLYMPUS", "E-1", DaylightFluorescent, 6, { 1.953125, 1, 1.187500, 0 } }, /*6600K*/ + { "OLYMPUS", "E-1", DaylightFluorescent, 7, { 1.929688, 1, 1.203125, 0 } }, /*6600K*/ + { "OLYMPUS", "E-1", Daylight, -7, { 1.726562, 1, 1.093750, 0 } }, /*5300K*/ + { "OLYMPUS", "E-1", Daylight, -6, { 1.710938, 1, 1.101562, 0 } }, /*5300K*/ + { "OLYMPUS", "E-1", Daylight, -5, { 1.703125, 1, 1.109375, 0 } }, /*5300K*/ + { "OLYMPUS", "E-1", Daylight, -4, { 1.695312, 1, 1.117188, 0 } }, /*5300K*/ + { "OLYMPUS", "E-1", Daylight, -3, { 1.687500, 1, 1.117188, 0 } }, /*5300K*/ + { "OLYMPUS", "E-1", Daylight, -2, { 1.671875, 1, 1.125000, 0 } }, /*5300K*/ + { "OLYMPUS", "E-1", Daylight, -1, { 1.664062, 1, 1.132812, 0 } }, /*5300K*/ + { "OLYMPUS", "E-1", Daylight, 0, { 1.664062, 1, 1.140625, 0 } }, /*5300K*/ + { "OLYMPUS", "E-1", Daylight, 1, { 1.648438, 1, 1.148438, 0 } }, /*5300K*/ + { "OLYMPUS", "E-1", Daylight, 2, { 1.640625, 1, 1.156250, 0 } }, /*5300K*/ + { "OLYMPUS", "E-1", Daylight, 3, { 1.632812, 1, 1.164062, 0 } }, /*5300K*/ + { "OLYMPUS", "E-1", Daylight, 4, { 1.617188, 1, 1.164062, 0 } }, /*5300K*/ + { "OLYMPUS", "E-1", Daylight, 5, { 1.609375, 1, 1.171875, 0 } }, /*5300K*/ + { "OLYMPUS", "E-1", Daylight, 6, { 1.601562, 1, 1.179688, 0 } }, /*5300K*/ + { "OLYMPUS", "E-1", Daylight, 7, { 1.593750, 1, 1.187500, 0 } }, /*5300K*/ + { "OLYMPUS", "E-1", Cloudy, -7, { 2.008130, 1.040650, 1, 0 } }, /*6000K*/ + { "OLYMPUS", "E-1", Cloudy, -6, { 1.967742, 1.032258, 1, 0 } }, /*6000K*/ + { "OLYMPUS", "E-1", Cloudy, -5, { 1.920635, 1.015873, 1, 0 } }, /*6000K*/ + { "OLYMPUS", "E-1", Cloudy, -4, { 1.867188, 1, 1.000000, 0 } }, /*6000K*/ + { "OLYMPUS", "E-1", Cloudy, -3, { 1.851562, 1, 1.007812, 0 } }, /*6000K*/ + { "OLYMPUS", "E-1", Cloudy, -2, { 1.828125, 1, 1.023438, 0 } }, /*6000K*/ + { "OLYMPUS", "E-1", Cloudy, -1, { 1.812500, 1, 1.031250, 0 } }, /*6000K*/ + { "OLYMPUS", "E-1", Cloudy, 0, { 1.796875, 1, 1.046875, 0 } }, /*6000K*/ + { "OLYMPUS", "E-1", Cloudy, 1, { 1.781250, 1, 1.054688, 0 } }, /*6000K*/ + { "OLYMPUS", "E-1", Cloudy, 2, { 1.773438, 1, 1.062500, 0 } }, /*6000K*/ + { "OLYMPUS", "E-1", Cloudy, 3, { 1.757812, 1, 1.070312, 0 } }, /*6000K*/ + { "OLYMPUS", "E-1", Cloudy, 4, { 1.750000, 1, 1.070312, 0 } }, /*6000K*/ + { "OLYMPUS", "E-1", Cloudy, 5, { 1.742188, 1, 1.078125, 0 } }, /*6000K*/ + { "OLYMPUS", "E-1", Cloudy, 6, { 1.734375, 1, 1.085938, 0 } }, /*6000K*/ + { "OLYMPUS", "E-1", Cloudy, 7, { 1.726562, 1, 1.093750, 0 } }, /*6000K*/ + { "OLYMPUS", "E-1", Shade, -7, { 2.584906, 1.207547, 1, 0 } }, /*7500K*/ + { "OLYMPUS", "E-1", Shade, -6, { 2.532710, 1.196262, 1, 0 } }, /*7500K*/ + { "OLYMPUS", "E-1", Shade, -5, { 2.467890, 1.174312, 1, 0 } }, /*7500K*/ + { "OLYMPUS", "E-1", Shade, -4, { 2.396396, 1.153153, 1, 0 } }, /*7500K*/ + { "OLYMPUS", "E-1", Shade, -3, { 2.357143, 1.142857, 1, 0 } }, /*7500K*/ + { "OLYMPUS", "E-1", Shade, -2, { 2.289474, 1.122807, 1, 0 } }, /*7500K*/ + { "OLYMPUS", "E-1", Shade, -1, { 2.252174, 1.113043, 1, 0 } }, /*7500K*/ + { "OLYMPUS", "E-1", Shade, 0, { 2.196581, 1.094017, 1, 0 } }, /*7500K*/ + { "OLYMPUS", "E-1", Shade, 1, { 2.126050, 1.075630, 1, 0 } }, /*7500K*/ + { "OLYMPUS", "E-1", Shade, 2, { 2.091667, 1.066667, 1, 0 } }, /*7500K*/ + { "OLYMPUS", "E-1", Shade, 3, { 2.032787, 1.049180, 1, 0 } }, /*7500K*/ + { "OLYMPUS", "E-1", Shade, 4, { 2.000000, 1.040650, 1, 0 } }, /*7500K*/ + { "OLYMPUS", "E-1", Shade, 5, { 1.944000, 1.024000, 1, 0 } }, /*7500K*/ + { "OLYMPUS", "E-1", Shade, 6, { 1.897638, 1.007874, 1, 0 } }, /*7500K*/ + { "OLYMPUS", "E-1", Shade, 7, { 1.859375, 1, 1.000000, 0 } }, /*7500K*/ + { "OLYMPUS", "E-1", "3300K", -7, { 1.109375, 1, 1.695312, 0 } }, + { "OLYMPUS", "E-1", "3300K", -6, { 1.101562, 1, 1.710938, 0 } }, + { "OLYMPUS", "E-1", "3300K", -5, { 1.093750, 1, 1.718750, 0 } }, + { "OLYMPUS", "E-1", "3300K", -4, { 1.093750, 1, 1.734375, 0 } }, + { "OLYMPUS", "E-1", "3300K", -3, { 1.085938, 1, 1.742188, 0 } }, + { "OLYMPUS", "E-1", "3300K", -2, { 1.078125, 1, 1.750000, 0 } }, + { "OLYMPUS", "E-1", "3300K", -1, { 1.070312, 1, 1.765625, 0 } }, + { "OLYMPUS", "E-1", "3300K", 0, { 1.070312, 1, 1.773438, 0 } }, + { "OLYMPUS", "E-1", "3300K", 1, { 1.054688, 1, 1.781250, 0 } }, + { "OLYMPUS", "E-1", "3300K", 2, { 1.046875, 1, 1.796875, 0 } }, + { "OLYMPUS", "E-1", "3300K", 3, { 1.046875, 1, 1.804688, 0 } }, + { "OLYMPUS", "E-1", "3300K", 4, { 1.039062, 1, 1.820312, 0 } }, + { "OLYMPUS", "E-1", "3300K", 5, { 1.031250, 1, 1.828125, 0 } }, + { "OLYMPUS", "E-1", "3300K", 6, { 1.023438, 1, 1.843750, 0 } }, + { "OLYMPUS", "E-1", "3300K", 7, { 1.015625, 1, 1.851562, 0 } }, + { "OLYMPUS", "E-1", "3900K", -7, { 1.335938, 1, 1.414062, 0 } }, + { "OLYMPUS", "E-1", "3900K", -6, { 1.320312, 1, 1.429688, 0 } }, + { "OLYMPUS", "E-1", "3900K", -5, { 1.304688, 1, 1.445312, 0 } }, + { "OLYMPUS", "E-1", "3900K", -4, { 1.289062, 1, 1.460938, 0 } }, + { "OLYMPUS", "E-1", "3900K", -3, { 1.273438, 1, 1.476562, 0 } }, + { "OLYMPUS", "E-1", "3900K", -2, { 1.257812, 1, 1.492188, 0 } }, + { "OLYMPUS", "E-1", "3900K", -1, { 1.242188, 1, 1.507812, 0 } }, + { "OLYMPUS", "E-1", "3900K", 0, { 1.234375, 1, 1.523438, 0 } }, + { "OLYMPUS", "E-1", "3900K", 1, { 1.218750, 1, 1.531250, 0 } }, + { "OLYMPUS", "E-1", "3900K", 2, { 1.210938, 1, 1.546875, 0 } }, + { "OLYMPUS", "E-1", "3900K", 3, { 1.203125, 1, 1.554688, 0 } }, + { "OLYMPUS", "E-1", "3900K", 4, { 1.195312, 1, 1.562500, 0 } }, + { "OLYMPUS", "E-1", "3900K", 5, { 1.187500, 1, 1.578125, 0 } }, + { "OLYMPUS", "E-1", "3900K", 6, { 1.187500, 1, 1.585938, 0 } }, + { "OLYMPUS", "E-1", "3900K", 7, { 1.179688, 1, 1.601562, 0 } }, + { "OLYMPUS", "E-1", "4300K", -7, { 1.484375, 1, 1.281250, 0 } }, + { "OLYMPUS", "E-1", "4300K", -6, { 1.468750, 1, 1.289062, 0 } }, + { "OLYMPUS", "E-1", "4300K", -5, { 1.460938, 1, 1.296875, 0 } }, + { "OLYMPUS", "E-1", "4300K", -4, { 1.445312, 1, 1.304688, 0 } }, + { "OLYMPUS", "E-1", "4300K", -3, { 1.437500, 1, 1.312500, 0 } }, + { "OLYMPUS", "E-1", "4300K", -2, { 1.429688, 1, 1.328125, 0 } }, + { "OLYMPUS", "E-1", "4300K", -1, { 1.414062, 1, 1.335938, 0 } }, + { "OLYMPUS", "E-1", "4300K", 0, { 1.414062, 1, 1.343750, 0 } }, + { "OLYMPUS", "E-1", "4300K", 1, { 1.390625, 1, 1.359375, 0 } }, + { "OLYMPUS", "E-1", "4300K", 2, { 1.375000, 1, 1.375000, 0 } }, + { "OLYMPUS", "E-1", "4300K", 3, { 1.359375, 1, 1.390625, 0 } }, + { "OLYMPUS", "E-1", "4300K", 4, { 1.343750, 1, 1.406250, 0 } }, + { "OLYMPUS", "E-1", "4300K", 5, { 1.328125, 1, 1.421875, 0 } }, + { "OLYMPUS", "E-1", "4300K", 6, { 1.312500, 1, 1.437500, 0 } }, + { "OLYMPUS", "E-1", "4300K", 7, { 1.296875, 1, 1.453125, 0 } }, + { "OLYMPUS", "E-1", "4800K", -7, { 1.601562, 1, 1.179688, 0 } }, + { "OLYMPUS", "E-1", "4800K", -6, { 1.593750, 1, 1.187500, 0 } }, + { "OLYMPUS", "E-1", "4800K", -5, { 1.585938, 1, 1.195312, 0 } }, + { "OLYMPUS", "E-1", "4800K", -4, { 1.578125, 1, 1.203125, 0 } }, + { "OLYMPUS", "E-1", "4800K", -3, { 1.562500, 1, 1.203125, 0 } }, + { "OLYMPUS", "E-1", "4800K", -2, { 1.554688, 1, 1.210938, 0 } }, + { "OLYMPUS", "E-1", "4800K", -1, { 1.546875, 1, 1.218750, 0 } }, + { "OLYMPUS", "E-1", "4800K", 0, { 1.546875, 1, 1.226562, 0 } }, + { "OLYMPUS", "E-1", "4800K", 1, { 1.531250, 1, 1.234375, 0 } }, + { "OLYMPUS", "E-1", "4800K", 2, { 1.515625, 1, 1.242188, 0 } }, + { "OLYMPUS", "E-1", "4800K", 3, { 1.507812, 1, 1.257812, 0 } }, + { "OLYMPUS", "E-1", "4800K", 4, { 1.500000, 1, 1.265625, 0 } }, + { "OLYMPUS", "E-1", "4800K", 5, { 1.484375, 1, 1.273438, 0 } }, + { "OLYMPUS", "E-1", "4800K", 6, { 1.476562, 1, 1.281250, 0 } }, + { "OLYMPUS", "E-1", "4800K", 7, { 1.460938, 1, 1.289062, 0 } }, + + { "OLYMPUS", "E-10", Incandescent, 0, { 1, 1.153153, 3.441442, 0 } }, /*3000K*/ + { "OLYMPUS", "E-10", IncandescentWarm, 0, { 1.101562, 1, 2.351562, 0 } }, /*3700K*/ + { "OLYMPUS", "E-10", WhiteFluorescent, 0, { 1.460938, 1, 2.546875, 0 } }, /*4000K*/ + { "OLYMPUS", "E-10", DaylightFluorescent, 0, { 1.460938, 1, 1.843750, 0 } }, /*4500K*/ + { "OLYMPUS", "E-10", Daylight, 0, { 1.523438, 1, 1.617188, 0 } }, /*5500K*/ + { "OLYMPUS", "E-10", Cloudy, 0, { 1.687500, 1, 1.437500, 0 } }, /*6500K*/ + { "OLYMPUS", "E-10", Shade, 0, { 1.812500, 1, 1.312500, 0 } }, /*7500K*/ + + /* Firmware version 1.4 */ + { "OLYMPUS", "E-3", Daylight, 0, { 1.7812, 1, 1.4688, 0 } }, + { "OLYMPUS", "E-3", Shade, 0, { 2.1406, 1, 1.1484, 0 } }, + { "OLYMPUS", "E-3", Cloudy, 0, { 1.9531, 1, 1.3359, 0 } }, + { "OLYMPUS", "E-3", Incandescent, 0, { 1.0312, 1, 2.8125, 0 } }, + { "OLYMPUS", "E-3", WhiteFluorescent, 0, { 1.6328, 1, 2.1953, 0 } }, + { "OLYMPUS", "E-3", NeutralFluorescent, 0, { 1.6641, 1, 1.7734, 0 } }, + { "OLYMPUS", "E-3", DaylightFluorescent, 0, { 1.9531, 1, 1.4844, 0 } }, + { "OLYMPUS", "E-3", Flash, 0, { 1.9609, 1, 1.3359, 0 } }, + { "OLYMPUS", "E-3", "2000K", 0, { 1, 2.5600, 11.3600, 0 } }, + { "OLYMPUS", "E-3", "2050K", 0, { 1, 2.2069, 9.4655, 0 } }, + { "OLYMPUS", "E-3", "2100K", 0, { 1, 2.0000, 8.3281, 0 } }, + { "OLYMPUS", "E-3", "2150K", 0, { 1, 1.8286, 7.3857, 0 } }, + { "OLYMPUS", "E-3", "2200K", 0, { 1, 1.6623, 6.4935, 0 } }, + { "OLYMPUS", "E-3", "2250K", 0, { 1, 1.5422, 5.8434, 0 } }, + { "OLYMPUS", "E-3", "2300K", 0, { 1, 1.4545, 5.3523, 0 } }, + { "OLYMPUS", "E-3", "2350K", 0, { 1, 1.3763, 4.9140, 0 } }, + { "OLYMPUS", "E-3", "2400K", 0, { 1, 1.2929, 4.4848, 0 } }, + { "OLYMPUS", "E-3", "2450K", 0, { 1, 1.2427, 4.1942, 0 } }, + { "OLYMPUS", "E-3", "2500K", 0, { 1, 1.1852, 3.8889, 0 } }, + { "OLYMPUS", "E-3", "2550K", 0, { 1, 1.1429, 3.6429, 0 } }, + { "OLYMPUS", "E-3", "2600K", 0, { 1, 1.0940, 3.3932, 0 } }, + { "OLYMPUS", "E-3", "2650K", 0, { 1, 1.0579, 3.1901, 0 } }, + { "OLYMPUS", "E-3", "2700K", 0, { 1, 1.0240, 3.0080, 0 } }, + { "OLYMPUS", "E-3", "2750K", 0, { 1.0078, 1, 2.8516, 0 } }, + { "OLYMPUS", "E-3", "2800K", 0, { 1.0312, 1, 2.7891, 0 } }, + { "OLYMPUS", "E-3", "2900K", 0, { 1.0859, 1, 2.6406, 0 } }, + { "OLYMPUS", "E-3", "3000K", 0, { 1.1328, 1, 2.5156, 0 } }, + { "OLYMPUS", "E-3", "3100K", 0, { 1.1875, 1, 2.3906, 0 } }, + { "OLYMPUS", "E-3", "3200K", 0, { 1.2266, 1, 2.2734, 0 } }, + { "OLYMPUS", "E-3", "3300K", 0, { 1.2734, 1, 2.1641, 0 } }, + { "OLYMPUS", "E-3", "3400K", 0, { 1.3047, 1, 2.1016, 0 } }, + { "OLYMPUS", "E-3", "3500K", 0, { 1.3438, 1, 2.0312, 0 } }, + { "OLYMPUS", "E-3", "3600K", 0, { 1.3750, 1, 1.9687, 0 } }, + { "OLYMPUS", "E-3", "3700K", 0, { 1.4063, 1, 1.9219, 0 } }, + { "OLYMPUS", "E-3", "3800K", 0, { 1.4375, 1, 1.8750, 0 } }, + { "OLYMPUS", "E-3", "3900K", 0, { 1.4687, 1, 1.8281, 0 } }, + { "OLYMPUS", "E-3", "4000K", 0, { 1.4844, 1, 1.8047, 0 } }, + { "OLYMPUS", "E-3", "4200K", 0, { 1.5234, 1, 1.7422, 0 } }, + { "OLYMPUS", "E-3", "4400K", 0, { 1.5703, 1, 1.6875, 0 } }, + { "OLYMPUS", "E-3", "4600K", 0, { 1.6250, 1, 1.6250, 0 } }, + { "OLYMPUS", "E-3", "4800K", 0, { 1.6797, 1, 1.5625, 0 } }, + { "OLYMPUS", "E-3", "5000K", 0, { 1.7266, 1, 1.5156, 0 } }, + { "OLYMPUS", "E-3", "5200K", 0, { 1.7734, 1, 1.4688, 0 } }, + { "OLYMPUS", "E-3", "5400K", 0, { 1.8203, 1, 1.4297, 0 } }, + { "OLYMPUS", "E-3", "5600K", 0, { 1.8750, 1, 1.3906, 0 } }, + { "OLYMPUS", "E-3", "5800K", 0, { 1.9297, 1, 1.3516, 0 } }, + { "OLYMPUS", "E-3", "6000K", 0, { 1.9844, 1, 1.3125, 0 } }, + { "OLYMPUS", "E-3", "6200K", 0, { 2.0078, 1, 1.2891, 0 } }, + { "OLYMPUS", "E-3", "6400K", 0, { 2.0312, 1, 1.2656, 0 } }, + { "OLYMPUS", "E-3", "6600K", 0, { 2.0625, 1, 1.2344, 0 } }, + { "OLYMPUS", "E-3", "6800K", 0, { 2.0859, 1, 1.2109, 0 } }, + { "OLYMPUS", "E-3", "7000K", 0, { 2.1094, 1, 1.1875, 0 } }, + { "OLYMPUS", "E-3", "7400K", 0, { 2.1484, 1, 1.1484, 0 } }, + { "OLYMPUS", "E-3", "7800K", 0, { 2.1875, 1, 1.1094, 0 } }, + { "OLYMPUS", "E-3", "8200K", 0, { 2.2266, 1, 1.0703, 0 } }, + { "OLYMPUS", "E-3", "8600K", 0, { 2.2500, 1, 1.0469, 0 } }, + { "OLYMPUS", "E-3", "9000K", 0, { 2.2813, 1, 1.0156, 0 } }, + { "OLYMPUS", "E-3", "9400K", 0, { 2.3228, 1.0079, 1, 0 } }, + { "OLYMPUS", "E-3", "9800K", 0, { 2.4032, 1.0323, 1, 0 } }, + { "OLYMPUS", "E-3", "10000K", 0, { 2.4590, 1.0492, 1, 0 } }, + { "OLYMPUS", "E-3", "11000K", 0, { 2.6379, 1.1034, 1, 0 } }, + { "OLYMPUS", "E-3", "12000K", 0, { 2.8018, 1.1532, 1, 0 } }, + { "OLYMPUS", "E-3", "13000K", 0, { 2.9811, 1.2075, 1, 0 } }, + { "OLYMPUS", "E-3", "14000K", 0, { 3.1373, 1.2549, 1, 0 } }, + + /* Firmware version 1.3 */ + { "OLYMPUS", "E-5", Daylight, 0, { 1.7344, 1, 1.3203, 0 } }, + { "OLYMPUS", "E-5", Shade, 0, { 2.1016, 1, 1.0313, 0 } }, + { "OLYMPUS", "E-5", Cloudy, 0, { 1.9141, 1, 1.1953, 0 } }, + { "OLYMPUS", "E-5", Incandescent, 0, { 1.0000, 1, 2.3906, 0 } }, + { "OLYMPUS", "E-5", Fluorescent, 0, { 1.6484, 1, 1.9141, 0 } }, + { "OLYMPUS", "E-5", Underwater, 0, { 1.7266, 1, 1.3828, 0 } }, + { "OLYMPUS", "E-5", Flash, 0, { 1.9063, 1, 1.1797, 0 } }, + { "OLYMPUS", "E-5", "2000K", 0, { 1, 2.6122, 9.7959, 0 } }, + { "OLYMPUS", "E-5", "2050K", 0, { 1, 2.2857, 8.2857, 0 } }, + { "OLYMPUS", "E-5", "2100K", 0, { 1, 2.0645, 7.2742, 0 } }, + { "OLYMPUS", "E-5", "2150K", 0, { 1, 1.8824, 6.4412, 0 } }, + { "OLYMPUS", "E-5", "2200K", 0, { 1, 1.7067, 5.6533, 0 } }, + { "OLYMPUS", "E-5", "2250K", 0, { 1, 1.6000, 5.1500, 0 } }, + { "OLYMPUS", "E-5", "2300K", 0, { 1, 1.4884, 4.6512, 0 } }, + { "OLYMPUS", "E-5", "2350K", 0, { 1, 1.4066, 4.2747, 0 } }, + { "OLYMPUS", "E-5", "2400K", 0, { 1, 1.3333, 3.9375, 0 } }, + { "OLYMPUS", "E-5", "2450K", 0, { 1, 1.2800, 3.6800, 0 } }, + { "OLYMPUS", "E-5", "2500K", 0, { 1, 1.2190, 3.4095, 0 } }, + { "OLYMPUS", "E-5", "2550K", 0, { 1, 1.1743, 3.1927, 0 } }, + { "OLYMPUS", "E-5", "2600K", 0, { 1, 1.1327, 3.0000, 0 } }, + { "OLYMPUS", "E-5", "2650K", 0, { 1, 1.0940, 2.8205, 0 } }, + { "OLYMPUS", "E-5", "2700K", 0, { 1, 1.0579, 2.6529, 0 } }, + { "OLYMPUS", "E-5", "2750K", 0, { 1, 1.0240, 2.5040, 0 } }, + { "OLYMPUS", "E-5", "2800K", 0, { 1.0000, 1, 2.3906, 0 } }, + { "OLYMPUS", "E-5", "2900K", 0, { 1.0547, 1, 2.2734, 0 } }, + { "OLYMPUS", "E-5", "3000K", 0, { 1.1016, 1, 2.1641, 0 } }, + { "OLYMPUS", "E-5", "3100K", 0, { 1.1484, 1, 2.0625, 0 } }, + { "OLYMPUS", "E-5", "3200K", 0, { 1.1953, 1, 1.9609, 0 } }, + { "OLYMPUS", "E-5", "3300K", 0, { 1.2344, 1, 1.8750, 0 } }, + { "OLYMPUS", "E-5", "3400K", 0, { 1.2656, 1, 1.8281, 0 } }, + { "OLYMPUS", "E-5", "3500K", 0, { 1.3047, 1, 1.7734, 0 } }, + { "OLYMPUS", "E-5", "3600K", 0, { 1.3359, 1, 1.7188, 0 } }, + { "OLYMPUS", "E-5", "3700K", 0, { 1.3594, 1, 1.6797, 0 } }, + { "OLYMPUS", "E-5", "3800K", 0, { 1.3906, 1, 1.6406, 0 } }, + { "OLYMPUS", "E-5", "3900K", 0, { 1.4219, 1, 1.6016, 0 } }, + { "OLYMPUS", "E-5", "4000K", 0, { 1.4375, 1, 1.5937, 0 } }, + { "OLYMPUS", "E-5", "4200K", 0, { 1.4766, 1, 1.5703, 0 } }, + { "OLYMPUS", "E-5", "4400K", 0, { 1.5234, 1, 1.5313, 0 } }, + { "OLYMPUS", "E-5", "4600K", 0, { 1.5781, 1, 1.4766, 0 } }, + { "OLYMPUS", "E-5", "4800K", 0, { 1.6250, 1, 1.4219, 0 } }, + { "OLYMPUS", "E-5", "5000K", 0, { 1.6641, 1, 1.3828, 0 } }, + { "OLYMPUS", "E-5", "5200K", 0, { 1.7109, 1, 1.3438, 0 } }, + { "OLYMPUS", "E-5", "5400K", 0, { 1.7578, 1, 1.3047, 0 } }, + { "OLYMPUS", "E-5", "5600K", 0, { 1.8125, 1, 1.2656, 0 } }, + { "OLYMPUS", "E-5", "5800K", 0, { 1.8594, 1, 1.2344, 0 } }, + { "OLYMPUS", "E-5", "6000K", 0, { 1.9141, 1, 1.1953, 0 } }, + { "OLYMPUS", "E-5", "6200K", 0, { 1.9375, 1, 1.1719, 0 } }, + { "OLYMPUS", "E-5", "6400K", 0, { 1.9687, 1, 1.1484, 0 } }, + { "OLYMPUS", "E-5", "6600K", 0, { 1.9922, 1, 1.1250, 0 } }, + { "OLYMPUS", "E-5", "6800K", 0, { 2.0156, 1, 1.1016, 0 } }, + { "OLYMPUS", "E-5", "7000K", 0, { 2.0469, 1, 1.0781, 0 } }, + { "OLYMPUS", "E-5", "7400K", 0, { 2.0859, 1, 1.0469, 0 } }, + { "OLYMPUS", "E-5", "7800K", 0, { 2.1250, 1, 1.0078, 0 } }, + { "OLYMPUS", "E-5", "8200K", 0, { 2.2160, 1.0240, 1, 0 } }, + { "OLYMPUS", "E-5", "8600K", 0, { 2.3033, 1.0492, 1, 0 } }, + { "OLYMPUS", "E-5", "9000K", 0, { 2.4153, 1.0847, 1, 0 } }, + { "OLYMPUS", "E-5", "9400K", 0, { 2.5043, 1.1130, 1, 0 } }, + { "OLYMPUS", "E-5", "9800K", 0, { 2.5752, 1.1327, 1, 0 } }, + { "OLYMPUS", "E-5", "10000K", 0, { 2.6396, 1.1532, 1, 0 } }, + { "OLYMPUS", "E-5", "11000K", 0, { 2.8571, 1.2190, 1, 0 } }, + { "OLYMPUS", "E-5", "12000K", 0, { 3.0198, 1.2673, 1, 0 } }, + { "OLYMPUS", "E-5", "13000K", 0, { 3.2292, 1.3333, 1, 0 } }, + { "OLYMPUS", "E-5", "14000K", 0, { 3.3763, 1.3763, 1, 0 } }, + + { "OLYMPUS", "E-30", Daylight, -7, { 1.554688, 1, 1.515625, 0 } }, + { "OLYMPUS", "E-30", Daylight, 0, { 1.812500, 1, 1.335937, 0 } }, + { "OLYMPUS", "E-30", Daylight, 7, { 2.062500, 1, 1.148437, 0 } }, + { "OLYMPUS", "E-30", Shade, -7, { 1.867188, 1, 1.171875, 0 } }, + { "OLYMPUS", "E-30", Shade, 0, { 2.179688, 1, 1.031250, 0 } }, + { "OLYMPUS", "E-30", Shade, 7, { 2.814159, 1.132743, 1, 0 } }, + { "OLYMPUS", "E-30", Cloudy, -7, { 1.710938, 1, 1.359375, 0 } }, + { "OLYMPUS", "E-30", Cloudy, 0, { 1.992187, 1, 1.195312, 0 } }, + { "OLYMPUS", "E-30", Cloudy, 7, { 2.265625, 1, 1.023438, 0 } }, + { "OLYMPUS", "E-30", Incandescent, -7, { 1, 1.103448, 3.137931, 0 } }, + { "OLYMPUS", "E-30", Incandescent, 0, { 1.054687, 1, 2.500000, 0 } }, + { "OLYMPUS", "E-30", Incandescent, 7, { 1.195313, 1, 2.148437, 0 } }, + { "OLYMPUS", "E-30", WhiteFluorescent, -7, { 1.453125, 1, 2.187500, 0 } }, + { "OLYMPUS", "E-30", WhiteFluorescent, 0, { 1.695313, 1, 1.921875, 0 } }, + { "OLYMPUS", "E-30", WhiteFluorescent, 7, { 1.929687, 1, 1.648437, 0 } }, + { "OLYMPUS", "E-30", NeutralFluorescent, -7, { 1.437500, 1, 1.929687, 0 } }, + { "OLYMPUS", "E-30", NeutralFluorescent, 0, { 1.679687, 1, 1.695313, 0 } }, + { "OLYMPUS", "E-30", NeutralFluorescent, 7, { 1.914063, 1, 1.453125, 0 } }, + { "OLYMPUS", "E-30", DaylightFluorescent, -7, { 1.765625, 1, 1.500000, 0 } }, + { "OLYMPUS", "E-30", DaylightFluorescent, 0, { 2.054688, 1, 1.320313, 0 } }, + { "OLYMPUS", "E-30", DaylightFluorescent, 7, { 2.335938, 1, 1.132812, 0 } }, + { "OLYMPUS", "E-30", Flash, -7, { 1.710938, 1, 1.359375, 0 } }, + { "OLYMPUS", "E-30", Flash, 0, { 1.992187, 1, 1.195312, 0 } }, + { "OLYMPUS", "E-30", Flash, 7, { 2.265625, 1, 1.023438, 0 } }, + { "OLYMPUS", "E-30", "2000K", 0, { 1, 2.509804, 10.058823, 0 } }, + { "OLYMPUS", "E-30", "2050K", 0, { 1, 2.206897, 8.534483, 0 } }, + { "OLYMPUS", "E-30", "2100K", 0, { 1, 1.969231, 7.384615, 0 } }, + { "OLYMPUS", "E-30", "2150K", 0, { 1, 1.802817, 6.563380, 0 } }, + { "OLYMPUS", "E-30", "2200K", 0, { 1, 1.641026, 5.782051, 0 } }, + { "OLYMPUS", "E-30", "2250K", 0, { 1, 1.523809, 5.202381, 0 } }, + { "OLYMPUS", "E-30", "2300K", 0, { 1, 1.422222, 4.711111, 0 } }, + { "OLYMPUS", "E-30", "2350K", 0, { 1, 1.347368, 4.326316, 0 } }, + { "OLYMPUS", "E-30", "2400K", 0, { 1, 1.267327, 3.950495, 0 } }, + { "OLYMPUS", "E-30", "2450K", 0, { 1, 1.219048, 3.695238, 0 } }, + { "OLYMPUS", "E-30", "2500K", 0, { 1, 1.163636, 3.436364, 0 } }, + { "OLYMPUS", "E-30", "2550K", 0, { 1, 1.113043, 3.191304, 0 } }, + { "OLYMPUS", "E-30", "2600K", 0, { 1, 1.075630, 2.991597, 0 } }, + { "OLYMPUS", "E-30", "2650K", 0, { 1, 1.032258, 2.798387, 0 } }, + { "OLYMPUS", "E-30", "2700K", 0, { 1.000000, 1, 2.632813, 0 } }, + { "OLYMPUS", "E-30", "2750K", 0, { 1.031250, 1, 2.562500, 0 } }, + { "OLYMPUS", "E-30", "2800K", 0, { 1.054687, 1, 2.500000, 0 } }, + { "OLYMPUS", "E-30", "2900K", 0, { 1.109375, 1, 2.367187, 0 } }, + { "OLYMPUS", "E-30", "3000K", 0, { 1.164062, 1, 2.250000, 0 } }, + { "OLYMPUS", "E-30", "3100K", 0, { 1.210938, 1, 2.132812, 0 } }, + { "OLYMPUS", "E-30", "3200K", 0, { 1.257812, 1, 2.031250, 0 } }, + { "OLYMPUS", "E-30", "3300K", 0, { 1.304687, 1, 1.929687, 0 } }, + { "OLYMPUS", "E-30", "3400K", 0, { 1.335937, 1, 1.875000, 0 } }, + { "OLYMPUS", "E-30", "3500K", 0, { 1.375000, 1, 1.812500, 0 } }, + { "OLYMPUS", "E-30", "3600K", 0, { 1.406250, 1, 1.757812, 0 } }, + { "OLYMPUS", "E-30", "3700K", 0, { 1.437500, 1, 1.718750, 0 } }, + { "OLYMPUS", "E-30", "3800K", 0, { 1.468750, 1, 1.679688, 0 } }, + { "OLYMPUS", "E-30", "3900K", 0, { 1.500000, 1, 1.632813, 0 } }, + { "OLYMPUS", "E-30", "4000K", 0, { 1.515625, 1, 1.625000, 0 } }, + { "OLYMPUS", "E-30", "4200K", 0, { 1.546875, 1, 1.601562, 0 } }, + { "OLYMPUS", "E-30", "4400K", 0, { 1.585938, 1, 1.562500, 0 } }, + { "OLYMPUS", "E-30", "4600K", 0, { 1.640625, 1, 1.500000, 0 } }, + { "OLYMPUS", "E-30", "4800K", 0, { 1.695313, 1, 1.445312, 0 } }, + { "OLYMPUS", "E-30", "5000K", 0, { 1.742187, 1, 1.406250, 0 } }, + { "OLYMPUS", "E-30", "5200K", 0, { 1.789062, 1, 1.359375, 0 } }, + { "OLYMPUS", "E-30", "5400K", 0, { 1.835938, 1, 1.320313, 0 } }, + { "OLYMPUS", "E-30", "5600K", 0, { 1.890625, 1, 1.273438, 0 } }, + { "OLYMPUS", "E-30", "5800K", 0, { 1.937500, 1, 1.234375, 0 } }, + { "OLYMPUS", "E-30", "6000K", 0, { 1.992187, 1, 1.195312, 0 } }, + { "OLYMPUS", "E-30", "6200K", 0, { 2.015625, 1, 1.171875, 0 } }, + { "OLYMPUS", "E-30", "6400K", 0, { 2.046875, 1, 1.148438, 0 } }, + { "OLYMPUS", "E-30", "6600K", 0, { 2.070312, 1, 1.125000, 0 } }, + { "OLYMPUS", "E-30", "6800K", 0, { 2.093750, 1, 1.101563, 0 } }, + { "OLYMPUS", "E-30", "7000K", 0, { 2.125000, 1, 1.078125, 0 } }, + { "OLYMPUS", "E-30", "7400K", 0, { 2.164063, 1, 1.046875, 0 } }, + { "OLYMPUS", "E-30", "7800K", 0, { 2.203125, 1, 1.007813, 0 } }, + { "OLYMPUS", "E-30", "8200K", 0, { 2.296000, 1.024000, 1, 0 } }, + { "OLYMPUS", "E-30", "8600K", 0, { 2.385246, 1.049180, 1, 0 } }, + { "OLYMPUS", "E-30", "9000K", 0, { 2.500000, 1.084746, 1, 0 } }, + { "OLYMPUS", "E-30", "9400K", 0, { 2.591304, 1.113043, 1, 0 } }, + { "OLYMPUS", "E-30", "9800K", 0, { 2.663717, 1.132743, 1, 0 } }, + { "OLYMPUS", "E-30", "10000K", 0, { 2.729730, 1.153153, 1, 0 } }, + { "OLYMPUS", "E-30", "11000K", 0, { 2.952381, 1.219048, 1, 0 } }, + { "OLYMPUS", "E-30", "12000K", 0, { 3.118812, 1.267327, 1, 0 } }, + { "OLYMPUS", "E-30", "13000K", 0, { 3.333333, 1.333333, 1, 0 } }, + { "OLYMPUS", "E-30", "14000K", 0, { 3.483871, 1.376344, 1, 0 } }, + + { "OLYMPUS", "E-300", Incandescent, -7, { 1.179688, 1, 2.125000, 0 } }, + { "OLYMPUS", "E-300", Incandescent, 0, { 1.140625, 1, 2.203125, 0 } }, + { "OLYMPUS", "E-300", Incandescent, 7, { 1.093750, 1, 2.273438, 0 } }, + { "OLYMPUS", "E-300", IncandescentWarm, -7, { 1.382812, 1, 1.859375, 0 } }, + { "OLYMPUS", "E-300", IncandescentWarm, 0, { 1.312500, 1, 1.906250, 0 } }, + { "OLYMPUS", "E-300", IncandescentWarm, 7, { 1.257812, 1, 1.984375, 0 } }, + { "OLYMPUS", "E-300", WhiteFluorescent, -7, { 2.109375, 1, 1.710938, 0 } }, + { "OLYMPUS", "E-300", WhiteFluorescent, 0, { 1.976562, 1, 1.921875, 0 } }, + { "OLYMPUS", "E-300", WhiteFluorescent, 7, { 1.804688, 1, 2.062500, 0 } }, + { "OLYMPUS", "E-300", NeutralFluorescent, -7, { 1.945312, 1, 1.445312, 0 } }, + { "OLYMPUS", "E-300", NeutralFluorescent, 0, { 1.820312, 1, 1.562500, 0 } }, + { "OLYMPUS", "E-300", NeutralFluorescent, 7, { 1.585938, 1, 1.945312, 0 } }, + { "OLYMPUS", "E-300", DaylightFluorescent, -7, { 2.203125, 1, 1.000000, 0 } }, + { "OLYMPUS", "E-300", DaylightFluorescent, 0, { 2.031250, 1, 1.328125, 0 } }, + { "OLYMPUS", "E-300", DaylightFluorescent, 7, { 1.765625, 1, 1.367188, 0 } }, + { "OLYMPUS", "E-300", Daylight, -7, { 1.835938, 1, 1.304688, 0 } }, + { "OLYMPUS", "E-300", Daylight, 0, { 1.789062, 1, 1.351562, 0 } }, + { "OLYMPUS", "E-300", Daylight, 7, { 1.726562, 1, 1.398438, 0 } }, + { "OLYMPUS", "E-300", Cloudy, -7, { 2.000000, 1, 1.156250, 0 } }, + { "OLYMPUS", "E-300", Cloudy, 0, { 1.890625, 1, 1.257812, 0 } }, + { "OLYMPUS", "E-300", Cloudy, 7, { 1.835938, 1, 1.304688, 0 } }, + { "OLYMPUS", "E-300", Shade, -7, { 2.179688, 1, 1.007812, 0 } }, + { "OLYMPUS", "E-300", Shade, 0, { 2.070312, 1, 1.109375, 0 } }, + { "OLYMPUS", "E-300", Shade, 7, { 1.945312, 1, 1.210938, 0 } }, + + { "OLYMPUS", "E-330", Daylight, 0, { 1.812500, 1, 1.296875, 0 } }, /*5300K*/ + { "OLYMPUS", "E-330", Cloudy, 0, { 1.953125, 1, 1.195312, 0 } }, /*6000K*/ + { "OLYMPUS", "E-330", Shade, 0, { 2.187500, 1, 1.054688, 0 } }, /*7500K*/ + { "OLYMPUS", "E-330", Incandescent, 0, { 1.039062, 1, 2.437500, 0 } }, /*3000K*/ + { "OLYMPUS", "E-330", WhiteFluorescent, 0, { 1.710938, 1, 1.906250, 0 } }, /*4000K*/ + { "OLYMPUS", "E-330", NeutralFluorescent, 0, { 1.750000, 1, 1.531250, 0 } }, /*4500K*/ + { "OLYMPUS", "E-330", DaylightFluorescent, 0, { 2.062500, 1, 1.289062, 0 } }, /*6600K*/ + + { "OLYMPUS", "E-400", Daylight, -7, { 2.554687, 1, 1.390625, 0 } }, + { "OLYMPUS", "E-400", Daylight, 0, { 2.312500, 1, 1.179687, 0 } }, + { "OLYMPUS", "E-400", Daylight, 7, { 2.096774, 1.032258, 1, 0 } }, + { "OLYMPUS", "E-400", Cloudy, -7, { 2.695312, 1, 1.289062, 0 } }, + { "OLYMPUS", "E-400", Cloudy, 0, { 2.437500, 1, 1.093750, 0 } }, + { "OLYMPUS", "E-400", Cloudy, 7, { 2.554545, 1.163636, 1, 0 } }, + { "OLYMPUS", "E-400", Shade, -7, { 2.835937, 1, 1.187500, 0 } }, + { "OLYMPUS", "E-400", Shade, 0, { 2.754098, 1.049180, 1, 0 } }, + { "OLYMPUS", "E-400", Shade, 7, { 3.202128, 1.361702, 1, 0 } }, + { "OLYMPUS", "E-400", Incandescent, -7, { 1.500000, 1, 2.710938, 0 } }, + { "OLYMPUS", "E-400", Incandescent, 0, { 1.460937, 1, 2.171875, 0 } }, + { "OLYMPUS", "E-400", Incandescent, 7, { 1.367187, 1, 1.679688, 0 } }, + { "OLYMPUS", "E-400", WhiteFluorescent, -7, { 2.523438, 1, 2.250000, 0 } }, + { "OLYMPUS", "E-400", WhiteFluorescent, 0, { 2.390625, 1, 1.796875, 0 } }, + { "OLYMPUS", "E-400", WhiteFluorescent, 7, { 2.164063, 1, 1.429688, 0 } }, + { "OLYMPUS", "E-400", NeutralFluorescent, -7, { 2.226562, 1, 1.828125, 0 } }, + { "OLYMPUS", "E-400", NeutralFluorescent, 0, { 2.132812, 1, 1.468750, 0 } }, + { "OLYMPUS", "E-400", NeutralFluorescent, 7, { 1.953125, 1, 1.156250, 0 } }, + { "OLYMPUS", "E-400", DaylightFluorescent, -7, { 2.593750, 1, 1.359375, 0 } }, + { "OLYMPUS", "E-400", DaylightFluorescent, 0, { 2.445313, 1, 1.195313, 0 } }, + { "OLYMPUS", "E-400", DaylightFluorescent, 7, { 3.293478, 1.391304, 1, 0 } }, + + { "OLYMPUS", "E-410", Daylight, 0, { 1.914063, 1, 1.367188, 0 } }, /*5300K*/ + { "OLYMPUS", "E-410", Cloudy, 0, { 2.054688, 1, 1.250000, 0 } }, /*6000K*/ + { "OLYMPUS", "E-410", Shade, 0, { 2.304688, 1, 1.031250, 0 } }, /*7500K*/ + { "OLYMPUS", "E-410", Incandescent, 0, { 1.062500, 1, 2.781250, 0 } }, /*3000K*/ + { "OLYMPUS", "E-410", WhiteFluorescent, 0, { 1.726562, 1, 2.226562, 0 } }, /*4000K*/ + { "OLYMPUS", "E-410", NeutralFluorescent, 0, { 1.703125, 1, 1.796875, 0 } }, /*4500K*/ + { "OLYMPUS", "E-410", DaylightFluorescent, 0, { 2.039063, 1, 1.476562, 0 } }, /*6600K*/ + + { "OLYMPUS", "E-420", Daylight, 0, { 1.820313, 1, 1.437500, 0 } }, + { "OLYMPUS", "E-420", Shade, 0, { 2.179688, 1, 1.140625, 0 } }, + { "OLYMPUS", "E-420", Cloudy, 0, { 2.000000, 1, 1.289062, 0 } }, + { "OLYMPUS", "E-420", Incandescent, 0, { 1.039062, 1, 2.726562, 0 } }, + { "OLYMPUS", "E-420", WhiteFluorescent, 0, { 1.703125, 1, 2.109375, 0 } }, + { "OLYMPUS", "E-420", NeutralFluorescent, 0, { 1.703125, 1, 1.757812, 0 } }, + { "OLYMPUS", "E-420", Flash, 0, { 2.078125, 1, 1.375000, 0 } }, + { "OLYMPUS", "E-420", "2000K", 0, { 1.992187, 1, 1.289062, 0 } }, + { "OLYMPUS", "E-420", "7000K", 0, { 2.125000, 1, 1.187500, 0 } }, + { "OLYMPUS", "E-420", "14000K", 0, { 2.900901, 1.153153, 1, 0 } }, + + { "OLYMPUS", "E-500", Daylight, 0, { 1.898438, 1, 1.359375, 0 } }, /*5300K*/ + { "OLYMPUS", "E-500", Cloudy, 0, { 1.992188, 1, 1.265625, 0 } }, /*6000K*/ + { "OLYMPUS", "E-500", Shade, 0, { 2.148438, 1, 1.125000, 0 } }, /*7500K*/ + { "OLYMPUS", "E-500", Incandescent, 0, { 1.265625, 1, 2.195312, 0 } }, /*3000K*/ + { "OLYMPUS", "E-500", WhiteFluorescent, 0, { 1.976562, 1, 1.914062, 0 } }, /*4000K*/ + { "OLYMPUS", "E-500", NeutralFluorescent, 0, { 1.828125, 1, 1.562500, 0 } }, /*4500K*/ + { "OLYMPUS", "E-500", DaylightFluorescent, 0, { 2.046875, 1, 1.359375, 0 } }, /*6600K*/ + + { "OLYMPUS", "E-510", Daylight, -7, { 2.164063, 1, 1.546875, 0 } }, + { "OLYMPUS", "E-510", Daylight, 0, { 1.968750, 1, 1.296875, 0 } }, + { "OLYMPUS", "E-510", Daylight, 7, { 1.742187, 1, 1.062500, 0 } }, + { "OLYMPUS", "E-510", Shade, -7, { 2.492188, 1, 1.273438, 0 } }, + { "OLYMPUS", "E-510", Shade, 0, { 2.439024, 1.040650, 1, 0 } }, + { "OLYMPUS", "E-510", Shade, 7, { 3.055556, 1.422222, 1, 0 } }, + { "OLYMPUS", "E-510", Cloudy, -7, { 2.312500, 1, 1.414062, 0 } }, + { "OLYMPUS", "E-510", Cloudy, 0, { 2.109375, 1, 1.187500, 0 } }, + { "OLYMPUS", "E-510", Cloudy, 7, { 2.192982, 1.122807, 1, 0 } }, + { "OLYMPUS", "E-510", Incandescent, -7, { 1.109375, 1, 3.351562, 0 } }, + { "OLYMPUS", "E-510", Incandescent, 0, { 1.093750, 1, 2.671875, 0 } }, + { "OLYMPUS", "E-510", Incandescent, 7, { 1.031250, 1, 2.054688, 0 } }, + { "OLYMPUS", "E-510", WhiteFluorescent, -7, { 1.578125, 1, 2.250000, 0 } }, + { "OLYMPUS", "E-510", WhiteFluorescent, 0, { 1.718750, 1, 2.109375, 0 } }, + { "OLYMPUS", "E-510", WhiteFluorescent, 7, { 1.523437, 1, 1.265625, 0 } }, + { "OLYMPUS", "E-510", NeutralFluorescent, -7, { 1.835938, 1, 1.828125, 0 } }, + { "OLYMPUS", "E-510", NeutralFluorescent, 0, { 1.687500, 1, 1.710938, 0 } }, + { "OLYMPUS", "E-510", NeutralFluorescent, 7, { 1.726562, 1, 1.078125, 0 } }, + { "OLYMPUS", "E-510", DaylightFluorescent, -7, { 2.203125, 1, 1.500000, 0 } }, + { "OLYMPUS", "E-510", DaylightFluorescent, 0, { 2.023438, 1, 1.398437, 0 } }, + { "OLYMPUS", "E-510", DaylightFluorescent, 7, { 3.193182, 1.454545, 1, 0 } }, + + { "OLYMPUS", "E-520", Daylight, 0, { 1.859375, 1, 1.445312, 0 } }, + { "OLYMPUS", "E-520", Shade, 0, { 2.234375, 1, 1.140625, 0 } }, + { "OLYMPUS", "E-520", Cloudy, 0, { 2.046875, 1, 1.296875, 0 } }, + { "OLYMPUS", "E-520", Tungsten, 0, { 1.062500, 1, 2.687500, 0 } }, + { "OLYMPUS", "E-520", WhiteFluorescent, 0, { 1.703125, 1, 2.109375, 0 } }, + { "OLYMPUS", "E-520", NeutralFluorescent, 0, { 1.718750, 1, 1.765625, 0 } }, + { "OLYMPUS", "E-520", DaylightFluorescent, 0, { 2.101563, 1, 1.375000, 0 } }, + { "OLYMPUS", "E-520", Flash, 0, { 2.039063, 1, 1.296875, 0 } }, + { "OLYMPUS", "E-520", "2000K", 0, { 1, 2.461538, 10.576923, 0 } }, + { "OLYMPUS", "E-520", "2050K", 0, { 1, 2.169491, 9.000000, 0 } }, + { "OLYMPUS", "E-520", "2100K", 0, { 1, 1.939394, 7.803031, 0 } }, + { "OLYMPUS", "E-520", "2150K", 0, { 1, 1.777778, 6.944445, 0 } }, + { "OLYMPUS", "E-520", "2200K", 0, { 1, 1.620253, 6.126582, 0 } }, + { "OLYMPUS", "E-520", "2250K", 0, { 1, 1.505882, 5.517647, 0 } }, + { "OLYMPUS", "E-520", "2300K", 0, { 1, 1.406593, 5.000000, 0 } }, + { "OLYMPUS", "E-520", "2350K", 0, { 1, 1.333333, 4.604167, 0 } }, + { "OLYMPUS", "E-520", "2400K", 0, { 1, 1.254902, 4.205882, 0 } }, + { "OLYMPUS", "E-520", "2450K", 0, { 1, 1.207547, 3.933962, 0 } }, + { "OLYMPUS", "E-520", "2500K", 0, { 1, 1.153153, 3.657658, 0 } }, + { "OLYMPUS", "E-520", "2550K", 0, { 1, 1.103448, 3.396552, 0 } }, + { "OLYMPUS", "E-520", "2600K", 0, { 1, 1.066667, 3.191667, 0 } }, + { "OLYMPUS", "E-520", "2650K", 0, { 1, 1.024000, 2.976000, 0 } }, + { "OLYMPUS", "E-520", "2700K", 0, { 1.007812, 1, 2.828125, 0 } }, + { "OLYMPUS", "E-520", "2750K", 0, { 1.039062, 1, 2.750000, 0 } }, + { "OLYMPUS", "E-520", "2800K", 0, { 1.062500, 1, 2.687500, 0 } }, + { "OLYMPUS", "E-520", "2900K", 0, { 1.117188, 1, 2.546875, 0 } }, + { "OLYMPUS", "E-520", "3000K", 0, { 1.171875, 1, 2.421875, 0 } }, + { "OLYMPUS", "E-520", "3100K", 0, { 1.218750, 1, 2.296875, 0 } }, + { "OLYMPUS", "E-520", "3200K", 0, { 1.265625, 1, 2.179688, 0 } }, + { "OLYMPUS", "E-520", "3300K", 0, { 1.312500, 1, 2.078125, 0 } }, + { "OLYMPUS", "E-520", "3400K", 0, { 1.343750, 1, 2.023438, 0 } }, + { "OLYMPUS", "E-520", "3500K", 0, { 1.382812, 1, 1.960937, 0 } }, + { "OLYMPUS", "E-520", "3600K", 0, { 1.414063, 1, 1.906250, 0 } }, + { "OLYMPUS", "E-520", "3700K", 0, { 1.445312, 1, 1.859375, 0 } }, + { "OLYMPUS", "E-520", "3800K", 0, { 1.476563, 1, 1.812500, 0 } }, + { "OLYMPUS", "E-520", "3900K", 0, { 1.507813, 1, 1.765625, 0 } }, + { "OLYMPUS", "E-520", "4000K", 0, { 1.531250, 1, 1.757812, 0 } }, + { "OLYMPUS", "E-520", "4200K", 0, { 1.578125, 1, 1.726562, 0 } }, + { "OLYMPUS", "E-520", "4400K", 0, { 1.625000, 1, 1.679688, 0 } }, + { "OLYMPUS", "E-520", "4600K", 0, { 1.687500, 1, 1.617187, 0 } }, + { "OLYMPUS", "E-520", "4800K", 0, { 1.742187, 1, 1.554687, 0 } }, + { "OLYMPUS", "E-520", "5000K", 0, { 1.789062, 1, 1.515625, 0 } }, + { "OLYMPUS", "E-520", "5200K", 0, { 1.835938, 1, 1.468750, 0 } }, + { "OLYMPUS", "E-520", "5400K", 0, { 1.882812, 1, 1.429687, 0 } }, + { "OLYMPUS", "E-520", "5600K", 0, { 1.937500, 1, 1.382812, 0 } }, + { "OLYMPUS", "E-520", "5800K", 0, { 1.992187, 1, 1.343750, 0 } }, + { "OLYMPUS", "E-520", "6000K", 0, { 2.046875, 1, 1.296875, 0 } }, + { "OLYMPUS", "E-520", "6200K", 0, { 2.070312, 1, 1.273438, 0 } }, + { "OLYMPUS", "E-520", "6400K", 0, { 2.101563, 1, 1.250000, 0 } }, + { "OLYMPUS", "E-520", "6600K", 0, { 2.125000, 1, 1.226563, 0 } }, + { "OLYMPUS", "E-520", "6800K", 0, { 2.148437, 1, 1.210937, 0 } }, + { "OLYMPUS", "E-520", "7000K", 0, { 2.179688, 1, 1.187500, 0 } }, + { "OLYMPUS", "E-520", "7400K", 0, { 2.218750, 1, 1.156250, 0 } }, + { "OLYMPUS", "E-520", "7800K", 0, { 2.257812, 1, 1.117187, 0 } }, + { "OLYMPUS", "E-520", "8200K", 0, { 2.296875, 1, 1.085938, 0 } }, + { "OLYMPUS", "E-520", "8600K", 0, { 2.328125, 1, 1.062500, 0 } }, + { "OLYMPUS", "E-520", "9000K", 0, { 2.359375, 1, 1.039063, 0 } }, + { "OLYMPUS", "E-520", "9400K", 0, { 2.382812, 1, 1.015625, 0 } }, + { "OLYMPUS", "E-520", "9800K", 0, { 2.406250, 1, 1.000000, 0 } }, + { "OLYMPUS", "E-520", "10000K", 0, { 2.460317, 1.015873, 1, 0 } }, + { "OLYMPUS", "E-520", "11000K", 0, { 2.641667, 1.066667, 1, 0 } }, + { "OLYMPUS", "E-520", "12000K", 0, { 2.775862, 1.103448, 1, 0 } }, + { "OLYMPUS", "E-520", "13000K", 0, { 2.919643, 1.142857, 1, 0 } }, + { "OLYMPUS", "E-520", "14000K", 0, { 3.036697, 1.174312, 1, 0 } }, + + /* -7/+7 fine tuning is -7/+7 in both amber-blue and green-magenta */ + { "OLYMPUS", "E-600", Daylight, -7, { 1.804688, 1, 1.671875, 0 } }, + { "OLYMPUS", "E-600", Daylight, 0, { 1.851563, 1, 1.289063, 0 } }, + { "OLYMPUS", "E-600", Daylight, 7, { 1.917355, 1.057851, 1, 0 } }, + { "OLYMPUS", "E-600", Shade, -7, { 2.179688, 1, 1.281250, 0 } }, + { "OLYMPUS", "E-600", Shade, 0, { 2.244094, 1.007874, 1, 0 } }, + { "OLYMPUS", "E-600", Shade, 7, { 2.989247, 1.376344, 1, 0 } }, + { "OLYMPUS", "E-600", Cloudy, -7, { 2.000000, 1, 1.500000, 0 } }, + { "OLYMPUS", "E-600", Cloudy, 0, { 2.046875, 1, 1.164062, 0 } }, + { "OLYMPUS", "E-600", Cloudy, 7, { 2.327273, 1.163636, 1, 0 } }, + { "OLYMPUS", "E-600", Incandescent, -7, { 1.062500, 1, 3.156250, 0 } }, + { "OLYMPUS", "E-600", Incandescent, 0, { 1.093750, 1, 2.437500, 0 } }, + { "OLYMPUS", "E-600", Incandescent, 7, { 1.062500, 1, 1.796875, 0 } }, + { "OLYMPUS", "E-600", WhiteFluorescent, -7, { 1.703125, 1, 2.398438, 0 } }, + { "OLYMPUS", "E-600", WhiteFluorescent, 0, { 1.750000, 1, 1.851563, 0 } }, + { "OLYMPUS", "E-600", WhiteFluorescent, 7, { 1.710938, 1, 1.359375, 0 } }, + { "OLYMPUS", "E-600", NeutralFluorescent, -7, { 1.671875, 1, 2.109375, 0 } }, + { "OLYMPUS", "E-600", NeutralFluorescent, 0, { 1.710938, 1, 1.625000, 0 } }, + { "OLYMPUS", "E-600", NeutralFluorescent, 7, { 1.671875, 1, 1.195312, 0 } }, + { "OLYMPUS", "E-600", DaylightFluorescent, -7, { 2.039063, 1, 1.632813, 0 } }, + { "OLYMPUS", "E-600", DaylightFluorescent, 0, { 2.085937, 1, 1.265625, 0 } }, + { "OLYMPUS", "E-600", DaylightFluorescent, 7, { 2.193277, 1.075630, 1, 0 } }, + { "OLYMPUS", "E-600", Flash, -7, { 1.992187, 1, 1.492187, 0 } }, + { "OLYMPUS", "E-600", Flash, 0, { 2.039063, 1, 1.156250, 0 } }, + { "OLYMPUS", "E-600", Flash, 7, { 2.339450, 1.174312, 1, 0 } }, + + /* -7/+7 fine tuning is -7/+7 in both amber-blue and green-magenta */ + { "OLYMPUS", "E-620", Daylight, -7, { 1.804688, 1, 1.726563, 0 } }, + { "OLYMPUS", "E-620", Daylight, 0, { 1.851563, 1, 1.335938, 0 } }, + { "OLYMPUS", "E-620", Daylight, 7, { 1.841270, 1.015873, 1, 0 } }, + { "OLYMPUS", "E-620", Shade, -7, { 2.171875, 1, 1.320312, 0 } }, + { "OLYMPUS", "E-620", Shade, 0, { 2.218750, 1, 1.023438, 0 } }, + { "OLYMPUS", "E-620", Shade, 7, { 2.885417, 1.333333, 1, 0 } }, + { "OLYMPUS", "E-620", Cloudy, -7, { 1.992187, 1, 1.539062, 0 } }, + { "OLYMPUS", "E-620", Cloudy, 0, { 2.039063, 1, 1.187500, 0 } }, + { "OLYMPUS", "E-620", Cloudy, 7, { 2.297297, 1.153153, 1, 0 } }, + { "OLYMPUS", "E-620", Incandescent, -7, { 1.070312, 1, 3.281250, 0 } }, + { "OLYMPUS", "E-620", Incandescent, 0, { 1.101563, 1, 2.531250, 0 } }, + { "OLYMPUS", "E-620", Incandescent, 7, { 1.070313, 1, 1.867188, 0 } }, + { "OLYMPUS", "E-620", WhiteFluorescent, -7, { 1.679687, 1, 2.500000, 0 } }, + { "OLYMPUS", "E-620", WhiteFluorescent, 0, { 1.718750, 1, 1.929687, 0 } }, + { "OLYMPUS", "E-620", WhiteFluorescent, 7, { 1.679688, 1, 1.421875, 0 } }, + { "OLYMPUS", "E-620", NeutralFluorescent, -7, { 1.632813, 1, 2.179688, 0 } }, + { "OLYMPUS", "E-620", NeutralFluorescent, 0, { 1.671875, 1, 1.679688, 0 } }, + { "OLYMPUS", "E-620", NeutralFluorescent, 7, { 1.625000, 1, 1.234375, 0 } }, + { "OLYMPUS", "E-620", DaylightFluorescent, -7, { 2.000000, 1, 1.687500, 0 } }, + { "OLYMPUS", "E-620", DaylightFluorescent, 0, { 2.046875, 1, 1.304687, 0 } }, + { "OLYMPUS", "E-620", DaylightFluorescent, 7, { 2.098361, 1.049180, 1, 0 } }, + { "OLYMPUS", "E-620", Flash, -7, { 1.992187, 1, 1.546875, 0 } }, + { "OLYMPUS", "E-620", Flash, 0, { 2.039063, 1, 1.195313, 0 } }, + { "OLYMPUS", "E-620", Flash, 7, { 2.276786, 1.142857, 1, 0 } }, + + { "OLYMPUS", "E-M1", Daylight, 0, { 1.9766, 1, 1.6094, 0 } }, + { "OLYMPUS", "E-M1", Shade, 0, { 2.3047, 1, 1.2578, 0 } }, + { "OLYMPUS", "E-M1", Cloudy, 0, { 2.1250, 1, 1.4688, 0 } }, + { "OLYMPUS", "E-M1", Incandescent, 0, { 1.1484, 1, 2.8516, 0 } }, + { "OLYMPUS", "E-M1", Fluorescent, 0, { 1.9219, 1, 2.2188, 0 } }, + { "OLYMPUS", "E-M1", Underwater, 0, { 1.3984, 1, 2.2813, 0 } }, + { "OLYMPUS", "E-M1", Flash, 0, { 2.3437, 1, 1.4219, 0 } }, + + /* -7/+7 fine tuning is -7/+7 in amber-blue and zero in green-magenta */ + { "OLYMPUS", "E-M1MarkII", Daylight, -7, { 1.523438, 1.000000, 2.335938, 1.000000} }, + { "OLYMPUS", "E-M1MarkII", Daylight, 0, { 1.789062, 1.000000, 2.062500, 1.000000} }, + { "OLYMPUS", "E-M1MarkII", Daylight, 7, { 2.015625, 1.000000, 1.765625, 1.000000} }, + { "OLYMPUS", "E-M1MarkII", Shade, -7, { 1.781250, 1.000000, 1.828125, 1.000000} }, + { "OLYMPUS", "E-M1MarkII", Shade, 0, { 2.078125, 1.000000, 1.609375, 1.000000} }, + { "OLYMPUS", "E-M1MarkII", Shade, 7, { 2.367187, 1.000000, 1.382812, 1.000000} }, + { "OLYMPUS", "E-M1MarkII", Cloudy, -7, { 1.640625, 1.000000, 2.125000, 1.000000} }, + { "OLYMPUS", "E-M1MarkII", Cloudy, 0, { 1.914063, 1.000000, 1.867188, 1.000000} }, + { "OLYMPUS", "E-M1MarkII", Cloudy, 7, { 2.179688, 1.000000, 1.601562, 1.000000} }, + { "OLYMPUS", "E-M1MarkII", Incandescent, -7, { 1.000000, 1.057851, 4.471074, 1.000000} }, + { "OLYMPUS", "E-M1MarkII", Incandescent, 0, { 1.101563, 1.000000, 3.710938, 1.000000} }, + { "OLYMPUS", "E-M1MarkII", Incandescent, 7, { 1.250000, 1.000000, 3.187500, 1.000000} }, + { "OLYMPUS", "E-M1MarkII", Fluorescent, -7, { 1.484375, 1.000000, 3.359375, 1.000000} }, + { "OLYMPUS", "E-M1MarkII", Fluorescent, 0, { 1.726562, 1.000000, 2.953125, 1.000000} }, + { "OLYMPUS", "E-M1MarkII", Fluorescent, 7, { 1.960938, 1.000000, 2.539062, 1.000000} }, + { "OLYMPUS", "E-M1MarkII", Underwater, -7, { 1.195313, 1.000000, 3.031250, 1.000000} }, + { "OLYMPUS", "E-M1MarkII", Underwater, 0, { 1.437500, 1.000000, 2.578125, 1.000000} }, + { "OLYMPUS", "E-M1MarkII", Underwater, 7, { 1.609375, 1.000000, 2.289063, 1.000000} }, + { "OLYMPUS", "E-M1MarkII", Flash, -7, { 1.726562, 1.000000, 1.992187, 1.000000} }, + { "OLYMPUS", "E-M1MarkII", Flash, 0, { 2.007813, 1.000000, 1.750000, 1.000000} }, + { "OLYMPUS", "E-M1MarkII", Flash, 7, { 2.281250, 1.000000, 1.500000, 1.000000} }, + + /* -7/+7 fine tuning is -7/+7 in amber-blue and zero in green-magenta */ + { "OLYMPUS", "E-M5", Daylight, -7, { 1.8047, 1, 2.0547, 0 } }, + { "OLYMPUS", "E-M5", Daylight, 0, { 2.1016, 1, 1.8047, 0 } }, + { "OLYMPUS", "E-M5", Daylight, 7, { 2.3906, 1, 1.5469, 0 } }, + { "OLYMPUS", "E-M5", Shade, -7, { 2.1484, 1, 1.6172, 0 } }, + { "OLYMPUS", "E-M5", Shade, 0, { 2.5000, 1, 1.4219, 0 } }, + { "OLYMPUS", "E-M5", Shade, 7, { 2.8437, 1, 1.2187, 0 } }, + { "OLYMPUS", "E-M5", Cloudy, -7, { 1.9766, 1, 1.8516, 0 } }, + { "OLYMPUS", "E-M5", Cloudy, 0, { 2.3047, 1, 1.6250, 0 } }, + { "OLYMPUS", "E-M5", Cloudy, 7, { 2.6250, 1, 1.3906, 0 } }, + { "OLYMPUS", "E-M5", Incandescent, -7, { 1.1250, 1, 3.6953, 0 } }, + { "OLYMPUS", "E-M5", Incandescent, 0, { 1.3125, 1, 3.2422, 0 } }, + { "OLYMPUS", "E-M5", Incandescent, 7, { 1.4922, 1, 2.7812, 0 } }, + { "OLYMPUS", "E-M5", Fluorescent, -7, { 1.7344, 1, 2.9375, 0 } }, + { "OLYMPUS", "E-M5", Fluorescent, 0, { 2.0234, 1, 2.5781, 0 } }, + { "OLYMPUS", "E-M5", Fluorescent, 7, { 2.3047, 1, 2.2109, 0 } }, + { "OLYMPUS", "E-M5", Underwater, -7, { 1.3906, 1, 2.8281, 0 } }, + { "OLYMPUS", "E-M5", Underwater, 0, { 1.6250, 1, 2.4844, 0 } }, + { "OLYMPUS", "E-M5", Underwater, 7, { 1.8516, 1, 2.1328, 0 } }, + { "OLYMPUS", "E-M5", Flash, -7, { 2.0391, 1, 1.8203, 0 } }, + { "OLYMPUS", "E-M5", Flash, 0, { 2.3750, 1, 1.6016, 0 } }, + { "OLYMPUS", "E-M5", Flash, 7, { 2.7031, 1, 1.3750, 0 } }, + + { "OLYMPUS", "E-M5MarkII", Daylight, 0, { 1.867188, 1, 1.812500, 0 } }, + { "OLYMPUS", "E-M5MarkII", Shade, 0, { 2.203125, 1, 1.406250, 0 } }, + { "OLYMPUS", "E-M5MarkII", Cloudy, 0, { 2.015625, 1, 1.648438, 0 } }, + { "OLYMPUS", "E-M5MarkII", Incandescent, 0, { 1.156250, 1, 3.539063, 0 } }, + { "OLYMPUS", "E-M5MarkII", Fluorescent, 0, { 1.835938, 1, 2.726563, 0 } }, + { "OLYMPUS", "E-M5MarkII", Underwater, 0, { 1.367188, 1, 2.812500, 0 } }, + { "OLYMPUS", "E-M5MarkII", Flash, 0, { 2.187500, 1, 1.570313, 0 } }, + + /* Firmware version 1.2 */ + /* -7/+7 fine tuning is -7/+7 in amber-blue and zero in green-magenta */ + { "OLYMPUS", "E-M10", Daylight, -7, { 1.671875, 1, 2.070312, 0 } }, + { "OLYMPUS", "E-M10", Daylight, 0, { 1.945313, 1, 1.820313, 0 } }, + { "OLYMPUS", "E-M10", Daylight, 7, { 2.210937, 1, 1.562500, 0 } }, + { "OLYMPUS", "E-M10", Shade, -7, { 1.898438, 1, 1.609375, 0 } }, + { "OLYMPUS", "E-M10", Shade, 0, { 2.210937, 1, 1.414062, 0 } }, + { "OLYMPUS", "E-M10", Shade, 7, { 2.515625, 1, 1.210937, 0 } }, + { "OLYMPUS", "E-M10", Cloudy, -7, { 1.781250, 1, 1.882812, 0 } }, + { "OLYMPUS", "E-M10", Cloudy, 0, { 2.078125, 1, 1.656250, 0 } }, + { "OLYMPUS", "E-M10", Cloudy, 7, { 2.367187, 1, 1.421875, 0 } }, + { "OLYMPUS", "E-M10", Tungsten, -7, { 1.046875, 1, 3.820313, 0 } }, + { "OLYMPUS", "E-M10", Tungsten, 0, { 1.218750, 1, 3.351562, 0 } }, + { "OLYMPUS", "E-M10", Tungsten, 7, { 1.382812, 1, 2.875000, 0 } }, + { "OLYMPUS", "E-M10", Fluorescent, -7, { 1.640625, 1, 2.945313, 0 } }, + { "OLYMPUS", "E-M10", Fluorescent, 0, { 1.914062, 1, 2.585938, 0 } }, + { "OLYMPUS", "E-M10", Fluorescent, 7, { 2.179687, 1, 2.218750, 0 } }, + { "OLYMPUS", "E-M10", Underwater, -7, { 1.921875, 1, 2.015625, 0 } }, + { "OLYMPUS", "E-M10", Underwater, 0, { 2.242187, 1, 1.773437, 0 } }, + { "OLYMPUS", "E-M10", Underwater, 7, { 2.554687, 1, 1.523437, 0 } }, + { "OLYMPUS", "E-M10", Flash, -7, { 1.960937, 1, 1.796875, 0 } }, + { "OLYMPUS", "E-M10", Flash, 0, { 2.281250, 1, 1.578125, 0 } }, + { "OLYMPUS", "E-M10", Flash, 7, { 2.593750, 1, 1.351562, 0 } }, + { "OLYMPUS", "E-M10", "2000K", 0, { 1, 1.662338, 8.688312, 0 } }, + { "OLYMPUS", "E-M10", "2050K", 0, { 1, 1.523810, 7.714286, 0 } }, + { "OLYMPUS", "E-M10", "2100K", 0, { 1, 1.422222, 6.988889, 0 } }, + { "OLYMPUS", "E-M10", "2150K", 0, { 1, 1.333333, 6.364583, 0 } }, + { "OLYMPUS", "E-M10", "2200K", 0, { 1, 1.242719, 5.747573, 0 } }, + { "OLYMPUS", "E-M10", "2250K", 0, { 1, 1.185185, 5.324074, 0 } }, + { "OLYMPUS", "E-M10", "2300K", 0, { 1, 1.122807, 4.894737, 0 } }, + { "OLYMPUS", "E-M10", "2350K", 0, { 1, 1.075630, 4.563025, 0 } }, + { "OLYMPUS", "E-M10", "2400K", 0, { 1, 1.032258, 4.258065, 0 } }, + { "OLYMPUS", "E-M10", "2450K", 0, { 1.000000, 1, 4.015625, 0 } }, + { "OLYMPUS", "E-M10", "2500K", 0, { 1.039063, 1, 3.914063, 0 } }, + { "OLYMPUS", "E-M10", "2550K", 0, { 1.070312, 1, 3.804687, 0 } }, + { "OLYMPUS", "E-M10", "2600K", 0, { 1.101563, 1, 3.703125, 0 } }, + { "OLYMPUS", "E-M10", "2650K", 0, { 1.132813, 1, 3.609375, 0 } }, + { "OLYMPUS", "E-M10", "2700K", 0, { 1.164062, 1, 3.515625, 0 } }, + { "OLYMPUS", "E-M10", "2750K", 0, { 1.195312, 1, 3.429687, 0 } }, + { "OLYMPUS", "E-M10", "2800K", 0, { 1.218750, 1, 3.351562, 0 } }, + { "OLYMPUS", "E-M10", "2900K", 0, { 1.273437, 1, 3.187500, 0 } }, + { "OLYMPUS", "E-M10", "3000K", 0, { 1.320312, 1, 3.039063, 0 } }, + { "OLYMPUS", "E-M10", "3100K", 0, { 1.367188, 1, 2.898438, 0 } }, + { "OLYMPUS", "E-M10", "3200K", 0, { 1.414062, 1, 2.765625, 0 } }, + { "OLYMPUS", "E-M10", "3300K", 0, { 1.453125, 1, 2.640625, 0 } }, + { "OLYMPUS", "E-M10", "3400K", 0, { 1.476563, 1, 2.562500, 0 } }, + { "OLYMPUS", "E-M10", "3500K", 0, { 1.507812, 1, 2.484375, 0 } }, + { "OLYMPUS", "E-M10", "3600K", 0, { 1.539062, 1, 2.414062, 0 } }, + { "OLYMPUS", "E-M10", "3700K", 0, { 1.562500, 1, 2.359375, 0 } }, + { "OLYMPUS", "E-M10", "3800K", 0, { 1.593750, 1, 2.304688, 0 } }, + { "OLYMPUS", "E-M10", "3900K", 0, { 1.625000, 1, 2.250000, 0 } }, + { "OLYMPUS", "E-M10", "4000K", 0, { 1.648438, 1, 2.226562, 0 } }, + { "OLYMPUS", "E-M10", "4200K", 0, { 1.695312, 1, 2.171875, 0 } }, + { "OLYMPUS", "E-M10", "4400K", 0, { 1.750000, 1, 2.101563, 0 } }, + { "OLYMPUS", "E-M10", "4600K", 0, { 1.796875, 1, 2.023438, 0 } }, + { "OLYMPUS", "E-M10", "4800K", 0, { 1.843750, 1, 1.953125, 0 } }, + { "OLYMPUS", "E-M10", "5000K", 0, { 1.882813, 1, 1.906250, 0 } }, + { "OLYMPUS", "E-M10", "5200K", 0, { 1.921875, 1, 1.851563, 0 } }, + { "OLYMPUS", "E-M10", "5400K", 0, { 1.960937, 1, 1.804687, 0 } }, + { "OLYMPUS", "E-M10", "5600K", 0, { 2.000000, 1, 1.750000, 0 } }, + { "OLYMPUS", "E-M10", "5800K", 0, { 2.039063, 1, 1.703125, 0 } }, + { "OLYMPUS", "E-M10", "6000K", 0, { 2.078125, 1, 1.656250, 0 } }, + { "OLYMPUS", "E-M10", "6200K", 0, { 2.093750, 1, 1.625000, 0 } }, + { "OLYMPUS", "E-M10", "6400K", 0, { 2.117187, 1, 1.585937, 0 } }, + { "OLYMPUS", "E-M10", "6600K", 0, { 2.132812, 1, 1.546875, 0 } }, + { "OLYMPUS", "E-M10", "6800K", 0, { 2.148437, 1, 1.523437, 0 } }, + { "OLYMPUS", "E-M10", "7000K", 0, { 2.171875, 1, 1.484375, 0 } }, + { "OLYMPUS", "E-M10", "7400K", 0, { 2.195313, 1, 1.429687, 0 } }, + { "OLYMPUS", "E-M10", "7800K", 0, { 2.226562, 1, 1.382812, 0 } }, + { "OLYMPUS", "E-M10", "8200K", 0, { 2.257812, 1, 1.328125, 0 } }, + { "OLYMPUS", "E-M10", "8600K", 0, { 2.273437, 1, 1.296875, 0 } }, + { "OLYMPUS", "E-M10", "9000K", 0, { 2.296875, 1, 1.257813, 0 } }, + { "OLYMPUS", "E-M10", "9400K", 0, { 2.312500, 1, 1.218750, 0 } }, + { "OLYMPUS", "E-M10", "9800K", 0, { 2.328125, 1, 1.187500, 0 } }, + { "OLYMPUS", "E-M10", "10000K", 0, { 2.343750, 1, 1.171875, 0 } }, + { "OLYMPUS", "E-M10", "11000K", 0, { 2.382812, 1, 1.101563, 0 } }, + { "OLYMPUS", "E-M10", "12000K", 0, { 2.406250, 1, 1.054688, 0 } }, + { "OLYMPUS", "E-M10", "13000K", 0, { 2.437500, 1, 1.000000, 0 } }, + { "OLYMPUS", "E-M10", "14000K", 0, { 2.552845, 1.040650, 1, 0 } }, + + { "OLYMPUS", "E-M10MarkII", Daylight, 0, { 1.851563, 1, 1.835938, 0 } }, + { "OLYMPUS", "E-M10MarkII", Shade, 0, { 2.171875, 1, 1.429688, 0 } }, + { "OLYMPUS", "E-M10MarkII", Cloudy, 0, { 1.992188, 1, 1.664063, 0 } }, + { "OLYMPUS", "E-M10MarkII", Tungsten, 0, { 1.140625, 1, 3.429688, 0 } }, + { "OLYMPUS", "E-M10MarkII", Fluorescent, 0, { 1.875000, 1, 2.695313, 0 } }, + { "OLYMPUS", "E-M10MarkII", Underwater, 0, { 1.890625, 1, 2.257813, 0 } }, + { "OLYMPUS", "E-M10MarkII", Flash, 0, { 2.148438, 1, 1.601563, 0 } }, + + { "OLYMPUS", "E-P1", Daylight, 0, { 1.835938, 1, 1.351563, 0 } }, + { "OLYMPUS", "E-P1", Shade, 0, { 2.195313, 1, 1.046875, 0 } }, + { "OLYMPUS", "E-P1", Cloudy, 0, { 2.031250, 1, 1.203125, 0 } }, + { "OLYMPUS", "E-P1", Incandescent, 0, { 1.078125, 1, 2.570312, 0 } }, + { "OLYMPUS", "E-P1", WhiteFluorescent, 0, { 1.695313, 1, 1.937500, 0 } }, + { "OLYMPUS", "E-P1", NeutralFluorescent, 0, { 1.687500, 1, 1.703125, 0 } }, + { "OLYMPUS", "E-P1", DaylightFluorescent, 0, { 2.070312, 1, 1.312500, 0 } }, + + { "OLYMPUS", "E-P2", Daylight, -7, { 1.789063, 1, 1.789063, 0 } }, + { "OLYMPUS", "E-P2", Daylight, -6, { 1.789063, 1, 1.726563, 0 } }, + { "OLYMPUS", "E-P2", Daylight, -5, { 1.804688, 1, 1.664063, 0 } }, + { "OLYMPUS", "E-P2", Daylight, -4, { 1.812500, 1, 1.609375, 0 } }, + { "OLYMPUS", "E-P2", Daylight, -3, { 1.812500, 1, 1.546875, 0 } }, + { "OLYMPUS", "E-P2", Daylight, -2, { 1.812500, 1, 1.492188, 0 } }, + { "OLYMPUS", "E-P2", Daylight, -1, { 1.820313, 1, 1.429688, 0 } }, + { "OLYMPUS", "E-P2", Daylight, 0, { 1.828125, 1, 1.382813, 0 } }, + { "OLYMPUS", "E-P2", Daylight, 1, { 1.820313, 1, 1.320313, 0 } }, + { "OLYMPUS", "E-P2", Daylight, 2, { 1.820313, 1, 1.265625, 0 } }, + { "OLYMPUS", "E-P2", Daylight, 3, { 1.820313, 1, 1.218750, 0 } }, + { "OLYMPUS", "E-P2", Daylight, 4, { 1.804688, 1, 1.164063, 0 } }, + { "OLYMPUS", "E-P2", Daylight, 5, { 1.804688, 1, 1.117188, 0 } }, + { "OLYMPUS", "E-P2", Daylight, 6, { 1.796875, 1, 1.062500, 0 } }, + { "OLYMPUS", "E-P2", Daylight, 7, { 1.781250, 1, 1.015625, 0 } }, + { "OLYMPUS", "E-P2", Shade, -7, { 2.125000, 1, 1.382813, 0 } }, + { "OLYMPUS", "E-P2", Shade, -6, { 2.132813, 1, 1.335938, 0 } }, + { "OLYMPUS", "E-P2", Shade, -5, { 2.148438, 1, 1.289063, 0 } }, + { "OLYMPUS", "E-P2", Shade, -4, { 2.148438, 1, 1.234375, 0 } }, + { "OLYMPUS", "E-P2", Shade, -3, { 2.156250, 1, 1.195313, 0 } }, + { "OLYMPUS", "E-P2", Shade, -2, { 2.156250, 1, 1.148438, 0 } }, + { "OLYMPUS", "E-P2", Shade, -1, { 2.164063, 1, 1.101563, 0 } }, + { "OLYMPUS", "E-P2", Shade, 0, { 2.171875, 1, 1.070313, 0 } }, + { "OLYMPUS", "E-P2", Shade, 1, { 2.164063, 1, 1.023438, 0 } }, + { "OLYMPUS", "E-P2", Shade, 2, { 2.164063, 1, 0.976563, 0 } }, + { "OLYMPUS", "E-P2", Shade, 3, { 2.156250, 1, 0.937500, 0 } }, + { "OLYMPUS", "E-P2", Shade, 4, { 2.156250, 1, 0.898438, 0 } }, + { "OLYMPUS", "E-P2", Shade, 5, { 2.140625, 1, 0.859375, 0 } }, + { "OLYMPUS", "E-P2", Shade, 6, { 2.132813, 1, 0.820313, 0 } }, + { "OLYMPUS", "E-P2", Shade, 7, { 2.117188, 1, 0.781250, 0 } }, + { "OLYMPUS", "E-P2", Cloudy, -7, { 1.953125, 1, 1.617188, 0 } }, + { "OLYMPUS", "E-P2", Cloudy, -6, { 1.968750, 1, 1.562500, 0 } }, + { "OLYMPUS", "E-P2", Cloudy, -5, { 1.976563, 1, 1.507813, 0 } }, + { "OLYMPUS", "E-P2", Cloudy, -4, { 1.976563, 1, 1.445313, 0 } }, + { "OLYMPUS", "E-P2", Cloudy, -3, { 1.984375, 1, 1.398438, 0 } }, + { "OLYMPUS", "E-P2", Cloudy, -2, { 1.984375, 1, 1.343750, 0 } }, + { "OLYMPUS", "E-P2", Cloudy, -1, { 1.992188, 1, 1.296875, 0 } }, + { "OLYMPUS", "E-P2", Cloudy, 0, { 2.000000, 1, 1.250000, 0 } }, + { "OLYMPUS", "E-P2", Cloudy, 1, { 1.992188, 1, 1.187500, 0 } }, + { "OLYMPUS", "E-P2", Cloudy, 2, { 1.992188, 1, 1.140625, 0 } }, + { "OLYMPUS", "E-P2", Cloudy, 3, { 1.984375, 1, 1.101563, 0 } }, + { "OLYMPUS", "E-P2", Cloudy, 4, { 1.976563, 1, 1.054688, 0 } }, + { "OLYMPUS", "E-P2", Cloudy, 5, { 1.968750, 1, 1.007813, 0 } }, + { "OLYMPUS", "E-P2", Cloudy, 6, { 1.960938, 1, 0.960938, 0 } }, + { "OLYMPUS", "E-P2", Cloudy, 7, { 1.953125, 1, 0.914063, 0 } }, + { "OLYMPUS", "E-P2", Incandescent, -7, { 1.039063, 1, 3.445313, 0 } }, + { "OLYMPUS", "E-P2", Incandescent, -6, { 1.046875, 1, 3.320313, 0 } }, + { "OLYMPUS", "E-P2", Incandescent, -5, { 1.054688, 1, 3.210938, 0 } }, + { "OLYMPUS", "E-P2", Incandescent, -4, { 1.062500, 1, 3.093750, 0 } }, + { "OLYMPUS", "E-P2", Incandescent, -3, { 1.054688, 1, 2.976563, 0 } }, + { "OLYMPUS", "E-P2", Incandescent, -2, { 1.062500, 1, 2.867188, 0 } }, + { "OLYMPUS", "E-P2", Incandescent, -1, { 1.062500, 1, 2.750000, 0 } }, + { "OLYMPUS", "E-P2", Incandescent, 0, { 1.070313, 1, 2.656250, 0 } }, + { "OLYMPUS", "E-P2", Incandescent, 1, { 1.062500, 1, 2.546875, 0 } }, + { "OLYMPUS", "E-P2", Incandescent, 2, { 1.062500, 1, 2.437500, 0 } }, + { "OLYMPUS", "E-P2", Incandescent, 3, { 1.062500, 1, 2.335938, 0 } }, + { "OLYMPUS", "E-P2", Incandescent, 4, { 1.054688, 1, 2.242188, 0 } }, + { "OLYMPUS", "E-P2", Incandescent, 5, { 1.054688, 1, 2.148438, 0 } }, + { "OLYMPUS", "E-P2", Incandescent, 6, { 1.046875, 1, 2.054688, 0 } }, + { "OLYMPUS", "E-P2", Incandescent, 7, { 1.046875, 1, 1.960938, 0 } }, + { "OLYMPUS", "E-P2", WhiteFluorescent, -7, { 1.742188, 1, 2.617188, 0 } }, + { "OLYMPUS", "E-P2", WhiteFluorescent, -6, { 1.750000, 1, 2.515625, 0 } }, + { "OLYMPUS", "E-P2", WhiteFluorescent, -5, { 1.757813, 1, 2.429688, 0 } }, + { "OLYMPUS", "E-P2", WhiteFluorescent, -4, { 1.757813, 1, 2.343750, 0 } }, + { "OLYMPUS", "E-P2", WhiteFluorescent, -3, { 1.765625, 1, 2.257813, 0 } }, + { "OLYMPUS", "E-P2", WhiteFluorescent, -2, { 1.765625, 1, 2.171875, 0 } }, + { "OLYMPUS", "E-P2", WhiteFluorescent, -1, { 1.773438, 1, 2.093750, 0 } }, + { "OLYMPUS", "E-P2", WhiteFluorescent, 0, { 1.781250, 1, 2.015625, 0 } }, + { "OLYMPUS", "E-P2", WhiteFluorescent, 1, { 1.773438, 1, 1.921875, 0 } }, + { "OLYMPUS", "E-P2", WhiteFluorescent, 2, { 1.773438, 1, 1.851563, 0 } }, + { "OLYMPUS", "E-P2", WhiteFluorescent, 3, { 1.765625, 1, 1.773438, 0 } }, + { "OLYMPUS", "E-P2", WhiteFluorescent, 4, { 1.765625, 1, 1.703125, 0 } }, + { "OLYMPUS", "E-P2", WhiteFluorescent, 5, { 1.757813, 1, 1.625000, 0 } }, + { "OLYMPUS", "E-P2", WhiteFluorescent, 6, { 1.750000, 1, 1.554688, 0 } }, + { "OLYMPUS", "E-P2", WhiteFluorescent, 7, { 1.734375, 1, 1.484375, 0 } }, + { "OLYMPUS", "E-P2", NeutralFluorescent, -7, { 1.695313, 1, 2.328125, 0 } }, + { "OLYMPUS", "E-P2", NeutralFluorescent, -6, { 1.710938, 1, 2.242188, 0 } }, + { "OLYMPUS", "E-P2", NeutralFluorescent, -5, { 1.718750, 1, 2.171875, 0 } }, + { "OLYMPUS", "E-P2", NeutralFluorescent, -4, { 1.726563, 1, 2.085938, 0 } }, + { "OLYMPUS", "E-P2", NeutralFluorescent, -3, { 1.726563, 1, 2.007813, 0 } }, + { "OLYMPUS", "E-P2", NeutralFluorescent, -2, { 1.734375, 1, 1.937500, 0 } }, + { "OLYMPUS", "E-P2", NeutralFluorescent, -1, { 1.734375, 1, 1.859375, 0 } }, + { "OLYMPUS", "E-P2", NeutralFluorescent, 0, { 1.742188, 1, 1.796875, 0 } }, + { "OLYMPUS", "E-P2", NeutralFluorescent, 1, { 1.734375, 1, 1.718750, 0 } }, + { "OLYMPUS", "E-P2", NeutralFluorescent, 2, { 1.726563, 1, 1.648438, 0 } }, + { "OLYMPUS", "E-P2", NeutralFluorescent, 3, { 1.726563, 1, 1.585938, 0 } }, + { "OLYMPUS", "E-P2", NeutralFluorescent, 4, { 1.718750, 1, 1.515625, 0 } }, + { "OLYMPUS", "E-P2", NeutralFluorescent, 5, { 1.718750, 1, 1.453125, 0 } }, + { "OLYMPUS", "E-P2", NeutralFluorescent, 6, { 1.710938, 1, 1.382813, 0 } }, + { "OLYMPUS", "E-P2", NeutralFluorescent, 7, { 1.703125, 1, 1.320313, 0 } }, + { "OLYMPUS", "E-P2", DaylightFluorescent, -7, { 2.078125, 1, 1.765625, 0 } }, + { "OLYMPUS", "E-P2", DaylightFluorescent, -6, { 2.093750, 1, 1.710938, 0 } }, + { "OLYMPUS", "E-P2", DaylightFluorescent, -5, { 2.101563, 1, 1.648438, 0 } }, + { "OLYMPUS", "E-P2", DaylightFluorescent, -4, { 2.117188, 1, 1.593750, 0 } }, + { "OLYMPUS", "E-P2", DaylightFluorescent, -3, { 2.117188, 1, 1.531250, 0 } }, + { "OLYMPUS", "E-P2", DaylightFluorescent, -2, { 2.125000, 1, 1.476563, 0 } }, + { "OLYMPUS", "E-P2", DaylightFluorescent, -1, { 2.125000, 1, 1.414063, 0 } }, + { "OLYMPUS", "E-P2", DaylightFluorescent, 0, { 2.132813, 1, 1.367188, 0 } }, + { "OLYMPUS", "E-P2", DaylightFluorescent, 1, { 2.125000, 1, 1.304688, 0 } }, + { "OLYMPUS", "E-P2", DaylightFluorescent, 2, { 2.117188, 1, 1.257813, 0 } }, + { "OLYMPUS", "E-P2", DaylightFluorescent, 3, { 2.117188, 1, 1.203125, 0 } }, + { "OLYMPUS", "E-P2", DaylightFluorescent, 4, { 2.109375, 1, 1.156250, 0 } }, + { "OLYMPUS", "E-P2", DaylightFluorescent, 5, { 2.109375, 1, 1.101563, 0 } }, + { "OLYMPUS", "E-P2", DaylightFluorescent, 6, { 2.093750, 1, 1.054688, 0 } }, + { "OLYMPUS", "E-P2", DaylightFluorescent, 7, { 2.085938, 1, 1.007813, 0 } }, + { "OLYMPUS", "E-P2", Flash, -7, { 1.960938, 1, 1.609375, 0 } }, + { "OLYMPUS", "E-P2", Flash, -6, { 1.976563, 1, 1.554688, 0 } }, + { "OLYMPUS", "E-P2", Flash, -5, { 1.984375, 1, 1.492188, 0 } }, + { "OLYMPUS", "E-P2", Flash, -4, { 1.984375, 1, 1.437500, 0 } }, + { "OLYMPUS", "E-P2", Flash, -3, { 1.992188, 1, 1.390625, 0 } }, + { "OLYMPUS", "E-P2", Flash, -2, { 1.992188, 1, 1.335938, 0 } }, + { "OLYMPUS", "E-P2", Flash, -1, { 2.000000, 1, 1.289063, 0 } }, + { "OLYMPUS", "E-P2", Flash, 0, { 2.007813, 1, 1.242188, 0 } }, + { "OLYMPUS", "E-P2", Flash, 1, { 2.000000, 1, 1.179688, 0 } }, + { "OLYMPUS", "E-P2", Flash, 2, { 2.000000, 1, 1.132813, 0 } }, + { "OLYMPUS", "E-P2", Flash, 3, { 1.992188, 1, 1.093750, 0 } }, + { "OLYMPUS", "E-P2", Flash, 4, { 1.984375, 1, 1.046875, 0 } }, + { "OLYMPUS", "E-P2", Flash, 5, { 1.976563, 1, 1.000000, 0 } }, + { "OLYMPUS", "E-P2", Flash, 6, { 1.968750, 1, 0.953125, 0 } }, + { "OLYMPUS", "E-P2", Flash, 7, { 1.960938, 1, 0.906250, 0 } }, + + { "OLYMPUS", "E-P3", Daylight, 0, { 2.0469, 1, 1.4922, 0 } }, + { "OLYMPUS", "E-P3", Shade, 0, { 2.4375, 1, 1.1875, 0 } }, + { "OLYMPUS", "E-P3", Cloudy, 0, { 2.2188, 1, 1.3750, 0 } }, + { "OLYMPUS", "E-P3", Incandescent, 0, { 1.2266, 1, 2.5312, 0 } }, + { "OLYMPUS", "E-P3", Fluorescent, 0, { 1.9766, 1, 1.9766, 0 } }, + { "OLYMPUS", "E-P3", Flash, 0, { 2.2109, 1, 1.3672, 0 } }, + + /* Firmware version 1.5 */ + { "OLYMPUS", "E-P5", Daylight, 0, { 1.945313, 1, 1.796875, 0 } }, + { "OLYMPUS", "E-P5", Shade, 0, { 2.273438, 1, 1.406250, 0 } }, + { "OLYMPUS", "E-P5", Cloudy, 0, { 2.093750, 1, 1.625000, 0 } }, + { "OLYMPUS", "E-P5", Incandescent, 0, { 1.203125, 1, 3.218750, 0 } }, + { "OLYMPUS", "E-P5", Fluorescent, 0, { 1.890625, 1, 2.585938, 0 } }, + { "OLYMPUS", "E-P5", Flash, 0, { 2.218750, 1, 1.531250, 0 } }, + + /* Firmware version 1.2 */ + /* -7/+7 fine tuning is -7/+7 in amber-blue and zero in green-magenta */ + { "OLYMPUS", "E-PL1", Daylight, -7, { 1.492188, 1, 1.531250, 0 } }, + { "OLYMPUS", "E-PL1", Daylight, 0, { 1.726562, 1, 1.343750, 0 } }, + { "OLYMPUS", "E-PL1", Daylight, 7, { 1.984375, 1, 1.148438, 0 } }, + { "OLYMPUS", "E-PL1", Shade, -7, { 1.796875, 1, 1.171875, 0 } }, + { "OLYMPUS", "E-PL1", Shade, 0, { 2.085937, 1, 1.039062, 0 } }, + { "OLYMPUS", "E-PL1", Shade, 7, { 2.699115, 1.132743, 1, 0 } }, + { "OLYMPUS", "E-PL1", Cloudy, -7, { 1.640625, 1, 1.367187, 0 } }, + { "OLYMPUS", "E-PL1", Cloudy, 0, { 1.906250, 1, 1.210938, 0 } }, + { "OLYMPUS", "E-PL1", Cloudy, 7, { 2.179688, 1, 1.031250, 0 } }, + { "OLYMPUS", "E-PL1", Incandescent, -7, { 1, 1.174312, 3.467890, 0 } }, + { "OLYMPUS", "E-PL1", Incandescent, 0, { 1, 1.015873, 2.619048, 0 } }, + { "OLYMPUS", "E-PL1", Incandescent, 7, { 1.125000, 1, 2.226562, 0 } }, + { "OLYMPUS", "E-PL1", WhiteFluorescent, -7, { 1.421875, 1, 2.234375, 0 } }, + { "OLYMPUS", "E-PL1", WhiteFluorescent, 0, { 1.648437, 1, 1.960937, 0 } }, + { "OLYMPUS", "E-PL1", WhiteFluorescent, 7, { 1.882812, 1, 1.679687, 0 } }, + { "OLYMPUS", "E-PL1", NeutralFluorescent, -7, { 1.390625, 1, 1.945313, 0 } }, + { "OLYMPUS", "E-PL1", NeutralFluorescent, 0, { 1.609375, 1, 1.710938, 0 } }, + { "OLYMPUS", "E-PL1", NeutralFluorescent, 7, { 1.851563, 1, 1.468750, 0 } }, + { "OLYMPUS", "E-PL1", DaylightFluorescent, -7, { 1.750000, 1, 1.507812, 0 } }, + { "OLYMPUS", "E-PL1", DaylightFluorescent, 0, { 2.015625, 1, 1.328125, 0 } }, + { "OLYMPUS", "E-PL1", DaylightFluorescent, 7, { 2.320313, 1.140625, 1, 0 } }, + { "OLYMPUS", "E-PL1", Flash, -7, { 1.640625, 1, 1.367187, 0 } }, + { "OLYMPUS", "E-PL1", Flash, 0, { 1.898438, 1, 1.203125, 0 } }, + { "OLYMPUS", "E-PL1", Flash, 7, { 2.179688, 1, 1.031250, 0 } }, + { "OLYMPUS", "E-PL1", "2000K", 0, { 1, 2.723404, 11.340426, 0 } }, + { "OLYMPUS", "E-PL1", "2050K", 0, { 1, 2.370370, 9.537037, 0 } }, + { "OLYMPUS", "E-PL1", "2100K", 0, { 1, 2.133333, 8.316667, 0 } }, + { "OLYMPUS", "E-PL1", "2150K", 0, { 1, 1.939394, 7.333333, 0 } }, + { "OLYMPUS", "E-PL1", "2200K", 0, { 1, 1.753425, 6.410959, 0 } }, + { "OLYMPUS", "E-PL1", "2250K", 0, { 1, 1.641026, 5.820513, 0 } }, + { "OLYMPUS", "E-PL1", "2300K", 0, { 1, 1.523810, 5.226190, 0 } }, + { "OLYMPUS", "E-PL1", "2350K", 0, { 1, 1.438202, 4.786517, 0 } }, + { "OLYMPUS", "E-PL1", "2400K", 0, { 1, 1.361702, 4.404255, 0 } }, + { "OLYMPUS", "E-PL1", "2450K", 0, { 1, 1.306122, 4.102041, 0 } }, + { "OLYMPUS", "E-PL1", "2500K", 0, { 1, 1.242718, 3.796117, 0 } }, + { "OLYMPUS", "E-PL1", "2550K", 0, { 1, 1.196262, 3.542056, 0 } }, + { "OLYMPUS", "E-PL1", "2600K", 0, { 1, 1.153153, 3.315315, 0 } }, + { "OLYMPUS", "E-PL1", "2650K", 0, { 1, 1.113043, 3.113044, 0 } }, + { "OLYMPUS", "E-PL1", "2700K", 0, { 1, 1.075630, 2.924370, 0 } }, + { "OLYMPUS", "E-PL1", "2750K", 0, { 1, 1.040650, 2.747968, 0 } }, + { "OLYMPUS", "E-PL1", "2800K", 0, { 1, 1.015873, 2.619048, 0 } }, + { "OLYMPUS", "E-PL1", "2900K", 0, { 1.039062, 1, 2.437500, 0 } }, + { "OLYMPUS", "E-PL1", "3000K", 0, { 1.085937, 1, 2.312500, 0 } }, + { "OLYMPUS", "E-PL1", "3100K", 0, { 1.132812, 1, 2.195313, 0 } }, + { "OLYMPUS", "E-PL1", "3200K", 0, { 1.179687, 1, 2.078125, 0 } }, + { "OLYMPUS", "E-PL1", "3300K", 0, { 1.218750, 1, 1.976562, 0 } }, + { "OLYMPUS", "E-PL1", "3400K", 0, { 1.250000, 1, 1.921875, 0 } }, + { "OLYMPUS", "E-PL1", "3500K", 0, { 1.281250, 1, 1.859375, 0 } }, + { "OLYMPUS", "E-PL1", "3600K", 0, { 1.312500, 1, 1.796875, 0 } }, + { "OLYMPUS", "E-PL1", "3700K", 0, { 1.343750, 1, 1.757812, 0 } }, + { "OLYMPUS", "E-PL1", "3800K", 0, { 1.375000, 1, 1.710938, 0 } }, + { "OLYMPUS", "E-PL1", "3900K", 0, { 1.406250, 1, 1.664062, 0 } }, + { "OLYMPUS", "E-PL1", "4000K", 0, { 1.421875, 1, 1.648437, 0 } }, + { "OLYMPUS", "E-PL1", "4200K", 0, { 1.468750, 1, 1.617188, 0 } }, + { "OLYMPUS", "E-PL1", "4400K", 0, { 1.515625, 1, 1.578125, 0 } }, + { "OLYMPUS", "E-PL1", "4600K", 0, { 1.570313, 1, 1.515625, 0 } }, + { "OLYMPUS", "E-PL1", "4800K", 0, { 1.617188, 1, 1.453125, 0 } }, + { "OLYMPUS", "E-PL1", "5000K", 0, { 1.656250, 1, 1.414062, 0 } }, + { "OLYMPUS", "E-PL1", "5200K", 0, { 1.703125, 1, 1.367188, 0 } }, + { "OLYMPUS", "E-PL1", "5400K", 0, { 1.750000, 1, 1.328125, 0 } }, + { "OLYMPUS", "E-PL1", "5600K", 0, { 1.804688, 1, 1.289063, 0 } }, + { "OLYMPUS", "E-PL1", "5800K", 0, { 1.851563, 1, 1.250000, 0 } }, + { "OLYMPUS", "E-PL1", "6000K", 0, { 1.906250, 1, 1.210938, 0 } }, + { "OLYMPUS", "E-PL1", "6200K", 0, { 1.929687, 1, 1.187500, 0 } }, + { "OLYMPUS", "E-PL1", "6400K", 0, { 1.953125, 1, 1.164062, 0 } }, + { "OLYMPUS", "E-PL1", "6600K", 0, { 1.984375, 1, 1.132813, 0 } }, + { "OLYMPUS", "E-PL1", "6800K", 0, { 2.007813, 1, 1.117187, 0 } }, + { "OLYMPUS", "E-PL1", "7000K", 0, { 2.031250, 1, 1.085938, 0 } }, + { "OLYMPUS", "E-PL1", "7400K", 0, { 2.070312, 1, 1.054688, 0 } }, + { "OLYMPUS", "E-PL1", "7800K", 0, { 2.109375, 1, 1.015625, 0 } }, + { "OLYMPUS", "E-PL1", "8200K", 0, { 2.200000, 1.024000, 1, 0 } }, + { "OLYMPUS", "E-PL1", "8600K", 0, { 2.278689, 1.049180, 1, 0 } }, + { "OLYMPUS", "E-PL1", "9000K", 0, { 2.369748, 1.075630, 1, 0 } }, + { "OLYMPUS", "E-PL1", "9400K", 0, { 2.478261, 1.113043, 1, 0 } }, + { "OLYMPUS", "E-PL1", "9800K", 0, { 2.548673, 1.132743, 1, 0 } }, + { "OLYMPUS", "E-PL1", "10000K", 0, { 2.612613, 1.153153, 1, 0 } }, + { "OLYMPUS", "E-PL1", "11000K", 0, { 2.819048, 1.219048, 1, 0 } }, + { "OLYMPUS", "E-PL1", "12000K", 0, { 3.010000, 1.280000, 1, 0 } }, + { "OLYMPUS", "E-PL1", "13000K", 0, { 3.221053, 1.347368, 1, 0 } }, + { "OLYMPUS", "E-PL1", "14000K", 0, { 3.369565, 1.391304, 1, 0 } }, + + { "OLYMPUS", "E-PL2", Daylight, 0, { 1.4609, 1, 1.4219, 0 } }, + { "OLYMPUS", "E-PL2", Shade, 0, { 1.7422, 1, 1.1094, 0 } }, + { "OLYMPUS", "E-PL2", Cloudy, 0, { 1.6172, 1, 1.2891, 0 } }, + { "OLYMPUS", "E-PL2", Tungsten, 0, { 1, 1.1327, 2.9115, 0 } }, + { "OLYMPUS", "E-PL2", Fluorescent, 0, { 1.3828, 1, 2.0859, 0 } }, + { "OLYMPUS", "E-PL2", Flash, 0, { 1.6016, 1, 1.2891, 0 } }, + { "OLYMPUS", "E-PL2", "2000K", 0, { 1, 2.3273, 9.1091, 0 } }, + { "OLYMPUS", "E-PL2", "2050K", 0, { 1, 2.0984, 7.9508, 0 } }, + { "OLYMPUS", "E-PL2", "2100K", 0, { 1, 1.9692, 7.2615, 0 } }, + { "OLYMPUS", "E-PL2", "2150K", 0, { 1, 1.8551, 6.6522, 0 } }, + { "OLYMPUS", "E-PL2", "2200K", 0, { 1, 1.7297, 6.0135, 0 } }, + { "OLYMPUS", "E-PL2", "2250K", 0, { 1, 1.6410, 5.5513, 0 } }, + { "OLYMPUS", "E-PL2", "2300K", 0, { 1, 1.5610, 5.1341, 0 } }, + { "OLYMPUS", "E-PL2", "2350K", 0, { 1, 1.4884, 4.7674, 0 } }, + { "OLYMPUS", "E-PL2", "2400K", 0, { 1, 1.4382, 4.4944, 0 } }, + { "OLYMPUS", "E-PL2", "2450K", 0, { 1, 1.3763, 4.1935, 0 } }, + { "OLYMPUS", "E-PL2", "2500K", 0, { 1, 1.3333, 3.9583, 0 } }, + { "OLYMPUS", "E-PL2", "2550K", 0, { 1, 1.2929, 3.7475, 0 } }, + { "OLYMPUS", "E-PL2", "2600K", 0, { 1, 1.2549, 3.5392, 0 } }, + { "OLYMPUS", "E-PL2", "2650K", 0, { 1, 1.2190, 3.3619, 0 } }, + { "OLYMPUS", "E-PL2", "2700K", 0, { 1, 1.1852, 3.1852, 0 } }, + { "OLYMPUS", "E-PL2", "2750K", 0, { 1, 1.1532, 3.0270, 0 } }, + { "OLYMPUS", "E-PL2", "2800K", 0, { 1, 1.1327, 2.9115, 0 } }, + { "OLYMPUS", "E-PL2", "2900K", 0, { 1, 1.0847, 2.6610, 0 } }, + { "OLYMPUS", "E-PL2", "3000K", 0, { 1, 1.0492, 2.4672, 0 } }, + { "OLYMPUS", "E-PL2", "3100K", 0, { 1, 1.0079, 2.2598, 0 } }, + { "OLYMPUS", "E-PL2", "3200K", 0, { 1.0234, 1, 2.1484, 0 } }, + { "OLYMPUS", "E-PL2", "3300K", 0, { 1.0547, 1, 2.0625, 0 } }, + { "OLYMPUS", "E-PL2", "3400K", 0, { 1.0781, 1, 2.0156, 0 } }, + { "OLYMPUS", "E-PL2", "3500K", 0, { 1.1016, 1, 1.9609, 0 } }, + { "OLYMPUS", "E-PL2", "3600K", 0, { 1.1250, 1, 1.9063, 0 } }, + { "OLYMPUS", "E-PL2", "3700K", 0, { 1.1484, 1, 1.8672, 0 } }, + { "OLYMPUS", "E-PL2", "3800K", 0, { 1.1719, 1, 1.8281, 0 } }, + { "OLYMPUS", "E-PL2", "3900K", 0, { 1.2031, 1, 1.7812, 0 } }, + { "OLYMPUS", "E-PL2", "4000K", 0, { 1.2187, 1, 1.7578, 0 } }, + { "OLYMPUS", "E-PL2", "4200K", 0, { 1.2578, 1, 1.6953, 0 } }, + { "OLYMPUS", "E-PL2", "4400K", 0, { 1.2969, 1, 1.6406, 0 } }, + { "OLYMPUS", "E-PL2", "4600K", 0, { 1.3359, 1, 1.5859, 0 } }, + { "OLYMPUS", "E-PL2", "4800K", 0, { 1.3750, 1, 1.5313, 0 } }, + { "OLYMPUS", "E-PL2", "5000K", 0, { 1.4062, 1, 1.4922, 0 } }, + { "OLYMPUS", "E-PL2", "5200K", 0, { 1.4375, 1, 1.4453, 0 } }, + { "OLYMPUS", "E-PL2", "5400K", 0, { 1.4766, 1, 1.4063, 0 } }, + { "OLYMPUS", "E-PL2", "5600K", 0, { 1.5313, 1, 1.3672, 0 } }, + { "OLYMPUS", "E-PL2", "5800K", 0, { 1.5703, 1, 1.3281, 0 } }, + { "OLYMPUS", "E-PL2", "6000K", 0, { 1.6172, 1, 1.2891, 0 } }, + { "OLYMPUS", "E-PL2", "6200K", 0, { 1.6328, 1, 1.2656, 0 } }, + { "OLYMPUS", "E-PL2", "6400K", 0, { 1.6484, 1, 1.2422, 0 } }, + { "OLYMPUS", "E-PL2", "6600K", 0, { 1.6719, 1, 1.2109, 0 } }, + { "OLYMPUS", "E-PL2", "6800K", 0, { 1.6875, 1, 1.1875, 0 } }, + { "OLYMPUS", "E-PL2", "7000K", 0, { 1.7031, 1, 1.1641, 0 } }, + { "OLYMPUS", "E-PL2", "7400K", 0, { 1.7344, 1, 1.1250, 0 } }, + { "OLYMPUS", "E-PL2", "7800K", 0, { 1.7578, 1, 1.0859, 0 } }, + { "OLYMPUS", "E-PL2", "8200K", 0, { 1.7812, 1, 1.0469, 0 } }, + { "OLYMPUS", "E-PL2", "8600K", 0, { 1.8047, 1, 1.0234, 0 } }, + { "OLYMPUS", "E-PL2", "9000K", 0, { 1.8346, 1.0079, 1, 0 } }, + { "OLYMPUS", "E-PL2", "9400K", 0, { 1.9032, 1.0323, 1, 0 } }, + { "OLYMPUS", "E-PL2", "9800K", 0, { 1.9669, 1.0579, 1, 0 } }, + { "OLYMPUS", "E-PL2", "10000K", 0, { 2.0084, 1.0756, 1, 0 } }, + { "OLYMPUS", "E-PL2", "11000K", 0, { 2.1504, 1.1327, 1, 0 } }, + { "OLYMPUS", "E-PL2", "12000K", 0, { 2.2870, 1.1852, 1, 0 } }, + { "OLYMPUS", "E-PL2", "13000K", 0, { 2.4272, 1.2427, 1, 0 } }, + { "OLYMPUS", "E-PL2", "14000K", 0, { 2.5556, 1.2929, 1, 0 } }, + + /* Firmware version 1.3 */ + /* -7/+7 fine tuning is -7/+7 in amber-blue and zero in green-magenta */ + { "OLYMPUS", "E-PL3", Daylight, -7, { 1.695313, 1, 1.656250, 0 } }, + { "OLYMPUS", "E-PL3", Daylight, 0, { 1.976562, 1, 1.453125, 0 } }, + { "OLYMPUS", "E-PL3", Daylight, 7, { 2.250000, 1, 1.242187, 0 } }, + { "OLYMPUS", "E-PL3", Shade, -7, { 2.046875, 1, 1.312500, 0 } }, + { "OLYMPUS", "E-PL3", Shade, 0, { 2.382812, 1, 1.156250, 0 } }, + { "OLYMPUS", "E-PL3", Shade, 7, { 2.732283, 1.007874, 1, 0 } }, + { "OLYMPUS", "E-PL3", Cloudy, -7, { 1.859375, 1, 1.515625, 0 } }, + { "OLYMPUS", "E-PL3", Cloudy, 0, { 2.164063, 1, 1.335938, 0 } }, + { "OLYMPUS", "E-PL3", Cloudy, 7, { 2.460937, 1, 1.148437, 0 } }, + { "OLYMPUS", "E-PL3", Tungsten, -7, { 1.007812, 1, 2.812500, 0 } }, + { "OLYMPUS", "E-PL3", Tungsten, 0, { 1.171875, 1, 2.468750, 0 } }, + { "OLYMPUS", "E-PL3", Tungsten, 7, { 1.335937, 1, 2.117187, 0 } }, + { "OLYMPUS", "E-PL3", Fluorescent, -7, { 1.679688, 1, 2.203125, 0 } }, + { "OLYMPUS", "E-PL3", Fluorescent, 0, { 1.953125, 1, 1.937500, 0 } }, + { "OLYMPUS", "E-PL3", Fluorescent, 7, { 2.226562, 1, 1.664062, 0 } }, + { "OLYMPUS", "E-PL3", Underwater, -7, { 1.812500, 1, 1.789062, 0 } }, + { "OLYMPUS", "E-PL3", Underwater, 0, { 2.390625, 1, 1.484375, 0 } }, + { "OLYMPUS", "E-PL3", Underwater, 7, { 2.429688, 1, 1.335937, 0 } }, + { "OLYMPUS", "E-PL3", Flash, -7, { 2.218750, 1, 1.421875, 0 } }, + { "OLYMPUS", "E-PL3", Flash, 0, { 2.585938, 1, 1.250000, 0 } }, + { "OLYMPUS", "E-PL3", Flash, 7, { 2.945313, 1, 1.070312, 0 } }, + { "OLYMPUS", "E-PL3", "2000K", 0, { 1, 1.882353, 6.897059, 0 } }, + { "OLYMPUS", "E-PL3", "2050K", 0, { 1, 1.684211, 5.986842, 0 } }, + { "OLYMPUS", "E-PL3", "2100K", 0, { 1, 1.560976, 5.402439, 0 } }, + { "OLYMPUS", "E-PL3", "2150K", 0, { 1, 1.454545, 4.909091, 0 } }, + { "OLYMPUS", "E-PL3", "2200K", 0, { 1, 1.347368, 4.421053, 0 } }, + { "OLYMPUS", "E-PL3", "2250K", 0, { 1, 1.267327, 4.049505, 0 } }, + { "OLYMPUS", "E-PL3", "2300K", 0, { 1, 1.207547, 3.754717, 0 } }, + { "OLYMPUS", "E-PL3", "2350K", 0, { 1, 1.153153, 3.504504, 0 } }, + { "OLYMPUS", "E-PL3", "2400K", 0, { 1, 1.094017, 3.239316, 0 } }, + { "OLYMPUS", "E-PL3", "2450K", 0, { 1, 1.057851, 3.057851, 0 } }, + { "OLYMPUS", "E-PL3", "2500K", 0, { 1, 1.015873, 2.873016, 0 } }, + { "OLYMPUS", "E-PL3", "2550K", 0, { 1.015625, 1, 2.757813, 0 } }, + { "OLYMPUS", "E-PL3", "2600K", 0, { 1.054687, 1, 2.695312, 0 } }, + { "OLYMPUS", "E-PL3", "2650K", 0, { 1.085938, 1, 2.632813, 0 } }, + { "OLYMPUS", "E-PL3", "2700K", 0, { 1.117187, 1, 2.570312, 0 } }, + { "OLYMPUS", "E-PL3", "2750K", 0, { 1.148438, 1, 2.515625, 0 } }, + { "OLYMPUS", "E-PL3", "2800K", 0, { 1.171875, 1, 2.468750, 0 } }, + { "OLYMPUS", "E-PL3", "2900K", 0, { 1.226562, 1, 2.367187, 0 } }, + { "OLYMPUS", "E-PL3", "3000K", 0, { 1.273437, 1, 2.273437, 0 } }, + { "OLYMPUS", "E-PL3", "3100K", 0, { 1.328125, 1, 2.179688, 0 } }, + { "OLYMPUS", "E-PL3", "3200K", 0, { 1.367188, 1, 2.093750, 0 } }, + { "OLYMPUS", "E-PL3", "3300K", 0, { 1.414062, 1, 2.015625, 0 } }, + { "OLYMPUS", "E-PL3", "3400K", 0, { 1.445312, 1, 1.968750, 0 } }, + { "OLYMPUS", "E-PL3", "3500K", 0, { 1.476563, 1, 1.914063, 0 } }, + { "OLYMPUS", "E-PL3", "3600K", 0, { 1.507812, 1, 1.867188, 0 } }, + { "OLYMPUS", "E-PL3", "3700K", 0, { 1.539062, 1, 1.828125, 0 } }, + { "OLYMPUS", "E-PL3", "3800K", 0, { 1.570312, 1, 1.789062, 0 } }, + { "OLYMPUS", "E-PL3", "3900K", 0, { 1.609375, 1, 1.750000, 0 } }, + { "OLYMPUS", "E-PL3", "4000K", 0, { 1.640625, 1, 1.734375, 0 } }, + { "OLYMPUS", "E-PL3", "4200K", 0, { 1.703125, 1, 1.695313, 0 } }, + { "OLYMPUS", "E-PL3", "4400K", 0, { 1.757812, 1, 1.648437, 0 } }, + { "OLYMPUS", "E-PL3", "4600K", 0, { 1.812500, 1, 1.601562, 0 } }, + { "OLYMPUS", "E-PL3", "4800K", 0, { 1.867188, 1, 1.554688, 0 } }, + { "OLYMPUS", "E-PL3", "5000K", 0, { 1.906250, 1, 1.515625, 0 } }, + { "OLYMPUS", "E-PL3", "5200K", 0, { 1.953125, 1, 1.476562, 0 } }, + { "OLYMPUS", "E-PL3", "5400K", 0, { 2.000000, 1, 1.437500, 0 } }, + { "OLYMPUS", "E-PL3", "5600K", 0, { 2.054688, 1, 1.406250, 0 } }, + { "OLYMPUS", "E-PL3", "5800K", 0, { 2.109375, 1, 1.375000, 0 } }, + { "OLYMPUS", "E-PL3", "6000K", 0, { 2.164063, 1, 1.335938, 0 } }, + { "OLYMPUS", "E-PL3", "6200K", 0, { 2.195313, 1, 1.312500, 0 } }, + { "OLYMPUS", "E-PL3", "6400K", 0, { 2.226562, 1, 1.289062, 0 } }, + { "OLYMPUS", "E-PL3", "6600K", 0, { 2.257812, 1, 1.257812, 0 } }, + { "OLYMPUS", "E-PL3", "6800K", 0, { 2.289063, 1, 1.234375, 0 } }, + { "OLYMPUS", "E-PL3", "7000K", 0, { 2.320313, 1, 1.210938, 0 } }, + { "OLYMPUS", "E-PL3", "7400K", 0, { 2.367187, 1, 1.171875, 0 } }, + { "OLYMPUS", "E-PL3", "7800K", 0, { 2.414062, 1, 1.132812, 0 } }, + { "OLYMPUS", "E-PL3", "8200K", 0, { 2.460937, 1, 1.093750, 0 } }, + { "OLYMPUS", "E-PL3", "8600K", 0, { 2.492188, 1, 1.070313, 0 } }, + { "OLYMPUS", "E-PL3", "9000K", 0, { 2.523438, 1, 1.039063, 0 } }, + { "OLYMPUS", "E-PL3", "9400K", 0, { 2.554687, 1, 1.015625, 0 } }, + { "OLYMPUS", "E-PL3", "9800K", 0, { 2.606299, 1.007874, 1, 0 } }, + { "OLYMPUS", "E-PL3", "10000K", 0, { 2.664000, 1.024000, 1, 0 } }, + { "OLYMPUS", "E-PL3", "11000K", 0, { 2.865546, 1.075630, 1, 0 } }, + { "OLYMPUS", "E-PL3", "12000K", 0, { 3.043860, 1.122807, 1, 0 } }, + { "OLYMPUS", "E-PL3", "13000K", 0, { 3.238532, 1.174312, 1, 0 } }, + { "OLYMPUS", "E-PL3", "14000K", 0, { 3.400000, 1.219048, 1, 0 } }, + + /* Firmware version 1.2 */ + /* -7/+7 fine tuning is -7/+7 in amber-blue and zero in green-magenta */ + { "OLYMPUS", "E-PL5", Daylight, -7, { 1.671875, 1, 2.164063, 0 } }, + { "OLYMPUS", "E-PL5", Daylight, 0, { 1.945313, 1, 1.898438, 0 } }, + { "OLYMPUS", "E-PL5", Daylight, 7, { 2.210938, 1, 1.625000, 0 } }, + { "OLYMPUS", "E-PL5", Shade, -7, { 1.953125, 1, 1.687500, 0 } }, + { "OLYMPUS", "E-PL5", Shade, 0, { 2.273438, 1, 1.484375, 0 } }, + { "OLYMPUS", "E-PL5", Shade, 7, { 2.585938, 1, 1.273438, 0 } }, + { "OLYMPUS", "E-PL5", Cloudy, -7, { 1.789063, 1, 1.945313, 0 } }, + { "OLYMPUS", "E-PL5", Cloudy, 0, { 2.085938, 1, 1.710938, 0 } }, + { "OLYMPUS", "E-PL5", Cloudy, 7, { 2.375000, 1, 1.468750, 0 } }, + { "OLYMPUS", "E-PL5", Tungsten, -7, { 1.023438, 1, 3.851563, 0 } }, + { "OLYMPUS", "E-PL5", Tungsten, 0, { 1.195313, 1, 3.382813, 0 } }, + { "OLYMPUS", "E-PL5", Tungsten, 7, { 1.359375, 1, 2.906250, 0 } }, + { "OLYMPUS", "E-PL5", Fluorescent, -7, { 1.625000, 1, 3.101563, 0 } }, + { "OLYMPUS", "E-PL5", Fluorescent, 0, { 1.890625, 1, 2.726563, 0 } }, + { "OLYMPUS", "E-PL5", Fluorescent, 7, { 2.148438, 1, 2.343750, 0 } }, + { "OLYMPUS", "E-PL5", Flash, -7, { 1.906250, 1, 1.835938, 0 } }, + { "OLYMPUS", "E-PL5", Flash, 0, { 2.218750, 1, 1.617188, 0 } }, + { "OLYMPUS", "E-PL5", Flash, 7, { 2.523438, 1, 1.390625, 0 } }, + { "OLYMPUS", "E-PL5", "2000K", 0, { 0.578125, 1, 5.343750, 0 } }, + { "OLYMPUS", "E-PL5", "2050K", 0, { 0.632813, 1, 5.164063, 0 } }, + { "OLYMPUS", "E-PL5", "2100K", 0, { 0.679688, 1, 5.015625, 0 } }, + { "OLYMPUS", "E-PL5", "2150K", 0, { 0.726563, 1, 4.867188, 0 } }, + { "OLYMPUS", "E-PL5", "2200K", 0, { 0.781250, 1, 4.710938, 0 } }, + { "OLYMPUS", "E-PL5", "2250K", 0, { 0.820313, 1, 4.578125, 0 } }, + { "OLYMPUS", "E-PL5", "2300K", 0, { 0.867188, 1, 4.437500, 0 } }, + { "OLYMPUS", "E-PL5", "2350K", 0, { 0.906250, 1, 4.312500, 0 } }, + { "OLYMPUS", "E-PL5", "2400K", 0, { 0.945313, 1, 4.187500, 0 } }, + { "OLYMPUS", "E-PL5", "2450K", 0, { 0.976563, 1, 4.078125, 0 } }, + { "OLYMPUS", "E-PL5", "2500K", 0, { 1.015625, 1, 3.968750, 0 } }, + { "OLYMPUS", "E-PL5", "2550K", 0, { 1.046875, 1, 3.859375, 0 } }, + { "OLYMPUS", "E-PL5", "2600K", 0, { 1.078125, 1, 3.750000, 0 } }, + { "OLYMPUS", "E-PL5", "2650K", 0, { 1.109375, 1, 3.656250, 0 } }, + { "OLYMPUS", "E-PL5", "2700K", 0, { 1.140625, 1, 3.554688, 0 } }, + { "OLYMPUS", "E-PL5", "2750K", 0, { 1.171875, 1, 3.460938, 0 } }, + { "OLYMPUS", "E-PL5", "2800K", 0, { 1.195313, 1, 3.382813, 0 } }, + { "OLYMPUS", "E-PL5", "2900K", 0, { 1.250000, 1, 3.210938, 0 } }, + { "OLYMPUS", "E-PL5", "3000K", 0, { 1.296875, 1, 3.054688, 0 } }, + { "OLYMPUS", "E-PL5", "3100K", 0, { 1.343750, 1, 2.906250, 0 } }, + { "OLYMPUS", "E-PL5", "3200K", 0, { 1.390625, 1, 2.765625, 0 } }, + { "OLYMPUS", "E-PL5", "3300K", 0, { 1.429688, 1, 2.640625, 0 } }, + { "OLYMPUS", "E-PL5", "3400K", 0, { 1.460938, 1, 2.562500, 0 } }, + { "OLYMPUS", "E-PL5", "3500K", 0, { 1.492188, 1, 2.484375, 0 } }, + { "OLYMPUS", "E-PL5", "3600K", 0, { 1.523438, 1, 2.414063, 0 } }, + { "OLYMPUS", "E-PL5", "3700K", 0, { 1.554688, 1, 2.359375, 0 } }, + { "OLYMPUS", "E-PL5", "3800K", 0, { 1.585938, 1, 2.304688, 0 } }, + { "OLYMPUS", "E-PL5", "3900K", 0, { 1.617188, 1, 2.250000, 0 } }, + { "OLYMPUS", "E-PL5", "4000K", 0, { 1.640625, 1, 2.242188, 0 } }, + { "OLYMPUS", "E-PL5", "4200K", 0, { 1.687500, 1, 2.226563, 0 } }, + { "OLYMPUS", "E-PL5", "4400K", 0, { 1.742188, 1, 2.179688, 0 } }, + { "OLYMPUS", "E-PL5", "4600K", 0, { 1.796875, 1, 2.101563, 0 } }, + { "OLYMPUS", "E-PL5", "4800K", 0, { 1.843750, 1, 2.031250, 0 } }, + { "OLYMPUS", "E-PL5", "5000K", 0, { 1.882813, 1, 1.984375, 0 } }, + { "OLYMPUS", "E-PL5", "5200K", 0, { 1.921875, 1, 1.929688, 0 } }, + { "OLYMPUS", "E-PL5", "5400K", 0, { 1.960938, 1, 1.875000, 0 } }, + { "OLYMPUS", "E-PL5", "5600K", 0, { 2.007813, 1, 1.820313, 0 } }, + { "OLYMPUS", "E-PL5", "5800K", 0, { 2.046875, 1, 1.765625, 0 } }, + { "OLYMPUS", "E-PL5", "6000K", 0, { 2.085938, 1, 1.710938, 0 } }, + { "OLYMPUS", "E-PL5", "6200K", 0, { 2.109375, 1, 1.679688, 0 } }, + { "OLYMPUS", "E-PL5", "6400K", 0, { 2.140625, 1, 1.648438, 0 } }, + { "OLYMPUS", "E-PL5", "6600K", 0, { 2.164063, 1, 1.609375, 0 } }, + { "OLYMPUS", "E-PL5", "6800K", 0, { 2.187500, 1, 1.585938, 0 } }, + { "OLYMPUS", "E-PL5", "7000K", 0, { 2.218750, 1, 1.546875, 0 } }, + { "OLYMPUS", "E-PL5", "7400K", 0, { 2.257813, 1, 1.500000, 0 } }, + { "OLYMPUS", "E-PL5", "7800K", 0, { 2.296875, 1, 1.453125, 0 } }, + { "OLYMPUS", "E-PL5", "8200K", 0, { 2.335938, 1, 1.406250, 0 } }, + { "OLYMPUS", "E-PL5", "8600K", 0, { 2.367188, 1, 1.375000, 0 } }, + { "OLYMPUS", "E-PL5", "9000K", 0, { 2.398438, 1, 1.335938, 0 } }, + { "OLYMPUS", "E-PL5", "9400K", 0, { 2.421875, 1, 1.304688, 0 } }, + { "OLYMPUS", "E-PL5", "9800K", 0, { 2.445313, 1, 1.273438, 0 } }, + { "OLYMPUS", "E-PL5", "10000K", 0, { 2.460938, 1, 1.257813, 0 } }, + { "OLYMPUS", "E-PL5", "11000K", 0, { 2.515625, 1, 1.195313, 0 } }, + { "OLYMPUS", "E-PL5", "12000K", 0, { 2.554688, 1, 1.148438, 0 } }, + { "OLYMPUS", "E-PL5", "13000K", 0, { 2.593750, 1, 1.093750, 0 } }, + { "OLYMPUS", "E-PL5", "14000K", 0, { 2.625000, 1, 1.062500, 0 } }, + + { "OLYMPUS", "E-PL7", Daylight, 0, { 1.890625, 1, 1.773438, 0 } }, + { "OLYMPUS", "E-PL7", Shade, 0, { 2.250000, 1, 1.359375, 0 } }, + { "OLYMPUS", "E-PL7", Cloudy, 0, { 2.046875, 1, 1.601563, 0 } }, + { "OLYMPUS", "E-PL7", Tungsten, 0, { 1.140625, 1, 3.585938, 0 } }, + { "OLYMPUS", "E-PL7", Fluorescent, 0, { 1.882813, 1, 2.671875, 0 } }, + { "OLYMPUS", "E-PL7", Underwater, 0, { 1.359375, 1, 2.632813, 0 } }, + { "OLYMPUS", "E-PL7", Flash, 0, { 2.218750, 1, 1.531250, 0 } }, + { "OLYMPUS", "E-PL7", "2700K", 0, { 1.093750, 1, 3.781250, 0 } }, + { "OLYMPUS", "E-PL7", "5000K", 0, { 1.828125, 1, 1.867188, 0 } }, + + /* Copied from OLYMPUS E-PL3 presets */ + /* -7/+7 fine tuning is -7/+7 in amber-blue and zero in green-magenta */ + { "OLYMPUS", "E-PM1", Daylight, -7, { 1.695313, 1, 1.656250, 0 } }, + { "OLYMPUS", "E-PM1", Daylight, 0, { 1.976562, 1, 1.453125, 0 } }, + { "OLYMPUS", "E-PM1", Daylight, 7, { 2.250000, 1, 1.242187, 0 } }, + { "OLYMPUS", "E-PM1", Shade, -7, { 2.046875, 1, 1.312500, 0 } }, + { "OLYMPUS", "E-PM1", Shade, 0, { 2.382812, 1, 1.156250, 0 } }, + { "OLYMPUS", "E-PM1", Shade, 7, { 2.732283, 1.007874, 1, 0 } }, + { "OLYMPUS", "E-PM1", Cloudy, -7, { 1.859375, 1, 1.515625, 0 } }, + { "OLYMPUS", "E-PM1", Cloudy, 0, { 2.164063, 1, 1.335938, 0 } }, + { "OLYMPUS", "E-PM1", Cloudy, 7, { 2.460937, 1, 1.148437, 0 } }, + { "OLYMPUS", "E-PM1", Tungsten, -7, { 1.007812, 1, 2.812500, 0 } }, + { "OLYMPUS", "E-PM1", Tungsten, 0, { 1.171875, 1, 2.468750, 0 } }, + { "OLYMPUS", "E-PM1", Tungsten, 7, { 1.335937, 1, 2.117187, 0 } }, + { "OLYMPUS", "E-PM1", Fluorescent, -7, { 1.679688, 1, 2.203125, 0 } }, + { "OLYMPUS", "E-PM1", Fluorescent, 0, { 1.953125, 1, 1.937500, 0 } }, + { "OLYMPUS", "E-PM1", Fluorescent, 7, { 2.226562, 1, 1.664062, 0 } }, + { "OLYMPUS", "E-PM1", Underwater, -7, { 1.812500, 1, 1.789062, 0 } }, + { "OLYMPUS", "E-PM1", Underwater, 0, { 2.390625, 1, 1.484375, 0 } }, + { "OLYMPUS", "E-PM1", Underwater, 7, { 2.429688, 1, 1.335937, 0 } }, + { "OLYMPUS", "E-PM1", Flash, -7, { 2.218750, 1, 1.421875, 0 } }, + { "OLYMPUS", "E-PM1", Flash, 0, { 2.585938, 1, 1.250000, 0 } }, + { "OLYMPUS", "E-PM1", Flash, 7, { 2.945313, 1, 1.070312, 0 } }, + { "OLYMPUS", "E-PM1", "2000K", 0, { 1, 1.882353, 6.897059, 0 } }, + { "OLYMPUS", "E-PM1", "2050K", 0, { 1, 1.684211, 5.986842, 0 } }, + { "OLYMPUS", "E-PM1", "2100K", 0, { 1, 1.560976, 5.402439, 0 } }, + { "OLYMPUS", "E-PM1", "2150K", 0, { 1, 1.454545, 4.909091, 0 } }, + { "OLYMPUS", "E-PM1", "2200K", 0, { 1, 1.347368, 4.421053, 0 } }, + { "OLYMPUS", "E-PM1", "2250K", 0, { 1, 1.267327, 4.049505, 0 } }, + { "OLYMPUS", "E-PM1", "2300K", 0, { 1, 1.207547, 3.754717, 0 } }, + { "OLYMPUS", "E-PM1", "2350K", 0, { 1, 1.153153, 3.504504, 0 } }, + { "OLYMPUS", "E-PM1", "2400K", 0, { 1, 1.094017, 3.239316, 0 } }, + { "OLYMPUS", "E-PM1", "2450K", 0, { 1, 1.057851, 3.057851, 0 } }, + { "OLYMPUS", "E-PM1", "2500K", 0, { 1, 1.015873, 2.873016, 0 } }, + { "OLYMPUS", "E-PM1", "2550K", 0, { 1.015625, 1, 2.757813, 0 } }, + { "OLYMPUS", "E-PM1", "2600K", 0, { 1.054687, 1, 2.695312, 0 } }, + { "OLYMPUS", "E-PM1", "2650K", 0, { 1.085938, 1, 2.632813, 0 } }, + { "OLYMPUS", "E-PM1", "2700K", 0, { 1.117187, 1, 2.570312, 0 } }, + { "OLYMPUS", "E-PM1", "2750K", 0, { 1.148438, 1, 2.515625, 0 } }, + { "OLYMPUS", "E-PM1", "2800K", 0, { 1.171875, 1, 2.468750, 0 } }, + { "OLYMPUS", "E-PM1", "2900K", 0, { 1.226562, 1, 2.367187, 0 } }, + { "OLYMPUS", "E-PM1", "3000K", 0, { 1.273437, 1, 2.273437, 0 } }, + { "OLYMPUS", "E-PM1", "3100K", 0, { 1.328125, 1, 2.179688, 0 } }, + { "OLYMPUS", "E-PM1", "3200K", 0, { 1.367188, 1, 2.093750, 0 } }, + { "OLYMPUS", "E-PM1", "3300K", 0, { 1.414062, 1, 2.015625, 0 } }, + { "OLYMPUS", "E-PM1", "3400K", 0, { 1.445312, 1, 1.968750, 0 } }, + { "OLYMPUS", "E-PM1", "3500K", 0, { 1.476563, 1, 1.914063, 0 } }, + { "OLYMPUS", "E-PM1", "3600K", 0, { 1.507812, 1, 1.867188, 0 } }, + { "OLYMPUS", "E-PM1", "3700K", 0, { 1.539062, 1, 1.828125, 0 } }, + { "OLYMPUS", "E-PM1", "3800K", 0, { 1.570312, 1, 1.789062, 0 } }, + { "OLYMPUS", "E-PM1", "3900K", 0, { 1.609375, 1, 1.750000, 0 } }, + { "OLYMPUS", "E-PM1", "4000K", 0, { 1.640625, 1, 1.734375, 0 } }, + { "OLYMPUS", "E-PM1", "4200K", 0, { 1.703125, 1, 1.695313, 0 } }, + { "OLYMPUS", "E-PM1", "4400K", 0, { 1.757812, 1, 1.648437, 0 } }, + { "OLYMPUS", "E-PM1", "4600K", 0, { 1.812500, 1, 1.601562, 0 } }, + { "OLYMPUS", "E-PM1", "4800K", 0, { 1.867188, 1, 1.554688, 0 } }, + { "OLYMPUS", "E-PM1", "5000K", 0, { 1.906250, 1, 1.515625, 0 } }, + { "OLYMPUS", "E-PM1", "5200K", 0, { 1.953125, 1, 1.476562, 0 } }, + { "OLYMPUS", "E-PM1", "5400K", 0, { 2.000000, 1, 1.437500, 0 } }, + { "OLYMPUS", "E-PM1", "5600K", 0, { 2.054688, 1, 1.406250, 0 } }, + { "OLYMPUS", "E-PM1", "5800K", 0, { 2.109375, 1, 1.375000, 0 } }, + { "OLYMPUS", "E-PM1", "6000K", 0, { 2.164063, 1, 1.335938, 0 } }, + { "OLYMPUS", "E-PM1", "6200K", 0, { 2.195313, 1, 1.312500, 0 } }, + { "OLYMPUS", "E-PM1", "6400K", 0, { 2.226562, 1, 1.289062, 0 } }, + { "OLYMPUS", "E-PM1", "6600K", 0, { 2.257812, 1, 1.257812, 0 } }, + { "OLYMPUS", "E-PM1", "6800K", 0, { 2.289063, 1, 1.234375, 0 } }, + { "OLYMPUS", "E-PM1", "7000K", 0, { 2.320313, 1, 1.210938, 0 } }, + { "OLYMPUS", "E-PM1", "7400K", 0, { 2.367187, 1, 1.171875, 0 } }, + { "OLYMPUS", "E-PM1", "7800K", 0, { 2.414062, 1, 1.132812, 0 } }, + { "OLYMPUS", "E-PM1", "8200K", 0, { 2.460937, 1, 1.093750, 0 } }, + { "OLYMPUS", "E-PM1", "8600K", 0, { 2.492188, 1, 1.070313, 0 } }, + { "OLYMPUS", "E-PM1", "9000K", 0, { 2.523438, 1, 1.039063, 0 } }, + { "OLYMPUS", "E-PM1", "9400K", 0, { 2.554687, 1, 1.015625, 0 } }, + { "OLYMPUS", "E-PM1", "9800K", 0, { 2.606299, 1.007874, 1, 0 } }, + { "OLYMPUS", "E-PM1", "10000K", 0, { 2.664000, 1.024000, 1, 0 } }, + { "OLYMPUS", "E-PM1", "11000K", 0, { 2.865546, 1.075630, 1, 0 } }, + { "OLYMPUS", "E-PM1", "12000K", 0, { 3.043860, 1.122807, 1, 0 } }, + { "OLYMPUS", "E-PM1", "13000K", 0, { 3.238532, 1.174312, 1, 0 } }, + { "OLYMPUS", "E-PM1", "14000K", 0, { 3.400000, 1.219048, 1, 0 } }, + + /* Copied from OLYMPUS E-PL5 presets */ + /* -7/+7 fine tuning is -7/+7 in amber-blue and zero in green-magenta */ + { "OLYMPUS", "E-PM2", Daylight, -7, { 1.671875, 1, 2.164063, 0 } }, + { "OLYMPUS", "E-PM2", Daylight, 0, { 1.945313, 1, 1.898438, 0 } }, + { "OLYMPUS", "E-PM2", Daylight, 7, { 2.210938, 1, 1.625000, 0 } }, + { "OLYMPUS", "E-PM2", Shade, -7, { 1.953125, 1, 1.687500, 0 } }, + { "OLYMPUS", "E-PM2", Shade, 0, { 2.273438, 1, 1.484375, 0 } }, + { "OLYMPUS", "E-PM2", Shade, 7, { 2.585938, 1, 1.273438, 0 } }, + { "OLYMPUS", "E-PM2", Cloudy, -7, { 1.789063, 1, 1.945313, 0 } }, + { "OLYMPUS", "E-PM2", Cloudy, 0, { 2.085938, 1, 1.710938, 0 } }, + { "OLYMPUS", "E-PM2", Cloudy, 7, { 2.375000, 1, 1.468750, 0 } }, + { "OLYMPUS", "E-PM2", Tungsten, -7, { 1.023438, 1, 3.851563, 0 } }, + { "OLYMPUS", "E-PM2", Tungsten, 0, { 1.195313, 1, 3.382813, 0 } }, + { "OLYMPUS", "E-PM2", Tungsten, 7, { 1.359375, 1, 2.906250, 0 } }, + { "OLYMPUS", "E-PM2", Fluorescent, -7, { 1.625000, 1, 3.101563, 0 } }, + { "OLYMPUS", "E-PM2", Fluorescent, 0, { 1.890625, 1, 2.726563, 0 } }, + { "OLYMPUS", "E-PM2", Fluorescent, 7, { 2.148438, 1, 2.343750, 0 } }, + { "OLYMPUS", "E-PM2", Flash, -7, { 1.906250, 1, 1.835938, 0 } }, + { "OLYMPUS", "E-PM2", Flash, 0, { 2.218750, 1, 1.617188, 0 } }, + { "OLYMPUS", "E-PM2", Flash, 7, { 2.523438, 1, 1.390625, 0 } }, + { "OLYMPUS", "E-PM2", "2000K", 0, { 0.578125, 1, 5.343750, 0 } }, + { "OLYMPUS", "E-PM2", "2050K", 0, { 0.632813, 1, 5.164063, 0 } }, + { "OLYMPUS", "E-PM2", "2100K", 0, { 0.679688, 1, 5.015625, 0 } }, + { "OLYMPUS", "E-PM2", "2150K", 0, { 0.726563, 1, 4.867188, 0 } }, + { "OLYMPUS", "E-PM2", "2200K", 0, { 0.781250, 1, 4.710938, 0 } }, + { "OLYMPUS", "E-PM2", "2250K", 0, { 0.820313, 1, 4.578125, 0 } }, + { "OLYMPUS", "E-PM2", "2300K", 0, { 0.867188, 1, 4.437500, 0 } }, + { "OLYMPUS", "E-PM2", "2350K", 0, { 0.906250, 1, 4.312500, 0 } }, + { "OLYMPUS", "E-PM2", "2400K", 0, { 0.945313, 1, 4.187500, 0 } }, + { "OLYMPUS", "E-PM2", "2450K", 0, { 0.976563, 1, 4.078125, 0 } }, + { "OLYMPUS", "E-PM2", "2500K", 0, { 1.015625, 1, 3.968750, 0 } }, + { "OLYMPUS", "E-PM2", "2550K", 0, { 1.046875, 1, 3.859375, 0 } }, + { "OLYMPUS", "E-PM2", "2600K", 0, { 1.078125, 1, 3.750000, 0 } }, + { "OLYMPUS", "E-PM2", "2650K", 0, { 1.109375, 1, 3.656250, 0 } }, + { "OLYMPUS", "E-PM2", "2700K", 0, { 1.140625, 1, 3.554688, 0 } }, + { "OLYMPUS", "E-PM2", "2750K", 0, { 1.171875, 1, 3.460938, 0 } }, + { "OLYMPUS", "E-PM2", "2800K", 0, { 1.195313, 1, 3.382813, 0 } }, + { "OLYMPUS", "E-PM2", "2900K", 0, { 1.250000, 1, 3.210938, 0 } }, + { "OLYMPUS", "E-PM2", "3000K", 0, { 1.296875, 1, 3.054688, 0 } }, + { "OLYMPUS", "E-PM2", "3100K", 0, { 1.343750, 1, 2.906250, 0 } }, + { "OLYMPUS", "E-PM2", "3200K", 0, { 1.390625, 1, 2.765625, 0 } }, + { "OLYMPUS", "E-PM2", "3300K", 0, { 1.429688, 1, 2.640625, 0 } }, + { "OLYMPUS", "E-PM2", "3400K", 0, { 1.460938, 1, 2.562500, 0 } }, + { "OLYMPUS", "E-PM2", "3500K", 0, { 1.492188, 1, 2.484375, 0 } }, + { "OLYMPUS", "E-PM2", "3600K", 0, { 1.523438, 1, 2.414063, 0 } }, + { "OLYMPUS", "E-PM2", "3700K", 0, { 1.554688, 1, 2.359375, 0 } }, + { "OLYMPUS", "E-PM2", "3800K", 0, { 1.585938, 1, 2.304688, 0 } }, + { "OLYMPUS", "E-PM2", "3900K", 0, { 1.617188, 1, 2.250000, 0 } }, + { "OLYMPUS", "E-PM2", "4000K", 0, { 1.640625, 1, 2.242188, 0 } }, + { "OLYMPUS", "E-PM2", "4200K", 0, { 1.687500, 1, 2.226563, 0 } }, + { "OLYMPUS", "E-PM2", "4400K", 0, { 1.742188, 1, 2.179688, 0 } }, + { "OLYMPUS", "E-PM2", "4600K", 0, { 1.796875, 1, 2.101563, 0 } }, + { "OLYMPUS", "E-PM2", "4800K", 0, { 1.843750, 1, 2.031250, 0 } }, + { "OLYMPUS", "E-PM2", "5000K", 0, { 1.882813, 1, 1.984375, 0 } }, + { "OLYMPUS", "E-PM2", "5200K", 0, { 1.921875, 1, 1.929688, 0 } }, + { "OLYMPUS", "E-PM2", "5400K", 0, { 1.960938, 1, 1.875000, 0 } }, + { "OLYMPUS", "E-PM2", "5600K", 0, { 2.007813, 1, 1.820313, 0 } }, + { "OLYMPUS", "E-PM2", "5800K", 0, { 2.046875, 1, 1.765625, 0 } }, + { "OLYMPUS", "E-PM2", "6000K", 0, { 2.085938, 1, 1.710938, 0 } }, + { "OLYMPUS", "E-PM2", "6200K", 0, { 2.109375, 1, 1.679688, 0 } }, + { "OLYMPUS", "E-PM2", "6400K", 0, { 2.140625, 1, 1.648438, 0 } }, + { "OLYMPUS", "E-PM2", "6600K", 0, { 2.164063, 1, 1.609375, 0 } }, + { "OLYMPUS", "E-PM2", "6800K", 0, { 2.187500, 1, 1.585938, 0 } }, + { "OLYMPUS", "E-PM2", "7000K", 0, { 2.218750, 1, 1.546875, 0 } }, + { "OLYMPUS", "E-PM2", "7400K", 0, { 2.257813, 1, 1.500000, 0 } }, + { "OLYMPUS", "E-PM2", "7800K", 0, { 2.296875, 1, 1.453125, 0 } }, + { "OLYMPUS", "E-PM2", "8200K", 0, { 2.335938, 1, 1.406250, 0 } }, + { "OLYMPUS", "E-PM2", "8600K", 0, { 2.367188, 1, 1.375000, 0 } }, + { "OLYMPUS", "E-PM2", "9000K", 0, { 2.398438, 1, 1.335938, 0 } }, + { "OLYMPUS", "E-PM2", "9400K", 0, { 2.421875, 1, 1.304688, 0 } }, + { "OLYMPUS", "E-PM2", "9800K", 0, { 2.445313, 1, 1.273438, 0 } }, + { "OLYMPUS", "E-PM2", "10000K", 0, { 2.460938, 1, 1.257813, 0 } }, + { "OLYMPUS", "E-PM2", "11000K", 0, { 2.515625, 1, 1.195313, 0 } }, + { "OLYMPUS", "E-PM2", "12000K", 0, { 2.554688, 1, 1.148438, 0 } }, + { "OLYMPUS", "E-PM2", "13000K", 0, { 2.593750, 1, 1.093750, 0 } }, + { "OLYMPUS", "E-PM2", "14000K", 0, { 2.625000, 1, 1.062500, 0 } }, + + { "OLYMPUS", "PEN-F", Daylight, 0, { 1.820312, 1, 1.804688, 0 } }, + { "OLYMPUS", "PEN-F", Shade, 0, { 2.132812, 1, 1.414062, 0 } }, + { "OLYMPUS", "PEN-F", Cloudy, 0, { 1.960938, 1, 1.617188, 0 } }, + { "OLYMPUS", "PEN-F", Tungsten, 0, { 1.156250, 1, 3.265625, 0 } }, + { "OLYMPUS", "PEN-F", CoolWhiteFluorescent, 0, { 1.765625, 1, 2.578125, 0 } }, + { "OLYMPUS", "PEN-F", Underwater, 0, { 1.789062, 1, 1.890625, 0 } }, + { "OLYMPUS", "PEN-F", Flash, 0, { 2.070312, 1, 1.539062, 0 } }, + + { "OLYMPUS", "SP500UZ", Daylight, -7, { 1.136719, 1, 2.359375, 0 } }, + { "OLYMPUS", "SP500UZ", Daylight, 0, { 1.960937, 1, 1.585937, 0 } }, + { "OLYMPUS", "SP500UZ", Daylight, 7, { 3.927660, 1.089362, 1, 0 } }, + { "OLYMPUS", "SP500UZ", Cloudy, -7, { 1.191406, 1, 2.210937, 0 } }, + { "OLYMPUS", "SP500UZ", Cloudy, 0, { 2.058594, 1, 1.484375, 0 } }, + { "OLYMPUS", "SP500UZ", Cloudy, 7, { 4.404545, 1.163636, 1, 0 } }, + { "OLYMPUS", "SP500UZ", EveningSun, -7, { 1.199219, 1, 2.214844, 0 } }, + { "OLYMPUS", "SP500UZ", EveningSun, 0, { 2.074219, 1, 1.488281, 0 } }, + { "OLYMPUS", "SP500UZ", EveningSun, 7, { 4.440909, 1.163636, 1, 0 } }, + { "OLYMPUS", "SP500UZ", Tungsten, -7, { 1, 1.590062, 6.490683, 0 } }, + { "OLYMPUS", "SP500UZ", Tungsten, 0, { 1.085937, 1, 2.742188, 0 } }, + { "OLYMPUS", "SP500UZ", Tungsten, 7, { 1.996094, 1, 1.589844, 0 } }, + { "OLYMPUS", "SP500UZ", Fluorescent, -7, { 1.324219, 1, 2.214844, 0 } }, + { "OLYMPUS", "SP500UZ", Fluorescent, 0, { 2.285156, 1, 1.488281, 0 } }, + { "OLYMPUS", "SP500UZ", Fluorescent, 7, { 4.890909, 1.163636, 1, 0 } }, + + { "OLYMPUS", "SP510UZ", Daylight, 0, { 1.656250, 1, 1.621094, 0 } }, + { "OLYMPUS", "SP510UZ", Cloudy, 0, { 1.789063, 1, 1.546875, 0 } }, + { "OLYMPUS", "SP510UZ", Incandescent, 0, { 1, 1.066667, 2.891667, 0 } }, + { "OLYMPUS", "SP510UZ", WhiteFluorescent, 0, { 1.929688, 1, 1.562500, 0 } }, + { "OLYMPUS", "SP510UZ", NeutralFluorescent, 0, { 1.644531, 1, 1.843750, 0 } }, + { "OLYMPUS", "SP510UZ", DaylightFluorescent, 0, { 1.628906, 1, 2.210938, 0 } }, + + /* Firmware version 1.002 */ + { "OLYMPUS", "TG-4", Daylight, 0, { 1.703125, 1, 1.695313, 0 } }, + { "OLYMPUS", "TG-4", Cloudy, 0, { 1.812500, 1, 1.562500, 0 } }, + { "OLYMPUS", "TG-4", Incandescent, 0, { 1.070313, 1, 2.765625, 0 } }, + { "OLYMPUS", "TG-4", Fluorescent, 0, { 1.601563, 1, 2.156250, 0 } }, + { "OLYMPUS", "TG-4", Underwater, 0, { 1.312500, 1, 2.257813, 0 } }, + + /* Firmware version 1.5 */ + /* -7/+7 fine tuning is -7/+7 in amber-blue and zero in green-magenta */ + { "OLYMPUS", "XZ-1", Daylight, -7, { 1.687500, 1, 2.054688, 0 } }, + { "OLYMPUS", "XZ-1", Daylight, 0, { 1.968750, 1, 1.804687, 0 } }, + { "OLYMPUS", "XZ-1", Daylight, 7, { 2.242187, 1, 1.546875, 0 } }, + { "OLYMPUS", "XZ-1", Shade, -7, { 2.000000, 1, 1.718750, 0 } }, + { "OLYMPUS", "XZ-1", Shade, 0, { 2.328125, 1, 1.507813, 0 } }, + { "OLYMPUS", "XZ-1", Shade, 7, { 2.648438, 1, 1.289062, 0 } }, + { "OLYMPUS", "XZ-1", Cloudy, -7, { 1.812500, 1, 1.898438, 0 } }, + { "OLYMPUS", "XZ-1", Cloudy, 0, { 2.109375, 1, 1.671875, 0 } }, + { "OLYMPUS", "XZ-1", Cloudy, 7, { 2.398438, 1, 1.437500, 0 } }, + { "OLYMPUS", "XZ-1", Incandescent, -7, { 1.031250, 1, 3.500000, 0 } }, + { "OLYMPUS", "XZ-1", Incandescent, 0, { 1.203125, 1, 3.070312, 0 } }, + { "OLYMPUS", "XZ-1", Incandescent, 7, { 1.367187, 1, 2.632813, 0 } }, + { "OLYMPUS", "XZ-1", Fluorescent, -7, { 1.640625, 1, 2.843750, 0 } }, + { "OLYMPUS", "XZ-1", Fluorescent, 0, { 1.914062, 1, 2.500000, 0 } }, + { "OLYMPUS", "XZ-1", Fluorescent, 7, { 2.179688, 1, 2.148437, 0 } }, + { "OLYMPUS", "XZ-1", Underwater, -7, { 1.468750, 1, 2.296875, 0 } }, + { "OLYMPUS", "XZ-1", Underwater, 0, { 1.710937, 1, 2.015625, 0 } }, + { "OLYMPUS", "XZ-1", Underwater, 7, { 1.937500, 1, 1.726563, 0 } }, + + // Firmware 1.001 + { "OLYMPUS", "XZ-10", Daylight, 0, { 1.910156, 1, 1.679688, 0 } }, + { "OLYMPUS", "XZ-10", Shade, 0, { 2.132813, 1, 1.343750, 0 } }, + { "OLYMPUS", "XZ-10", Cloudy, 0, { 1.980469, 1, 1.644531, 0 } }, + { "OLYMPUS", "XZ-10", Incandescent, 0, { 1.289063, 1, 2.878906, 0 } }, + { "OLYMPUS", "XZ-10", Fluorescent, 0, { 1.781250, 1, 2.414063, 0 } }, + { "OLYMPUS", "XZ-10", Flash, 0, { 2.289063, 1, 1.394531, 0 } }, + + { "Panasonic", "DMC-FZ8", Daylight, 0, { 1.904943, 1, 1.596958, 0 } }, + { "Panasonic", "DMC-FZ8", Cloudy, 0, { 2.060836, 1, 1.498099, 0 } }, + { "Panasonic", "DMC-FZ8", Shade, 0, { 2.258555, 1, 1.391635, 0 } }, + { "Panasonic", "DMC-FZ8", Incandescent, 0, { 1.247148, 1, 2.288973, 0 } }, + { "Panasonic", "DMC-FZ8", Flash, 0, { 2.072243, 1, 1.456274, 0 } }, + + { "Panasonic", "DMC-FZ18", Daylight, 0, { 1.783270, 1, 1.889734, 0 } }, + { "Panasonic", "DMC-FZ18", Cloudy, 0, { 1.946768, 1, 1.680608, 0 } }, + { "Panasonic", "DMC-FZ18", Shade, 0, { 2.117871, 1, 1.558935, 0 } }, + { "Panasonic", "DMC-FZ18", Incandescent, 0, { 1.140684, 1, 2.627376, 0 } }, + { "Panasonic", "DMC-FZ18", Flash, 0, { 1.882129, 1, 1.703422, 0 } }, + + { "Panasonic", "DMC-FZ28", Daylight, 0, { 1.684411, 1, 1.802281, 0 } }, + { "Panasonic", "DMC-FZ28", Cloudy, 0, { 1.825095, 1, 1.676806, 0 } }, + { "Panasonic", "DMC-FZ28", Shade, 0, { 1.996198, 1, 1.566540, 0 } }, + { "Panasonic", "DMC-FZ28", Incandescent, 0, { 1.117871, 1, 2.558935, 0 } }, + { "Panasonic", "DMC-FZ28", Flash, 0, { 1.939164, 1, 1.596958, 0 } }, + { "Panasonic", "DMC-FZ28", "3000K", 0, { 1.015209, 1, 2.771863, 0 } }, + { "Panasonic", "DMC-FZ28", "4000K", 0, { 1.277566, 1, 2.171103, 0 } }, + { "Panasonic", "DMC-FZ28", "5000K", 0, { 1.585551, 1, 1.889734, 0 } }, + { "Panasonic", "DMC-FZ28", "6000K", 0, { 1.764258, 1, 1.737642, 0 } }, + { "Panasonic", "DMC-FZ28", "7000K", 0, { 1.939164, 1, 1.596958, 0 } }, + { "Panasonic", "DMC-FZ28", "8000K", 0, { 2.049430, 1, 1.528517, 0 } }, + + { "Panasonic", "DMC-FZ30", Daylight, 0, { 1.757576, 1, 1.446970, 0 } }, + { "Panasonic", "DMC-FZ30", Cloudy, 0, { 1.943182, 1, 1.276515, 0 } }, + { "Panasonic", "DMC-FZ30", Incandescent, 0, { 1.098485, 1, 2.106061, 0 } }, + { "Panasonic", "DMC-FZ30", Flash, 0, { 1.965909, 1, 1.303030, 0 } }, + + { "Panasonic", "DMC-FZ50", Daylight, 0, { 2.095057, 1, 1.642586, 0 } }, + { "Panasonic", "DMC-FZ50", Cloudy, 0, { 2.319392, 1, 1.482890, 0 } }, + { "Panasonic", "DMC-FZ50", Shade, 0, { 2.463878, 1, 1.414449, 0 } }, + { "Panasonic", "DMC-FZ50", Incandescent, 0, { 1.365019, 1, 2.311787, 0 } }, + { "Panasonic", "DMC-FZ50", Flash, 0, { 2.338403, 1, 1.338403, 0 } }, + + /* Firmware version 1.0 */ + /* -9/+9 fine tuning is -9/+9 in blue-amber and zero in magenta-green */ + { "Panasonic", "DMC-FZ200", Daylight, -9, { 1.811321, 1, 2.049057, 0 } }, + { "Panasonic", "DMC-FZ200", Daylight, 0, { 2.015094, 1, 1.758491, 0 } }, + { "Panasonic", "DMC-FZ200", Daylight, 9, { 2.264151, 1, 1.550943, 0 } }, + { "Panasonic", "DMC-FZ200", Cloudy, -9, { 1.935849, 1, 1.890566, 0 } }, + { "Panasonic", "DMC-FZ200", Cloudy, 0, { 2.154717, 1, 1.622642, 0 } }, + { "Panasonic", "DMC-FZ200", Cloudy, 9, { 2.426415, 1, 1.433962, 0 } }, + { "Panasonic", "DMC-FZ200", Shade, -9, { 2.052830, 1, 1.773585, 0 } }, + { "Panasonic", "DMC-FZ200", Shade, 0, { 2.286792, 1, 1.524528, 0 } }, + { "Panasonic", "DMC-FZ200", Shade, 9, { 2.569811, 1, 1.343396, 0 } }, + { "Panasonic", "DMC-FZ200", Incandescent, -9, { 1.230189, 1, 3.143396, 0 } }, + { "Panasonic", "DMC-FZ200", Incandescent, 0, { 1.369811, 1, 2.701887, 0 } }, + { "Panasonic", "DMC-FZ200", Incandescent, 9, { 1.539623, 1, 2.384906, 0 } }, + { "Panasonic", "DMC-FZ200", Flash, -9, { 1.962264, 1, 1.932076, 0 } }, + { "Panasonic", "DMC-FZ200", Flash, 0, { 2.184906, 1, 1.660377, 0 } }, + { "Panasonic", "DMC-FZ200", Flash, 9, { 2.460377, 1, 1.464151, 0 } }, + { "Panasonic", "DMC-FZ200", "2500K", 0, { 1.158491, 1, 3.169811, 0 } }, + { "Panasonic", "DMC-FZ200", "2600K", 0, { 1.188679, 1, 3.094340, 0 } }, + { "Panasonic", "DMC-FZ200", "2700K", 0, { 1.226415, 1, 3.018868, 0 } }, + { "Panasonic", "DMC-FZ200", "2800K", 0, { 1.256604, 1, 2.943396, 0 } }, + { "Panasonic", "DMC-FZ200", "2900K", 0, { 1.294340, 1, 2.867925, 0 } }, + { "Panasonic", "DMC-FZ200", "3000K", 0, { 1.332075, 1, 2.784906, 0 } }, + { "Panasonic", "DMC-FZ200", "3100K", 0, { 1.362264, 1, 2.716981, 0 } }, + { "Panasonic", "DMC-FZ200", "3200K", 0, { 1.392453, 1, 2.641509, 0 } }, + { "Panasonic", "DMC-FZ200", "3300K", 0, { 1.422642, 1, 2.573585, 0 } }, + { "Panasonic", "DMC-FZ200", "3400K", 0, { 1.452830, 1, 2.498113, 0 } }, + { "Panasonic", "DMC-FZ200", "3500K", 0, { 1.490566, 1, 2.422642, 0 } }, + { "Panasonic", "DMC-FZ200", "3600K", 0, { 1.520755, 1, 2.362264, 0 } }, + { "Panasonic", "DMC-FZ200", "3700K", 0, { 1.558491, 1, 2.294340, 0 } }, + { "Panasonic", "DMC-FZ200", "3800K", 0, { 1.588679, 1, 2.233962, 0 } }, + { "Panasonic", "DMC-FZ200", "3900K", 0, { 1.626415, 1, 2.166038, 0 } }, + { "Panasonic", "DMC-FZ200", "4000K", 0, { 1.664151, 1, 2.098113, 0 } }, + { "Panasonic", "DMC-FZ200", "4100K", 0, { 1.686792, 1, 2.067925, 0 } }, + { "Panasonic", "DMC-FZ200", "4200K", 0, { 1.720755, 1, 2.030189, 0 } }, + { "Panasonic", "DMC-FZ200", "4300K", 0, { 1.750943, 1, 2.000000, 0 } }, + { "Panasonic", "DMC-FZ200", "4400K", 0, { 1.781132, 1, 1.962264, 0 } }, + { "Panasonic", "DMC-FZ200", "4500K", 0, { 1.811321, 1, 1.924528, 0 } }, + { "Panasonic", "DMC-FZ200", "4600K", 0, { 1.830189, 1, 1.909434, 0 } }, + { "Panasonic", "DMC-FZ200", "4700K", 0, { 1.852830, 1, 1.894340, 0 } }, + { "Panasonic", "DMC-FZ200", "4800K", 0, { 1.879245, 1, 1.879245, 0 } }, + { "Panasonic", "DMC-FZ200", "4900K", 0, { 1.905660, 1, 1.864151, 0 } }, + { "Panasonic", "DMC-FZ200", "5000K", 0, { 1.928302, 1, 1.841509, 0 } }, + { "Panasonic", "DMC-FZ200", "5100K", 0, { 1.939623, 1, 1.826415, 0 } }, + { "Panasonic", "DMC-FZ200", "5200K", 0, { 1.958491, 1, 1.811321, 0 } }, + { "Panasonic", "DMC-FZ200", "5300K", 0, { 1.977358, 1, 1.796226, 0 } }, + { "Panasonic", "DMC-FZ200", "5400K", 0, { 1.996226, 1, 1.781132, 0 } }, + { "Panasonic", "DMC-FZ200", "5500K", 0, { 2.015094, 1, 1.758491, 0 } }, + { "Panasonic", "DMC-FZ200", "5600K", 0, { 2.033962, 1, 1.743396, 0 } }, + { "Panasonic", "DMC-FZ200", "5700K", 0, { 2.052830, 1, 1.720755, 0 } }, + { "Panasonic", "DMC-FZ200", "5800K", 0, { 2.075472, 1, 1.698113, 0 } }, + { "Panasonic", "DMC-FZ200", "5900K", 0, { 2.094340, 1, 1.675472, 0 } }, + { "Panasonic", "DMC-FZ200", "6000K", 0, { 2.120755, 1, 1.652830, 0 } }, + { "Panasonic", "DMC-FZ200", "6100K", 0, { 2.132075, 1, 1.637736, 0 } }, + { "Panasonic", "DMC-FZ200", "6200K", 0, { 2.150943, 1, 1.622642, 0 } }, + { "Panasonic", "DMC-FZ200", "6300K", 0, { 2.169811, 1, 1.607547, 0 } }, + { "Panasonic", "DMC-FZ200", "6400K", 0, { 2.184906, 1, 1.592453, 0 } }, + { "Panasonic", "DMC-FZ200", "6500K", 0, { 2.203774, 1, 1.577358, 0 } }, + { "Panasonic", "DMC-FZ200", "6600K", 0, { 2.211321, 1, 1.569811, 0 } }, + { "Panasonic", "DMC-FZ200", "6700K", 0, { 2.218868, 1, 1.562264, 0 } }, + { "Panasonic", "DMC-FZ200", "6800K", 0, { 2.230189, 1, 1.554717, 0 } }, + { "Panasonic", "DMC-FZ200", "6900K", 0, { 2.237736, 1, 1.547170, 0 } }, + { "Panasonic", "DMC-FZ200", "7000K", 0, { 2.249057, 1, 1.532075, 0 } }, + { "Panasonic", "DMC-FZ200", "7100K", 0, { 2.260377, 1, 1.524528, 0 } }, + { "Panasonic", "DMC-FZ200", "7200K", 0, { 2.279245, 1, 1.516981, 0 } }, + { "Panasonic", "DMC-FZ200", "7300K", 0, { 2.290566, 1, 1.501887, 0 } }, + { "Panasonic", "DMC-FZ200", "7400K", 0, { 2.309434, 1, 1.494340, 0 } }, + { "Panasonic", "DMC-FZ200", "7500K", 0, { 2.328302, 1, 1.479245, 0 } }, + { "Panasonic", "DMC-FZ200", "7600K", 0, { 2.343396, 1, 1.471698, 0 } }, + { "Panasonic", "DMC-FZ200", "7700K", 0, { 2.354717, 1, 1.464151, 0 } }, + { "Panasonic", "DMC-FZ200", "7800K", 0, { 2.366038, 1, 1.456604, 0 } }, + { "Panasonic", "DMC-FZ200", "7900K", 0, { 2.377358, 1, 1.449057, 0 } }, + { "Panasonic", "DMC-FZ200", "8000K", 0, { 2.388679, 1, 1.441509, 0 } }, + { "Panasonic", "DMC-FZ200", "8100K", 0, { 2.396226, 1, 1.441509, 0 } }, + { "Panasonic", "DMC-FZ200", "8200K", 0, { 2.407547, 1, 1.433962, 0 } }, + { "Panasonic", "DMC-FZ200", "8300K", 0, { 2.415094, 1, 1.433962, 0 } }, + { "Panasonic", "DMC-FZ200", "8400K", 0, { 2.426415, 1, 1.426415, 0 } }, + { "Panasonic", "DMC-FZ200", "8500K", 0, { 2.437736, 1, 1.418868, 0 } }, + { "Panasonic", "DMC-FZ200", "8600K", 0, { 2.445283, 1, 1.418868, 0 } }, + { "Panasonic", "DMC-FZ200", "8700K", 0, { 2.452830, 1, 1.411321, 0 } }, + { "Panasonic", "DMC-FZ200", "8800K", 0, { 2.464151, 1, 1.411321, 0 } }, + { "Panasonic", "DMC-FZ200", "8900K", 0, { 2.471698, 1, 1.403774, 0 } }, + { "Panasonic", "DMC-FZ200", "9000K", 0, { 2.483019, 1, 1.396226, 0 } }, + { "Panasonic", "DMC-FZ200", "9100K", 0, { 2.486792, 1, 1.396226, 0 } }, + { "Panasonic", "DMC-FZ200", "9200K", 0, { 2.494340, 1, 1.396226, 0 } }, + { "Panasonic", "DMC-FZ200", "9300K", 0, { 2.501887, 1, 1.388679, 0 } }, + { "Panasonic", "DMC-FZ200", "9400K", 0, { 2.505660, 1, 1.388679, 0 } }, + { "Panasonic", "DMC-FZ200", "9500K", 0, { 2.520755, 1, 1.381132, 0 } }, + { "Panasonic", "DMC-FZ200", "9600K", 0, { 2.524528, 1, 1.381132, 0 } }, + { "Panasonic", "DMC-FZ200", "9700K", 0, { 2.532075, 1, 1.381132, 0 } }, + { "Panasonic", "DMC-FZ200", "9800K", 0, { 2.543396, 1, 1.373585, 0 } }, + { "Panasonic", "DMC-FZ200", "9900K", 0, { 2.550943, 1, 1.373585, 0 } }, + { "Panasonic", "DMC-FZ200", "10000K", 0, { 2.562264, 1, 1.366038, 0 } }, + + /* Firmware version 2.2 */ + /* -9/+9 fine tuning is -9/+9 in blue-amber and zero in magenta-green */ + { "Panasonic", "DMC-FZ300", Daylight, -9, { 1.800781, 1, 2.355469, 0 } }, + { "Panasonic", "DMC-FZ300", Daylight, 0, { 2.046875, 1, 1.972656, 0 } }, + { "Panasonic", "DMC-FZ300", Daylight, 9, { 2.382813, 1, 1.742188, 0 } }, + { "Panasonic", "DMC-FZ300", Cloudy, -9, { 1.937500, 1, 2.179688, 0 } }, + { "Panasonic", "DMC-FZ300", Cloudy, 0, { 2.203125, 1, 1.824219, 0 } }, + { "Panasonic", "DMC-FZ300", Cloudy, 9, { 2.566406, 1, 1.609375, 0 } }, + { "Panasonic", "DMC-FZ300", Shade, -9, { 2.042969, 1, 2.066406, 0 } }, + { "Panasonic", "DMC-FZ300", Shade, 0, { 2.324219, 1, 1.730469, 0 } }, + { "Panasonic", "DMC-FZ300", Shade, 9, { 2.703125, 1, 1.527344, 0 } }, + { "Panasonic", "DMC-FZ300", Incandescent, -9, { 1.250000, 1, 3.355469, 0 } }, + { "Panasonic", "DMC-FZ300", Incandescent, 0, { 1.425781, 1, 2.808594, 0 } }, + { "Panasonic", "DMC-FZ300", Incandescent, 9, { 1.656250, 1, 2.476563, 0 } }, + { "Panasonic", "DMC-FZ300", Flash, -9, { 1.937500, 1, 2.246094, 0 } }, + { "Panasonic", "DMC-FZ300", Flash, 0, { 2.203125, 1, 1.878906, 0 } }, + { "Panasonic", "DMC-FZ300", Flash, 9, { 2.566406, 1, 1.656250, 0 } }, + { "Panasonic", "DMC-FZ300", "2500K", 0, { 1.234375, 1, 3.289063, 0 } }, + { "Panasonic", "DMC-FZ300", "2600K", 0, { 1.269531, 1, 3.214844, 0 } }, + { "Panasonic", "DMC-FZ300", "2700K", 0, { 1.300781, 1, 3.140625, 0 } }, + { "Panasonic", "DMC-FZ300", "2800K", 0, { 1.335938, 1, 3.066406, 0 } }, + { "Panasonic", "DMC-FZ300", "2900K", 0, { 1.371094, 1, 2.980469, 0 } }, + { "Panasonic", "DMC-FZ300", "3000K", 0, { 1.410156, 1, 2.890625, 0 } }, + { "Panasonic", "DMC-FZ300", "3100K", 0, { 1.453125, 1, 2.785156, 0 } }, + { "Panasonic", "DMC-FZ300", "3200K", 0, { 1.500000, 1, 2.679688, 0 } }, + { "Panasonic", "DMC-FZ300", "3300K", 0, { 1.542969, 1, 2.574219, 0 } }, + { "Panasonic", "DMC-FZ300", "3400K", 0, { 1.589844, 1, 2.472656, 0 } }, + { "Panasonic", "DMC-FZ300", "3500K", 0, { 1.617188, 1, 2.441406, 0 } }, + { "Panasonic", "DMC-FZ300", "3600K", 0, { 1.644531, 1, 2.410156, 0 } }, + { "Panasonic", "DMC-FZ300", "3700K", 0, { 1.667969, 1, 2.382813, 0 } }, + { "Panasonic", "DMC-FZ300", "3800K", 0, { 1.691406, 1, 2.355469, 0 } }, + { "Panasonic", "DMC-FZ300", "3900K", 0, { 1.714844, 1, 2.328125, 0 } }, + { "Panasonic", "DMC-FZ300", "4000K", 0, { 1.734375, 1, 2.300781, 0 } }, + { "Panasonic", "DMC-FZ300", "4100K", 0, { 1.753906, 1, 2.281250, 0 } }, + { "Panasonic", "DMC-FZ300", "4200K", 0, { 1.773438, 1, 2.257813, 0 } }, + { "Panasonic", "DMC-FZ300", "4300K", 0, { 1.792969, 1, 2.238281, 0 } }, + { "Panasonic", "DMC-FZ300", "4400K", 0, { 1.812500, 1, 2.214844, 0 } }, + { "Panasonic", "DMC-FZ300", "4500K", 0, { 1.832031, 1, 2.191406, 0 } }, + { "Panasonic", "DMC-FZ300", "4600K", 0, { 1.843750, 1, 2.175781, 0 } }, + { "Panasonic", "DMC-FZ300", "4700K", 0, { 1.859375, 1, 2.160156, 0 } }, + { "Panasonic", "DMC-FZ300", "4800K", 0, { 1.875000, 1, 2.144531, 0 } }, + { "Panasonic", "DMC-FZ300", "4900K", 0, { 1.890625, 1, 2.125000, 0 } }, + { "Panasonic", "DMC-FZ300", "5000K", 0, { 1.906250, 1, 2.109375, 0 } }, + { "Panasonic", "DMC-FZ300", "5100K", 0, { 1.933594, 1, 2.082031, 0 } }, + { "Panasonic", "DMC-FZ300", "5200K", 0, { 1.960938, 1, 2.054688, 0 } }, + { "Panasonic", "DMC-FZ300", "5300K", 0, { 1.988281, 1, 2.027344, 0 } }, + { "Panasonic", "DMC-FZ300", "5400K", 0, { 2.019531, 1, 2.000000, 0 } }, + { "Panasonic", "DMC-FZ300", "5500K", 0, { 2.046875, 1, 1.972656, 0 } }, + { "Panasonic", "DMC-FZ300", "5600K", 0, { 2.066406, 1, 1.953125, 0 } }, + { "Panasonic", "DMC-FZ300", "5700K", 0, { 2.089844, 1, 1.933594, 0 } }, + { "Panasonic", "DMC-FZ300", "5800K", 0, { 2.109375, 1, 1.914063, 0 } }, + { "Panasonic", "DMC-FZ300", "5900K", 0, { 2.128906, 1, 1.894531, 0 } }, + { "Panasonic", "DMC-FZ300", "6000K", 0, { 2.152344, 1, 1.875000, 0 } }, + { "Panasonic", "DMC-FZ300", "6100K", 0, { 2.167969, 1, 1.859375, 0 } }, + { "Panasonic", "DMC-FZ300", "6200K", 0, { 2.187500, 1, 1.843750, 0 } }, + { "Panasonic", "DMC-FZ300", "6300K", 0, { 2.203125, 1, 1.824219, 0 } }, + { "Panasonic", "DMC-FZ300", "6400K", 0, { 2.218750, 1, 1.816406, 0 } }, + { "Panasonic", "DMC-FZ300", "6500K", 0, { 2.230469, 1, 1.804688, 0 } }, + { "Panasonic", "DMC-FZ300", "6600K", 0, { 2.242188, 1, 1.792969, 0 } }, + { "Panasonic", "DMC-FZ300", "6700K", 0, { 2.253906, 1, 1.785156, 0 } }, + { "Panasonic", "DMC-FZ300", "6800K", 0, { 2.265625, 1, 1.777344, 0 } }, + { "Panasonic", "DMC-FZ300", "6900K", 0, { 2.277344, 1, 1.765625, 0 } }, + { "Panasonic", "DMC-FZ300", "7000K", 0, { 2.292969, 1, 1.753906, 0 } }, + { "Panasonic", "DMC-FZ300", "7100K", 0, { 2.300781, 1, 1.746094, 0 } }, + { "Panasonic", "DMC-FZ300", "7200K", 0, { 2.312500, 1, 1.738281, 0 } }, + { "Panasonic", "DMC-FZ300", "7300K", 0, { 2.324219, 1, 1.730469, 0 } }, + { "Panasonic", "DMC-FZ300", "7400K", 0, { 2.335938, 1, 1.718750, 0 } }, + { "Panasonic", "DMC-FZ300", "7500K", 0, { 2.347656, 1, 1.707031, 0 } }, + { "Panasonic", "DMC-FZ300", "7600K", 0, { 2.359375, 1, 1.699219, 0 } }, + { "Panasonic", "DMC-FZ300", "7700K", 0, { 2.371094, 1, 1.691406, 0 } }, + { "Panasonic", "DMC-FZ300", "7800K", 0, { 2.382813, 1, 1.679688, 0 } }, + { "Panasonic", "DMC-FZ300", "7900K", 0, { 2.394531, 1, 1.671875, 0 } }, + { "Panasonic", "DMC-FZ300", "8000K", 0, { 2.410156, 1, 1.660156, 0 } }, + { "Panasonic", "DMC-FZ300", "8100K", 0, { 2.417969, 1, 1.652344, 0 } }, + { "Panasonic", "DMC-FZ300", "8200K", 0, { 2.429688, 1, 1.644531, 0 } }, + { "Panasonic", "DMC-FZ300", "8300K", 0, { 2.441406, 1, 1.636719, 0 } }, + { "Panasonic", "DMC-FZ300", "8400K", 0, { 2.453125, 1, 1.628906, 0 } }, + { "Panasonic", "DMC-FZ300", "8500K", 0, { 2.464844, 1, 1.617188, 0 } }, + { "Panasonic", "DMC-FZ300", "8600K", 0, { 2.472656, 1, 1.609375, 0 } }, + { "Panasonic", "DMC-FZ300", "8700K", 0, { 2.480469, 1, 1.601563, 0 } }, + { "Panasonic", "DMC-FZ300", "8800K", 0, { 2.492188, 1, 1.593750, 0 } }, + { "Panasonic", "DMC-FZ300", "8900K", 0, { 2.500000, 1, 1.585938, 0 } }, + { "Panasonic", "DMC-FZ300", "9000K", 0, { 2.511719, 1, 1.578125, 0 } }, + { "Panasonic", "DMC-FZ300", "9100K", 0, { 2.519531, 1, 1.574219, 0 } }, + { "Panasonic", "DMC-FZ300", "9200K", 0, { 2.527344, 1, 1.566406, 0 } }, + { "Panasonic", "DMC-FZ300", "9300K", 0, { 2.535156, 1, 1.558594, 0 } }, + { "Panasonic", "DMC-FZ300", "9400K", 0, { 2.542969, 1, 1.554688, 0 } }, + { "Panasonic", "DMC-FZ300", "9500K", 0, { 2.550781, 1, 1.546875, 0 } }, + { "Panasonic", "DMC-FZ300", "9600K", 0, { 2.558594, 1, 1.542969, 0 } }, + { "Panasonic", "DMC-FZ300", "9700K", 0, { 2.566406, 1, 1.535156, 0 } }, + { "Panasonic", "DMC-FZ300", "9800K", 0, { 2.574219, 1, 1.531250, 0 } }, + { "Panasonic", "DMC-FZ300", "9900K", 0, { 2.582031, 1, 1.523438, 0 } }, + { "Panasonic", "DMC-FZ300", "10000K", 0, { 2.589844, 1, 1.515625, 0 } }, + + /* Firmware version 2.2 */ + /* -9/+9 fine tuning is -9/+9 in blue-amber and zero in magenta-green */ + { "Panasonic", "DMC-FZ330", Daylight, -9, { 1.800781, 1, 2.355469, 0 } }, + { "Panasonic", "DMC-FZ330", Daylight, 0, { 2.046875, 1, 1.972656, 0 } }, + { "Panasonic", "DMC-FZ330", Daylight, 9, { 2.382813, 1, 1.742188, 0 } }, + { "Panasonic", "DMC-FZ330", Cloudy, -9, { 1.937500, 1, 2.179688, 0 } }, + { "Panasonic", "DMC-FZ330", Cloudy, 0, { 2.203125, 1, 1.824219, 0 } }, + { "Panasonic", "DMC-FZ330", Cloudy, 9, { 2.566406, 1, 1.609375, 0 } }, + { "Panasonic", "DMC-FZ330", Shade, -9, { 2.042969, 1, 2.066406, 0 } }, + { "Panasonic", "DMC-FZ330", Shade, 0, { 2.324219, 1, 1.730469, 0 } }, + { "Panasonic", "DMC-FZ330", Shade, 9, { 2.703125, 1, 1.527344, 0 } }, + { "Panasonic", "DMC-FZ330", Incandescent, -9, { 1.250000, 1, 3.355469, 0 } }, + { "Panasonic", "DMC-FZ330", Incandescent, 0, { 1.425781, 1, 2.808594, 0 } }, + { "Panasonic", "DMC-FZ330", Incandescent, 9, { 1.656250, 1, 2.476563, 0 } }, + { "Panasonic", "DMC-FZ330", Flash, -9, { 1.937500, 1, 2.246094, 0 } }, + { "Panasonic", "DMC-FZ330", Flash, 0, { 2.203125, 1, 1.878906, 0 } }, + { "Panasonic", "DMC-FZ330", Flash, 9, { 2.566406, 1, 1.656250, 0 } }, + { "Panasonic", "DMC-FZ330", "2500K", 0, { 1.234375, 1, 3.289063, 0 } }, + { "Panasonic", "DMC-FZ330", "2600K", 0, { 1.269531, 1, 3.214844, 0 } }, + { "Panasonic", "DMC-FZ330", "2700K", 0, { 1.300781, 1, 3.140625, 0 } }, + { "Panasonic", "DMC-FZ330", "2800K", 0, { 1.335938, 1, 3.066406, 0 } }, + { "Panasonic", "DMC-FZ330", "2900K", 0, { 1.371094, 1, 2.980469, 0 } }, + { "Panasonic", "DMC-FZ330", "3000K", 0, { 1.410156, 1, 2.890625, 0 } }, + { "Panasonic", "DMC-FZ330", "3100K", 0, { 1.453125, 1, 2.785156, 0 } }, + { "Panasonic", "DMC-FZ330", "3200K", 0, { 1.500000, 1, 2.679688, 0 } }, + { "Panasonic", "DMC-FZ330", "3300K", 0, { 1.542969, 1, 2.574219, 0 } }, + { "Panasonic", "DMC-FZ330", "3400K", 0, { 1.589844, 1, 2.472656, 0 } }, + { "Panasonic", "DMC-FZ330", "3500K", 0, { 1.617188, 1, 2.441406, 0 } }, + { "Panasonic", "DMC-FZ330", "3600K", 0, { 1.644531, 1, 2.410156, 0 } }, + { "Panasonic", "DMC-FZ330", "3700K", 0, { 1.667969, 1, 2.382813, 0 } }, + { "Panasonic", "DMC-FZ330", "3800K", 0, { 1.691406, 1, 2.355469, 0 } }, + { "Panasonic", "DMC-FZ330", "3900K", 0, { 1.714844, 1, 2.328125, 0 } }, + { "Panasonic", "DMC-FZ330", "4000K", 0, { 1.734375, 1, 2.300781, 0 } }, + { "Panasonic", "DMC-FZ330", "4100K", 0, { 1.753906, 1, 2.281250, 0 } }, + { "Panasonic", "DMC-FZ330", "4200K", 0, { 1.773438, 1, 2.257813, 0 } }, + { "Panasonic", "DMC-FZ330", "4300K", 0, { 1.792969, 1, 2.238281, 0 } }, + { "Panasonic", "DMC-FZ330", "4400K", 0, { 1.812500, 1, 2.214844, 0 } }, + { "Panasonic", "DMC-FZ330", "4500K", 0, { 1.832031, 1, 2.191406, 0 } }, + { "Panasonic", "DMC-FZ330", "4600K", 0, { 1.843750, 1, 2.175781, 0 } }, + { "Panasonic", "DMC-FZ330", "4700K", 0, { 1.859375, 1, 2.160156, 0 } }, + { "Panasonic", "DMC-FZ330", "4800K", 0, { 1.875000, 1, 2.144531, 0 } }, + { "Panasonic", "DMC-FZ330", "4900K", 0, { 1.890625, 1, 2.125000, 0 } }, + { "Panasonic", "DMC-FZ330", "5000K", 0, { 1.906250, 1, 2.109375, 0 } }, + { "Panasonic", "DMC-FZ330", "5100K", 0, { 1.933594, 1, 2.082031, 0 } }, + { "Panasonic", "DMC-FZ330", "5200K", 0, { 1.960938, 1, 2.054688, 0 } }, + { "Panasonic", "DMC-FZ330", "5300K", 0, { 1.988281, 1, 2.027344, 0 } }, + { "Panasonic", "DMC-FZ330", "5400K", 0, { 2.019531, 1, 2.000000, 0 } }, + { "Panasonic", "DMC-FZ330", "5500K", 0, { 2.046875, 1, 1.972656, 0 } }, + { "Panasonic", "DMC-FZ330", "5600K", 0, { 2.066406, 1, 1.953125, 0 } }, + { "Panasonic", "DMC-FZ330", "5700K", 0, { 2.089844, 1, 1.933594, 0 } }, + { "Panasonic", "DMC-FZ330", "5800K", 0, { 2.109375, 1, 1.914063, 0 } }, + { "Panasonic", "DMC-FZ330", "5900K", 0, { 2.128906, 1, 1.894531, 0 } }, + { "Panasonic", "DMC-FZ330", "6000K", 0, { 2.152344, 1, 1.875000, 0 } }, + { "Panasonic", "DMC-FZ330", "6100K", 0, { 2.167969, 1, 1.859375, 0 } }, + { "Panasonic", "DMC-FZ330", "6200K", 0, { 2.187500, 1, 1.843750, 0 } }, + { "Panasonic", "DMC-FZ330", "6300K", 0, { 2.203125, 1, 1.824219, 0 } }, + { "Panasonic", "DMC-FZ330", "6400K", 0, { 2.218750, 1, 1.816406, 0 } }, + { "Panasonic", "DMC-FZ330", "6500K", 0, { 2.230469, 1, 1.804688, 0 } }, + { "Panasonic", "DMC-FZ330", "6600K", 0, { 2.242188, 1, 1.792969, 0 } }, + { "Panasonic", "DMC-FZ330", "6700K", 0, { 2.253906, 1, 1.785156, 0 } }, + { "Panasonic", "DMC-FZ330", "6800K", 0, { 2.265625, 1, 1.777344, 0 } }, + { "Panasonic", "DMC-FZ330", "6900K", 0, { 2.277344, 1, 1.765625, 0 } }, + { "Panasonic", "DMC-FZ330", "7000K", 0, { 2.292969, 1, 1.753906, 0 } }, + { "Panasonic", "DMC-FZ330", "7100K", 0, { 2.300781, 1, 1.746094, 0 } }, + { "Panasonic", "DMC-FZ330", "7200K", 0, { 2.312500, 1, 1.738281, 0 } }, + { "Panasonic", "DMC-FZ330", "7300K", 0, { 2.324219, 1, 1.730469, 0 } }, + { "Panasonic", "DMC-FZ330", "7400K", 0, { 2.335938, 1, 1.718750, 0 } }, + { "Panasonic", "DMC-FZ330", "7500K", 0, { 2.347656, 1, 1.707031, 0 } }, + { "Panasonic", "DMC-FZ330", "7600K", 0, { 2.359375, 1, 1.699219, 0 } }, + { "Panasonic", "DMC-FZ330", "7700K", 0, { 2.371094, 1, 1.691406, 0 } }, + { "Panasonic", "DMC-FZ330", "7800K", 0, { 2.382813, 1, 1.679688, 0 } }, + { "Panasonic", "DMC-FZ330", "7900K", 0, { 2.394531, 1, 1.671875, 0 } }, + { "Panasonic", "DMC-FZ330", "8000K", 0, { 2.410156, 1, 1.660156, 0 } }, + { "Panasonic", "DMC-FZ330", "8100K", 0, { 2.417969, 1, 1.652344, 0 } }, + { "Panasonic", "DMC-FZ330", "8200K", 0, { 2.429688, 1, 1.644531, 0 } }, + { "Panasonic", "DMC-FZ330", "8300K", 0, { 2.441406, 1, 1.636719, 0 } }, + { "Panasonic", "DMC-FZ330", "8400K", 0, { 2.453125, 1, 1.628906, 0 } }, + { "Panasonic", "DMC-FZ330", "8500K", 0, { 2.464844, 1, 1.617188, 0 } }, + { "Panasonic", "DMC-FZ330", "8600K", 0, { 2.472656, 1, 1.609375, 0 } }, + { "Panasonic", "DMC-FZ330", "8700K", 0, { 2.480469, 1, 1.601563, 0 } }, + { "Panasonic", "DMC-FZ330", "8800K", 0, { 2.492188, 1, 1.593750, 0 } }, + { "Panasonic", "DMC-FZ330", "8900K", 0, { 2.500000, 1, 1.585938, 0 } }, + { "Panasonic", "DMC-FZ330", "9000K", 0, { 2.511719, 1, 1.578125, 0 } }, + { "Panasonic", "DMC-FZ330", "9100K", 0, { 2.519531, 1, 1.574219, 0 } }, + { "Panasonic", "DMC-FZ330", "9200K", 0, { 2.527344, 1, 1.566406, 0 } }, + { "Panasonic", "DMC-FZ330", "9300K", 0, { 2.535156, 1, 1.558594, 0 } }, + { "Panasonic", "DMC-FZ330", "9400K", 0, { 2.542969, 1, 1.554688, 0 } }, + { "Panasonic", "DMC-FZ330", "9500K", 0, { 2.550781, 1, 1.546875, 0 } }, + { "Panasonic", "DMC-FZ330", "9600K", 0, { 2.558594, 1, 1.542969, 0 } }, + { "Panasonic", "DMC-FZ330", "9700K", 0, { 2.566406, 1, 1.535156, 0 } }, + { "Panasonic", "DMC-FZ330", "9800K", 0, { 2.574219, 1, 1.531250, 0 } }, + { "Panasonic", "DMC-FZ330", "9900K", 0, { 2.582031, 1, 1.523438, 0 } }, + { "Panasonic", "DMC-FZ330", "10000K", 0, { 2.589844, 1, 1.515625, 0 } }, + + // Panasonic DMC-FZ1000 Firmware 2.0.0 + { "Panasonic", "DMC-FZ1000", Daylight, 0, { 2.425781, 1, 1.886719, 0 } }, + { "Panasonic", "DMC-FZ1000", Cloudy, 0, { 2.621094, 1, 1.714844, 0 } }, + { "Panasonic", "DMC-FZ1000", Shade, 0, { 2.765625, 1, 1.625000, 0 } }, + { "Panasonic", "DMC-FZ1000", Incandescent, 0, { 1.718750, 1, 2.750000, 0 } }, + { "Panasonic", "DMC-FZ1000", Flash, 0, { 2.585938, 1, 1.796875, 0 } }, + + // Panasonic DMC-TZ60, DMC-TZ61 and DMC-ZS40 are the same camera model. + { "Panasonic", "DMC-TZ60", Daylight, 0, { 2.060377, 1, 1.656604, 0 } }, + { "Panasonic", "DMC-TZ60", Cloudy, 0, { 2.192453, 1, 1.520755, 0 } }, + { "Panasonic", "DMC-TZ60", Shade, 0, { 2.335849, 1, 1.415094, 0 } }, + { "Panasonic", "DMC-TZ60", Incandescent, 0, { 1.384906, 1, 2.577358, 0 } }, + + // Panasonic DMC-TZ60, DMC-TZ61 and DMC-ZS40 are the same camera model. + { "Panasonic", "DMC-TZ61", Daylight, 0, { 2.060377, 1, 1.656604, 0 } }, + { "Panasonic", "DMC-TZ61", Cloudy, 0, { 2.192453, 1, 1.520755, 0 } }, + { "Panasonic", "DMC-TZ61", Shade, 0, { 2.335849, 1, 1.415094, 0 } }, + { "Panasonic", "DMC-TZ61", Incandescent, 0, { 1.384906, 1, 2.577358, 0 } }, + + // Panasonic DMC-TZ60, DMC-TZ61 and DMC-ZS40 are the same camera model. + { "Panasonic", "DMC-ZS40", Daylight, 0, { 2.060377, 1, 1.656604, 0 } }, + { "Panasonic", "DMC-ZS40", Cloudy, 0, { 2.192453, 1, 1.520755, 0 } }, + { "Panasonic", "DMC-ZS40", Shade, 0, { 2.335849, 1, 1.415094, 0 } }, + { "Panasonic", "DMC-ZS40", Incandescent, 0, { 1.384906, 1, 2.577358, 0 } }, + + // Panasonic DMC-TZ70, DMC-TZ71 and DMC-ZS50 are the same camera model. + { "Panasonic", "DMC-TZ70", Daylight, 0, { 2.090909, 1, 1.818182, 0 } }, + { "Panasonic", "DMC-TZ70", Cloudy, 0, { 2.241509, 1, 1.660377, 0 } }, + { "Panasonic", "DMC-TZ70", Shade, 0, { 2.378788, 1, 1.590909, 0 } }, + { "Panasonic", "DMC-TZ70", Incandescent, 0, { 1.420455, 1, 2.727273, 0 } }, + + // Panasonic DMC-TZ70, DMC-TZ71 and DMC-ZS50 are the same camera model. + { "Panasonic", "DMC-TZ71", Daylight, 0, { 2.090909, 1, 1.818182, 0 } }, + { "Panasonic", "DMC-TZ71", Cloudy, 0, { 2.241509, 1, 1.660377, 0 } }, + { "Panasonic", "DMC-TZ71", Shade, 0, { 2.378788, 1, 1.590909, 0 } }, + { "Panasonic", "DMC-TZ71", Incandescent, 0, { 1.420455, 1, 2.727273, 0 } }, + + // Panasonic DMC-TZ70, DMC-TZ71 and DMC-ZS50 are the same camera model. + { "Panasonic", "DMC-ZS50", Daylight, 0, { 2.090909, 1, 1.818182, 0 } }, + { "Panasonic", "DMC-ZS50", Cloudy, 0, { 2.241509, 1, 1.660377, 0 } }, + { "Panasonic", "DMC-ZS50", Shade, 0, { 2.378788, 1, 1.590909, 0 } }, + { "Panasonic", "DMC-ZS50", Incandescent, 0, { 1.420455, 1, 2.727273, 0 } }, + + { "Panasonic", "DMC-G1", Daylight, 0, { 1.942966, 1, 1.448669, 0 } }, + { "Panasonic", "DMC-G1", Cloudy, 0, { 2.106464, 1, 1.326996, 0 } }, + { "Panasonic", "DMC-G1", Shade, 0, { 2.323194, 1, 1.224335, 0 } }, + { "Panasonic", "DMC-G1", Incandescent, 0, { 1.319392, 1, 2.148289, 0 } }, + { "Panasonic", "DMC-G1", Flash, 0, { 1.528517, 1, 1.277567, 0 } }, + + { "Panasonic", "DMC-G2", Daylight, 0, { 1.931559, 1, 1.414449, 0 } }, + { "Panasonic", "DMC-G2", Cloudy, 0, { 2.292776, 1, 1.231939, 0 } }, + { "Panasonic", "DMC-G2", Shade, 0, { 2.243346, 1, 1.231939, 0 } }, + { "Panasonic", "DMC-G2", Incandescent, 0, { 2.190114, 1, 1.250951, 0 } }, + { "Panasonic", "DMC-G2", Flash, 0, { 2.296578, 1, 1.190114, 0 } }, + + { "Panasonic", "DMC-G3", Daylight, 0, { 2.7925, 1, 1.5472, 0 } }, + { "Panasonic", "DMC-G3", Cloudy, 0, { 2.9660, 1, 1.4528, 0 } }, + { "Panasonic", "DMC-G3", Shade, 0, { 3.2642, 1, 1.3698, 0 } }, + { "Panasonic", "DMC-G3", Incandescent, 0, { 1.8491, 1, 2.2566, 0 } }, + { "Panasonic", "DMC-G3", Flash, 0, { 3.2868, 1, 1.3547, 0 } }, + { "Panasonic", "DMC-G3", "2500K", 0, { 1.4226, 1, 2.8302, 0 } }, + { "Panasonic", "DMC-G3", "2600K", 0, { 1.4755, 1, 2.7547, 0 } }, + { "Panasonic", "DMC-G3", "2700K", 0, { 1.5283, 1, 2.6717, 0 } }, + { "Panasonic", "DMC-G3", "2800K", 0, { 1.5925, 1, 2.5849, 0 } }, + { "Panasonic", "DMC-G3", "2900K", 0, { 1.6491, 1, 2.5019, 0 } }, + { "Panasonic", "DMC-G3", "3000K", 0, { 1.7094, 1, 2.4189, 0 } }, + { "Panasonic", "DMC-G3", "3100K", 0, { 1.7660, 1, 2.3434, 0 } }, + { "Panasonic", "DMC-G3", "3200K", 0, { 1.8189, 1, 2.2604, 0 } }, + { "Panasonic", "DMC-G3", "3300K", 0, { 1.8792, 1, 2.1849, 0 } }, + { "Panasonic", "DMC-G3", "3400K", 0, { 1.9358, 1, 2.1019, 0 } }, + { "Panasonic", "DMC-G3", "3500K", 0, { 1.9962, 1, 2.0189, 0 } }, + { "Panasonic", "DMC-G3", "3700K", 0, { 2.1245, 1, 1.9358, 0 } }, + { "Panasonic", "DMC-G3", "4000K", 0, { 2.3245, 1, 1.8113, 0 } }, + { "Panasonic", "DMC-G3", "4200K", 0, { 2.4189, 1, 1.7623, 0 } }, + { "Panasonic", "DMC-G3", "4500K", 0, { 2.5585, 1, 1.6868, 0 } }, + { "Panasonic", "DMC-G3", "4700K", 0, { 2.6000, 1, 1.6679, 0 } }, + { "Panasonic", "DMC-G3", "5000K", 0, { 2.6679, 1, 1.6264, 0 } }, + { "Panasonic", "DMC-G3", "5200K", 0, { 2.7170, 1, 1.5962, 0 } }, + { "Panasonic", "DMC-G3", "5500K", 0, { 2.7925, 1, 1.5472, 0 } }, + { "Panasonic", "DMC-G3", "5700K", 0, { 2.8415, 1, 1.5208, 0 } }, + { "Panasonic", "DMC-G3", "6000K", 0, { 2.9283, 1, 1.4717, 0 } }, + { "Panasonic", "DMC-G3", "6500K", 0, { 3.0679, 1, 1.4189, 0 } }, + { "Panasonic", "DMC-G3", "7000K", 0, { 3.1925, 1, 1.3811, 0 } }, + { "Panasonic", "DMC-G3", "7500K", 0, { 3.3170, 1, 1.3472, 0 } }, + { "Panasonic", "DMC-G3", "8000K", 0, { 3.3962, 1, 1.3283, 0 } }, + { "Panasonic", "DMC-G3", "8500K", 0, { 3.4792, 1, 1.3057, 0 } }, + { "Panasonic", "DMC-G3", "9000K", 0, { 3.5585, 1, 1.2868, 0 } }, + { "Panasonic", "DMC-G3", "9500K", 0, { 3.6302, 1, 1.2642, 0 } }, + { "Panasonic", "DMC-G3", "10000K", 0, { 3.7094, 1, 1.2528, 0 } }, + + { "Panasonic", "DMC-G5", Daylight, 0, { 2.343396, 1, 1.618868, 0 } }, + { "Panasonic", "DMC-G5", Cloudy, 0, { 2.452830, 1, 1.532075, 0 } }, + { "Panasonic", "DMC-G5", Shade, 0, { 2.637736, 1, 1.445283, 0 } }, + { "Panasonic", "DMC-G5", Incandescent, 0, { 1.615094, 1, 2.339623, 0 } }, + { "Panasonic", "DMC-G5", Flash, 0, { 2.433962, 1, 1.475472, 0 } }, + { "Panasonic", "DMC-G5", "2500K", 0, { 1.271698, 1, 2.901887, 0 } }, + { "Panasonic", "DMC-G5", "2700K", 0, { 1.369811, 1, 2.743396, 0 } }, + { "Panasonic", "DMC-G5", "3000K", 0, { 1.516981, 1, 2.490566, 0 } }, + { "Panasonic", "DMC-G5", "3500K", 0, { 1.720755, 1, 2.094340, 0 } }, + { "Panasonic", "DMC-G5", "4000K", 0, { 1.966038, 1, 1.901887, 0 } }, + { "Panasonic", "DMC-G5", "4500K", 0, { 2.120755, 1, 1.784906, 0 } }, + { "Panasonic", "DMC-G5", "5000K", 0, { 2.230189, 1, 1.713208, 0 } }, + { "Panasonic", "DMC-G5", "5500K", 0, { 2.343396, 1, 1.618868, 0 } }, + { "Panasonic", "DMC-G5", "6000K", 0, { 2.422642, 1, 1.554717, 0 } }, + { "Panasonic", "DMC-G5", "6500K", 0, { 2.501887, 1, 1.505660, 0 } }, + { "Panasonic", "DMC-G5", "7000K", 0, { 2.603774, 1, 1.460377, 0 } }, + { "Panasonic", "DMC-G5", "8000K", 0, { 2.754717, 1, 1.381132, 0 } }, + { "Panasonic", "DMC-G5", "9000K", 0, { 2.867925, 1, 1.332075, 0 } }, + { "Panasonic", "DMC-G5", "10000K", 0, { 2.966038, 1, 1.286792, 0 } }, + + /* Firmware version 1.1 */ + { "Panasonic", "DMC-G6", Daylight, 0, { 2.265625, 1, 1.699219, 0 } }, + { "Panasonic", "DMC-G6", Cloudy, 0, { 2.406250, 1, 1.593750, 0 } }, + { "Panasonic", "DMC-G6", Shade, 0, { 2.617188, 1, 1.511719, 0 } }, + { "Panasonic", "DMC-G6", Incandescent, 0, { 1.535156, 1, 2.375000, 0 } }, + { "Panasonic", "DMC-G6", Flash, 0, { 2.332031, 1, 1.566406, 0 } }, + + { "Panasonic", "DMC-G7", Daylight, 0, { 2.351563, 1, 1.664063, 0 } }, + { "Panasonic", "DMC-G7", Cloudy, 0, { 2.519531, 1, 1.542969, 0 } }, + { "Panasonic", "DMC-G7", Shade, 0, { 2.691406, 1, 1.464844, 0 } }, + { "Panasonic", "DMC-G7", Incandescent, 0, { 1.625000, 1, 2.425781, 0 } }, + { "Panasonic", "DMC-G7", Flash, 0, { 2.371094, 1, 1.589844, 0 } }, + + /* The Panasonic DMC-G7 is named DMC-G70 in Germany. */ + { "Panasonic", "DMC-G70", Daylight, 0, { 2.351563, 1, 1.664063, 0 } }, + { "Panasonic", "DMC-G70", Cloudy, 0, { 2.519531, 1, 1.542969, 0 } }, + { "Panasonic", "DMC-G70", Shade, 0, { 2.691406, 1, 1.464844, 0 } }, + { "Panasonic", "DMC-G70", Incandescent, 0, { 1.625000, 1, 2.425781, 0 } }, + { "Panasonic", "DMC-G70", Flash, 0, { 2.371094, 1, 1.589844, 0 } }, + + /* Firmware version 1.2 */ + /* -9/+9 fine tuning is -9/+9 in blue-amber and zero in magenta-green */ + { "Panasonic", "DMC-GF1", Daylight, -9, { 1.817490, 1, 1.760456, 0 } }, + { "Panasonic", "DMC-GF1", Daylight, 0, { 2.049430, 1, 1.437262, 0 } }, + { "Panasonic", "DMC-GF1", Daylight, 9, { 2.368821, 1, 1.254753, 0 } }, + { "Panasonic", "DMC-GF1", Cloudy, -9, { 1.969582, 1, 1.608365, 0 } }, + { "Panasonic", "DMC-GF1", Cloudy, 0, { 2.220532, 1, 1.311787, 0 } }, + { "Panasonic", "DMC-GF1", Cloudy, 9, { 2.566540, 1, 1.148289, 0 } }, + { "Panasonic", "DMC-GF1", Shade, -9, { 2.171103, 1, 1.482890, 0 } }, + { "Panasonic", "DMC-GF1", Shade, 0, { 2.448669, 1, 1.209125, 0 } }, + { "Panasonic", "DMC-GF1", Shade, 9, { 2.832700, 1, 1.057034, 0 } }, + { "Panasonic", "DMC-GF1", Incandescent, -9, { 1.231939, 1, 2.623574, 0 } }, + { "Panasonic", "DMC-GF1", Incandescent, 0, { 1.391635, 1, 2.136882, 0 } }, + { "Panasonic", "DMC-GF1", Incandescent, 9, { 1.608365, 1, 1.870722, 0 } }, + { "Panasonic", "DMC-GF1", Flash, -9, { 2.125475, 1, 1.528517, 0 } }, + { "Panasonic", "DMC-GF1", Flash, 0, { 2.399239, 1, 1.247148, 0 } }, + { "Panasonic", "DMC-GF1", Flash, 9, { 2.775665, 1, 1.091255, 0 } }, + { "Panasonic", "DMC-GF1", "2500K", 0, { 1.068441, 1, 2.760456, 0 } }, + { "Panasonic", "DMC-GF1", "2600K", 0, { 1.110266, 1, 2.676806, 0 } }, + { "Panasonic", "DMC-GF1", "2700K", 0, { 1.155894, 1, 2.589354, 0 } }, + { "Panasonic", "DMC-GF1", "2800K", 0, { 1.193916, 1, 2.501901, 0 } }, + { "Panasonic", "DMC-GF1", "2900K", 0, { 1.239544, 1, 2.414449, 0 } }, + { "Panasonic", "DMC-GF1", "3000K", 0, { 1.285171, 1, 2.319392, 0 } }, + { "Panasonic", "DMC-GF1", "3100K", 0, { 1.323194, 1, 2.239544, 0 } }, + { "Panasonic", "DMC-GF1", "3200K", 0, { 1.357415, 1, 2.159696, 0 } }, + { "Panasonic", "DMC-GF1", "3300K", 0, { 1.391635, 1, 2.079848, 0 } }, + { "Panasonic", "DMC-GF1", "3400K", 0, { 1.425856, 1, 2.000000, 0 } }, + { "Panasonic", "DMC-GF1", "3500K", 0, { 1.463878, 1, 1.920152, 0 } }, + { "Panasonic", "DMC-GF1", "3600K", 0, { 1.509506, 1, 1.878327, 0 } }, + { "Panasonic", "DMC-GF1", "3700K", 0, { 1.555133, 1, 1.832700, 0 } }, + { "Panasonic", "DMC-GF1", "3800K", 0, { 1.600761, 1, 1.790875, 0 } }, + { "Panasonic", "DMC-GF1", "3900K", 0, { 1.646388, 1, 1.745247, 0 } }, + { "Panasonic", "DMC-GF1", "4000K", 0, { 1.695817, 1, 1.695817, 0 } }, + { "Panasonic", "DMC-GF1", "4100K", 0, { 1.730038, 1, 1.673004, 0 } }, + { "Panasonic", "DMC-GF1", "4200K", 0, { 1.768061, 1, 1.653992, 0 } }, + { "Panasonic", "DMC-GF1", "4300K", 0, { 1.802281, 1, 1.631179, 0 } }, + { "Panasonic", "DMC-GF1", "4400K", 0, { 1.836502, 1, 1.608365, 0 } }, + { "Panasonic", "DMC-GF1", "4500K", 0, { 1.874525, 1, 1.581749, 0 } }, + { "Panasonic", "DMC-GF1", "4600K", 0, { 1.885932, 1, 1.566540, 0 } }, + { "Panasonic", "DMC-GF1", "4700K", 0, { 1.908745, 1, 1.551331, 0 } }, + { "Panasonic", "DMC-GF1", "4800K", 0, { 1.927757, 1, 1.536122, 0 } }, + { "Panasonic", "DMC-GF1", "4900K", 0, { 1.946768, 1, 1.520913, 0 } }, + { "Panasonic", "DMC-GF1", "5000K", 0, { 1.969582, 1, 1.501901, 0 } }, + { "Panasonic", "DMC-GF1", "5100K", 0, { 1.984791, 1, 1.494296, 0 } }, + { "Panasonic", "DMC-GF1", "5200K", 0, { 2.000000, 1, 1.479087, 0 } }, + { "Panasonic", "DMC-GF1", "5300K", 0, { 2.015209, 1, 1.463878, 0 } }, + { "Panasonic", "DMC-GF1", "5400K", 0, { 2.030418, 1, 1.448669, 0 } }, + { "Panasonic", "DMC-GF1", "5500K", 0, { 2.049430, 1, 1.437262, 0 } }, + { "Panasonic", "DMC-GF1", "5600K", 0, { 2.076046, 1, 1.422053, 0 } }, + { "Panasonic", "DMC-GF1", "5700K", 0, { 2.098859, 1, 1.406844, 0 } }, + { "Panasonic", "DMC-GF1", "5800K", 0, { 2.125475, 1, 1.384030, 0 } }, + { "Panasonic", "DMC-GF1", "5900K", 0, { 2.152091, 1, 1.368821, 0 } }, + { "Panasonic", "DMC-GF1", "6000K", 0, { 2.174905, 1, 1.349810, 0 } }, + { "Panasonic", "DMC-GF1", "6100K", 0, { 2.197719, 1, 1.342205, 0 } }, + { "Panasonic", "DMC-GF1", "6200K", 0, { 2.216730, 1, 1.326996, 0 } }, + { "Panasonic", "DMC-GF1", "6300K", 0, { 2.243346, 1, 1.311787, 0 } }, + { "Panasonic", "DMC-GF1", "6400K", 0, { 2.262357, 1, 1.296578, 0 } }, + { "Panasonic", "DMC-GF1", "6500K", 0, { 2.288973, 1, 1.281369, 0 } }, + { "Panasonic", "DMC-GF1", "6600K", 0, { 2.304183, 1, 1.277567, 0 } }, + { "Panasonic", "DMC-GF1", "6700K", 0, { 2.323194, 1, 1.266160, 0 } }, + { "Panasonic", "DMC-GF1", "6800K", 0, { 2.342205, 1, 1.254753, 0 } }, + { "Panasonic", "DMC-GF1", "6900K", 0, { 2.365019, 1, 1.247148, 0 } }, + { "Panasonic", "DMC-GF1", "7000K", 0, { 2.384030, 1, 1.231939, 0 } }, + { "Panasonic", "DMC-GF1", "7100K", 0, { 2.403042, 1, 1.224335, 0 } }, + { "Panasonic", "DMC-GF1", "7200K", 0, { 2.425856, 1, 1.216730, 0 } }, + { "Panasonic", "DMC-GF1", "7300K", 0, { 2.444867, 1, 1.209125, 0 } }, + { "Panasonic", "DMC-GF1", "7400K", 0, { 2.463878, 1, 1.201521, 0 } }, + { "Panasonic", "DMC-GF1", "7500K", 0, { 2.490494, 1, 1.190114, 0 } }, + { "Panasonic", "DMC-GF1", "7600K", 0, { 2.501901, 1, 1.190114, 0 } }, + { "Panasonic", "DMC-GF1", "7700K", 0, { 2.509506, 1, 1.182509, 0 } }, + { "Panasonic", "DMC-GF1", "7800K", 0, { 2.520913, 1, 1.182509, 0 } }, + { "Panasonic", "DMC-GF1", "7900K", 0, { 2.532319, 1, 1.174905, 0 } }, + { "Panasonic", "DMC-GF1", "8000K", 0, { 2.547528, 1, 1.167300, 0 } }, + { "Panasonic", "DMC-GF1", "8100K", 0, { 2.555133, 1, 1.167300, 0 } }, + { "Panasonic", "DMC-GF1", "8200K", 0, { 2.566540, 1, 1.159696, 0 } }, + { "Panasonic", "DMC-GF1", "8300K", 0, { 2.574145, 1, 1.152091, 0 } }, + { "Panasonic", "DMC-GF1", "8400K", 0, { 2.585551, 1, 1.144487, 0 } }, + { "Panasonic", "DMC-GF1", "8500K", 0, { 2.600760, 1, 1.136882, 0 } }, + { "Panasonic", "DMC-GF1", "8600K", 0, { 2.612167, 1, 1.136882, 0 } }, + { "Panasonic", "DMC-GF1", "8700K", 0, { 2.623574, 1, 1.129278, 0 } }, + { "Panasonic", "DMC-GF1", "8800K", 0, { 2.634981, 1, 1.129278, 0 } }, + { "Panasonic", "DMC-GF1", "8900K", 0, { 2.646388, 1, 1.121673, 0 } }, + { "Panasonic", "DMC-GF1", "9000K", 0, { 2.661597, 1, 1.117871, 0 } }, + { "Panasonic", "DMC-GF1", "9100K", 0, { 2.673004, 1, 1.117871, 0 } }, + { "Panasonic", "DMC-GF1", "9200K", 0, { 2.684411, 1, 1.110266, 0 } }, + { "Panasonic", "DMC-GF1", "9300K", 0, { 2.692015, 1, 1.110266, 0 } }, + { "Panasonic", "DMC-GF1", "9400K", 0, { 2.703422, 1, 1.102662, 0 } }, + { "Panasonic", "DMC-GF1", "9500K", 0, { 2.718631, 1, 1.095057, 0 } }, + { "Panasonic", "DMC-GF1", "9600K", 0, { 2.726236, 1, 1.095057, 0 } }, + { "Panasonic", "DMC-GF1", "9700K", 0, { 2.737643, 1, 1.087452, 0 } }, + { "Panasonic", "DMC-GF1", "9800K", 0, { 2.752852, 1, 1.079848, 0 } }, + { "Panasonic", "DMC-GF1", "9900K", 0, { 2.764259, 1, 1.072243, 0 } }, + { "Panasonic", "DMC-GF1", "10000K", 0, { 2.779468, 1, 1.064639, 0 } }, + + { "Panasonic", "DMC-GF3", Daylight, 0, { 1.9396, 1, 1.4377, 0 } }, + { "Panasonic", "DMC-GF3", Cloudy, 0, { 2.0679, 1, 1.3396, 0 } }, + { "Panasonic", "DMC-GF3", Shade, 0, { 2.2566, 1, 1.2717, 0 } }, + { "Panasonic", "DMC-GF3", Incandescent, 0, { 1.3019, 1, 2.0868, 0 } }, + { "Panasonic", "DMC-GF3", Flash, 0, { 2.1962, 1, 1.2717, 0 } }, + + { "Panasonic", "DMC-GF5", Daylight, 0, { 2.354717, 1, 1.637736, 0 } }, + { "Panasonic", "DMC-GF5", Cloudy, 0, { 2.498113, 1, 1.547170, 0 } }, + { "Panasonic", "DMC-GF5", Shade, 0, { 2.720755, 1, 1.460377, 0 } }, + { "Panasonic", "DMC-GF5", Incandescent, 0, { 1.615094, 1, 2.335849, 0 } }, + { "Panasonic", "DMC-GF5", Flash, 0, { 2.626415, 1, 1.445283, 0 } }, + + { "Panasonic", "DMC-GH2", Daylight, 0, { 2.399240, 1, 1.634981, 0 } }, + { "Panasonic", "DMC-GH2", Cloudy, 0, { 2.520913, 1, 1.547529, 0 } }, + { "Panasonic", "DMC-GH2", Shade, 0, { 2.718631, 1, 1.460076, 0 } }, + { "Panasonic", "DMC-GH2", Incandescent, 0, { 1.634981, 1, 2.307985, 0 } }, + { "Panasonic", "DMC-GH2", Flash, 0, { 2.745247, 1, 1.444867, 0 } }, + + { "Panasonic", "DMC-GH3", Daylight, 0, { 2.313208, 1, 1.845283, 0 } }, + { "Panasonic", "DMC-GH3", Cloudy, 0, { 2.422642, 1, 1.720755, 0 } }, + { "Panasonic", "DMC-GH3", Shade, 0, { 2.607547, 1, 1.615094, 0 } }, + { "Panasonic", "DMC-GH3", Incandescent, 0, { 1.641509, 1, 2.747170, 0 } }, + { "Panasonic", "DMC-GH3", Flash, 0, { 2.369811, 1, 1.694340, 0 } }, + + /* Firmware version 2.0 */ + { "Panasonic", "DMC-GH4", Daylight, 0, { 2.390625, 1, 1.855469, 0 } }, + { "Panasonic", "DMC-GH4", Cloudy, 0, { 2.531250, 1, 1.718750, 0 } }, + { "Panasonic", "DMC-GH4", Shade, 0, { 2.691406, 1, 1.597656, 0 } }, + { "Panasonic", "DMC-GH4", Incandescent, 0, { 1.734375, 1, 2.781250, 0 } }, + { "Panasonic", "DMC-GH4", Flash, 0, { 2.445313, 1, 1.773438, 0 } }, + + /* Firmware version 1.1 */ + { "Panasonic", "DMC-GM1", Daylight, 0, { 2.469697, 1, 1.659091, 0 } }, + { "Panasonic", "DMC-GM1", Cloudy, 0, { 2.609848, 1, 1.553030, 0 } }, + { "Panasonic", "DMC-GM1", Shade, 0, { 2.840909, 1, 1.465909, 0 } }, + { "Panasonic", "DMC-GM1", Incandescent, 0, { 1.613636, 1, 2.386364, 0 } }, + { "Panasonic", "DMC-GM1", Flash, 0, { 2.530303, 1, 1.496212, 0 } }, + + /* Firmware version 1.1 */ + { "Panasonic", "DMC-GM5", Daylight, 0, { 2.394531, 1, 1.554687, 0 } }, + { "Panasonic", "DMC-GM5", Cloudy, 0, { 2.621093, 1, 1.437500, 0 } }, + { "Panasonic", "DMC-GM5", Shade, 0, { 2.781250, 1, 1.371093, 0 } }, + { "Panasonic", "DMC-GM5", Incandescent, 0, { 1.640625, 1, 2.253906, 0 } }, + { "Panasonic", "DMC-GM5", Flash, 0, { 2.492187, 1, 1.402343, 0 } }, + + /* Firmware version 1.1 */ + /* -9/+9 fine tuning is -9/+9 in blue-amber and zero in magenta-green */ + { "Panasonic", "DMC-GX1", Daylight, -9, { 2.256604, 1, 1.916981, 0 } }, + { "Panasonic", "DMC-GX1", Daylight, 0, { 2.611321, 1, 1.615094, 0 } }, + { "Panasonic", "DMC-GX1", Daylight, 9, { 3.060377, 1, 1.411321, 0 } }, + { "Panasonic", "DMC-GX1", Cloudy, -9, { 2.407547, 1, 1.796226, 0 } }, + { "Panasonic", "DMC-GX1", Cloudy, 0, { 2.792453, 1, 1.513208, 0 } }, + { "Panasonic", "DMC-GX1", Cloudy, 9, { 3.271698, 1, 1.324528, 0 } }, + { "Panasonic", "DMC-GX1", Shade, -9, { 2.626415, 1, 1.698113, 0 } }, + { "Panasonic", "DMC-GX1", Shade, 0, { 3.045283, 1, 1.430189, 0 } }, + { "Panasonic", "DMC-GX1", Shade, 9, { 3.569811, 1, 1.249057, 0 } }, + { "Panasonic", "DMC-GX1", Incandescent, -9, { 1.464151, 1, 2.864151, 0 } }, + { "Panasonic", "DMC-GX1", Incandescent, 0, { 1.698113, 1, 2.415094, 0 } }, + { "Panasonic", "DMC-GX1", Incandescent, 9, { 1.988679, 1, 2.109434, 0 } }, + { "Panasonic", "DMC-GX1", Flash, -9, { 2.683019, 1, 1.667925, 0 } }, + { "Panasonic", "DMC-GX1", Flash, 0, { 3.109434, 1, 1.407547, 0 } }, + { "Panasonic", "DMC-GX1", Flash, 9, { 3.645283, 1, 1.230189, 0 } }, + { "Panasonic", "DMC-GX1", "2500K", 0, { 1.286792, 1, 3.052830, 0 } }, + { "Panasonic", "DMC-GX1", "2600K", 0, { 1.339623, 1, 2.966038, 0 } }, + { "Panasonic", "DMC-GX1", "2700K", 0, { 1.392453, 1, 2.875472, 0 } }, + { "Panasonic", "DMC-GX1", "2800K", 0, { 1.452830, 1, 2.781132, 0 } }, + { "Panasonic", "DMC-GX1", "2900K", 0, { 1.505660, 1, 2.690566, 0 } }, + { "Panasonic", "DMC-GX1", "3000K", 0, { 1.566038, 1, 2.596226, 0 } }, + { "Panasonic", "DMC-GX1", "3100K", 0, { 1.615094, 1, 2.513208, 0 } }, + { "Panasonic", "DMC-GX1", "3200K", 0, { 1.667925, 1, 2.418868, 0 } }, + { "Panasonic", "DMC-GX1", "3300K", 0, { 1.728302, 1, 2.335849, 0 } }, + { "Panasonic", "DMC-GX1", "3400K", 0, { 1.777359, 1, 2.245283, 0 } }, + { "Panasonic", "DMC-GX1", "3500K", 0, { 1.837736, 1, 2.150943, 0 } }, + { "Panasonic", "DMC-GX1", "3600K", 0, { 1.898113, 1, 2.105660, 0 } }, + { "Panasonic", "DMC-GX1", "3700K", 0, { 1.958491, 1, 2.052830, 0 } }, + { "Panasonic", "DMC-GX1", "3800K", 0, { 2.022642, 1, 2.000000, 0 } }, + { "Panasonic", "DMC-GX1", "3900K", 0, { 2.083019, 1, 1.943396, 0 } }, + { "Panasonic", "DMC-GX1", "4000K", 0, { 2.150943, 1, 1.890566, 0 } }, + { "Panasonic", "DMC-GX1", "4100K", 0, { 2.196226, 1, 1.867925, 0 } }, + { "Panasonic", "DMC-GX1", "4200K", 0, { 2.241509, 1, 1.845283, 0 } }, + { "Panasonic", "DMC-GX1", "4300K", 0, { 2.286792, 1, 1.815094, 0 } }, + { "Panasonic", "DMC-GX1", "4400K", 0, { 2.328302, 1, 1.788679, 0 } }, + { "Panasonic", "DMC-GX1", "4500K", 0, { 2.373585, 1, 1.758491, 0 } }, + { "Panasonic", "DMC-GX1", "4600K", 0, { 2.388679, 1, 1.750943, 0 } }, + { "Panasonic", "DMC-GX1", "4700K", 0, { 2.403774, 1, 1.735849, 0 } }, + { "Panasonic", "DMC-GX1", "4800K", 0, { 2.426415, 1, 1.728302, 0 } }, + { "Panasonic", "DMC-GX1", "4900K", 0, { 2.441510, 1, 1.713208, 0 } }, + { "Panasonic", "DMC-GX1", "5000K", 0, { 2.464151, 1, 1.698113, 0 } }, + { "Panasonic", "DMC-GX1", "5100K", 0, { 2.494340, 1, 1.683019, 0 } }, + { "Panasonic", "DMC-GX1", "5200K", 0, { 2.524528, 1, 1.667924, 0 } }, + { "Panasonic", "DMC-GX1", "5300K", 0, { 2.554717, 1, 1.652830, 0 } }, + { "Panasonic", "DMC-GX1", "5400K", 0, { 2.581132, 1, 1.637736, 0 } }, + { "Panasonic", "DMC-GX1", "5500K", 0, { 2.611321, 1, 1.615094, 0 } }, + { "Panasonic", "DMC-GX1", "5600K", 0, { 2.633962, 1, 1.603774, 0 } }, + { "Panasonic", "DMC-GX1", "5700K", 0, { 2.656604, 1, 1.588679, 0 } }, + { "Panasonic", "DMC-GX1", "5800K", 0, { 2.686792, 1, 1.573585, 0 } }, + { "Panasonic", "DMC-GX1", "5900K", 0, { 2.709434, 1, 1.558491, 0 } }, + { "Panasonic", "DMC-GX1", "6000K", 0, { 2.739623, 1, 1.543396, 0 } }, + { "Panasonic", "DMC-GX1", "6100K", 0, { 2.762264, 1, 1.535849, 0 } }, + { "Panasonic", "DMC-GX1", "6200K", 0, { 2.784906, 1, 1.528302, 0 } }, + { "Panasonic", "DMC-GX1", "6300K", 0, { 2.807547, 1, 1.513208, 0 } }, + { "Panasonic", "DMC-GX1", "6400K", 0, { 2.830189, 1, 1.505660, 0 } }, + { "Panasonic", "DMC-GX1", "6500K", 0, { 2.860377, 1, 1.490566, 0 } }, + { "Panasonic", "DMC-GX1", "6600K", 0, { 2.879245, 1, 1.483019, 0 } }, + { "Panasonic", "DMC-GX1", "6700K", 0, { 2.901887, 1, 1.475472, 0 } }, + { "Panasonic", "DMC-GX1", "6800K", 0, { 2.924528, 1, 1.467925, 0 } }, + { "Panasonic", "DMC-GX1", "6900K", 0, { 2.947170, 1, 1.460377, 0 } }, + { "Panasonic", "DMC-GX1", "7000K", 0, { 2.977359, 1, 1.452830, 0 } }, + { "Panasonic", "DMC-GX1", "7100K", 0, { 3.000000, 1, 1.445283, 0 } }, + { "Panasonic", "DMC-GX1", "7200K", 0, { 3.022642, 1, 1.437736, 0 } }, + { "Panasonic", "DMC-GX1", "7300K", 0, { 3.045283, 1, 1.430189, 0 } }, + { "Panasonic", "DMC-GX1", "7400K", 0, { 3.067925, 1, 1.418868, 0 } }, + { "Panasonic", "DMC-GX1", "7500K", 0, { 3.098113, 1, 1.407547, 0 } }, + { "Panasonic", "DMC-GX1", "7600K", 0, { 3.109434, 1, 1.407547, 0 } }, + { "Panasonic", "DMC-GX1", "7700K", 0, { 3.128302, 1, 1.396226, 0 } }, + { "Panasonic", "DMC-GX1", "7800K", 0, { 3.139623, 1, 1.396226, 0 } }, + { "Panasonic", "DMC-GX1", "7900K", 0, { 3.154717, 1, 1.388679, 0 } }, + { "Panasonic", "DMC-GX1", "8000K", 0, { 3.169811, 1, 1.381132, 0 } }, + { "Panasonic", "DMC-GX1", "8100K", 0, { 3.184906, 1, 1.381132, 0 } }, + { "Panasonic", "DMC-GX1", "8200K", 0, { 3.200000, 1, 1.373585, 0 } }, + { "Panasonic", "DMC-GX1", "8300K", 0, { 3.215094, 1, 1.373585, 0 } }, + { "Panasonic", "DMC-GX1", "8400K", 0, { 3.230189, 1, 1.366038, 0 } }, + { "Panasonic", "DMC-GX1", "8500K", 0, { 3.252830, 1, 1.358491, 0 } }, + { "Panasonic", "DMC-GX1", "8600K", 0, { 3.267925, 1, 1.358491, 0 } }, + { "Panasonic", "DMC-GX1", "8700K", 0, { 3.283019, 1, 1.350943, 0 } }, + { "Panasonic", "DMC-GX1", "8800K", 0, { 3.298113, 1, 1.350943, 0 } }, + { "Panasonic", "DMC-GX1", "8900K", 0, { 3.313207, 1, 1.343396, 0 } }, + { "Panasonic", "DMC-GX1", "9000K", 0, { 3.328302, 1, 1.335849, 0 } }, + { "Panasonic", "DMC-GX1", "9100K", 0, { 3.335849, 1, 1.335849, 0 } }, + { "Panasonic", "DMC-GX1", "9200K", 0, { 3.350944, 1, 1.328302, 0 } }, + { "Panasonic", "DMC-GX1", "9300K", 0, { 3.366038, 1, 1.328302, 0 } }, + { "Panasonic", "DMC-GX1", "9400K", 0, { 3.377359, 1, 1.320755, 0 } }, + { "Panasonic", "DMC-GX1", "9500K", 0, { 3.396226, 1, 1.313208, 0 } }, + { "Panasonic", "DMC-GX1", "9600K", 0, { 3.411321, 1, 1.313208, 0 } }, + { "Panasonic", "DMC-GX1", "9700K", 0, { 3.422642, 1, 1.313208, 0 } }, + { "Panasonic", "DMC-GX1", "9800K", 0, { 3.437736, 1, 1.305660, 0 } }, + { "Panasonic", "DMC-GX1", "9900K", 0, { 3.452830, 1, 1.305660, 0 } }, + { "Panasonic", "DMC-GX1", "10000K", 0, { 3.467925, 1, 1.298113, 0 } }, + + { "Panasonic", "DMC-GX7", Daylight, 0, { 2.539623, 1, 1.611321, 0 } }, + { "Panasonic", "DMC-GX7", Cloudy, 0, { 2.667925, 1, 1.509434, 0 } }, + { "Panasonic", "DMC-GX7", Shade, 0, { 2.879245, 1, 1.422642, 0 } }, + { "Panasonic", "DMC-GX7", Incandescent, 0, { 1.758491, 1, 2.320755, 0 } }, + { "Panasonic", "DMC-GX7", Flash, 0, { 2.607547, 1, 1.479245, 0 } }, + + { "Panasonic", "DMC-GX8", Daylight, 0, { 2.296875, 1, 1.914063, 0 } }, + { "Panasonic", "DMC-GX8", Cloudy, 0, { 2.437500, 1, 1.761719, 0 } }, + { "Panasonic", "DMC-GX8", Shade, 0, { 2.605469, 1, 1.656250, 0 } }, + { "Panasonic", "DMC-GX8", Incandescent, 0, { 1.664063, 1, 2.800781, 0 } }, + { "Panasonic", "DMC-GX8", Flash, 0, { 2.320313, 1, 1.824219, 0 } }, + + { "Panasonic", "DMC-L1", Daylight, 0, { 1.980989, 1, 1.444867, 0 } }, + { "Panasonic", "DMC-L1", Cloudy, 0, { 2.129278, 1, 1.300380, 0 } }, + { "Panasonic", "DMC-L1", Shade, 0, { 2.361217, 1, 1.167300, 0 } }, + { "Panasonic", "DMC-L1", Incandescent, 0, { 1.368821, 1, 2.091255, 0 } }, + /* Flash multipliers are variable */ + { "Panasonic", "DMC-L1", Flash, 0, { 2.319392, 1, 1.053232, 0 } }, + + /* DMC-L1 Kelvin presets */ + { "Panasonic", "DMC-L1", "2500K", 0, { 1.209126, 1, 2.722434, 0 } }, + { "Panasonic", "DMC-L1", "2600K", 0, { 1.243346, 1, 2.623574, 0 } }, + { "Panasonic", "DMC-L1", "2700K", 0, { 1.285171, 1, 2.520913, 0 } }, + { "Panasonic", "DMC-L1", "2800K", 0, { 1.323194, 1, 2.418251, 0 } }, + { "Panasonic", "DMC-L1", "2900K", 0, { 1.365019, 1, 2.319392, 0 } }, + { "Panasonic", "DMC-L1", "3000K", 0, { 1.406844, 1, 2.209126, 0 } }, + { "Panasonic", "DMC-L1", "3100K", 0, { 1.441065, 1, 2.193916, 0 } }, + { "Panasonic", "DMC-L1", "3200K", 0, { 1.482890, 1, 2.178707, 0 } }, + { "Panasonic", "DMC-L1", "3300K", 0, { 1.524715, 1, 2.163498, 0 } }, + { "Panasonic", "DMC-L1", "3400K", 0, { 1.566540, 1, 2.148289, 0 } }, + { "Panasonic", "DMC-L1", "3500K", 0, { 1.608365, 1, 2.136882, 0 } }, + { "Panasonic", "DMC-L1", "3600K", 0, { 1.638783, 1, 2.091255, 0 } }, + { "Panasonic", "DMC-L1", "3800K", 0, { 1.699620, 1, 2.000000, 0 } }, + { "Panasonic", "DMC-L1", "4000K", 0, { 1.760456, 1, 1.897338, 0 } }, + { "Panasonic", "DMC-L1", "4200K", 0, { 1.813688, 1, 1.809886, 0 } }, + { "Panasonic", "DMC-L1", "4400K", 0, { 1.874525, 1, 1.722433, 0 } }, + { "Panasonic", "DMC-L1", "4600K", 0, { 1.912547, 1, 1.642585, 0 } }, + { "Panasonic", "DMC-L1", "4800K", 0, { 1.923954, 1, 1.585551, 0 } }, + { "Panasonic", "DMC-L1", "5000K", 0, { 1.942966, 1, 1.528517, 0 } }, + { "Panasonic", "DMC-L1", "5300K", 0, { 1.984791, 1, 1.456274, 0 } }, + { "Panasonic", "DMC-L1", "5500K", 0, { 2.019011, 1, 1.403042, 0 } }, + { "Panasonic", "DMC-L1", "5800K", 0, { 2.057034, 1, 1.361217, 0 } }, + { "Panasonic", "DMC-L1", "6000K", 0, { 2.079848, 1, 1.323194, 0 } }, + { "Panasonic", "DMC-L1", "6300K", 0, { 2.159696, 1, 1.281369, 0 } }, + { "Panasonic", "DMC-L1", "6500K", 0, { 2.216730, 1, 1.243346, 0 } }, + { "Panasonic", "DMC-L1", "6800K", 0, { 2.273764, 1, 1.228137, 0 } }, + { "Panasonic", "DMC-L1", "7300K", 0, { 2.380228, 1, 1.186312, 0 } }, + { "Panasonic", "DMC-L1", "7800K", 0, { 2.452471, 1, 1.144487, 0 } }, + { "Panasonic", "DMC-L1", "8300K", 0, { 2.501901, 1, 1.106464, 0 } }, + { "Panasonic", "DMC-L1", "9000K", 0, { 2.574145, 1, 1.068441, 0 } }, + { "Panasonic", "DMC-L1", "10000K", 0, { 2.692015, 1.011407, 1, 0 } }, + + {"Panasonic", "DMC-LF1", Daylight, 0, { 1.912879, 1, 1.750000, 0 } }, + {"Panasonic", "DMC-LF1", Cloudy, 0, { 2.037879, 1, 1.609848, 0 } }, + {"Panasonic", "DMC-LF1", Shade, 0, { 2.159091, 1, 1.511364, 0 } }, + {"Panasonic", "DMC-LF1", Incandescent, 0, { 1.268939, 1, 2.799242, 0 } }, + + { "Panasonic", "DMC-LX1", Daylight, 0, { 1.837121, 1, 1.484848, 0 } }, + { "Panasonic", "DMC-LX1", Cloudy, 0, { 2.003788, 1, 1.310606, 0 } }, + { "Panasonic", "DMC-LX1", Incandescent, 0, { 1.098485, 1, 2.272727, 0 } }, + + { "Panasonic", "DMC-LX2", Daylight, -3, { 2.456274, 1, 1.806084, 0 } }, + { "Panasonic", "DMC-LX2", Daylight, 0, { 2.114068, 1, 1.726236, 0 } }, + { "Panasonic", "DMC-LX2", Daylight, 3, { 1.916350, 1, 1.585551, 0 } }, + { "Panasonic", "DMC-LX2", Cloudy, -3, { 2.714829, 1, 1.650190, 0 } }, + { "Panasonic", "DMC-LX2", Cloudy, 0, { 2.338403, 1, 1.577947, 0 } }, + { "Panasonic", "DMC-LX2", Cloudy, 3, { 2.121673, 1, 1.448669, 0 } }, + { "Panasonic", "DMC-LX2", Shade, -3, { 2.939163, 1, 1.577947, 0 } }, + { "Panasonic", "DMC-LX2", Shade, 0, { 2.532319, 1, 1.509506, 0 } }, + { "Panasonic", "DMC-LX2", Shade, 3, { 2.292776, 1, 1.384030, 0 } }, + { "Panasonic", "DMC-LX2", Incandescent, -3, { 1.581749, 1, 2.524715, 0 } }, + { "Panasonic", "DMC-LX2", Incandescent, 0, { 1.365019, 1, 2.410646, 0 } }, + { "Panasonic", "DMC-LX2", Incandescent, 3, { 1.235741, 1, 2.212928, 0 } }, + + { "Panasonic", "DMC-LX3", Daylight, 0, { 2.022814, 1, 1.623574, 0 } }, + { "Panasonic", "DMC-LX3", Cloudy, 0, { 2.224335, 1, 1.520913, 0 } }, + { "Panasonic", "DMC-LX3", Shade, 0, { 2.475285, 1, 1.399240, 0 } }, + { "Panasonic", "DMC-LX3", Flash, 0, { 2.296578, 1, 1.482890, 0 } }, + { "Panasonic", "DMC-LX3", Incandescent, 0, { 1.346008, 1, 2.269962, 0 } }, + + { "Panasonic", "DMC-LX5", Daylight, 0, { 1.9202, 1, 1.7567, 0 } }, + { "Panasonic", "DMC-LX5", Cloudy, 0, { 2.0760, 1, 1.6388, 0 } }, + { "Panasonic", "DMC-LX5", Shade, 0, { 2.1635, 1, 1.5817, 0 } }, + { "Panasonic", "DMC-LX5", Flash, 0, { 2.0760, 1, 1.6388, 0 } }, + { "Panasonic", "DMC-LX5", Incandescent, 0, { 1.2243, 1, 2.5741, 0 } }, + + { "Panasonic", "DMC-LX7", Daylight, -9, { 2.1358, 1, 1.5547, 0 } }, + { "Panasonic", "DMC-LX7", Daylight, 0, { 1.8906, 1, 1.7698, 0 } }, + { "Panasonic", "DMC-LX7", Daylight, 9, { 1.6755, 1, 2.0868, 0 } }, + { "Panasonic", "DMC-LX7", Cloudy, -9, { 2.2906, 1, 1.4226, 0 } }, + { "Panasonic", "DMC-LX7", Cloudy, 0, { 2.0341, 1, 1.6250, 0 } }, + { "Panasonic", "DMC-LX7", Cloudy, 9, { 1.8000, 1, 1.9132, 0 } }, + { "Panasonic", "DMC-LX7", Shade, -9, { 2.4415, 1, 1.3283, 0 } }, + { "Panasonic", "DMC-LX7", Shade, 0, { 2.1623, 1, 1.5132, 0 } }, + { "Panasonic", "DMC-LX7", Shade, 9, { 1.9170, 1, 1.7849, 0 } }, + { "Panasonic", "DMC-LX7", Flash, -9, { 2.3660, 1, 1.4679, 0 } }, + { "Panasonic", "DMC-LX7", Flash, 0, { 2.0943, 1, 1.6679, 0 } }, + { "Panasonic", "DMC-LX7", Flash, 9, { 1.8566, 1, 1.9698, 0 } }, + { "Panasonic", "DMC-LX7", Incandescent, -9, { 1.4566, 1, 2.4377, 0 } }, + { "Panasonic", "DMC-LX7", Incandescent, 0, { 1.2917, 1, 2.7841, 0 } }, + { "Panasonic", "DMC-LX7", Incandescent, 9, { 1.1434, 1, 3.2755, 0 } }, + + { "Panasonic", "DMC-LX100", Daylight, 0, { 2.316406, 1, 1.601563, 0 } }, + { "Panasonic", "DMC-LX100", Cloudy, 0, { 2.468750, 1, 1.484375, 0 } }, + { "Panasonic", "DMC-LX100", Shade, 0, { 2.640625, 1, 1.410156, 0 } }, + { "Panasonic", "DMC-LX100", Flash, 0, { 2.410156, 1, 1.578125, 0 } }, + { "Panasonic", "DMC-LX100", Incandescent, 0, { 1.585938, 1, 2.382813, 0 } }, + + /* It seems that the *ist D WB settings are not really presets. */ + { "PENTAX", "*ist D", Daylight, 0, { 1.460938, 1, 1.019531, 0 } }, + { "PENTAX", "*ist D", Shade, 0, { 1.734375, 1, 1.000000, 0 } }, + { "PENTAX", "*ist D", Cloudy, 0, { 1.634921, 1.015873, 1, 0 } }, + { "PENTAX", "*ist D", DaylightFluorescent, 0, { 1.657025, 1.057851, 1, 0 } }, + { "PENTAX", "*ist D", NeutralFluorescent, 0, { 1.425781, 1, 1.117188, 0 } }, + { "PENTAX", "*ist D", WhiteFluorescent, 0, { 1.328125, 1, 1.210938, 0 } }, + { "PENTAX", "*ist D", Tungsten, 0, { 1.000000, 1, 2.226563, 0 } }, + { "PENTAX", "*ist D", Flash, 0, { 1.750000, 1, 1.000000, 0 } }, + + /* It seems that the *ist DL WB settings are not really presets. */ + { "PENTAX", "*ist DL", Daylight, 0, { 1.546875, 1, 1.007812, 0 } }, + { "PENTAX", "*ist DL", Shade, 0, { 1.933594, 1, 1.027344, 0 } }, + { "PENTAX", "*ist DL", Cloudy, 0, { 1.703125, 1, 1.003906, 0 } }, + { "PENTAX", "*ist DL", DaylightFluorescent, 0, { 2.593909, 1.299492, 1, 0 } }, + { "PENTAX", "*ist DL", NeutralFluorescent, 0, { 1.539062, 1, 1.003906, 0 } }, + { "PENTAX", "*ist DL", WhiteFluorescent, 0, { 1.390625, 1, 1.117188, 0 } }, + { "PENTAX", "*ist DL", Tungsten, 0, { 1.000000, 1, 2.074219, 0 } }, + { "PENTAX", "*ist DL", Flash, 0, { 1.621094, 1, 1.027344, 0 } }, + + { "PENTAX", "*ist DL2", Daylight, 0, { 1.491333, 1, 1.000000, 0 } }, + { "PENTAX", "*ist DL2", Shade, 0, { 1.797485, 1, 0.763184, 0 } }, + { "PENTAX", "*ist DL2", Cloudy, 0, { 1.612305, 1, 0.896729, 0 } }, + { "PENTAX", "*ist DL2", Tungsten, 0, { 0.846924, 1, 2.078125, 0 } }, + { "PENTAX", "*ist DL2", DaylightFluorescent, 0, { 1.748169, 1, 1.015137, 0 } }, + { "PENTAX", "*ist DL2", NeutralFluorescent, 0, { 1.446899, 1, 1.133545, 0 } }, + { "PENTAX", "*ist DL2", WhiteFluorescent, 0, { 1.286377, 1, 1.377808, 0 } }, + { "PENTAX", "*ist DL2", Flash, 0, { 1.553101, 1, 0.937012, 0 } }, + + /* It seems that the *ist DS WB settings are not really presets. */ + { "PENTAX", "*ist DS", Daylight, 0, { 1.632812, 1, 1.000000, 0 } }, + { "PENTAX", "*ist DS", Shade, 0, { 1.964844, 1, 1.000000, 0 } }, + { "PENTAX", "*ist DS", Cloudy, 0, { 1.761719, 1, 1.000000, 0 } }, + { "PENTAX", "*ist DS", DaylightFluorescent, 0, { 1.910156, 1, 1.000000, 0 } }, + { "PENTAX", "*ist DS", NeutralFluorescent, 0, { 1.521569, 1.003922, 1, 0 } }, + { "PENTAX", "*ist DS", WhiteFluorescent, 0, { 1.496094, 1, 1.023438, 0 } }, + { "PENTAX", "*ist DS", Tungsten, 0, { 1.000000, 1, 2.027344, 0 } }, + { "PENTAX", "*ist DS", Flash, 0, { 1.695312, 1, 1.000000, 0 } }, + + { "PENTAX", "K10D", Daylight, 0, { 1.660156, 1, 1.066406, 0 } }, + { "PENTAX", "K10D", Shade, 0, { 2.434783, 1.236715, 1, 0 } }, + { "PENTAX", "K10D", Cloudy, 0, { 1.872428, 1.053498, 1, 0 } }, + { "PENTAX", "K10D", DaylightFluorescent, 0, { 2.121094, 1, 1.078125, 0 } }, + { "PENTAX", "K10D", NeutralFluorescent, 0, { 1.773438, 1, 1.226562, 0 } }, + { "PENTAX", "K10D", WhiteFluorescent, 0, { 1.597656, 1, 1.488281, 0 } }, + { "PENTAX", "K10D", Tungsten, 0, { 1.000000, 1, 2.558594, 0 } }, + { "PENTAX", "K10D", Flash, 0, { 1.664062, 1, 1.046875, 0 } }, + + /* DSP Firmware version 1.04.00.11 */ + { "PENTAX", "K20D", Daylight, 0, { 1.578735, 1, 1.263428, 0 } }, + { "PENTAX", "K20D", Shade, 0, { 1.800293, 1, 0.961304, 0 } }, + { "PENTAX", "K20D", Cloudy, 0, { 1.673706, 1, 1.116943, 0 } }, + { "PENTAX", "K20D", DaylightFluorescent, 0, { 2.089111, 1, 1.190186, 0 } }, + { "PENTAX", "K20D", NeutralFluorescent, 0, { 1.772583, 1, 1.354980, 0 } }, + { "PENTAX", "K20D", WhiteFluorescent, 0, { 1.653931, 1, 1.684570, 0 } }, + { "PENTAX", "K20D", Tungsten, 0, { 1.012939, 1, 2.343750, 0 } }, + { "PENTAX", "K20D", Flash, 0, { 1.673706, 1, 1.190186, 0 } }, + + { "PENTAX", "K100D", Daylight, 0, { 1.468750, 1, 1.023438, 0 } }, + { "PENTAX", "K100D", Shade, 0, { 1.769531, 1, 1.000000, 0 } }, + { "PENTAX", "K100D", Cloudy, 0, { 1.589844, 1, 1.000000, 0 } }, + { "PENTAX", "K100D", DaylightFluorescent, 0, { 1.722656, 1, 1.039063, 0 } }, + { "PENTAX", "K100D", NeutralFluorescent, 0, { 1.425781, 1, 1.160156, 0 } }, + { "PENTAX", "K100D", WhiteFluorescent, 0, { 1.265625, 1, 1.414063, 0 } }, + { "PENTAX", "K100D", Tungsten, 0, { 1, 1.015873, 2.055556, 0 } }, + { "PENTAX", "K100D", Flash, 0, { 1.527344, 1, 1.000000, 0 } }, + + { "PENTAX", "K100D Super", Daylight, 0, { 1.593750, 1, 1.011719, 0 } }, + { "PENTAX", "K100D Super", Shade, 0, { 1.917969, 1, 1.000000, 0 } }, + { "PENTAX", "K100D Super", Cloudy, 0, { 1.703125, 1, 1.015625, 0 } }, + { "PENTAX", "K100D Super", DaylightFluorescent, 0, { 1.708502, 1.036437, 1, 0 } }, + { "PENTAX", "K100D Super", NeutralFluorescent, 0, { 1.634538, 1.028112, 1, 0 } }, + { "PENTAX", "K100D Super", WhiteFluorescent, 0, { 1.425781, 1, 1.136719, 0 } }, + { "PENTAX", "K100D Super", Tungsten, 0, { 1.015625, 1, 2.046875, 0 } }, + { "PENTAX", "K100D Super", Flash, 0, { 1.670588, 1.003922, 1, 0 } }, + + { "PENTAX", "K110D", Daylight, 0, { 1.468750, 1, 1.023438, 0 } }, + { "PENTAX", "K110D", Shade, 0, { 1.769531, 1, 1.000000, 0 } }, + { "PENTAX", "K110D", Cloudy, 0, { 1.589844, 1, 1.000000, 0 } }, + { "PENTAX", "K110D", DaylightFluorescent, 0, { 1.722656, 1, 1.039063, 0 } }, + { "PENTAX", "K110D", NeutralFluorescent, 0, { 1.425781, 1, 1.160156, 0 } }, + { "PENTAX", "K110D", WhiteFluorescent, 0, { 1.265625, 1, 1.414063, 0 } }, + { "PENTAX", "K110D", Tungsten, 0, { 1, 1.015873, 2.055556, 0 } }, + { "PENTAX", "K110D", Flash, 0, { 1.527344, 1, 1.000000, 0 } }, + + { "PENTAX", "K200D", Daylight, 0, { 1.804688, 1, 1.304688, 0 } }, + { "PENTAX", "K200D", Shade, 0, { 2.140625, 1, 1.085937, 0 } }, + { "PENTAX", "K200D", Cloudy, 0, { 1.957031, 1, 1.179687, 0 } }, + { "PENTAX", "K200D", DaylightFluorescent, 0, { 2.121094, 1, 1.195313, 0 } }, + { "PENTAX", "K200D", NeutralFluorescent, 0, { 1.773438, 1, 1.359375, 0 } }, + { "PENTAX", "K200D", WhiteFluorescent, 0, { 1.597656, 1, 1.648437, 0 } }, + { "PENTAX", "K200D", Tungsten, 0, { 1.000000, 1, 2.835937, 0 } }, + { "PENTAX", "K200D", Flash, 0, { 1.917969, 1, 1.214844, 0 } }, + + /* PENTAX K-01 Firmware Version 1.00 */ + { "PENTAX", "K-01", Daylight, 0, { 2.197021, 1, 1.613647, 0 } }, + { "PENTAX", "K-01", Shade, 0, { 2.625122, 1, 1.204348, 0 } }, + { "PENTAX", "K-01", Cloudy, 0, { 2.367188, 1, 1.379761, 0 } }, + { "PENTAX", "K-01", DaylightFluorescent, 0, { 2.712769, 1, 1.555176, 0 } }, + { "PENTAX", "K-01", WhiteFluorescent, 0, { 2.325928, 1, 1.730591, 0 } }, + { "PENTAX", "K-01", CoolWhiteFluorescent, 0, { 2.114502, 1, 2.139893, 0 } }, + { "PENTAX", "K-01", WarmWhiteFluorescent, 0, { 1.768921, 1, 2.677734, 0 } }, + { "PENTAX", "K-01", Tungsten, 0, { 1.320313, 1, 2.993530, 0 } }, + { "PENTAX", "K-01", Flash, 0, { 2.490967, 1, 1.484985, 0 } }, + + /* PENTAX K-1 Firmware Version 1.10 */ + { "PENTAX", "K-1", Daylight, 0, { 2.14062, 1, 1.66406, 0 } }, + { "PENTAX", "K-1", Shade, 0, { 2.65625, 1, 1.25000, 0 } }, + { "PENTAX", "K-1", Cloudy, 0, { 2.37109, 1, 1.43750, 0 } }, + { "PENTAX", "K-1", DaylightFluorescent, 0, { 2.61328, 1, 1.60938, 0 } }, + { "PENTAX", "K-1", CoolWhiteFluorescent, 0, { 2.23047, 1, 1.82031, 0 } }, + { "PENTAX", "K-1", WhiteFluorescent, 0, { 2.01953, 1, 2.19531, 0 } }, + { "PENTAX", "K-1", WarmWhiteFluorescent, 0, { 1.70312, 1, 2.77734, 0 } }, + { "PENTAX", "K-1", Tungsten, 0, { 1.32422, 1, 2.92969, 0 } }, + { "PENTAX", "K-1", "2500K", 0, { 1.14062, 1, 2.75391, 0 } }, + { "PENTAX", "K-1", "3000K", 0, { 1.40234, 1, 2.33984, 0 } }, + { "PENTAX", "K-1", "5000K", 0, { 2.07812, 1, 1.54688, 0 } }, + { "PENTAX", "K-1", "5500K", 0, { 2.19141, 1, 1.45703, 0 } }, + + /* PENTAX K-3 Firmware version 1.00 */ + { "PENTAX", "K-3", Daylight, 0, { 2.31250, 1, 1.48047, 0 } }, + { "PENTAX", "K-3", Shade, 0, { 2.78516, 1, 1.16797, 0 } }, + { "PENTAX", "K-3", Cloudy, 0, { 2.49219, 1, 1.35156, 0 } }, + { "PENTAX", "K-3", Tungsten, 0, { 1.35938, 1, 2.74609, 0 } }, + { "PENTAX", "K-3", DaylightFluorescent, 0, { 2.71094, 1, 1.51953, 0 } }, + { "PENTAX", "K-3", DayWhiteFluorescent, 0, { 2.30469, 1, 1.70312, 0 } }, + { "PENTAX", "K-3", WhiteFluorescent, 0, { 2.07031, 1, 2.03516, 0 } }, + { "PENTAX", "K-3", WarmWhiteFluorescent, 0, { 1.74609, 1, 2.53125, 0 } }, + { "PENTAX", "K-3", Flash, 0, { 2.56641, 1, 1.31641, 0 } }, + + { "PENTAX", "K-5", Daylight, 0, { 2.1211, 1, 1.5781, 0 } }, + { "PENTAX", "K-5", Shade, 0, { 2.5312, 1, 1.1758, 0 } }, + { "PENTAX", "K-5", Cloudy, 0, { 2.2852, 1, 1.3477, 0 } }, + { "PENTAX", "K-5", DaylightFluorescent, 0, { 2.6172, 1, 1.5195, 0 } }, + { "PENTAX", "K-5", WhiteFluorescent, 0, { 2.2422, 1, 1.6914, 0 } }, + { "PENTAX", "K-5", CoolWhiteFluorescent, 0, { 2.0391, 1, 2.0898, 0 } }, + { "PENTAX", "K-5", WarmWhiteFluorescent, 0, { 1.7070, 1, 2.6172, 0 } }, + { "PENTAX", "K-5", Tungsten, 0, { 1.2734, 1, 2.9258, 0 } }, + { "PENTAX", "K-5", Flash, 0, { 2.4023, 1, 1.4492, 0 } }, + { "PENTAX", "K-5", "2500K", 0, { 1.1445, 1, 2.7891, 0 } }, + { "PENTAX", "K-5", "3000K", 0, { 1.3867, 1, 2.2578, 0 } }, + { "PENTAX", "K-5", "4000K", 0, { 1.7695, 1, 1.7344, 0 } }, + { "PENTAX", "K-5", "5000K", 0, { 2.0508, 1, 1.4883, 0 } }, + { "PENTAX", "K-5", "6000K", 0, { 2.2578, 1, 1.3477, 0 } }, + { "PENTAX", "K-5", "7000K", 0, { 2.4141, 1, 1.2578, 0 } }, + { "PENTAX", "K-5", "8000K", 0, { 2.5312, 1, 1.1992, 0 } }, + { "PENTAX", "K-5", "9000K", 0, { 2.6250, 1, 1.1523, 0 } }, + { "PENTAX", "K-5", "10000K", 0, { 2.6992, 1, 1.1211, 0 } }, + + // copied from K-5 II s + { "PENTAX", "K-5 II", Daylight, 0, { 2.136719, 1, 1.628906, 0 } }, + { "PENTAX", "K-5 II", Shade, 0, { 2.550781, 1, 1.214844, 0 } }, + { "PENTAX", "K-5 II", Cloudy, 0, { 2.300781, 1, 1.390625, 0 } }, + { "PENTAX", "K-5 II", DaylightFluorescent, 0, { 2.636719, 1, 1.566406, 0 } }, + { "PENTAX", "K-5 II", WhiteFluorescent, 0, { 2.261719, 1, 1.746094, 0 } }, + { "PENTAX", "K-5 II", CoolWhiteFluorescent, 0, { 2.054688, 1, 2.156250, 0 } }, + { "PENTAX", "K-5 II", WarmWhiteFluorescent, 0, { 1.718750, 1, 2.699219, 0 } }, + { "PENTAX", "K-5 II", Tungsten, 0, { 1.265625, 1, 2.816406, 0 } }, + { "PENTAX", "K-5 II", Flash, 0, { 1.851562, 1, 1.792969, 0 } }, + + // firmware K-5 II s Ver 1.02 + { "PENTAX", "K-5 II s", Daylight, 0, { 2.136719, 1, 1.628906, 0 } }, + { "PENTAX", "K-5 II s", Shade, 0, { 2.550781, 1, 1.214844, 0 } }, + { "PENTAX", "K-5 II s", Cloudy, 0, { 2.300781, 1, 1.390625, 0 } }, + { "PENTAX", "K-5 II s", DaylightFluorescent, 0, { 2.636719, 1, 1.566406, 0 } }, + { "PENTAX", "K-5 II s", WhiteFluorescent, 0, { 2.261719, 1, 1.746094, 0 } }, + { "PENTAX", "K-5 II s", CoolWhiteFluorescent, 0, { 2.054688, 1, 2.156250, 0 } }, + { "PENTAX", "K-5 II s", WarmWhiteFluorescent, 0, { 1.718750, 1, 2.699219, 0 } }, + { "PENTAX", "K-5 II s", Tungsten, 0, { 1.265625, 1, 2.816406, 0 } }, + { "PENTAX", "K-5 II s", Flash, 0, { 1.851562, 1, 1.792969, 0 } }, + + { "PENTAX", "K-7", Daylight, 0, { 1.808594, 1, 1.285156, 0 } }, + { "PENTAX", "K-7", Shade, 0, { 2.207171, 1.019920, 1, 0 } }, + { "PENTAX", "K-7", Cloudy, 0, { 1.960937, 1, 1.136719, 0 } }, + { "PENTAX", "K-7", DaylightFluorescent, 0, { 2.281250, 1, 1.191406, 0 } }, + { "PENTAX", "K-7", NeutralFluorescent, 0, { 1.937500, 1, 1.355469, 0 } }, + { "PENTAX", "K-7", CoolWhiteFluorescent, 0, { 1.808594, 1, 1.687500, 0 } }, + { "PENTAX", "K-7", WarmWhiteFluorescent, 0, { 1.589844, 1, 2.164063, 0 } }, + { "PENTAX", "K-7", Tungsten, 0, { 1.105469, 1, 2.347656, 0 } }, + { "PENTAX", "K-7", Flash, 0, { 2.093750, 1, 1.082031, 0 } }, + + // PENTAX K-30 (FW v1.05) + { "PENTAX", "K-30", Daylight, 0, { 2.213013, 1, 1.629150, 0 } }, + { "PENTAX", "K-30", Shade, 0, { 2.644287, 1, 1.215942, 0 } }, + { "PENTAX", "K-30", Cloudy, 0, { 2.384521, 1, 1.392944, 0 } }, + { "PENTAX", "K-30", DaylightFluorescent, 0, { 2.732544, 1, 1.570068, 0 } }, + { "PENTAX", "K-30", WhiteFluorescent, 0, { 2.342896, 1, 1.747192, 0 } }, + { "PENTAX", "K-30", CoolWhiteFluorescent, 0, { 2.130005, 1, 2.160400, 0 } }, + { "PENTAX", "K-30", WarmWhiteFluorescent, 0, { 1.781860, 1, 2.703369, 0 } }, + { "PENTAX", "K-30", Tungsten, 0, { 1.329956, 1, 3.022217, 0 } }, + { "PENTAX", "K-30", Flash, 0, { 2.509155, 1, 1.499268, 0 } }, + + /* PENTAX K-50 Firmware Version 1.00 */ + { "PENTAX", "K-50", Daylight, 0, { 2.244385, 1, 1.560303, 0 } }, + { "PENTAX", "K-50", Shade, 0, { 2.681641, 1, 1.164551, 0 } }, + { "PENTAX", "K-50", Cloudy, 0, { 2.418213, 1, 1.334229, 0 } }, + { "PENTAX", "K-50", DaylightFluorescent, 0, { 2.771240, 1, 1.503784, 0 } }, + { "PENTAX", "K-50", WhiteFluorescent, 0, { 2.376099, 1, 1.673462, 0 } }, + { "PENTAX", "K-50", CoolWhiteFluorescent, 0, { 2.160034, 1, 2.069214, 0 } }, + { "PENTAX", "K-50", WarmWhiteFluorescent, 0, { 1.807007, 1, 2.589355, 0 } }, + { "PENTAX", "K-50", Tungsten, 0, { 1.348755, 1, 2.894653, 0 } }, + { "PENTAX", "K-50", Flash, 0, { 2.544678, 1, 1.435913, 0 } }, + + /* PENTAX K-70 Firmware Version 1.10 */ + { "PENTAX", "K-70", Daylight, 0, { 2.144531, 1, 1.707031, 0 } }, + { "PENTAX", "K-70", Shade, 0, { 2.656250, 1, 1.250000, 0 } }, + { "PENTAX", "K-70", Cloudy, 0, { 2.378906, 1, 1.464844, 0 } }, + { "PENTAX", "K-70", Tungsten, 0, { 1.312500, 1, 2.976563, 0 } }, + { "PENTAX", "K-70", WarmWhiteFluorescent, 0, { 1.699219, 1, 2.910156, 0 } }, + { "PENTAX", "K-70", DayWhiteFluorescent, 0, { 2.230469, 1, 1.914063, 0 } }, + { "PENTAX", "K-70", DaylightFluorescent, 0, { 2.628906, 1, 1.671875, 0 } }, + { "PENTAX", "K-70", WhiteFluorescent, 0, { 2.019531, 1, 2.304688, 0 } }, + + /* PENTAX K-500 Firmware Version 1.00 */ + { "PENTAX", "K-500", Daylight, 0, { 2.207642, 1, 1.606079, 0 } }, + { "PENTAX", "K-500", Shade, 0, { 2.637695, 1, 1.198730, 0 } }, + { "PENTAX", "K-500", Cloudy, 0, { 2.378540, 1, 1.373413, 0 } }, + { "PENTAX", "K-500", DaylightFluorescent, 0, { 2.725830, 1, 1.547974, 0 } }, + { "PENTAX", "K-500", WhiteFluorescent, 0, { 2.337158, 1, 1.722534, 0 } }, + { "PENTAX", "K-500", CoolWhiteFluorescent, 0, { 2.124634, 1, 2.129883, 0 } }, + { "PENTAX", "K-500", WarmWhiteFluorescent, 0, { 1.777466, 1, 2.665283, 0 } }, + { "PENTAX", "K-500", Tungsten, 0, { 1.326660, 1, 2.979614, 0 } }, + { "PENTAX", "K-500", Flash, 0, { 2.502930, 1, 1.478149, 0 } }, + + { "PENTAX", "K-m", Daylight, 0, { 1.738281, 1, 1.363281, 0 } }, + { "PENTAX", "K-m", Shade, 0, { 2.027344, 1, 1.027344, 0 } }, + { "PENTAX", "K-m", Cloudy, 0, { 1.832031, 1, 1.183594, 0 } }, + { "PENTAX", "K-m", DaylightFluorescent, 0, { 2.183594, 1, 1.250000, 0 } }, + { "PENTAX", "K-m", NeutralFluorescent, 0, { 1.824219, 1, 1.417969, 0 } }, + { "PENTAX", "K-m", WhiteFluorescent, 0, { 1.644531, 1, 1.714844, 0 } }, + { "PENTAX", "K-m", Tungsten, 0, { 1.429687, 1, 1.980469, 0 } }, + { "PENTAX", "K-m", Flash, 0, { 1.738281, 1, 1.363281, 0 } }, + + /* Firmware version 1.11 */ + { "PENTAX", "K-r", Daylight, 0, { 1.8477, 1, 1.3906, 0 } }, + { "PENTAX", "K-r", Shade, 0, { 2.1133, 1, 1.0586, 0 } }, + { "PENTAX", "K-r", Cloudy, 0, { 1.9766, 1, 1.1445, 0 } }, + { "PENTAX", "K-r", DaylightFluorescent, 0, { 2.2617, 1, 1.3203, 0 } }, + { "PENTAX", "K-r", WhiteFluorescent, 0, { 1.9414, 1, 1.4688, 0 } }, + { "PENTAX", "K-r", CoolWhiteFluorescent, 0, { 1.7656, 1, 1.8164, 0 } }, + { "PENTAX", "K-r", WarmWhiteFluorescent, 0, { 1.4766, 1, 2.2734, 0 } }, + { "PENTAX", "K-r", Tungsten, 0, { 1.1016, 1, 2.5391, 0 } }, + { "PENTAX", "K-r", Flash, 0, { 2.0117, 1, 1.1172, 0 } }, + + { "PENTAX", "K-x", Daylight, 0, { 1.8803, 1, 1.4054, 0 } }, + { "PENTAX", "K-x", Shade, 0, { 2.2278, 1, 1.0309, 0 } }, + { "PENTAX", "K-x", Cloudy, 0, { 2.0077, 1, 1.1853, 0 } }, + { "PENTAX", "K-x", DaylightFluorescent, 0, { 2.3012, 1, 1.3359, 0 } }, + { "PENTAX", "K-x", WhiteFluorescent, 0, { 1.9730, 1, 1.4826, 0 } }, + { "PENTAX", "K-x", CoolWhiteFluorescent, 0, { 1.7915, 1, 1.8378, 0 } }, + { "PENTAX", "K-x", WarmWhiteFluorescent, 0, { 1.5019, 1, 2.2973, 0 } }, + { "PENTAX", "K-x", Tungsten, 0, { 1.0463, 1, 3.4015, 0 } }, + { "PENTAX", "K-x", Flash, 0, { 2.1120, 1, 1.2741, 0 } }, + + { "PENTAX", "K-S1", Daylight, 0, { 2.277344, 1, 1.656250, 0 } }, + { "PENTAX", "K-S1", Shade, 0, { 2.847656, 1, 1.230469, 0 } }, + { "PENTAX", "K-S1", Cloudy, 0, { 2.546875, 1, 1.429688, 0 } }, + { "PENTAX", "K-S1", Tungsten, 0, { 1.343750, 1, 3.089844, 0 } }, + { "PENTAX", "K-S1", WarmWhiteFluorescent, 0, { 1.777344, 1, 2.781250, 0 } }, + { "PENTAX", "K-S1", DayWhiteFluorescent, 0, { 2.367188, 1, 1.824219, 0 } }, + { "PENTAX", "K-S1", DaylightFluorescent, 0, { 2.761719, 1, 1.617188, 0 } }, + { "PENTAX", "K-S1", WhiteFluorescent, 0, { 2.125000, 1, 2.210938, 0 } }, + { "PENTAX", "K-S1", Flash, 0, { 2.613281, 1, 1.351562, 0 } }, + + { "PENTAX", "K-S2", Daylight, 0, { 2.257812, 1, 1.683594, 0 } }, + { "PENTAX", "K-S2", Shade, 0, { 2.882812, 1, 1.218750, 0 } }, + { "PENTAX", "K-S2", Cloudy, 0, { 2.574219, 1, 1.414062, 0 } }, + { "PENTAX", "K-S2", Tungsten, 0, { 1.234375, 1, 3.644531, 0 } }, + { "PENTAX", "K-S2", WarmWhiteFluorescent, 0, { 1.785156, 1, 2.769531, 0 } }, + { "PENTAX", "K-S2", DayWhiteFluorescent, 0, { 2.367188, 1, 1.832031, 0 } }, + { "PENTAX", "K-S2", DaylightFluorescent, 0, { 2.804688, 1, 1.625000, 0 } }, + { "PENTAX", "K-S2", WhiteFluorescent, 0, { 2.125000, 1, 2.199219, 0 } }, + { "PENTAX", "K-S2", Flash, 0, { 2.746094, 1, 1.359375, 0 } }, + + /* PENTAX Q Firmware Version 1.00 */ + { "PENTAX", "Q", Daylight, 0, { 1.515137, 1, 1.858890, 0 } }, + { "PENTAX", "Q", Shade, 0, { 1.818237, 1, 1.417951, 0 } }, + { "PENTAX", "Q", Cloudy, 0, { 1.704590, 1, 1.608584, 0 } }, + { "PENTAX", "Q", DaylightFluorescent, 0, { 1.969727, 1, 1.787356, 0 } }, + { "PENTAX", "Q", WhiteFluorescent, 0, { 1.742432, 1, 2.025679, 0 } }, + { "PENTAX", "Q", CoolWhiteFluorescent, 0, { 1.579590, 1, 2.502323, 0 } }, + { "PENTAX", "Q", WarmWhiteFluorescent, 0, { 1.325684, 1, 2.907435, 0 } }, + { "PENTAX", "Q", Tungsten, 0, { 0.969727, 1, 3.050501, 0 } }, + { "PENTAX", "Q", Flash, 0, { 1.829590, 1, 1.513328, 0 } }, + + /* PENTAX Q7 Firmware Version 1.00 */ + { "PENTAX", "Q7", Daylight, 0, { 1.668823, 1, 1.794344, 0 } }, + { "PENTAX", "Q7", Shade, 0, { 2.050293, 1, 1.401073, 0 } }, + { "PENTAX", "Q7", Cloudy, 0, { 1.923096, 1, 1.597708, 0 } }, + { "PENTAX", "Q7", DaylightFluorescent, 0, { 2.221069, 1, 1.769840, 0 } }, + { "PENTAX", "Q7", WhiteFluorescent, 0, { 1.907227, 1, 2.003291, 0 } }, + { "PENTAX", "Q7", CoolWhiteFluorescent, 0, { 1.780029, 1, 2.482628, 0 } }, + { "PENTAX", "Q7", WarmWhiteFluorescent, 0, { 1.494019, 1, 2.888212, 0 } }, + { "PENTAX", "Q7", Tungsten, 0, { 1.017212, 1, 3.146410, 0 } }, + { "PENTAX", "Q7", Flash, 0, { 1.986694, 1, 1.499451, 0 } }, + + /* PENTAX Q10 Firmware Version 1.00 */ + { "PENTAX", "Q10", Daylight, 0, { 1.561401, 1, 1.653244, 0 } }, + { "PENTAX", "Q10", Shade, 0, { 1.965088, 1, 1.327173, 0 } }, + { "PENTAX", "Q10", Cloudy, 0, { 1.843262, 1, 1.513464, 0 } }, + { "PENTAX", "Q10", DaylightFluorescent, 0, { 2.128906, 1, 1.676499, 0 } }, + { "PENTAX", "Q10", WhiteFluorescent, 0, { 1.828003, 1, 1.897674, 0 } }, + { "PENTAX", "Q10", CoolWhiteFluorescent, 0, { 1.706177, 1, 2.351775, 0 } }, + { "PENTAX", "Q10", WarmWhiteFluorescent, 0, { 1.431885, 1, 2.735985, 0 } }, + { "PENTAX", "Q10", Tungsten, 0, { 0.974976, 1, 2.980539, 0 } }, + { "PENTAX", "Q10", Flash, 0, { 1.904175, 1, 1.420318, 0 } }, + + /* PENTAX 645D Firmware Version 1.00 */ + { "PENTAX", "645D", Daylight, 0, { 1.805664, 1, 1.327393, 0 } }, + { "PENTAX", "645D", Shade, 0, { 2.092651, 1, 0.983276, 0 } }, + { "PENTAX", "645D", Cloudy, 0, { 1.916016, 1, 1.106079, 0 } }, + { "PENTAX", "645D", DaylightFluorescent, 0, { 2.207397, 1, 1.294556, 0 } }, + { "PENTAX", "645D", WhiteFluorescent, 0, { 1.889526, 1, 1.458496, 0 } }, + { "PENTAX", "645D", CoolWhiteFluorescent, 0, { 1.748291, 1, 1.737061, 0 } }, + { "PENTAX", "645D", WarmWhiteFluorescent, 0, { 1.492188, 1, 2.146729, 0 } }, + { "PENTAX", "645D", Tungsten, 0, { 1.130249, 1, 2.097656, 0 } }, + { "PENTAX", "645D", Flash, 0, { 1.986694, 1, 1.081543, 0 } }, + + { "RICOH", "Caplio GX100", Daylight, 0, { 1.910001, 1, 1.820002, 0 } }, + { "RICOH", "Caplio GX100", Cloudy, 0, { 2.240003, 1, 1.530002, 0 } }, + { "RICOH", "Caplio GX100", Incandescent, 0, { 1.520002, 1, 2.520003, 0 } }, + { "RICOH", "Caplio GX100", Fluorescent, 0, { 1.840001, 1, 1.970001, 0 } }, + + /* RICOH GR Firmware Version 4.00 */ + { "RICOH", "GR", Daylight, 0, { 2.980000, 1, 1.580000, 0 } }, + { "RICOH", "GR", Shade, 0, { 3.450000, 1, 1.360000, 0 } }, + { "RICOH", "GR", Cloudy, 0, { 3.170000, 1, 1.500000, 0 } }, + { "RICOH", "GR", Incandescent, 0, { 1.920000, 1, 2.530000, 0 } }, + { "RICOH", "GR", IncandescentWarm, 0, { 2.090000, 1, 2.030000, 0 } }, + { "RICOH", "GR", DaylightFluorescent, 0, { 3.220000, 1, 1.510000, 0 } }, + { "RICOH", "GR", WhiteFluorescent, 0, { 2.860000, 1, 1.700000, 0 } }, + { "RICOH", "GR", CoolWhiteFluorescent, 0, { 2.610000, 1, 2.080000, 0 } }, + { "RICOH", "GR", WarmWhiteFluorescent, 0, { 2.240000, 1, 2.160000, 0 } }, + { "RICOH", "GR", "5000K", 0, { 2.890000, 1, 1.520000, 0 } }, + + { "SAMSUNG", "EX1", Daylight, 0, { 1.8711, 1, 2.0039, 0 } }, + { "SAMSUNG", "EX1", Cloudy, 0, { 2.3672, 1, 1.6797, 0 } }, + { "SAMSUNG", "EX1", DaylightFluorescent, 0, { 1.9492, 1, 2.0586, 0 } }, + { "SAMSUNG", "EX1", WhiteFluorescent, 0, { 1.4844, 1, 2.7852, 0 } }, + { "SAMSUNG", "EX1", Tungsten, 0, { 1.2500, 1, 3.6834, 0 } }, + + { "SAMSUNG", "GX-1S", Daylight, 0, { 1.574219, 1, 1.109375, 0 } }, + { "SAMSUNG", "GX-1S", Shade, 0, { 1.855469, 1, 1.000000, 0 } }, + { "SAMSUNG", "GX-1S", Cloudy, 0, { 1.664062, 1, 1.000000, 0 } }, + { "SAMSUNG", "GX-1S", DaylightFluorescent, 0, { 1.854251, 1.036437, 1, 0 } }, + { "SAMSUNG", "GX-1S", NeutralFluorescent, 0, { 1.574219, 1, 1.171875, 0 } }, + { "SAMSUNG", "GX-1S", WhiteFluorescent, 0, { 1.363281, 1, 1.335938, 0 } }, + { "SAMSUNG", "GX-1S", Tungsten, 0, { 1.000000, 1, 2.226562, 0 } }, + { "SAMSUNG", "GX-1S", Flash, 0, { 1.609375, 1, 1.031250, 0 } }, + + { "SAMSUNG", "GX10", Daylight, 0, { 1.660156, 1, 1.066406, 0 } }, + { "SAMSUNG", "GX10", Shade, 0, { 2.434783, 1.236715, 1, 0 } }, + { "SAMSUNG", "GX10", Cloudy, 0, { 1.872428, 1.053498, 1, 0 } }, + { "SAMSUNG", "GX10", DaylightFluorescent, 0, { 2.121094, 1, 1.078125, 0 } }, + { "SAMSUNG", "GX10", NeutralFluorescent, 0, { 1.773438, 1, 1.226562, 0 } }, + { "SAMSUNG", "GX10", WhiteFluorescent, 0, { 1.597656, 1, 1.488281, 0 } }, + { "SAMSUNG", "GX10", Tungsten, 0, { 1.000000, 1, 2.558594, 0 } }, + { "SAMSUNG", "GX10", Flash, 0, { 1.664062, 1, 1.046875, 0 } }, + + // Copied from SAMSUNG NX100 + { "SAMSUNG", "NX5", Daylight, -7, { 1.566333, 1, 1.526753, 0 } }, + { "SAMSUNG", "NX5", Daylight, -6, { 1.593941, 1, 1.475202, 0 } }, + { "SAMSUNG", "NX5", Daylight, -5, { 1.621793, 1, 1.423650, 0 } }, + { "SAMSUNG", "NX5", Daylight, -4, { 1.649401, 1, 1.371854, 0 } }, + { "SAMSUNG", "NX5", Daylight, -3, { 1.677010, 1, 1.320303, 0 } }, + { "SAMSUNG", "NX5", Daylight, -2, { 1.704618, 1, 1.268507, 0 } }, + { "SAMSUNG", "NX5", Daylight, -1, { 1.732470, 1, 1.216956, 0 } }, + { "SAMSUNG", "NX5", Daylight, 0, { 1.760078, 1, 1.165404, 0 } }, + { "SAMSUNG", "NX5", Daylight, 1, { 1.790129, 1, 1.137063, 0 } }, + { "SAMSUNG", "NX5", Daylight, 2, { 1.820425, 1, 1.108722, 0 } }, + { "SAMSUNG", "NX5", Daylight, 3, { 1.850721, 1, 1.080381, 0 } }, + { "SAMSUNG", "NX5", Daylight, 4, { 1.880772, 1, 1.052040, 0 } }, + { "SAMSUNG", "NX5", Daylight, 5, { 1.911068, 1, 1.023699, 0 } }, + { "SAMSUNG", "NX5", Daylight, 6, { 1.941377, 1, 0.995622, 0 } }, + { "SAMSUNG", "NX5", Daylight, 7, { 1.971874, 1, 0.967384, 0 } }, + { "SAMSUNG", "NX5", Cloudy, -7, { 1.638896, 1, 1.446372, 0 } }, + { "SAMSUNG", "NX5", Cloudy, -6, { 1.667725, 1, 1.397508, 0 } }, + { "SAMSUNG", "NX5", Cloudy, -5, { 1.696555, 1, 1.348644, 0 } }, + { "SAMSUNG", "NX5", Cloudy, -4, { 1.725629, 1, 1.299780, 0 } }, + { "SAMSUNG", "NX5", Cloudy, -3, { 1.754459, 1, 1.250672, 0 } }, + { "SAMSUNG", "NX5", Cloudy, -2, { 1.783533, 1, 1.201808, 0 } }, + { "SAMSUNG", "NX5", Cloudy, -1, { 1.812607, 1, 1.152944, 0 } }, + { "SAMSUNG", "NX5", Cloudy, 0, { 1.841437, 1, 1.103836, 0 } }, + { "SAMSUNG", "NX5", Cloudy, 1, { 1.872954, 1, 1.077205, 0 } }, + { "SAMSUNG", "NX5", Cloudy, 2, { 1.904471, 1, 1.050330, 0 } }, + { "SAMSUNG", "NX5", Cloudy, 3, { 1.936233, 1, 1.023455, 0 } }, + { "SAMSUNG", "NX5", Cloudy, 4, { 1.967852, 1, 0.996834, 0 } }, + { "SAMSUNG", "NX5", Cloudy, 5, { 1.999289, 1, 0.969905, 0 } }, + { "SAMSUNG", "NX5", Cloudy, 6, { 2.030876, 1, 0.943088, 0 } }, + { "SAMSUNG", "NX5", Cloudy, 7, { 2.062458, 1, 0.916275, 0 } }, + { "SAMSUNG", "NX5", WhiteFluorescent, -7, { 1.526020, 1, 2.316638, 0 } }, + { "SAMSUNG", "NX5", WhiteFluorescent, -6, { 1.553140, 1, 2.238212, 0 } }, + { "SAMSUNG", "NX5", WhiteFluorescent, -5, { 1.580015, 1, 2.159785, 0 } }, + { "SAMSUNG", "NX5", WhiteFluorescent, -4, { 1.606890, 1, 2.081603, 0 } }, + { "SAMSUNG", "NX5", WhiteFluorescent, -3, { 1.634009, 1, 2.003176, 0 } }, + { "SAMSUNG", "NX5", WhiteFluorescent, -2, { 1.660884, 1, 1.924750, 0 } }, + { "SAMSUNG", "NX5", WhiteFluorescent, -1, { 1.687760, 1, 1.846567, 0 } }, + { "SAMSUNG", "NX5", WhiteFluorescent, 0, { 1.714879, 1, 1.768141, 0 } }, + { "SAMSUNG", "NX5", WhiteFluorescent, 1, { 1.744197, 1, 1.725140, 0 } }, + { "SAMSUNG", "NX5", WhiteFluorescent, 2, { 1.773516, 1, 1.682140, 0 } }, + { "SAMSUNG", "NX5", WhiteFluorescent, 3, { 1.803078, 1, 1.639384, 0 } }, + { "SAMSUNG", "NX5", WhiteFluorescent, 4, { 1.832397, 1, 1.596384, 0 } }, + { "SAMSUNG", "NX5", WhiteFluorescent, 5, { 1.861959, 1, 1.553384, 0 } }, + { "SAMSUNG", "NX5", WhiteFluorescent, 6, { 1.891522, 1, 1.510628, 0 } }, + { "SAMSUNG", "NX5", WhiteFluorescent, 7, { 1.920596, 1, 1.467628, 0 } }, + { "SAMSUNG", "NX5", NeutralFluorescent, -7, { 1.691180, 1, 1.884437, 0 } }, + { "SAMSUNG", "NX5", NeutralFluorescent, -6, { 1.720987, 1, 1.821158, 0 } }, + { "SAMSUNG", "NX5", NeutralFluorescent, -5, { 1.751038, 1, 1.757146, 0 } }, + { "SAMSUNG", "NX5", NeutralFluorescent, -4, { 1.780845, 1, 1.693379, 0 } }, + { "SAMSUNG", "NX5", NeutralFluorescent, -3, { 1.810897, 1, 1.629612, 0 } }, + { "SAMSUNG", "NX5", NeutralFluorescent, -2, { 1.840704, 1, 1.565844, 0 } }, + { "SAMSUNG", "NX5", NeutralFluorescent, -1, { 1.870755, 1, 1.502077, 0 } }, + { "SAMSUNG", "NX5", NeutralFluorescent, 0, { 1.900318, 1, 1.438309, 0 } }, + { "SAMSUNG", "NX5", NeutralFluorescent, 1, { 1.933056, 1, 1.403616, 0 } }, + { "SAMSUNG", "NX5", NeutralFluorescent, 2, { 1.965795, 1, 1.368678, 0 } }, + { "SAMSUNG", "NX5", NeutralFluorescent, 3, { 1.998045, 1, 1.333741, 0 } }, + { "SAMSUNG", "NX5", NeutralFluorescent, 4, { 2.030784, 1, 1.298803, 0 } }, + { "SAMSUNG", "NX5", NeutralFluorescent, 5, { 2.063279, 1, 1.263621, 0 } }, + { "SAMSUNG", "NX5", NeutralFluorescent, 6, { 2.095773, 1, 1.228927, 0 } }, + { "SAMSUNG", "NX5", NeutralFluorescent, 7, { 2.128756, 1, 1.193990, 0 } }, + { "SAMSUNG", "NX5", DaylightFluorescent, -7, { 1.995358, 1, 1.613731, 0 } }, + { "SAMSUNG", "NX5", DaylightFluorescent, -6, { 2.030784, 1, 1.559492, 0 } }, + { "SAMSUNG", "NX5", DaylightFluorescent, -5, { 2.065722, 1, 1.504764, 0 } }, + { "SAMSUNG", "NX5", DaylightFluorescent, -4, { 2.101393, 1, 1.450037, 0 } }, + { "SAMSUNG", "NX5", DaylightFluorescent, -3, { 2.136330, 1, 1.395553, 0 } }, + { "SAMSUNG", "NX5", DaylightFluorescent, -2, { 2.171757, 1, 1.341070, 0 } }, + { "SAMSUNG", "NX5", DaylightFluorescent, -1, { 2.207183, 1, 1.286343, 0 } }, + { "SAMSUNG", "NX5", DaylightFluorescent, 0, { 2.242365, 1, 1.231859, 0 } }, + { "SAMSUNG", "NX5", DaylightFluorescent, 1, { 2.280723, 1, 1.202052, 0 } }, + { "SAMSUNG", "NX5", DaylightFluorescent, 2, { 2.319326, 1, 1.172001, 0 } }, + { "SAMSUNG", "NX5", DaylightFluorescent, 3, { 2.357684, 1, 1.142194, 0 } }, + { "SAMSUNG", "NX5", DaylightFluorescent, 4, { 2.396042, 1, 1.112143, 0 } }, + { "SAMSUNG", "NX5", DaylightFluorescent, 5, { 2.434645, 1, 1.082336, 0 } }, + { "SAMSUNG", "NX5", DaylightFluorescent, 6, { 2.473003, 1, 1.052284, 0 } }, + { "SAMSUNG", "NX5", DaylightFluorescent, 7, { 2.511361, 1, 1.022233, 0 } }, + { "SAMSUNG", "NX5", Tungsten, -7, { 0.951650, 1, 3.086007, 0 } }, + { "SAMSUNG", "NX5", Tungsten, -6, { 0.968307, 1, 2.981315, 0 } }, + { "SAMSUNG", "NX5", Tungsten, -5, { 0.985078, 1, 2.877497, 0 } }, + { "SAMSUNG", "NX5", Tungsten, -4, { 1.001710, 1, 2.772538, 0 } }, + { "SAMSUNG", "NX5", Tungsten, -3, { 1.018568, 1, 2.668214, 0 } }, + { "SAMSUNG", "NX5", Tungsten, -2, { 1.035426, 1, 2.563645, 0 } }, + { "SAMSUNG", "NX5", Tungsten, -1, { 1.052284, 1, 2.459565, 0 } }, + { "SAMSUNG", "NX5", Tungsten, 0, { 1.069142, 1, 2.354996, 0 } }, + { "SAMSUNG", "NX5", Tungsten, 1, { 1.087466, 1, 2.298070, 0 } }, + { "SAMSUNG", "NX5", Tungsten, 2, { 1.105790, 1, 2.240655, 0 } }, + { "SAMSUNG", "NX5", Tungsten, 3, { 1.123870, 1, 2.183484, 0 } }, + { "SAMSUNG", "NX5", Tungsten, 4, { 1.142438, 1, 2.126313, 0 } }, + { "SAMSUNG", "NX5", Tungsten, 5, { 1.160762, 1, 2.069142, 0 } }, + { "SAMSUNG", "NX5", Tungsten, 6, { 1.179086, 1, 2.011972, 0 } }, + { "SAMSUNG", "NX5", Tungsten, 7, { 1.197410, 1, 1.954801, 0 } }, + { "SAMSUNG", "NX5", Flash, -7, { 1.843635, 1, 1.282189, 0 } }, + { "SAMSUNG", "NX5", Flash, -6, { 1.876130, 1, 1.238700, 0 } }, + { "SAMSUNG", "NX5", Flash, -5, { 1.908624, 1, 1.195456, 0 } }, + { "SAMSUNG", "NX5", Flash, -4, { 1.941363, 1, 1.151967, 0 } }, + { "SAMSUNG", "NX5", Flash, -3, { 1.973858, 1, 1.108722, 0 } }, + { "SAMSUNG", "NX5", Flash, -2, { 2.006108, 1, 1.064989, 0 } }, + { "SAMSUNG", "NX5", Flash, -1, { 2.038847, 1, 1.021989, 0 } }, + { "SAMSUNG", "NX5", Flash, 0, { 2.071719, 1, 0.978723, 0 } }, + { "SAMSUNG", "NX5", Flash, 1, { 2.107068, 1, 0.954980, 0 } }, + { "SAMSUNG", "NX5", Flash, 2, { 2.142857, 1, 0.931301, 0 } }, + { "SAMSUNG", "NX5", Flash, 3, { 2.178191, 1, 0.907358, 0 } }, + { "SAMSUNG", "NX5", Flash, 4, { 2.213684, 1, 0.883661, 0 } }, + { "SAMSUNG", "NX5", Flash, 5, { 2.249317, 1, 0.859903, 0 } }, + { "SAMSUNG", "NX5", Flash, 6, { 2.284664, 1, 0.836022, 0 } }, + { "SAMSUNG", "NX5", Flash, 7, { 2.320238, 1, 0.812302, 0 } }, + { "SAMSUNG", "NX5", "5000K", 0, { 1.684339, 1, 1.094063, 0 } }, + { "SAMSUNG", "NX5", "5500K", 0, { 1.692022, 1, 0.843950, 0 } }, + { "SAMSUNG", "NX5", "6500K", 0, { 2.110371, 1, 0.879107, 0 } }, + + // Copied from SAMSUNG NX100 + { "SAMSUNG", "NX10", Daylight, -7, { 1.566333, 1, 1.526753, 0 } }, + { "SAMSUNG", "NX10", Daylight, -6, { 1.593941, 1, 1.475202, 0 } }, + { "SAMSUNG", "NX10", Daylight, -5, { 1.621793, 1, 1.423650, 0 } }, + { "SAMSUNG", "NX10", Daylight, -4, { 1.649401, 1, 1.371854, 0 } }, + { "SAMSUNG", "NX10", Daylight, -3, { 1.677010, 1, 1.320303, 0 } }, + { "SAMSUNG", "NX10", Daylight, -2, { 1.704618, 1, 1.268507, 0 } }, + { "SAMSUNG", "NX10", Daylight, -1, { 1.732470, 1, 1.216956, 0 } }, + { "SAMSUNG", "NX10", Daylight, 0, { 1.760078, 1, 1.165404, 0 } }, + { "SAMSUNG", "NX10", Daylight, 1, { 1.790129, 1, 1.137063, 0 } }, + { "SAMSUNG", "NX10", Daylight, 2, { 1.820425, 1, 1.108722, 0 } }, + { "SAMSUNG", "NX10", Daylight, 3, { 1.850721, 1, 1.080381, 0 } }, + { "SAMSUNG", "NX10", Daylight, 4, { 1.880772, 1, 1.052040, 0 } }, + { "SAMSUNG", "NX10", Daylight, 5, { 1.911068, 1, 1.023699, 0 } }, + { "SAMSUNG", "NX10", Daylight, 6, { 1.941377, 1, 0.995622, 0 } }, + { "SAMSUNG", "NX10", Daylight, 7, { 1.971874, 1, 0.967384, 0 } }, + { "SAMSUNG", "NX10", Cloudy, -7, { 1.638896, 1, 1.446372, 0 } }, + { "SAMSUNG", "NX10", Cloudy, -6, { 1.667725, 1, 1.397508, 0 } }, + { "SAMSUNG", "NX10", Cloudy, -5, { 1.696555, 1, 1.348644, 0 } }, + { "SAMSUNG", "NX10", Cloudy, -4, { 1.725629, 1, 1.299780, 0 } }, + { "SAMSUNG", "NX10", Cloudy, -3, { 1.754459, 1, 1.250672, 0 } }, + { "SAMSUNG", "NX10", Cloudy, -2, { 1.783533, 1, 1.201808, 0 } }, + { "SAMSUNG", "NX10", Cloudy, -1, { 1.812607, 1, 1.152944, 0 } }, + { "SAMSUNG", "NX10", Cloudy, 0, { 1.841437, 1, 1.103836, 0 } }, + { "SAMSUNG", "NX10", Cloudy, 1, { 1.872954, 1, 1.077205, 0 } }, + { "SAMSUNG", "NX10", Cloudy, 2, { 1.904471, 1, 1.050330, 0 } }, + { "SAMSUNG", "NX10", Cloudy, 3, { 1.936233, 1, 1.023455, 0 } }, + { "SAMSUNG", "NX10", Cloudy, 4, { 1.967852, 1, 0.996834, 0 } }, + { "SAMSUNG", "NX10", Cloudy, 5, { 1.999289, 1, 0.969905, 0 } }, + { "SAMSUNG", "NX10", Cloudy, 6, { 2.030876, 1, 0.943088, 0 } }, + { "SAMSUNG", "NX10", Cloudy, 7, { 2.062458, 1, 0.916275, 0 } }, + { "SAMSUNG", "NX10", WhiteFluorescent, -7, { 1.526020, 1, 2.316638, 0 } }, + { "SAMSUNG", "NX10", WhiteFluorescent, -6, { 1.553140, 1, 2.238212, 0 } }, + { "SAMSUNG", "NX10", WhiteFluorescent, -5, { 1.580015, 1, 2.159785, 0 } }, + { "SAMSUNG", "NX10", WhiteFluorescent, -4, { 1.606890, 1, 2.081603, 0 } }, + { "SAMSUNG", "NX10", WhiteFluorescent, -3, { 1.634009, 1, 2.003176, 0 } }, + { "SAMSUNG", "NX10", WhiteFluorescent, -2, { 1.660884, 1, 1.924750, 0 } }, + { "SAMSUNG", "NX10", WhiteFluorescent, -1, { 1.687760, 1, 1.846567, 0 } }, + { "SAMSUNG", "NX10", WhiteFluorescent, 0, { 1.714879, 1, 1.768141, 0 } }, + { "SAMSUNG", "NX10", WhiteFluorescent, 1, { 1.744197, 1, 1.725140, 0 } }, + { "SAMSUNG", "NX10", WhiteFluorescent, 2, { 1.773516, 1, 1.682140, 0 } }, + { "SAMSUNG", "NX10", WhiteFluorescent, 3, { 1.803078, 1, 1.639384, 0 } }, + { "SAMSUNG", "NX10", WhiteFluorescent, 4, { 1.832397, 1, 1.596384, 0 } }, + { "SAMSUNG", "NX10", WhiteFluorescent, 5, { 1.861959, 1, 1.553384, 0 } }, + { "SAMSUNG", "NX10", WhiteFluorescent, 6, { 1.891522, 1, 1.510628, 0 } }, + { "SAMSUNG", "NX10", WhiteFluorescent, 7, { 1.920596, 1, 1.467628, 0 } }, + { "SAMSUNG", "NX10", NeutralFluorescent, -7, { 1.691180, 1, 1.884437, 0 } }, + { "SAMSUNG", "NX10", NeutralFluorescent, -6, { 1.720987, 1, 1.821158, 0 } }, + { "SAMSUNG", "NX10", NeutralFluorescent, -5, { 1.751038, 1, 1.757146, 0 } }, + { "SAMSUNG", "NX10", NeutralFluorescent, -4, { 1.780845, 1, 1.693379, 0 } }, + { "SAMSUNG", "NX10", NeutralFluorescent, -3, { 1.810897, 1, 1.629612, 0 } }, + { "SAMSUNG", "NX10", NeutralFluorescent, -2, { 1.840704, 1, 1.565844, 0 } }, + { "SAMSUNG", "NX10", NeutralFluorescent, -1, { 1.870755, 1, 1.502077, 0 } }, + { "SAMSUNG", "NX10", NeutralFluorescent, 0, { 1.900318, 1, 1.438309, 0 } }, + { "SAMSUNG", "NX10", NeutralFluorescent, 1, { 1.933056, 1, 1.403616, 0 } }, + { "SAMSUNG", "NX10", NeutralFluorescent, 2, { 1.965795, 1, 1.368678, 0 } }, + { "SAMSUNG", "NX10", NeutralFluorescent, 3, { 1.998045, 1, 1.333741, 0 } }, + { "SAMSUNG", "NX10", NeutralFluorescent, 4, { 2.030784, 1, 1.298803, 0 } }, + { "SAMSUNG", "NX10", NeutralFluorescent, 5, { 2.063279, 1, 1.263621, 0 } }, + { "SAMSUNG", "NX10", NeutralFluorescent, 6, { 2.095773, 1, 1.228927, 0 } }, + { "SAMSUNG", "NX10", NeutralFluorescent, 7, { 2.128756, 1, 1.193990, 0 } }, + { "SAMSUNG", "NX10", DaylightFluorescent, -7, { 1.995358, 1, 1.613731, 0 } }, + { "SAMSUNG", "NX10", DaylightFluorescent, -6, { 2.030784, 1, 1.559492, 0 } }, + { "SAMSUNG", "NX10", DaylightFluorescent, -5, { 2.065722, 1, 1.504764, 0 } }, + { "SAMSUNG", "NX10", DaylightFluorescent, -4, { 2.101393, 1, 1.450037, 0 } }, + { "SAMSUNG", "NX10", DaylightFluorescent, -3, { 2.136330, 1, 1.395553, 0 } }, + { "SAMSUNG", "NX10", DaylightFluorescent, -2, { 2.171757, 1, 1.341070, 0 } }, + { "SAMSUNG", "NX10", DaylightFluorescent, -1, { 2.207183, 1, 1.286343, 0 } }, + { "SAMSUNG", "NX10", DaylightFluorescent, 0, { 2.242365, 1, 1.231859, 0 } }, + { "SAMSUNG", "NX10", DaylightFluorescent, 1, { 2.280723, 1, 1.202052, 0 } }, + { "SAMSUNG", "NX10", DaylightFluorescent, 2, { 2.319326, 1, 1.172001, 0 } }, + { "SAMSUNG", "NX10", DaylightFluorescent, 3, { 2.357684, 1, 1.142194, 0 } }, + { "SAMSUNG", "NX10", DaylightFluorescent, 4, { 2.396042, 1, 1.112143, 0 } }, + { "SAMSUNG", "NX10", DaylightFluorescent, 5, { 2.434645, 1, 1.082336, 0 } }, + { "SAMSUNG", "NX10", DaylightFluorescent, 6, { 2.473003, 1, 1.052284, 0 } }, + { "SAMSUNG", "NX10", DaylightFluorescent, 7, { 2.511361, 1, 1.022233, 0 } }, + { "SAMSUNG", "NX10", Tungsten, -7, { 0.951650, 1, 3.086007, 0 } }, + { "SAMSUNG", "NX10", Tungsten, -6, { 0.968307, 1, 2.981315, 0 } }, + { "SAMSUNG", "NX10", Tungsten, -5, { 0.985078, 1, 2.877497, 0 } }, + { "SAMSUNG", "NX10", Tungsten, -4, { 1.001710, 1, 2.772538, 0 } }, + { "SAMSUNG", "NX10", Tungsten, -3, { 1.018568, 1, 2.668214, 0 } }, + { "SAMSUNG", "NX10", Tungsten, -2, { 1.035426, 1, 2.563645, 0 } }, + { "SAMSUNG", "NX10", Tungsten, -1, { 1.052284, 1, 2.459565, 0 } }, + { "SAMSUNG", "NX10", Tungsten, 0, { 1.069142, 1, 2.354996, 0 } }, + { "SAMSUNG", "NX10", Tungsten, 1, { 1.087466, 1, 2.298070, 0 } }, + { "SAMSUNG", "NX10", Tungsten, 2, { 1.105790, 1, 2.240655, 0 } }, + { "SAMSUNG", "NX10", Tungsten, 3, { 1.123870, 1, 2.183484, 0 } }, + { "SAMSUNG", "NX10", Tungsten, 4, { 1.142438, 1, 2.126313, 0 } }, + { "SAMSUNG", "NX10", Tungsten, 5, { 1.160762, 1, 2.069142, 0 } }, + { "SAMSUNG", "NX10", Tungsten, 6, { 1.179086, 1, 2.011972, 0 } }, + { "SAMSUNG", "NX10", Tungsten, 7, { 1.197410, 1, 1.954801, 0 } }, + { "SAMSUNG", "NX10", Flash, -7, { 1.843635, 1, 1.282189, 0 } }, + { "SAMSUNG", "NX10", Flash, -6, { 1.876130, 1, 1.238700, 0 } }, + { "SAMSUNG", "NX10", Flash, -5, { 1.908624, 1, 1.195456, 0 } }, + { "SAMSUNG", "NX10", Flash, -4, { 1.941363, 1, 1.151967, 0 } }, + { "SAMSUNG", "NX10", Flash, -3, { 1.973858, 1, 1.108722, 0 } }, + { "SAMSUNG", "NX10", Flash, -2, { 2.006108, 1, 1.064989, 0 } }, + { "SAMSUNG", "NX10", Flash, -1, { 2.038847, 1, 1.021989, 0 } }, + { "SAMSUNG", "NX10", Flash, 0, { 2.071719, 1, 0.978723, 0 } }, + { "SAMSUNG", "NX10", Flash, 1, { 2.107068, 1, 0.954980, 0 } }, + { "SAMSUNG", "NX10", Flash, 2, { 2.142857, 1, 0.931301, 0 } }, + { "SAMSUNG", "NX10", Flash, 3, { 2.178191, 1, 0.907358, 0 } }, + { "SAMSUNG", "NX10", Flash, 4, { 2.213684, 1, 0.883661, 0 } }, + { "SAMSUNG", "NX10", Flash, 5, { 2.249317, 1, 0.859903, 0 } }, + { "SAMSUNG", "NX10", Flash, 6, { 2.284664, 1, 0.836022, 0 } }, + { "SAMSUNG", "NX10", Flash, 7, { 2.320238, 1, 0.812302, 0 } }, + { "SAMSUNG", "NX10", "5000K", 0, { 1.684339, 1, 1.094063, 0 } }, + { "SAMSUNG", "NX10", "5500K", 0, { 1.692022, 1, 0.843950, 0 } }, + { "SAMSUNG", "NX10", "6500K", 0, { 2.110371, 1, 0.879107, 0 } }, + + // Copied from SAMSUNG NX100 + { "SAMSUNG", "NX11", Daylight, -7, { 1.566333, 1, 1.526753, 0 } }, + { "SAMSUNG", "NX11", Daylight, -6, { 1.593941, 1, 1.475202, 0 } }, + { "SAMSUNG", "NX11", Daylight, -5, { 1.621793, 1, 1.423650, 0 } }, + { "SAMSUNG", "NX11", Daylight, -4, { 1.649401, 1, 1.371854, 0 } }, + { "SAMSUNG", "NX11", Daylight, -3, { 1.677010, 1, 1.320303, 0 } }, + { "SAMSUNG", "NX11", Daylight, -2, { 1.704618, 1, 1.268507, 0 } }, + { "SAMSUNG", "NX11", Daylight, -1, { 1.732470, 1, 1.216956, 0 } }, + { "SAMSUNG", "NX11", Daylight, 0, { 1.760078, 1, 1.165404, 0 } }, + { "SAMSUNG", "NX11", Daylight, 1, { 1.790129, 1, 1.137063, 0 } }, + { "SAMSUNG", "NX11", Daylight, 2, { 1.820425, 1, 1.108722, 0 } }, + { "SAMSUNG", "NX11", Daylight, 3, { 1.850721, 1, 1.080381, 0 } }, + { "SAMSUNG", "NX11", Daylight, 4, { 1.880772, 1, 1.052040, 0 } }, + { "SAMSUNG", "NX11", Daylight, 5, { 1.911068, 1, 1.023699, 0 } }, + { "SAMSUNG", "NX11", Daylight, 6, { 1.941377, 1, 0.995622, 0 } }, + { "SAMSUNG", "NX11", Daylight, 7, { 1.971874, 1, 0.967384, 0 } }, + { "SAMSUNG", "NX11", Cloudy, -7, { 1.638896, 1, 1.446372, 0 } }, + { "SAMSUNG", "NX11", Cloudy, -6, { 1.667725, 1, 1.397508, 0 } }, + { "SAMSUNG", "NX11", Cloudy, -5, { 1.696555, 1, 1.348644, 0 } }, + { "SAMSUNG", "NX11", Cloudy, -4, { 1.725629, 1, 1.299780, 0 } }, + { "SAMSUNG", "NX11", Cloudy, -3, { 1.754459, 1, 1.250672, 0 } }, + { "SAMSUNG", "NX11", Cloudy, -2, { 1.783533, 1, 1.201808, 0 } }, + { "SAMSUNG", "NX11", Cloudy, -1, { 1.812607, 1, 1.152944, 0 } }, + { "SAMSUNG", "NX11", Cloudy, 0, { 1.841437, 1, 1.103836, 0 } }, + { "SAMSUNG", "NX11", Cloudy, 1, { 1.872954, 1, 1.077205, 0 } }, + { "SAMSUNG", "NX11", Cloudy, 2, { 1.904471, 1, 1.050330, 0 } }, + { "SAMSUNG", "NX11", Cloudy, 3, { 1.936233, 1, 1.023455, 0 } }, + { "SAMSUNG", "NX11", Cloudy, 4, { 1.967852, 1, 0.996834, 0 } }, + { "SAMSUNG", "NX11", Cloudy, 5, { 1.999289, 1, 0.969905, 0 } }, + { "SAMSUNG", "NX11", Cloudy, 6, { 2.030876, 1, 0.943088, 0 } }, + { "SAMSUNG", "NX11", Cloudy, 7, { 2.062458, 1, 0.916275, 0 } }, + { "SAMSUNG", "NX11", WhiteFluorescent, -7, { 1.526020, 1, 2.316638, 0 } }, + { "SAMSUNG", "NX11", WhiteFluorescent, -6, { 1.553140, 1, 2.238212, 0 } }, + { "SAMSUNG", "NX11", WhiteFluorescent, -5, { 1.580015, 1, 2.159785, 0 } }, + { "SAMSUNG", "NX11", WhiteFluorescent, -4, { 1.606890, 1, 2.081603, 0 } }, + { "SAMSUNG", "NX11", WhiteFluorescent, -3, { 1.634009, 1, 2.003176, 0 } }, + { "SAMSUNG", "NX11", WhiteFluorescent, -2, { 1.660884, 1, 1.924750, 0 } }, + { "SAMSUNG", "NX11", WhiteFluorescent, -1, { 1.687760, 1, 1.846567, 0 } }, + { "SAMSUNG", "NX11", WhiteFluorescent, 0, { 1.714879, 1, 1.768141, 0 } }, + { "SAMSUNG", "NX11", WhiteFluorescent, 1, { 1.744197, 1, 1.725140, 0 } }, + { "SAMSUNG", "NX11", WhiteFluorescent, 2, { 1.773516, 1, 1.682140, 0 } }, + { "SAMSUNG", "NX11", WhiteFluorescent, 3, { 1.803078, 1, 1.639384, 0 } }, + { "SAMSUNG", "NX11", WhiteFluorescent, 4, { 1.832397, 1, 1.596384, 0 } }, + { "SAMSUNG", "NX11", WhiteFluorescent, 5, { 1.861959, 1, 1.553384, 0 } }, + { "SAMSUNG", "NX11", WhiteFluorescent, 6, { 1.891522, 1, 1.510628, 0 } }, + { "SAMSUNG", "NX11", WhiteFluorescent, 7, { 1.920596, 1, 1.467628, 0 } }, + { "SAMSUNG", "NX11", NeutralFluorescent, -7, { 1.691180, 1, 1.884437, 0 } }, + { "SAMSUNG", "NX11", NeutralFluorescent, -6, { 1.720987, 1, 1.821158, 0 } }, + { "SAMSUNG", "NX11", NeutralFluorescent, -5, { 1.751038, 1, 1.757146, 0 } }, + { "SAMSUNG", "NX11", NeutralFluorescent, -4, { 1.780845, 1, 1.693379, 0 } }, + { "SAMSUNG", "NX11", NeutralFluorescent, -3, { 1.810897, 1, 1.629612, 0 } }, + { "SAMSUNG", "NX11", NeutralFluorescent, -2, { 1.840704, 1, 1.565844, 0 } }, + { "SAMSUNG", "NX11", NeutralFluorescent, -1, { 1.870755, 1, 1.502077, 0 } }, + { "SAMSUNG", "NX11", NeutralFluorescent, 0, { 1.900318, 1, 1.438309, 0 } }, + { "SAMSUNG", "NX11", NeutralFluorescent, 1, { 1.933056, 1, 1.403616, 0 } }, + { "SAMSUNG", "NX11", NeutralFluorescent, 2, { 1.965795, 1, 1.368678, 0 } }, + { "SAMSUNG", "NX11", NeutralFluorescent, 3, { 1.998045, 1, 1.333741, 0 } }, + { "SAMSUNG", "NX11", NeutralFluorescent, 4, { 2.030784, 1, 1.298803, 0 } }, + { "SAMSUNG", "NX11", NeutralFluorescent, 5, { 2.063279, 1, 1.263621, 0 } }, + { "SAMSUNG", "NX11", NeutralFluorescent, 6, { 2.095773, 1, 1.228927, 0 } }, + { "SAMSUNG", "NX11", NeutralFluorescent, 7, { 2.128756, 1, 1.193990, 0 } }, + { "SAMSUNG", "NX11", DaylightFluorescent, -7, { 1.995358, 1, 1.613731, 0 } }, + { "SAMSUNG", "NX11", DaylightFluorescent, -6, { 2.030784, 1, 1.559492, 0 } }, + { "SAMSUNG", "NX11", DaylightFluorescent, -5, { 2.065722, 1, 1.504764, 0 } }, + { "SAMSUNG", "NX11", DaylightFluorescent, -4, { 2.101393, 1, 1.450037, 0 } }, + { "SAMSUNG", "NX11", DaylightFluorescent, -3, { 2.136330, 1, 1.395553, 0 } }, + { "SAMSUNG", "NX11", DaylightFluorescent, -2, { 2.171757, 1, 1.341070, 0 } }, + { "SAMSUNG", "NX11", DaylightFluorescent, -1, { 2.207183, 1, 1.286343, 0 } }, + { "SAMSUNG", "NX11", DaylightFluorescent, 0, { 2.242365, 1, 1.231859, 0 } }, + { "SAMSUNG", "NX11", DaylightFluorescent, 1, { 2.280723, 1, 1.202052, 0 } }, + { "SAMSUNG", "NX11", DaylightFluorescent, 2, { 2.319326, 1, 1.172001, 0 } }, + { "SAMSUNG", "NX11", DaylightFluorescent, 3, { 2.357684, 1, 1.142194, 0 } }, + { "SAMSUNG", "NX11", DaylightFluorescent, 4, { 2.396042, 1, 1.112143, 0 } }, + { "SAMSUNG", "NX11", DaylightFluorescent, 5, { 2.434645, 1, 1.082336, 0 } }, + { "SAMSUNG", "NX11", DaylightFluorescent, 6, { 2.473003, 1, 1.052284, 0 } }, + { "SAMSUNG", "NX11", DaylightFluorescent, 7, { 2.511361, 1, 1.022233, 0 } }, + { "SAMSUNG", "NX11", Tungsten, -7, { 0.951650, 1, 3.086007, 0 } }, + { "SAMSUNG", "NX11", Tungsten, -6, { 0.968307, 1, 2.981315, 0 } }, + { "SAMSUNG", "NX11", Tungsten, -5, { 0.985078, 1, 2.877497, 0 } }, + { "SAMSUNG", "NX11", Tungsten, -4, { 1.001710, 1, 2.772538, 0 } }, + { "SAMSUNG", "NX11", Tungsten, -3, { 1.018568, 1, 2.668214, 0 } }, + { "SAMSUNG", "NX11", Tungsten, -2, { 1.035426, 1, 2.563645, 0 } }, + { "SAMSUNG", "NX11", Tungsten, -1, { 1.052284, 1, 2.459565, 0 } }, + { "SAMSUNG", "NX11", Tungsten, 0, { 1.069142, 1, 2.354996, 0 } }, + { "SAMSUNG", "NX11", Tungsten, 1, { 1.087466, 1, 2.298070, 0 } }, + { "SAMSUNG", "NX11", Tungsten, 2, { 1.105790, 1, 2.240655, 0 } }, + { "SAMSUNG", "NX11", Tungsten, 3, { 1.123870, 1, 2.183484, 0 } }, + { "SAMSUNG", "NX11", Tungsten, 4, { 1.142438, 1, 2.126313, 0 } }, + { "SAMSUNG", "NX11", Tungsten, 5, { 1.160762, 1, 2.069142, 0 } }, + { "SAMSUNG", "NX11", Tungsten, 6, { 1.179086, 1, 2.011972, 0 } }, + { "SAMSUNG", "NX11", Tungsten, 7, { 1.197410, 1, 1.954801, 0 } }, + { "SAMSUNG", "NX11", Flash, -7, { 1.843635, 1, 1.282189, 0 } }, + { "SAMSUNG", "NX11", Flash, -6, { 1.876130, 1, 1.238700, 0 } }, + { "SAMSUNG", "NX11", Flash, -5, { 1.908624, 1, 1.195456, 0 } }, + { "SAMSUNG", "NX11", Flash, -4, { 1.941363, 1, 1.151967, 0 } }, + { "SAMSUNG", "NX11", Flash, -3, { 1.973858, 1, 1.108722, 0 } }, + { "SAMSUNG", "NX11", Flash, -2, { 2.006108, 1, 1.064989, 0 } }, + { "SAMSUNG", "NX11", Flash, -1, { 2.038847, 1, 1.021989, 0 } }, + { "SAMSUNG", "NX11", Flash, 0, { 2.071719, 1, 0.978723, 0 } }, + { "SAMSUNG", "NX11", Flash, 1, { 2.107068, 1, 0.954980, 0 } }, + { "SAMSUNG", "NX11", Flash, 2, { 2.142857, 1, 0.931301, 0 } }, + { "SAMSUNG", "NX11", Flash, 3, { 2.178191, 1, 0.907358, 0 } }, + { "SAMSUNG", "NX11", Flash, 4, { 2.213684, 1, 0.883661, 0 } }, + { "SAMSUNG", "NX11", Flash, 5, { 2.249317, 1, 0.859903, 0 } }, + { "SAMSUNG", "NX11", Flash, 6, { 2.284664, 1, 0.836022, 0 } }, + { "SAMSUNG", "NX11", Flash, 7, { 2.320238, 1, 0.812302, 0 } }, + { "SAMSUNG", "NX11", "5000K", 0, { 1.684339, 1, 1.094063, 0 } }, + { "SAMSUNG", "NX11", "5500K", 0, { 1.692022, 1, 0.843950, 0 } }, + { "SAMSUNG", "NX11", "6500K", 0, { 2.110371, 1, 0.879107, 0 } }, + + // Copied from SAMSUNG NX200 + { "SAMSUNG", "NX20", Daylight, 0, { 2.773438, 1, 1.625000, 0 } }, + { "SAMSUNG", "NX20", Cloudy, 0, { 2.902344, 1, 1.546875, 0 } }, + { "SAMSUNG", "NX20", WhiteFluorescent, 0, { 2.445313, 1, 2.316406, 0 } }, + { "SAMSUNG", "NX20", NeutralFluorescent, 0, { 2.746094, 1, 1.937500, 0 } }, + { "SAMSUNG", "NX20", DaylightFluorescent, 0, { 3.214844, 1, 1.679688, 0 } }, + { "SAMSUNG", "NX20", Tungsten, 0, { 1.511719, 1, 2.941406, 0 } }, + { "SAMSUNG", "NX20", Flash, 0, { 2.914063, 1, 1.191406, 0 } }, + + // SAMSUNG NX100 (firmware 1.12) white balance presets with finetuning steps + { "SAMSUNG", "NX100", Daylight, -7, { 1.566333, 1, 1.526753, 0 } }, + { "SAMSUNG", "NX100", Daylight, -6, { 1.593941, 1, 1.475202, 0 } }, + { "SAMSUNG", "NX100", Daylight, -5, { 1.621793, 1, 1.423650, 0 } }, + { "SAMSUNG", "NX100", Daylight, -4, { 1.649401, 1, 1.371854, 0 } }, + { "SAMSUNG", "NX100", Daylight, -3, { 1.677010, 1, 1.320303, 0 } }, + { "SAMSUNG", "NX100", Daylight, -2, { 1.704618, 1, 1.268507, 0 } }, + { "SAMSUNG", "NX100", Daylight, -1, { 1.732470, 1, 1.216956, 0 } }, + { "SAMSUNG", "NX100", Daylight, 0, { 1.760078, 1, 1.165404, 0 } }, + { "SAMSUNG", "NX100", Daylight, 1, { 1.790129, 1, 1.137063, 0 } }, + { "SAMSUNG", "NX100", Daylight, 2, { 1.820425, 1, 1.108722, 0 } }, + { "SAMSUNG", "NX100", Daylight, 3, { 1.850721, 1, 1.080381, 0 } }, + { "SAMSUNG", "NX100", Daylight, 4, { 1.880772, 1, 1.052040, 0 } }, + { "SAMSUNG", "NX100", Daylight, 5, { 1.911068, 1, 1.023699, 0 } }, + { "SAMSUNG", "NX100", Daylight, 6, { 1.941377, 1, 0.995622, 0 } }, + { "SAMSUNG", "NX100", Daylight, 7, { 1.971874, 1, 0.967384, 0 } }, + { "SAMSUNG", "NX100", Cloudy, -7, { 1.638896, 1, 1.446372, 0 } }, + { "SAMSUNG", "NX100", Cloudy, -6, { 1.667725, 1, 1.397508, 0 } }, + { "SAMSUNG", "NX100", Cloudy, -5, { 1.696555, 1, 1.348644, 0 } }, + { "SAMSUNG", "NX100", Cloudy, -4, { 1.725629, 1, 1.299780, 0 } }, + { "SAMSUNG", "NX100", Cloudy, -3, { 1.754459, 1, 1.250672, 0 } }, + { "SAMSUNG", "NX100", Cloudy, -2, { 1.783533, 1, 1.201808, 0 } }, + { "SAMSUNG", "NX100", Cloudy, -1, { 1.812607, 1, 1.152944, 0 } }, + { "SAMSUNG", "NX100", Cloudy, 0, { 1.841437, 1, 1.103836, 0 } }, + { "SAMSUNG", "NX100", Cloudy, 1, { 1.872954, 1, 1.077205, 0 } }, + { "SAMSUNG", "NX100", Cloudy, 2, { 1.904471, 1, 1.050330, 0 } }, + { "SAMSUNG", "NX100", Cloudy, 3, { 1.936233, 1, 1.023455, 0 } }, + { "SAMSUNG", "NX100", Cloudy, 4, { 1.967852, 1, 0.996834, 0 } }, + { "SAMSUNG", "NX100", Cloudy, 5, { 1.999289, 1, 0.969905, 0 } }, + { "SAMSUNG", "NX100", Cloudy, 6, { 2.030876, 1, 0.943088, 0 } }, + { "SAMSUNG", "NX100", Cloudy, 7, { 2.062458, 1, 0.916275, 0 } }, + { "SAMSUNG", "NX100", WhiteFluorescent, -7, { 1.526020, 1, 2.316638, 0 } }, + { "SAMSUNG", "NX100", WhiteFluorescent, -6, { 1.553140, 1, 2.238212, 0 } }, + { "SAMSUNG", "NX100", WhiteFluorescent, -5, { 1.580015, 1, 2.159785, 0 } }, + { "SAMSUNG", "NX100", WhiteFluorescent, -4, { 1.606890, 1, 2.081603, 0 } }, + { "SAMSUNG", "NX100", WhiteFluorescent, -3, { 1.634009, 1, 2.003176, 0 } }, + { "SAMSUNG", "NX100", WhiteFluorescent, -2, { 1.660884, 1, 1.924750, 0 } }, + { "SAMSUNG", "NX100", WhiteFluorescent, -1, { 1.687760, 1, 1.846567, 0 } }, + { "SAMSUNG", "NX100", WhiteFluorescent, 0, { 1.714879, 1, 1.768141, 0 } }, + { "SAMSUNG", "NX100", WhiteFluorescent, 1, { 1.744197, 1, 1.725140, 0 } }, + { "SAMSUNG", "NX100", WhiteFluorescent, 2, { 1.773516, 1, 1.682140, 0 } }, + { "SAMSUNG", "NX100", WhiteFluorescent, 3, { 1.803078, 1, 1.639384, 0 } }, + { "SAMSUNG", "NX100", WhiteFluorescent, 4, { 1.832397, 1, 1.596384, 0 } }, + { "SAMSUNG", "NX100", WhiteFluorescent, 5, { 1.861959, 1, 1.553384, 0 } }, + { "SAMSUNG", "NX100", WhiteFluorescent, 6, { 1.891522, 1, 1.510628, 0 } }, + { "SAMSUNG", "NX100", WhiteFluorescent, 7, { 1.920596, 1, 1.467628, 0 } }, + { "SAMSUNG", "NX100", NeutralFluorescent, -7, { 1.691180, 1, 1.884437, 0 } }, + { "SAMSUNG", "NX100", NeutralFluorescent, -6, { 1.720987, 1, 1.821158, 0 } }, + { "SAMSUNG", "NX100", NeutralFluorescent, -5, { 1.751038, 1, 1.757146, 0 } }, + { "SAMSUNG", "NX100", NeutralFluorescent, -4, { 1.780845, 1, 1.693379, 0 } }, + { "SAMSUNG", "NX100", NeutralFluorescent, -3, { 1.810897, 1, 1.629612, 0 } }, + { "SAMSUNG", "NX100", NeutralFluorescent, -2, { 1.840704, 1, 1.565844, 0 } }, + { "SAMSUNG", "NX100", NeutralFluorescent, -1, { 1.870755, 1, 1.502077, 0 } }, + { "SAMSUNG", "NX100", NeutralFluorescent, 0, { 1.900318, 1, 1.438309, 0 } }, + { "SAMSUNG", "NX100", NeutralFluorescent, 1, { 1.933056, 1, 1.403616, 0 } }, + { "SAMSUNG", "NX100", NeutralFluorescent, 2, { 1.965795, 1, 1.368678, 0 } }, + { "SAMSUNG", "NX100", NeutralFluorescent, 3, { 1.998045, 1, 1.333741, 0 } }, + { "SAMSUNG", "NX100", NeutralFluorescent, 4, { 2.030784, 1, 1.298803, 0 } }, + { "SAMSUNG", "NX100", NeutralFluorescent, 5, { 2.063279, 1, 1.263621, 0 } }, + { "SAMSUNG", "NX100", NeutralFluorescent, 6, { 2.095773, 1, 1.228927, 0 } }, + { "SAMSUNG", "NX100", NeutralFluorescent, 7, { 2.128756, 1, 1.193990, 0 } }, + { "SAMSUNG", "NX100", DaylightFluorescent, -7, { 1.995358, 1, 1.613731, 0 } }, + { "SAMSUNG", "NX100", DaylightFluorescent, -6, { 2.030784, 1, 1.559492, 0 } }, + { "SAMSUNG", "NX100", DaylightFluorescent, -5, { 2.065722, 1, 1.504764, 0 } }, + { "SAMSUNG", "NX100", DaylightFluorescent, -4, { 2.101393, 1, 1.450037, 0 } }, + { "SAMSUNG", "NX100", DaylightFluorescent, -3, { 2.136330, 1, 1.395553, 0 } }, + { "SAMSUNG", "NX100", DaylightFluorescent, -2, { 2.171757, 1, 1.341070, 0 } }, + { "SAMSUNG", "NX100", DaylightFluorescent, -1, { 2.207183, 1, 1.286343, 0 } }, + { "SAMSUNG", "NX100", DaylightFluorescent, 0, { 2.242365, 1, 1.231859, 0 } }, + { "SAMSUNG", "NX100", DaylightFluorescent, 1, { 2.280723, 1, 1.202052, 0 } }, + { "SAMSUNG", "NX100", DaylightFluorescent, 2, { 2.319326, 1, 1.172001, 0 } }, + { "SAMSUNG", "NX100", DaylightFluorescent, 3, { 2.357684, 1, 1.142194, 0 } }, + { "SAMSUNG", "NX100", DaylightFluorescent, 4, { 2.396042, 1, 1.112143, 0 } }, + { "SAMSUNG", "NX100", DaylightFluorescent, 5, { 2.434645, 1, 1.082336, 0 } }, + { "SAMSUNG", "NX100", DaylightFluorescent, 6, { 2.473003, 1, 1.052284, 0 } }, + { "SAMSUNG", "NX100", DaylightFluorescent, 7, { 2.511361, 1, 1.022233, 0 } }, + { "SAMSUNG", "NX100", Tungsten, -7, { 0.951650, 1, 3.086007, 0 } }, + { "SAMSUNG", "NX100", Tungsten, -6, { 0.968307, 1, 2.981315, 0 } }, + { "SAMSUNG", "NX100", Tungsten, -5, { 0.985078, 1, 2.877497, 0 } }, + { "SAMSUNG", "NX100", Tungsten, -4, { 1.001710, 1, 2.772538, 0 } }, + { "SAMSUNG", "NX100", Tungsten, -3, { 1.018568, 1, 2.668214, 0 } }, + { "SAMSUNG", "NX100", Tungsten, -2, { 1.035426, 1, 2.563645, 0 } }, + { "SAMSUNG", "NX100", Tungsten, -1, { 1.052284, 1, 2.459565, 0 } }, + { "SAMSUNG", "NX100", Tungsten, 0, { 1.069142, 1, 2.354996, 0 } }, + { "SAMSUNG", "NX100", Tungsten, 1, { 1.087466, 1, 2.298070, 0 } }, + { "SAMSUNG", "NX100", Tungsten, 2, { 1.105790, 1, 2.240655, 0 } }, + { "SAMSUNG", "NX100", Tungsten, 3, { 1.123870, 1, 2.183484, 0 } }, + { "SAMSUNG", "NX100", Tungsten, 4, { 1.142438, 1, 2.126313, 0 } }, + { "SAMSUNG", "NX100", Tungsten, 5, { 1.160762, 1, 2.069142, 0 } }, + { "SAMSUNG", "NX100", Tungsten, 6, { 1.179086, 1, 2.011972, 0 } }, + { "SAMSUNG", "NX100", Tungsten, 7, { 1.197410, 1, 1.954801, 0 } }, + { "SAMSUNG", "NX100", Flash, -7, { 1.843635, 1, 1.282189, 0 } }, + { "SAMSUNG", "NX100", Flash, -6, { 1.876130, 1, 1.238700, 0 } }, + { "SAMSUNG", "NX100", Flash, -5, { 1.908624, 1, 1.195456, 0 } }, + { "SAMSUNG", "NX100", Flash, -4, { 1.941363, 1, 1.151967, 0 } }, + { "SAMSUNG", "NX100", Flash, -3, { 1.973858, 1, 1.108722, 0 } }, + { "SAMSUNG", "NX100", Flash, -2, { 2.006108, 1, 1.064989, 0 } }, + { "SAMSUNG", "NX100", Flash, -1, { 2.038847, 1, 1.021989, 0 } }, + { "SAMSUNG", "NX100", Flash, 0, { 2.071719, 1, 0.978723, 0 } }, + { "SAMSUNG", "NX100", Flash, 1, { 2.107068, 1, 0.954980, 0 } }, + { "SAMSUNG", "NX100", Flash, 2, { 2.142857, 1, 0.931301, 0 } }, + { "SAMSUNG", "NX100", Flash, 3, { 2.178191, 1, 0.907358, 0 } }, + { "SAMSUNG", "NX100", Flash, 4, { 2.213684, 1, 0.883661, 0 } }, + { "SAMSUNG", "NX100", Flash, 5, { 2.249317, 1, 0.859903, 0 } }, + { "SAMSUNG", "NX100", Flash, 6, { 2.284664, 1, 0.836022, 0 } }, + { "SAMSUNG", "NX100", Flash, 7, { 2.320238, 1, 0.812302, 0 } }, + { "SAMSUNG", "NX100", "5000K", 0, { 1.684339, 1, 1.094063, 0 } }, + { "SAMSUNG", "NX100", "5500K", 0, { 1.692022, 1, 0.843950, 0 } }, + { "SAMSUNG", "NX100", "6500K", 0, { 2.110371, 1, 0.879107, 0 } }, + + // SAMSUNG NX200 Firmware Version 1.04 + { "SAMSUNG", "NX200", Daylight, 0, { 2.773438, 1, 1.625000, 0 } }, + { "SAMSUNG", "NX200", Cloudy, 0, { 2.902344, 1, 1.546875, 0 } }, + { "SAMSUNG", "NX200", WhiteFluorescent, 0, { 2.445313, 1, 2.316406, 0 } }, + { "SAMSUNG", "NX200", NeutralFluorescent, 0, { 2.746094, 1, 1.937500, 0 } }, + { "SAMSUNG", "NX200", DaylightFluorescent, 0, { 3.214844, 1, 1.679688, 0 } }, + { "SAMSUNG", "NX200", Tungsten, 0, { 1.511719, 1, 2.941406, 0 } }, + { "SAMSUNG", "NX200", Flash, 0, { 2.914063, 1, 1.191406, 0 } }, + + // Copied from SAMSUNG NX200 + { "SAMSUNG", "NX210", Daylight, 0, { 2.773438, 1, 1.625000, 0 } }, + { "SAMSUNG", "NX210", Cloudy, 0, { 2.902344, 1, 1.546875, 0 } }, + { "SAMSUNG", "NX210", WhiteFluorescent, 0, { 2.445313, 1, 2.316406, 0 } }, + { "SAMSUNG", "NX210", NeutralFluorescent, 0, { 2.746094, 1, 1.937500, 0 } }, + { "SAMSUNG", "NX210", DaylightFluorescent, 0, { 3.214844, 1, 1.679688, 0 } }, + { "SAMSUNG", "NX210", Tungsten, 0, { 1.511719, 1, 2.941406, 0 } }, + { "SAMSUNG", "NX210", Flash, 0, { 2.914063, 1, 1.191406, 0 } }, + + // SAMSUNG NX300 Firmware Version 1.40 + { "SAMSUNG", "NX300", Daylight, -7, { 2.308594, 1, 2.097656, 0 } }, + { "SAMSUNG", "NX300", Daylight, -6, { 2.347656, 1, 2.027344, 0 } }, + { "SAMSUNG", "NX300", Daylight, -5, { 2.390625, 1, 1.953125, 0 } }, + { "SAMSUNG", "NX300", Daylight, -4, { 2.429688, 1, 1.882813, 0 } }, + { "SAMSUNG", "NX300", Daylight, -3, { 2.472656, 1, 1.812500, 0 } }, + { "SAMSUNG", "NX300", Daylight, -2, { 2.511719, 1, 1.742188, 0 } }, + { "SAMSUNG", "NX300", Daylight, -1, { 2.554688, 1, 1.671875, 0 } }, + { "SAMSUNG", "NX300", Daylight, 0, { 2.593750, 1, 1.601563, 0 } }, + { "SAMSUNG", "NX300", Daylight, 1, { 2.636719, 1, 1.562500, 0 } }, + { "SAMSUNG", "NX300", Daylight, 2, { 2.683594, 1, 1.523438, 0 } }, + { "SAMSUNG", "NX300", Daylight, 3, { 2.726563, 1, 1.484375, 0 } }, + { "SAMSUNG", "NX300", Daylight, 4, { 2.773438, 1, 1.445313, 0 } }, + { "SAMSUNG", "NX300", Daylight, 5, { 2.816406, 1, 1.406250, 0 } }, + { "SAMSUNG", "NX300", Daylight, 6, { 2.859375, 1, 1.367188, 0 } }, + { "SAMSUNG", "NX300", Daylight, 7, { 2.906250, 1, 1.328125, 0 } }, + { "SAMSUNG", "NX300", Cloudy, -7, { 2.394531, 1, 2.011719, 0 } }, + { "SAMSUNG", "NX300", Cloudy, -6, { 2.433594, 1, 1.945313, 0 } }, + { "SAMSUNG", "NX300", Cloudy, -5, { 2.476563, 1, 1.878906, 0 } }, + { "SAMSUNG", "NX300", Cloudy, -4, { 2.519531, 1, 1.808594, 0 } }, + { "SAMSUNG", "NX300", Cloudy, -3, { 2.562500, 1, 1.742188, 0 } }, + { "SAMSUNG", "NX300", Cloudy, -2, { 2.605469, 1, 1.671875, 0 } }, + { "SAMSUNG", "NX300", Cloudy, -1, { 2.644531, 1, 1.605469, 0 } }, + { "SAMSUNG", "NX300", Cloudy, 0, { 2.687500, 1, 1.535156, 0 } }, + { "SAMSUNG", "NX300", Cloudy, 1, { 2.734375, 1, 1.500000, 0 } }, + { "SAMSUNG", "NX300", Cloudy, 2, { 2.781250, 1, 1.460938, 0 } }, + { "SAMSUNG", "NX300", Cloudy, 3, { 2.828125, 1, 1.425781, 0 } }, + { "SAMSUNG", "NX300", Cloudy, 4, { 2.875000, 1, 1.386719, 0 } }, + { "SAMSUNG", "NX300", Cloudy, 5, { 2.917969, 1, 1.351563, 0 } }, + { "SAMSUNG", "NX300", Cloudy, 6, { 2.964844, 1, 1.312500, 0 } }, + { "SAMSUNG", "NX300", Cloudy, 7, { 3.011719, 1, 1.273438, 0 } }, + { "SAMSUNG", "NX300", CoolWhiteFluorescent, -7, { 2.000000, 1, 2.933594, 0 } }, + { "SAMSUNG", "NX300", CoolWhiteFluorescent, -6, { 2.035156, 1, 2.835938, 0 } }, + { "SAMSUNG", "NX300", CoolWhiteFluorescent, -5, { 2.070313, 1, 2.734375, 0 } }, + { "SAMSUNG", "NX300", CoolWhiteFluorescent, -4, { 2.105469, 1, 2.636719, 0 } }, + { "SAMSUNG", "NX300", CoolWhiteFluorescent, -3, { 2.140625, 1, 2.539063, 0 } }, + { "SAMSUNG", "NX300", CoolWhiteFluorescent, -2, { 2.175781, 1, 2.437500, 0 } }, + { "SAMSUNG", "NX300", CoolWhiteFluorescent, -1, { 2.214844, 1, 2.339844, 0 } }, + { "SAMSUNG", "NX300", CoolWhiteFluorescent, 0, { 2.250000, 1, 2.238281, 0 } }, + { "SAMSUNG", "NX300", CoolWhiteFluorescent, 1, { 2.285156, 1, 2.183594, 0 } }, + { "SAMSUNG", "NX300", CoolWhiteFluorescent, 2, { 2.324219, 1, 2.128906, 0 } }, + { "SAMSUNG", "NX300", CoolWhiteFluorescent, 3, { 2.363281, 1, 2.078125, 0 } }, + { "SAMSUNG", "NX300", CoolWhiteFluorescent, 4, { 2.402344, 1, 2.023438, 0 } }, + { "SAMSUNG", "NX300", CoolWhiteFluorescent, 5, { 2.441406, 1, 1.968750, 0 } }, + { "SAMSUNG", "NX300", CoolWhiteFluorescent, 6, { 2.480469, 1, 1.914063, 0 } }, + { "SAMSUNG", "NX300", CoolWhiteFluorescent, 7, { 2.519531, 1, 1.859375, 0 } }, + { "SAMSUNG", "NX300", DayWhiteFluorescent, -7, { 2.253906, 1, 2.445313, 0 } }, + { "SAMSUNG", "NX300", DayWhiteFluorescent, -6, { 2.292969, 1, 2.363281, 0 } }, + { "SAMSUNG", "NX300", DayWhiteFluorescent, -5, { 2.332031, 1, 2.281250, 0 } }, + { "SAMSUNG", "NX300", DayWhiteFluorescent, -4, { 2.371094, 1, 2.199219, 0 } }, + { "SAMSUNG", "NX300", DayWhiteFluorescent, -3, { 2.410156, 1, 2.117188, 0 } }, + { "SAMSUNG", "NX300", DayWhiteFluorescent, -2, { 2.453125, 1, 2.031250, 0 } }, + { "SAMSUNG", "NX300", DayWhiteFluorescent, -1, { 2.492188, 1, 1.949219, 0 } }, + { "SAMSUNG", "NX300", DayWhiteFluorescent, 0, { 2.531250, 1, 1.867188, 0 } }, + { "SAMSUNG", "NX300", DayWhiteFluorescent, 1, { 2.574219, 1, 1.820313, 0 } }, + { "SAMSUNG", "NX300", DayWhiteFluorescent, 2, { 2.617188, 1, 1.777344, 0 } }, + { "SAMSUNG", "NX300", DayWhiteFluorescent, 3, { 2.660156, 1, 1.730469, 0 } }, + { "SAMSUNG", "NX300", DayWhiteFluorescent, 4, { 2.703125, 1, 1.687500, 0 } }, + { "SAMSUNG", "NX300", DayWhiteFluorescent, 5, { 2.750000, 1, 1.640625, 0 } }, + { "SAMSUNG", "NX300", DayWhiteFluorescent, 6, { 2.792969, 1, 1.593750, 0 } }, + { "SAMSUNG", "NX300", DayWhiteFluorescent, 7, { 2.835938, 1, 1.550781, 0 } }, + { "SAMSUNG", "NX300", DaylightFluorescent, -7, { 2.699219, 1, 2.128906, 0 } }, + { "SAMSUNG", "NX300", DaylightFluorescent, -6, { 2.746094, 1, 2.054688, 0 } }, + { "SAMSUNG", "NX300", DaylightFluorescent, -5, { 2.792969, 1, 1.984375, 0 } }, + { "SAMSUNG", "NX300", DaylightFluorescent, -4, { 2.839844, 1, 1.910156, 0 } }, + { "SAMSUNG", "NX300", DaylightFluorescent, -3, { 2.890625, 1, 1.839844, 0 } }, + { "SAMSUNG", "NX300", DaylightFluorescent, -2, { 2.937500, 1, 1.765625, 0 } }, + { "SAMSUNG", "NX300", DaylightFluorescent, -1, { 2.984375, 1, 1.695313, 0 } }, + { "SAMSUNG", "NX300", DaylightFluorescent, 0, { 3.031250, 1, 1.625000, 0 } }, + { "SAMSUNG", "NX300", DaylightFluorescent, 1, { 3.082031, 1, 1.582031, 0 } }, + { "SAMSUNG", "NX300", DaylightFluorescent, 2, { 3.136719, 1, 1.542969, 0 } }, + { "SAMSUNG", "NX300", DaylightFluorescent, 3, { 3.187500, 1, 1.503906, 0 } }, + { "SAMSUNG", "NX300", DaylightFluorescent, 4, { 3.238281, 1, 1.464844, 0 } }, + { "SAMSUNG", "NX300", DaylightFluorescent, 5, { 3.292969, 1, 1.425781, 0 } }, + { "SAMSUNG", "NX300", DaylightFluorescent, 6, { 3.343750, 1, 1.386719, 0 } }, + { "SAMSUNG", "NX300", DaylightFluorescent, 7, { 3.394531, 1, 1.347656, 0 } }, + { "SAMSUNG", "NX300", Tungsten, -7, { 1.390625, 1, 3.695313, 0 } }, + { "SAMSUNG", "NX300", Tungsten, -6, { 1.414063, 1, 3.570313, 0 } }, + { "SAMSUNG", "NX300", Tungsten, -5, { 1.437500, 1, 3.445313, 0 } }, + { "SAMSUNG", "NX300", Tungsten, -4, { 1.460938, 1, 3.320313, 0 } }, + { "SAMSUNG", "NX300", Tungsten, -3, { 1.488281, 1, 3.195313, 0 } }, + { "SAMSUNG", "NX300", Tungsten, -2, { 1.511719, 1, 3.070313, 0 } }, + { "SAMSUNG", "NX300", Tungsten, -1, { 1.535156, 1, 2.945313, 0 } }, + { "SAMSUNG", "NX300", Tungsten, 0, { 1.562500, 1, 2.820313, 0 } }, + { "SAMSUNG", "NX300", Tungsten, 1, { 1.585938, 1, 2.753906, 0 } }, + { "SAMSUNG", "NX300", Tungsten, 2, { 1.613281, 1, 2.683594, 0 } }, + { "SAMSUNG", "NX300", Tungsten, 3, { 1.640625, 1, 2.617188, 0 } }, + { "SAMSUNG", "NX300", Tungsten, 4, { 1.667969, 1, 2.546875, 0 } }, + { "SAMSUNG", "NX300", Tungsten, 5, { 1.695313, 1, 2.480469, 0 } }, + { "SAMSUNG", "NX300", Tungsten, 6, { 1.722656, 1, 2.410156, 0 } }, + { "SAMSUNG", "NX300", Tungsten, 7, { 1.750000, 1, 2.339844, 0 } }, + { "SAMSUNG", "NX300", Flash, -7, { 2.613281, 1, 1.957031, 0 } }, + { "SAMSUNG", "NX300", Flash, -6, { 2.660156, 1, 1.890625, 0 } }, + { "SAMSUNG", "NX300", Flash, -5, { 2.707031, 1, 1.824219, 0 } }, + { "SAMSUNG", "NX300", Flash, -4, { 2.753906, 1, 1.757813, 0 } }, + { "SAMSUNG", "NX300", Flash, -3, { 2.800781, 1, 1.691406, 0 } }, + { "SAMSUNG", "NX300", Flash, -2, { 2.843750, 1, 1.625000, 0 } }, + { "SAMSUNG", "NX300", Flash, -1, { 2.890625, 1, 1.558594, 0 } }, + { "SAMSUNG", "NX300", Flash, 0, { 2.937500, 1, 1.492188, 0 } }, + { "SAMSUNG", "NX300", Flash, 1, { 2.988281, 1, 1.457031, 0 } }, + { "SAMSUNG", "NX300", Flash, 2, { 3.039063, 1, 1.421875, 0 } }, + { "SAMSUNG", "NX300", Flash, 3, { 3.089844, 1, 1.386719, 0 } }, + { "SAMSUNG", "NX300", Flash, 4, { 3.140625, 1, 1.347656, 0 } }, + { "SAMSUNG", "NX300", Flash, 5, { 3.191406, 1, 1.312500, 0 } }, + { "SAMSUNG", "NX300", Flash, 6, { 3.238281, 1, 1.277344, 0 } }, + { "SAMSUNG", "NX300", Flash, 7, { 3.289063, 1, 1.238281, 0 } }, + { "SAMSUNG", "NX300", "5000K", 0, { 2.402344, 1, 1.945313, 0 } }, + { "SAMSUNG", "NX300", "5500K", 0, { 2.636719, 1, 1.792969, 0 } }, + { "SAMSUNG", "NX300", "6500K", 0, { 3.003906, 1, 1.644531, 0 } }, + + // copy of NX300 + { "SAMSUNG", "NX300M", Daylight, -7, { 2.308594, 1, 2.097656, 0 } }, + { "SAMSUNG", "NX300M", Daylight, -6, { 2.347656, 1, 2.027344, 0 } }, + { "SAMSUNG", "NX300M", Daylight, -5, { 2.390625, 1, 1.953125, 0 } }, + { "SAMSUNG", "NX300M", Daylight, -4, { 2.429688, 1, 1.882813, 0 } }, + { "SAMSUNG", "NX300M", Daylight, -3, { 2.472656, 1, 1.812500, 0 } }, + { "SAMSUNG", "NX300M", Daylight, -2, { 2.511719, 1, 1.742188, 0 } }, + { "SAMSUNG", "NX300M", Daylight, -1, { 2.554688, 1, 1.671875, 0 } }, + { "SAMSUNG", "NX300M", Daylight, 0, { 2.593750, 1, 1.601563, 0 } }, + { "SAMSUNG", "NX300M", Daylight, 1, { 2.636719, 1, 1.562500, 0 } }, + { "SAMSUNG", "NX300M", Daylight, 2, { 2.683594, 1, 1.523438, 0 } }, + { "SAMSUNG", "NX300M", Daylight, 3, { 2.726563, 1, 1.484375, 0 } }, + { "SAMSUNG", "NX300M", Daylight, 4, { 2.773438, 1, 1.445313, 0 } }, + { "SAMSUNG", "NX300M", Daylight, 5, { 2.816406, 1, 1.406250, 0 } }, + { "SAMSUNG", "NX300M", Daylight, 6, { 2.859375, 1, 1.367188, 0 } }, + { "SAMSUNG", "NX300M", Daylight, 7, { 2.906250, 1, 1.328125, 0 } }, + { "SAMSUNG", "NX300M", Cloudy, -7, { 2.394531, 1, 2.011719, 0 } }, + { "SAMSUNG", "NX300M", Cloudy, -6, { 2.433594, 1, 1.945313, 0 } }, + { "SAMSUNG", "NX300M", Cloudy, -5, { 2.476563, 1, 1.878906, 0 } }, + { "SAMSUNG", "NX300M", Cloudy, -4, { 2.519531, 1, 1.808594, 0 } }, + { "SAMSUNG", "NX300M", Cloudy, -3, { 2.562500, 1, 1.742188, 0 } }, + { "SAMSUNG", "NX300M", Cloudy, -2, { 2.605469, 1, 1.671875, 0 } }, + { "SAMSUNG", "NX300M", Cloudy, -1, { 2.644531, 1, 1.605469, 0 } }, + { "SAMSUNG", "NX300M", Cloudy, 0, { 2.687500, 1, 1.535156, 0 } }, + { "SAMSUNG", "NX300M", Cloudy, 1, { 2.734375, 1, 1.500000, 0 } }, + { "SAMSUNG", "NX300M", Cloudy, 2, { 2.781250, 1, 1.460938, 0 } }, + { "SAMSUNG", "NX300M", Cloudy, 3, { 2.828125, 1, 1.425781, 0 } }, + { "SAMSUNG", "NX300M", Cloudy, 4, { 2.875000, 1, 1.386719, 0 } }, + { "SAMSUNG", "NX300M", Cloudy, 5, { 2.917969, 1, 1.351563, 0 } }, + { "SAMSUNG", "NX300M", Cloudy, 6, { 2.964844, 1, 1.312500, 0 } }, + { "SAMSUNG", "NX300M", Cloudy, 7, { 3.011719, 1, 1.273438, 0 } }, + { "SAMSUNG", "NX300M", CoolWhiteFluorescent, -7, { 2.000000, 1, 2.933594, 0 } }, + { "SAMSUNG", "NX300M", CoolWhiteFluorescent, -6, { 2.035156, 1, 2.835938, 0 } }, + { "SAMSUNG", "NX300M", CoolWhiteFluorescent, -5, { 2.070313, 1, 2.734375, 0 } }, + { "SAMSUNG", "NX300M", CoolWhiteFluorescent, -4, { 2.105469, 1, 2.636719, 0 } }, + { "SAMSUNG", "NX300M", CoolWhiteFluorescent, -3, { 2.140625, 1, 2.539063, 0 } }, + { "SAMSUNG", "NX300M", CoolWhiteFluorescent, -2, { 2.175781, 1, 2.437500, 0 } }, + { "SAMSUNG", "NX300M", CoolWhiteFluorescent, -1, { 2.214844, 1, 2.339844, 0 } }, + { "SAMSUNG", "NX300M", CoolWhiteFluorescent, 0, { 2.250000, 1, 2.238281, 0 } }, + { "SAMSUNG", "NX300M", CoolWhiteFluorescent, 1, { 2.285156, 1, 2.183594, 0 } }, + { "SAMSUNG", "NX300M", CoolWhiteFluorescent, 2, { 2.324219, 1, 2.128906, 0 } }, + { "SAMSUNG", "NX300M", CoolWhiteFluorescent, 3, { 2.363281, 1, 2.078125, 0 } }, + { "SAMSUNG", "NX300M", CoolWhiteFluorescent, 4, { 2.402344, 1, 2.023438, 0 } }, + { "SAMSUNG", "NX300M", CoolWhiteFluorescent, 5, { 2.441406, 1, 1.968750, 0 } }, + { "SAMSUNG", "NX300M", CoolWhiteFluorescent, 6, { 2.480469, 1, 1.914063, 0 } }, + { "SAMSUNG", "NX300M", CoolWhiteFluorescent, 7, { 2.519531, 1, 1.859375, 0 } }, + { "SAMSUNG", "NX300M", DayWhiteFluorescent, -7, { 2.253906, 1, 2.445313, 0 } }, + { "SAMSUNG", "NX300M", DayWhiteFluorescent, -6, { 2.292969, 1, 2.363281, 0 } }, + { "SAMSUNG", "NX300M", DayWhiteFluorescent, -5, { 2.332031, 1, 2.281250, 0 } }, + { "SAMSUNG", "NX300M", DayWhiteFluorescent, -4, { 2.371094, 1, 2.199219, 0 } }, + { "SAMSUNG", "NX300M", DayWhiteFluorescent, -3, { 2.410156, 1, 2.117188, 0 } }, + { "SAMSUNG", "NX300M", DayWhiteFluorescent, -2, { 2.453125, 1, 2.031250, 0 } }, + { "SAMSUNG", "NX300M", DayWhiteFluorescent, -1, { 2.492188, 1, 1.949219, 0 } }, + { "SAMSUNG", "NX300M", DayWhiteFluorescent, 0, { 2.531250, 1, 1.867188, 0 } }, + { "SAMSUNG", "NX300M", DayWhiteFluorescent, 1, { 2.574219, 1, 1.820313, 0 } }, + { "SAMSUNG", "NX300M", DayWhiteFluorescent, 2, { 2.617188, 1, 1.777344, 0 } }, + { "SAMSUNG", "NX300M", DayWhiteFluorescent, 3, { 2.660156, 1, 1.730469, 0 } }, + { "SAMSUNG", "NX300M", DayWhiteFluorescent, 4, { 2.703125, 1, 1.687500, 0 } }, + { "SAMSUNG", "NX300M", DayWhiteFluorescent, 5, { 2.750000, 1, 1.640625, 0 } }, + { "SAMSUNG", "NX300M", DayWhiteFluorescent, 6, { 2.792969, 1, 1.593750, 0 } }, + { "SAMSUNG", "NX300M", DayWhiteFluorescent, 7, { 2.835938, 1, 1.550781, 0 } }, + { "SAMSUNG", "NX300M", DaylightFluorescent, -7, { 2.699219, 1, 2.128906, 0 } }, + { "SAMSUNG", "NX300M", DaylightFluorescent, -6, { 2.746094, 1, 2.054688, 0 } }, + { "SAMSUNG", "NX300M", DaylightFluorescent, -5, { 2.792969, 1, 1.984375, 0 } }, + { "SAMSUNG", "NX300M", DaylightFluorescent, -4, { 2.839844, 1, 1.910156, 0 } }, + { "SAMSUNG", "NX300M", DaylightFluorescent, -3, { 2.890625, 1, 1.839844, 0 } }, + { "SAMSUNG", "NX300M", DaylightFluorescent, -2, { 2.937500, 1, 1.765625, 0 } }, + { "SAMSUNG", "NX300M", DaylightFluorescent, -1, { 2.984375, 1, 1.695313, 0 } }, + { "SAMSUNG", "NX300M", DaylightFluorescent, 0, { 3.031250, 1, 1.625000, 0 } }, + { "SAMSUNG", "NX300M", DaylightFluorescent, 1, { 3.082031, 1, 1.582031, 0 } }, + { "SAMSUNG", "NX300M", DaylightFluorescent, 2, { 3.136719, 1, 1.542969, 0 } }, + { "SAMSUNG", "NX300M", DaylightFluorescent, 3, { 3.187500, 1, 1.503906, 0 } }, + { "SAMSUNG", "NX300M", DaylightFluorescent, 4, { 3.238281, 1, 1.464844, 0 } }, + { "SAMSUNG", "NX300M", DaylightFluorescent, 5, { 3.292969, 1, 1.425781, 0 } }, + { "SAMSUNG", "NX300M", DaylightFluorescent, 6, { 3.343750, 1, 1.386719, 0 } }, + { "SAMSUNG", "NX300M", DaylightFluorescent, 7, { 3.394531, 1, 1.347656, 0 } }, + { "SAMSUNG", "NX300M", Tungsten, -7, { 1.390625, 1, 3.695313, 0 } }, + { "SAMSUNG", "NX300M", Tungsten, -6, { 1.414063, 1, 3.570313, 0 } }, + { "SAMSUNG", "NX300M", Tungsten, -5, { 1.437500, 1, 3.445313, 0 } }, + { "SAMSUNG", "NX300M", Tungsten, -4, { 1.460938, 1, 3.320313, 0 } }, + { "SAMSUNG", "NX300M", Tungsten, -3, { 1.488281, 1, 3.195313, 0 } }, + { "SAMSUNG", "NX300M", Tungsten, -2, { 1.511719, 1, 3.070313, 0 } }, + { "SAMSUNG", "NX300M", Tungsten, -1, { 1.535156, 1, 2.945313, 0 } }, + { "SAMSUNG", "NX300M", Tungsten, 0, { 1.562500, 1, 2.820313, 0 } }, + { "SAMSUNG", "NX300M", Tungsten, 1, { 1.585938, 1, 2.753906, 0 } }, + { "SAMSUNG", "NX300M", Tungsten, 2, { 1.613281, 1, 2.683594, 0 } }, + { "SAMSUNG", "NX300M", Tungsten, 3, { 1.640625, 1, 2.617188, 0 } }, + { "SAMSUNG", "NX300M", Tungsten, 4, { 1.667969, 1, 2.546875, 0 } }, + { "SAMSUNG", "NX300M", Tungsten, 5, { 1.695313, 1, 2.480469, 0 } }, + { "SAMSUNG", "NX300M", Tungsten, 6, { 1.722656, 1, 2.410156, 0 } }, + { "SAMSUNG", "NX300M", Tungsten, 7, { 1.750000, 1, 2.339844, 0 } }, + { "SAMSUNG", "NX300M", Flash, -7, { 2.613281, 1, 1.957031, 0 } }, + { "SAMSUNG", "NX300M", Flash, -6, { 2.660156, 1, 1.890625, 0 } }, + { "SAMSUNG", "NX300M", Flash, -5, { 2.707031, 1, 1.824219, 0 } }, + { "SAMSUNG", "NX300M", Flash, -4, { 2.753906, 1, 1.757813, 0 } }, + { "SAMSUNG", "NX300M", Flash, -3, { 2.800781, 1, 1.691406, 0 } }, + { "SAMSUNG", "NX300M", Flash, -2, { 2.843750, 1, 1.625000, 0 } }, + { "SAMSUNG", "NX300M", Flash, -1, { 2.890625, 1, 1.558594, 0 } }, + { "SAMSUNG", "NX300M", Flash, 0, { 2.937500, 1, 1.492188, 0 } }, + { "SAMSUNG", "NX300M", Flash, 1, { 2.988281, 1, 1.457031, 0 } }, + { "SAMSUNG", "NX300M", Flash, 2, { 3.039063, 1, 1.421875, 0 } }, + { "SAMSUNG", "NX300M", Flash, 3, { 3.089844, 1, 1.386719, 0 } }, + { "SAMSUNG", "NX300M", Flash, 4, { 3.140625, 1, 1.347656, 0 } }, + { "SAMSUNG", "NX300M", Flash, 5, { 3.191406, 1, 1.312500, 0 } }, + { "SAMSUNG", "NX300M", Flash, 6, { 3.238281, 1, 1.277344, 0 } }, + { "SAMSUNG", "NX300M", Flash, 7, { 3.289063, 1, 1.238281, 0 } }, + { "SAMSUNG", "NX300M", "5000K", 0, { 2.402344, 1, 1.945313, 0 } }, + { "SAMSUNG", "NX300M", "5500K", 0, { 2.636719, 1, 1.792969, 0 } }, + { "SAMSUNG", "NX300M", "6500K", 0, { 3.003906, 1, 1.644531, 0 } }, + + // Firmware 1.00 + { "SAMSUNG", "NX500", Daylight, 0, { 1.810484, 1, 1.471774, 0 } }, + { "SAMSUNG", "NX500", Cloudy, 0, { 1.895161, 1, 1.302419, 0 } }, + { "SAMSUNG", "NX500", CoolWhiteFluorescent, 0, { 1.802419, 1, 2.350806, 0 } }, + { "SAMSUNG", "NX500", DayWhiteFluorescent, 0, { 1.975806, 1, 1.826613, 0 } }, + { "SAMSUNG", "NX500", DaylightFluorescent, 0, { 2.274194, 1, 1.512097, 0 } }, + { "SAMSUNG", "NX500", Tungsten, 0, { 1.298387, 1, 2.439516, 0 } }, + { "SAMSUNG", "NX500", Flash, 0, { 1.959677, 1, 1.169355, 0 } }, + + // Copied from SAMSUNG NX200 + { "SAMSUNG", "NX1000", Daylight, 0, { 2.773438, 1, 1.625000, 0 } }, + { "SAMSUNG", "NX1000", Cloudy, 0, { 2.902344, 1, 1.546875, 0 } }, + { "SAMSUNG", "NX1000", WhiteFluorescent, 0, { 2.445313, 1, 2.316406, 0 } }, + { "SAMSUNG", "NX1000", NeutralFluorescent, 0, { 2.746094, 1, 1.937500, 0 } }, + { "SAMSUNG", "NX1000", DaylightFluorescent, 0, { 3.214844, 1, 1.679688, 0 } }, + { "SAMSUNG", "NX1000", Tungsten, 0, { 1.511719, 1, 2.941406, 0 } }, + { "SAMSUNG", "NX1000", Flash, 0, { 2.914063, 1, 1.191406, 0 } }, + + // Copied from SAMSUNG NX200 + { "SAMSUNG", "NX1100", Daylight, 0, { 2.773438, 1, 1.625000, 0 } }, + { "SAMSUNG", "NX1100", Cloudy, 0, { 2.902344, 1, 1.546875, 0 } }, + { "SAMSUNG", "NX1100", WhiteFluorescent, 0, { 2.445313, 1, 2.316406, 0 } }, + { "SAMSUNG", "NX1100", NeutralFluorescent, 0, { 2.746094, 1, 1.937500, 0 } }, + { "SAMSUNG", "NX1100", DaylightFluorescent, 0, { 3.214844, 1, 1.679688, 0 } }, + { "SAMSUNG", "NX1100", Tungsten, 0, { 1.511719, 1, 2.941406, 0 } }, + { "SAMSUNG", "NX1100", Flash, 0, { 2.914063, 1, 1.191406, 0 } }, + + // Firmware NXF1_01.01 + { "SAMSUNG", "NX3000", Daylight, 0, { 2.214844, 1, 1.816406, 0 } }, + { "SAMSUNG", "NX3000", Cloudy, 0, { 2.347656, 1, 1.656250, 0 } }, + { "SAMSUNG", "NX3000", CoolWhiteFluorescent, 0, { 2.023438, 1, 2.460938, 0 } }, + { "SAMSUNG", "NX3000", DayWhiteFluorescent, 0, { 2.175781, 1, 2.152344, 0 } }, + { "SAMSUNG", "NX3000", DaylightFluorescent, 0, { 2.582031, 1, 1.835938, 0 } }, + { "SAMSUNG", "NX3000", Tungsten, 0, { 1.539063, 1, 2.816406, 0 } }, + { "SAMSUNG", "NX3000", Flash, 0, { 2.597656, 1, 1.566406, 0 } }, + + { "SONY", "DSC-RX1", Daylight, 0, { 2.386719, 1, 1.550781, 0 } }, + { "SONY", "DSC-RX1", Shade, 0, { 2.843750, 1, 1.273438, 0 } }, + { "SONY", "DSC-RX1", Cloudy, 0, { 2.578125, 1, 1.417969, 0 } }, + { "SONY", "DSC-RX1", Tungsten, 0, { 1.472656, 1, 2.871094, 0 } }, + { "SONY", "DSC-RX1", WarmWhiteFluorescent, 0, { 1.703125, 1, 2.851563, 0 } }, + { "SONY", "DSC-RX1", CoolWhiteFluorescent, 0, { 2.148438, 1, 2.339844, 0 } }, + { "SONY", "DSC-RX1", DayWhiteFluorescent, 0, { 2.308594, 1, 1.695313, 0 } }, + { "SONY", "DSC-RX1", DaylightFluorescent, 0, { 2.605469, 1, 1.484375, 0 } }, + { "SONY", "DSC-RX1", Flash, 0, { 2.835938, 1, 1.300781, 0 } }, + { "SONY", "DSC-RX1", "2500K", 0, { 1.277344, 1, 3.507813, 0 } }, + { "SONY", "DSC-RX1", "3200K", 0, { 1.644531, 1, 2.468750, 0 } }, + { "SONY", "DSC-RX1", "4500K", 0, { 2.152344, 1, 1.753906, 0 } }, + { "SONY", "DSC-RX1", "6000K", 0, { 2.558594, 1, 1.433594, 0 } }, + { "SONY", "DSC-RX1", "8500K", 0, { 2.992188, 1, 1.203125, 0 } }, + + { "SONY", "DSC-RX1R", Daylight, 0, { 2.390625, 1, 1.597656, 0 } }, + { "SONY", "DSC-RX1R", Shade, 0, { 2.843750, 1, 1.312500, 0 } }, + { "SONY", "DSC-RX1R", Cloudy, 0, { 2.582031, 1, 1.464844, 0 } }, + { "SONY", "DSC-RX1R", Tungsten, 0, { 1.476563, 1, 2.914063, 0 } }, + { "SONY", "DSC-RX1R", WarmWhiteFluorescent, 0, { 1.707031, 1, 2.894531, 0 } }, + { "SONY", "DSC-RX1R", CoolWhiteFluorescent, 0, { 2.152344, 1, 2.386719, 0 } }, + { "SONY", "DSC-RX1R", DayWhiteFluorescent, 0, { 2.312500, 1, 1.742188, 0 } }, + { "SONY", "DSC-RX1R", DaylightFluorescent, 0, { 2.605469, 1, 1.531250, 0 } }, + { "SONY", "DSC-RX1R", Flash, 0, { 2.816406, 1, 1.312500, 0 } }, + { "SONY", "DSC-RX1R", "2500K", 0, { 1.281250, 1, 3.535156, 0 } }, + { "SONY", "DSC-RX1R", "3200K", 0, { 1.648438, 1, 2.515625, 0 } }, + { "SONY", "DSC-RX1R", "4500K", 0, { 2.156250, 1, 1.800781, 0 } }, + { "SONY", "DSC-RX1R", "6000K", 0, { 2.558594, 1, 1.476563, 0 } }, + { "SONY", "DSC-RX1R", "8500K", 0, { 2.992188, 1, 1.242188, 0 } }, + + /* Firmware version 2.00 */ + /* -7/+7 fine tuning is -7/+7 in amber-blue and zero in green-magenta */ + { "SONY", "DSC-RX10", Daylight, -7, { 2.035156, 1, 2.292969, 0 } }, + { "SONY", "DSC-RX10", Daylight, 0, { 2.503906, 1, 1.824219, 0 } }, + { "SONY", "DSC-RX10", Daylight, 7, { 3.105469, 1, 1.449219, 0 } }, + { "SONY", "DSC-RX10", Shade, -7, { 2.398438, 1, 1.910156, 0 } }, + { "SONY", "DSC-RX10", Shade, 0, { 2.968750, 1, 1.519531, 0 } }, + { "SONY", "DSC-RX10", Shade, 7, { 3.710938, 1, 1.210938, 0 } }, + { "SONY", "DSC-RX10", Cloudy, -7, { 2.187500, 1, 2.113281, 0 } }, + { "SONY", "DSC-RX10", Cloudy, 0, { 2.699219, 1, 1.679688, 0 } }, + { "SONY", "DSC-RX10", Cloudy, 7, { 3.359375, 1, 1.335938, 0 } }, + { "SONY", "DSC-RX10", Incandescent, -7, { 1.285156, 1, 3.925781, 0 } }, + { "SONY", "DSC-RX10", Incandescent, 0, { 1.562500, 1, 3.109375, 0 } }, + { "SONY", "DSC-RX10", Incandescent, 7, { 1.906250, 1, 2.468750, 0 } }, + { "SONY", "DSC-RX10", WarmWhiteFluorescent, -7, { 1.515625, 1, 3.808594, 0 } }, + { "SONY", "DSC-RX10", WarmWhiteFluorescent, 0, { 1.828125, 1, 3.058594, 0 } }, + { "SONY", "DSC-RX10", WarmWhiteFluorescent, 7, { 2.214844, 1, 2.460938, 0 } }, + { "SONY", "DSC-RX10", CoolWhiteFluorescent, -7, { 1.921875, 1, 3.207031, 0 } }, + { "SONY", "DSC-RX10", CoolWhiteFluorescent, 0, { 2.316406, 1, 2.601563, 0 } }, + { "SONY", "DSC-RX10", CoolWhiteFluorescent, 7, { 2.804688, 1, 2.113281, 0 } }, + { "SONY", "DSC-RX10", DayWhiteFluorescent, -7, { 1.949219, 1, 2.332031, 0 } }, + { "SONY", "DSC-RX10", DayWhiteFluorescent, 0, { 2.402344, 1, 1.851563, 0 } }, + { "SONY", "DSC-RX10", DayWhiteFluorescent, 7, { 2.976563, 1, 1.468750, 0 } }, + { "SONY", "DSC-RX10", DaylightFluorescent, -7, { 2.156250, 1, 2.097656, 0 } }, + { "SONY", "DSC-RX10", DaylightFluorescent, 0, { 2.664063, 1, 1.664063, 0 } }, + { "SONY", "DSC-RX10", DaylightFluorescent, 7, { 3.316406, 1, 1.324219, 0 } }, + { "SONY", "DSC-RX10", Flash, -7, { 2.367188, 1, 1.867188, 0 } }, + { "SONY", "DSC-RX10", Flash, 0, { 2.937500, 1, 1.484375, 0 } }, + { "SONY", "DSC-RX10", Flash, 7, { 3.675781, 1, 1.179688, 0 } }, + { "SONY", "DSC-RX10", "2500K", 0, { 1.359375, 1, 3.660156, 0 } }, + { "SONY", "DSC-RX10", "2600K", 0, { 1.421875, 1, 3.480469, 0 } }, + { "SONY", "DSC-RX10", "2700K", 0, { 1.476563, 1, 3.316406, 0 } }, + { "SONY", "DSC-RX10", "2800K", 0, { 1.535156, 1, 3.175781, 0 } }, + { "SONY", "DSC-RX10", "2900K", 0, { 1.589844, 1, 3.046875, 0 } }, + { "SONY", "DSC-RX10", "3000K", 0, { 1.640625, 1, 2.933594, 0 } }, + { "SONY", "DSC-RX10", "3100K", 0, { 1.691406, 1, 2.832031, 0 } }, + { "SONY", "DSC-RX10", "3200K", 0, { 1.742188, 1, 2.738281, 0 } }, + { "SONY", "DSC-RX10", "3300K", 0, { 1.789063, 1, 2.656250, 0 } }, + { "SONY", "DSC-RX10", "3400K", 0, { 1.835938, 1, 2.578125, 0 } }, + { "SONY", "DSC-RX10", "3500K", 0, { 1.882813, 1, 2.507813, 0 } }, + { "SONY", "DSC-RX10", "3600K", 0, { 1.925781, 1, 2.441406, 0 } }, + { "SONY", "DSC-RX10", "3700K", 0, { 1.968750, 1, 2.382813, 0 } }, + { "SONY", "DSC-RX10", "3800K", 0, { 2.007813, 1, 2.328125, 0 } }, + { "SONY", "DSC-RX10", "3900K", 0, { 2.046875, 1, 2.277344, 0 } }, + { "SONY", "DSC-RX10", "4000K", 0, { 2.085938, 1, 2.226563, 0 } }, + { "SONY", "DSC-RX10", "4100K", 0, { 2.125000, 1, 2.183594, 0 } }, + { "SONY", "DSC-RX10", "4200K", 0, { 2.160156, 1, 2.144531, 0 } }, + { "SONY", "DSC-RX10", "4300K", 0, { 2.195313, 1, 2.105469, 0 } }, + { "SONY", "DSC-RX10", "4400K", 0, { 2.230469, 1, 2.066406, 0 } }, + { "SONY", "DSC-RX10", "4500K", 0, { 2.265625, 1, 2.035156, 0 } }, + { "SONY", "DSC-RX10", "4600K", 0, { 2.300781, 1, 2.003906, 0 } }, + { "SONY", "DSC-RX10", "4700K", 0, { 2.332031, 1, 1.972656, 0 } }, + { "SONY", "DSC-RX10", "4800K", 0, { 2.363281, 1, 1.945313, 0 } }, + { "SONY", "DSC-RX10", "4900K", 0, { 2.390625, 1, 1.917969, 0 } }, + { "SONY", "DSC-RX10", "5000K", 0, { 2.421875, 1, 1.890625, 0 } }, + { "SONY", "DSC-RX10", "5100K", 0, { 2.449219, 1, 1.867188, 0 } }, + { "SONY", "DSC-RX10", "5200K", 0, { 2.476563, 1, 1.843750, 0 } }, + { "SONY", "DSC-RX10", "5300K", 0, { 2.503906, 1, 1.824219, 0 } }, + { "SONY", "DSC-RX10", "5400K", 0, { 2.531250, 1, 1.800781, 0 } }, + { "SONY", "DSC-RX10", "5500K", 0, { 2.558594, 1, 1.781250, 0 } }, + { "SONY", "DSC-RX10", "5600K", 0, { 2.582031, 1, 1.761719, 0 } }, + { "SONY", "DSC-RX10", "5700K", 0, { 2.609375, 1, 1.746094, 0 } }, + { "SONY", "DSC-RX10", "5800K", 0, { 2.632813, 1, 1.726563, 0 } }, + { "SONY", "DSC-RX10", "5900K", 0, { 2.656250, 1, 1.710938, 0 } }, + { "SONY", "DSC-RX10", "6000K", 0, { 2.679688, 1, 1.695313, 0 } }, + { "SONY", "DSC-RX10", "6100K", 0, { 2.699219, 1, 1.679688, 0 } }, + { "SONY", "DSC-RX10", "6200K", 0, { 2.722656, 1, 1.667969, 0 } }, + { "SONY", "DSC-RX10", "6300K", 0, { 2.746094, 1, 1.652344, 0 } }, + { "SONY", "DSC-RX10", "6400K", 0, { 2.765625, 1, 1.640625, 0 } }, + { "SONY", "DSC-RX10", "6500K", 0, { 2.785156, 1, 1.625000, 0 } }, + { "SONY", "DSC-RX10", "6600K", 0, { 2.804688, 1, 1.613281, 0 } }, + { "SONY", "DSC-RX10", "6700K", 0, { 2.824219, 1, 1.601563, 0 } }, + { "SONY", "DSC-RX10", "6800K", 0, { 2.843750, 1, 1.589844, 0 } }, + { "SONY", "DSC-RX10", "6900K", 0, { 2.863281, 1, 1.578125, 0 } }, + { "SONY", "DSC-RX10", "7000K", 0, { 2.882813, 1, 1.570313, 0 } }, + { "SONY", "DSC-RX10", "7100K", 0, { 2.898438, 1, 1.558594, 0 } }, + { "SONY", "DSC-RX10", "7200K", 0, { 2.917969, 1, 1.546875, 0 } }, + { "SONY", "DSC-RX10", "7300K", 0, { 2.933594, 1, 1.539063, 0 } }, + { "SONY", "DSC-RX10", "7400K", 0, { 2.953125, 1, 1.531250, 0 } }, + { "SONY", "DSC-RX10", "7500K", 0, { 2.968750, 1, 1.519531, 0 } }, + { "SONY", "DSC-RX10", "7600K", 0, { 2.984375, 1, 1.511719, 0 } }, + { "SONY", "DSC-RX10", "7700K", 0, { 3.000000, 1, 1.503906, 0 } }, + { "SONY", "DSC-RX10", "7800K", 0, { 3.015625, 1, 1.496094, 0 } }, + { "SONY", "DSC-RX10", "7900K", 0, { 3.031250, 1, 1.488281, 0 } }, + { "SONY", "DSC-RX10", "8000K", 0, { 3.046875, 1, 1.480469, 0 } }, + { "SONY", "DSC-RX10", "8100K", 0, { 3.062500, 1, 1.472656, 0 } }, + { "SONY", "DSC-RX10", "8200K", 0, { 3.074219, 1, 1.464844, 0 } }, + { "SONY", "DSC-RX10", "8300K", 0, { 3.089844, 1, 1.457031, 0 } }, + { "SONY", "DSC-RX10", "8400K", 0, { 3.101563, 1, 1.453125, 0 } }, + { "SONY", "DSC-RX10", "8500K", 0, { 3.117188, 1, 1.445313, 0 } }, + { "SONY", "DSC-RX10", "8600K", 0, { 3.128906, 1, 1.437500, 0 } }, + { "SONY", "DSC-RX10", "8700K", 0, { 3.144531, 1, 1.433594, 0 } }, + { "SONY", "DSC-RX10", "8800K", 0, { 3.156250, 1, 1.425781, 0 } }, + { "SONY", "DSC-RX10", "8900K", 0, { 3.167969, 1, 1.421875, 0 } }, + { "SONY", "DSC-RX10", "9000K", 0, { 3.183594, 1, 1.414063, 0 } }, + { "SONY", "DSC-RX10", "9100K", 0, { 3.195313, 1, 1.410156, 0 } }, + { "SONY", "DSC-RX10", "9200K", 0, { 3.207031, 1, 1.402344, 0 } }, + { "SONY", "DSC-RX10", "9300K", 0, { 3.218750, 1, 1.398438, 0 } }, + { "SONY", "DSC-RX10", "9400K", 0, { 3.230469, 1, 1.394531, 0 } }, + { "SONY", "DSC-RX10", "9500K", 0, { 3.242188, 1, 1.386719, 0 } }, + { "SONY", "DSC-RX10", "9600K", 0, { 3.253906, 1, 1.382813, 0 } }, + { "SONY", "DSC-RX10", "9700K", 0, { 3.265625, 1, 1.378906, 0 } }, + { "SONY", "DSC-RX10", "9800K", 0, { 3.273438, 1, 1.375000, 0 } }, + { "SONY", "DSC-RX10", "9900K", 0, { 3.285156, 1, 1.367188, 0 } }, + + { "SONY", "DSC-RX10M2", Cloudy, 0, { 2.886719, 1, 1.652344, 0 } }, + { "SONY", "DSC-RX10M2", Daylight, 0, { 2.667969, 1, 1.796875, 0 } }, + { "SONY", "DSC-RX10M2", Incandescent, 0, { 1.636719, 1, 3.117188, 0 } }, + { "SONY", "DSC-RX10M2", WarmWhiteFluorescent, 0, { 1.996094, 1, 3.039063, 0 } }, + { "SONY", "DSC-RX10M2", CoolWhiteFluorescent, 0, { 2.578125, 1, 2.476563, 0 } }, + { "SONY", "DSC-RX10M2", DayWhiteFluorescent, 0, { 2.628906, 1, 1.812500, 0 } }, + { "SONY", "DSC-RX10M2", DaylightFluorescent, 0, { 2.921875, 1, 1.628906, 0 } }, + { "SONY", "DSC-RX10M2", Flash, 0, { 3.140625, 1, 1.460938, 0 } }, + + { "SONY", "DSC-RX100", Daylight, 0, { 2.0703, 1, 2.1602, 0 } }, + { "SONY", "DSC-RX100", Shade, 0, { 2.4531, 1, 1.7852, 0 } }, + { "SONY", "DSC-RX100", Cloudy, 0, { 2.2305, 1, 1.9844, 0 } }, + { "SONY", "DSC-RX100", Tungsten, 0, { 1.2891, 1, 3.8242, 0 } }, + { "SONY", "DSC-RX100", WarmWhiteFluorescent, 0, { 1.5156, 1, 3.7656, 0 } }, + { "SONY", "DSC-RX100", CoolWhiteFluorescent, 0, { 2.0430, 1, 3.1055, 0 } }, + { "SONY", "DSC-RX100", DayWhiteFluorescent, 0, { 2.0000, 1, 2.1602, 0 } }, + { "SONY", "DSC-RX100", DaylightFluorescent, 0, { 2.2266, 1, 1.8789, 0 } }, + { "SONY", "DSC-RX100", Flash, 0, { 2.5352, 1, 1.6797, 0 } }, + + { "SONY", "DSC-RX100M2", Daylight, 0, { 2.695313, 1, 2.046875, 0 } }, + { "SONY", "DSC-RX100M2", Shade, 0, { 3.230469, 1, 1.687500, 0 } }, + { "SONY", "DSC-RX100M2", Cloudy, 0, { 2.921875, 1, 1.878906, 0 } }, + { "SONY", "DSC-RX100M2", Incandescent, 0, { 1.644531, 1, 3.660156, 0 } }, + { "SONY", "DSC-RX100M2", WarmWhiteFluorescent, 0, { 1.968750, 1, 3.566406, 0 } }, + { "SONY", "DSC-RX100M2", CoolWhiteFluorescent, 0, { 2.515625, 1, 2.988281, 0 } }, + { "SONY", "DSC-RX100M2", DayWhiteFluorescent, 0, { 2.593750, 1, 2.121094, 0 } }, + { "SONY", "DSC-RX100M2", DaylightFluorescent, 0, { 2.890625, 1, 1.796875, 0 } }, + { "SONY", "DSC-RX100M2", Flash, 0, { 3.175781, 1, 1.597656, 0 } }, + + { "SONY", "DSC-RX100M3", Daylight, 0, { 2.390625, 1, 1.785156, 0 } }, + { "SONY", "DSC-RX100M3", Shade, 0, { 2.832031, 1, 1.480469, 0 } }, + { "SONY", "DSC-RX100M3", Cloudy, 0, { 2.578125, 1, 1.640625, 0 } }, + { "SONY", "DSC-RX100M3", Incandescent, 0, { 1.488281, 1, 3.109375, 0 } }, + { "SONY", "DSC-RX100M3", WarmWhiteFluorescent, 0, { 1.734375, 1, 3.015625, 0 } }, + { "SONY", "DSC-RX100M3", CoolWhiteFluorescent, 0, { 2.222656, 1, 2.476563, 0 } }, + { "SONY", "DSC-RX100M3", DayWhiteFluorescent, 0, { 2.277344, 1, 1.796875, 0 } }, + { "SONY", "DSC-RX100M3", DaylightFluorescent, 0, { 2.531250, 1, 1.601563, 0 } }, + { "SONY", "DSC-RX100M3", Flash, 0, { 2.761719, 1, 1.515625, 0 } }, + { "SONY", "DSC-RX100M3", "5500K", 0, { 2.441406, 1, 1.742188, 0 } }, + + { "SONY", "DSC-RX100M4", Daylight, 0, { 2.566406, 1, 1.769531, 0 } }, + { "SONY", "DSC-RX100M4", Cloudy, 0, { 2.773438, 1, 1.628906, 0 } }, + { "SONY", "DSC-RX100M4", Incandescent, 0, { 1.582031, 1, 3.082031, 0 } }, + { "SONY", "DSC-RX100M4", WarmWhiteFluorescent, 0, { 1.917969, 1, 2.933594, 0 } }, + { "SONY", "DSC-RX100M4", CoolWhiteFluorescent, 0, { 2.488281, 1, 2.402344, 0 } }, + { "SONY", "DSC-RX100M4", DayWhiteFluorescent, 0, { 2.535156, 1, 1.769531, 0 } }, + { "SONY", "DSC-RX100M4", DaylightFluorescent, 0, { 2.808594, 1, 1.582031, 0 } }, + { "SONY", "DSC-RX100M4", Flash, 0, { 2.953125, 1, 1.464844, 0 } }, + { "SONY", "DSC-RX100M4", "5500K", 0, { 2.625000, 1, 1.726563, 0 } }, + + { "SONY", "DSLR-A100", Daylight, -3, { 1.601562, 1, 2.101562, 0 } }, + { "SONY", "DSLR-A100", Daylight, 0, { 1.746094, 1, 1.843750, 0 } }, + { "SONY", "DSLR-A100", Daylight, 3, { 1.914062, 1, 1.628906, 0 } }, + { "SONY", "DSLR-A100", Shade, -3, { 1.906250, 1, 1.843750, 0 } }, + { "SONY", "DSLR-A100", Shade, 0, { 2.070312, 1, 1.609375, 0 } }, + { "SONY", "DSLR-A100", Shade, 3, { 2.281250, 1, 1.429688, 0 } }, + { "SONY", "DSLR-A100", Cloudy, -3, { 1.691406, 1, 1.863281, 0 } }, + { "SONY", "DSLR-A100", Cloudy, 0, { 1.855469, 1, 1.628906, 0 } }, + { "SONY", "DSLR-A100", Cloudy, 3, { 2.023438, 1, 1.445312, 0 } }, + { "SONY", "DSLR-A100", Tungsten, -3, { 1, 1.028112, 4.610442, 0 } }, + { "SONY", "DSLR-A100", Tungsten, 0, { 1.054688, 1, 3.917969, 0 } }, + { "SONY", "DSLR-A100", Tungsten, 3, { 1.164062, 1, 3.476562, 0 } }, + { "SONY", "DSLR-A100", Fluorescent, -2, { 1.058594, 1, 4.453125, 0 } }, + { "SONY", "DSLR-A100", Fluorescent, 0, { 1.718750, 1, 3.058594, 0 } }, + { "SONY", "DSLR-A100", Fluorescent, 3, { 2.238281, 1, 1.949219, 0 } }, + { "SONY", "DSLR-A100", Fluorescent, 4, { 1.992188, 1, 1.757812, 0 } }, + { "SONY", "DSLR-A100", Flash, -3, { 1.710938, 1, 1.988281, 0 } }, + { "SONY", "DSLR-A100", Flash, 0, { 1.859375, 1, 1.746094, 0 } }, + { "SONY", "DSLR-A100", Flash, 3, { 2.046875, 1, 1.542969, 0 } }, + + { "SONY", "DSLR-A200", Daylight, -3 , { 1.507812, 1, 1.996094, 0 } }, + { "SONY", "DSLR-A200", Daylight, 0 , { 1.664062, 1, 1.757812, 0 } }, + { "SONY", "DSLR-A200", Daylight, 3 , { 1.820313, 1, 1.546875, 0 } }, + { "SONY", "DSLR-A200", Shade, -3 , { 1.800781, 1, 1.578125, 0 } }, + { "SONY", "DSLR-A200", Shade, 0 , { 1.972656, 1, 1.390625, 0 } }, + { "SONY", "DSLR-A200", Shade, 3 , { 2.164063, 1, 1.218750, 0 } }, + { "SONY", "DSLR-A200", Cloudy, -3 , { 1.636719, 1, 1.800781, 0 } }, + { "SONY", "DSLR-A200", Cloudy, 0 , { 1.800781, 1, 1.585937, 0 } }, + { "SONY", "DSLR-A200", Cloudy, 3 , { 1.972656, 1, 1.390625, 0 } }, + { "SONY", "DSLR-A200", Tungsten, -3 , { 1, 1.136719, 4.355469, 0 } }, + { "SONY", "DSLR-A200", Tungsten, 0 , { 1, 1.027344, 3.492187, 0 } }, + { "SONY", "DSLR-A200", Tungsten, 3 , { 1.082031, 1, 3.019531, 0 } }, + { "SONY", "DSLR-A200", Fluorescent, -2 , { 1, 1.066406, 4.453125, 0 } }, + { "SONY", "DSLR-A200", Fluorescent, 0 , { 1.554687, 1, 2.601562, 0 } }, + { "SONY", "DSLR-A200", Fluorescent, 3 , { 2.109375, 1, 1.828125, 0 } }, + { "SONY", "DSLR-A200", Flash, -3 , { 1.746094, 1, 1.660156, 0 } }, + { "SONY", "DSLR-A200", Flash, 0 , { 1.917969, 1, 1.460937, 0 } }, + { "SONY", "DSLR-A200", Flash, 3 , { 2.109375, 1, 1.285156, 0 } }, + { "SONY", "DSLR-A200", "5600K", 0 , { 1.710938, 1, 1.683594, 0 } }, + + /* SONY DSLR-A230 presets - firmware v1.10 */ + { "SONY", "DSLR-A230", Daylight, -3, { 1.621094, 1, 1.949219, 0 } }, + { "SONY", "DSLR-A230", Daylight, -2, { 1.675781, 1, 1.859375, 0 } }, + { "SONY", "DSLR-A230", Daylight, -1, { 1.726563, 1, 1.773438, 0 } }, + { "SONY", "DSLR-A230", Daylight, 0, { 1.789063, 1, 1.695313, 0 } }, + { "SONY", "DSLR-A230", Daylight, 1, { 1.839844, 1, 1.625000, 0 } }, + { "SONY", "DSLR-A230", Daylight, 2, { 1.898438, 1, 1.546875, 0 } }, + { "SONY", "DSLR-A230", Daylight, 3, { 1.957031, 1, 1.472656, 0 } }, + { "SONY", "DSLR-A230", Shade, -3, { 1.937500, 1, 1.503906, 0 } }, + { "SONY", "DSLR-A230", Shade, -2, { 1.996094, 1, 1.433594, 0 } }, + { "SONY", "DSLR-A230", Shade, -1, { 2.054688, 1, 1.371094, 0 } }, + { "SONY", "DSLR-A230", Shade, 0, { 2.121094, 1, 1.304688, 0 } }, + { "SONY", "DSLR-A230", Shade, 1, { 2.187500, 1, 1.238281, 0 } }, + { "SONY", "DSLR-A230", Shade, 2, { 2.261719, 1, 1.175781, 0 } }, + { "SONY", "DSLR-A230", Shade, 3, { 2.324219, 1, 1.121094, 0 } }, + { "SONY", "DSLR-A230", Cloudy, -3, { 1.761719, 1, 1.738281, 0 } }, + { "SONY", "DSLR-A230", Cloudy, -2, { 1.816406, 1, 1.656250, 0 } }, + { "SONY", "DSLR-A230", Cloudy, -1, { 1.875000, 1, 1.582031, 0 } }, + { "SONY", "DSLR-A230", Cloudy, 0, { 1.937500, 1, 1.515625, 0 } }, + { "SONY", "DSLR-A230", Cloudy, 1, { 1.996094, 1, 1.441406, 0 } }, + { "SONY", "DSLR-A230", Cloudy, 2, { 2.054688, 1, 1.371094, 0 } }, + { "SONY", "DSLR-A230", Cloudy, 3, { 2.121094, 1, 1.304688, 0 } }, + { "SONY", "DSLR-A230", Tungsten, -3, { 0.944649, 1, 3.896679, 0 } }, + { "SONY", "DSLR-A230", Tungsten, -2, { 0.977099, 1, 3.740458, 0 } }, + { "SONY", "DSLR-A230", Tungsten, -1, { 1.015625, 1, 3.582031, 0 } }, + { "SONY", "DSLR-A230", Tungsten, 0, { 1.046875, 1, 3.437500, 0 } }, + { "SONY", "DSLR-A230", Tungsten, 1, { 1.082031, 1, 3.292969, 0 } }, + { "SONY", "DSLR-A230", Tungsten, 2, { 1.121094, 1, 3.167969, 0 } }, + { "SONY", "DSLR-A230", Tungsten, 3, { 1.164063, 1, 3.035156, 0 } }, + { "SONY", "DSLR-A230", Fluorescent, -2, { 0.977099, 1, 3.942748, 0 } }, + { "SONY", "DSLR-A230", Fluorescent, -1, { 1.250000, 1, 3.250000, 0 } }, + { "SONY", "DSLR-A230", Fluorescent, 0, { 1.648438, 1, 2.457031, 0 } }, + { "SONY", "DSLR-A230", Fluorescent, 1, { 1.867188, 1, 2.035156, 0 } }, + { "SONY", "DSLR-A230", Fluorescent, 2, { 1.769531, 1, 1.742188, 0 } }, + { "SONY", "DSLR-A230", Fluorescent, 3, { 2.277344, 1, 1.742188, 0 } }, + { "SONY", "DSLR-A230", Fluorescent, 4, { 2.027344, 1, 1.527344, 0 } }, + { "SONY", "DSLR-A230", Flash, -3, { 1.804688, 1, 1.722656, 0 } }, + { "SONY", "DSLR-A230", Flash, -2, { 1.863281, 1, 1.656250, 0 } }, + { "SONY", "DSLR-A230", Flash, -1, { 1.921875, 1, 1.582031, 0 } }, + { "SONY", "DSLR-A230", Flash, 0, { 1.980469, 1, 1.500000, 0 } }, + { "SONY", "DSLR-A230", Flash, 1, { 2.046875, 1, 1.433594, 0 } }, + { "SONY", "DSLR-A230", Flash, 2, { 2.113281, 1, 1.359375, 0 } }, + { "SONY", "DSLR-A230", Flash, 3, { 2.175781, 1, 1.304688, 0 } }, + + { "SONY", "DSLR-A300", Daylight, -3, { 1.480469, 1, 1.960937, 0 } }, + { "SONY", "DSLR-A300", Daylight, 0, { 1.632813, 1, 1.730469, 0 } }, + { "SONY", "DSLR-A300", Daylight, 3, { 1.789062, 1, 1.527344, 0 } }, + { "SONY", "DSLR-A300", Shade, -3, { 1.769531, 1, 1.554687, 0 } }, + { "SONY", "DSLR-A300", Shade, 0, { 1.937500, 1, 1.371094, 0 } }, + { "SONY", "DSLR-A300", Shade, 3, { 2.121094, 1, 1.207031, 0 } }, + { "SONY", "DSLR-A300", Cloudy, -3, { 1.609375, 1, 1.769531, 0 } }, + { "SONY", "DSLR-A300", Cloudy, 0, { 1.769531, 1, 1.566406, 0 } }, + { "SONY", "DSLR-A300", Cloudy, 3, { 1.937500, 1, 1.371094, 0 } }, + { "SONY", "DSLR-A300", Tungsten, -3, { 1, 1.152344, 4.308594, 0 } }, + { "SONY", "DSLR-A300", Tungsten, 0, { 1, 1.039063, 3.449219, 0 } }, + { "SONY", "DSLR-A300", Tungsten, 3, { 1.066406, 1, 2.953125, 0 } }, + { "SONY", "DSLR-A300", Fluorescent, -2, { 1, 1.082031, 4.410156, 0 } }, + { "SONY", "DSLR-A300", Fluorescent, -1, { 1.117187, 1, 3.343750, 0 } }, + { "SONY", "DSLR-A300", Fluorescent, 0, { 1.527344, 1, 2.546875, 0 } }, + { "SONY", "DSLR-A300", Fluorescent, 1, { 1.714844, 1, 2.109375, 0 } }, + { "SONY", "DSLR-A300", Fluorescent, 2, { 1.546875, 1, 1.769531, 0 } }, + { "SONY", "DSLR-A300", Fluorescent, 3, { 2.070312, 1, 1.796875, 0 } }, + { "SONY", "DSLR-A300", Fluorescent, 4, { 1.761719, 1, 1.527344, 0 } }, + { "SONY", "DSLR-A300", Flash, -3, { 1.714844, 1, 1.632812, 0 } }, + { "SONY", "DSLR-A300", Flash, 0, { 1.882812, 1, 1.441406, 0 } }, + { "SONY", "DSLR-A300", Flash, 3, { 2.070312, 1, 1.273438, 0 } }, + + { "SONY", "DSLR-A330", Daylight, -3, { 1.5898, 1, 1.9687, 0 } }, + { "SONY", "DSLR-A330", Daylight, -2, { 1.6406, 1, 1.8789, 0 } }, + { "SONY", "DSLR-A330", Daylight, -1, { 1.6914, 1, 1.7969, 0 } }, + { "SONY", "DSLR-A330", Daylight, 0, { 1.7500, 1, 1.7227, 0 } }, + { "SONY", "DSLR-A330", Daylight, 1, { 1.7969, 1, 1.6523, 0 } }, + { "SONY", "DSLR-A330", Daylight, 2, { 1.8555, 1, 1.5742, 0 } }, + { "SONY", "DSLR-A330", Daylight, 3, { 1.9141, 1, 1.5000, 0 } }, + { "SONY", "DSLR-A330", Shade, -3, { 1.8906, 1, 1.5352, 0 } }, + { "SONY", "DSLR-A330", Shade, -2, { 1.9492, 1, 1.4648, 0 } }, + { "SONY", "DSLR-A330", Shade, -1, { 2.0078, 1, 1.4023, 0 } }, + { "SONY", "DSLR-A330", Shade, 0, { 2.0703, 1, 1.3359, 0 } }, + { "SONY", "DSLR-A330", Shade, 1, { 2.1328, 1, 1.2734, 0 } }, + { "SONY", "DSLR-A330", Shade, 2, { 2.2031, 1, 1.2109, 0 } }, + { "SONY", "DSLR-A330", Shade, 3, { 2.2656, 1, 1.1602, 0 } }, + { "SONY", "DSLR-A330", Cloudy, -3, { 1.7227, 1, 1.7617, 0 } }, + { "SONY", "DSLR-A330", Cloudy, -2, { 1.7773, 1, 1.6836, 0 } }, + { "SONY", "DSLR-A330", Cloudy, -1, { 1.8359, 1, 1.6094, 0 } }, + { "SONY", "DSLR-A330", Cloudy, 0, { 1.8906, 1, 1.5430, 0 } }, + { "SONY", "DSLR-A330", Cloudy, 1, { 1.9492, 1, 1.4727, 0 } }, + { "SONY", "DSLR-A330", Cloudy, 2, { 2.0078, 1, 1.4023, 0 } }, + { "SONY", "DSLR-A330", Cloudy, 3, { 2.0703, 1, 1.3359, 0 } }, + { "SONY", "DSLR-A330", Tungsten, -3, { 1.0664, 1, 1.0664, 0 } }, + { "SONY", "DSLR-A330", Tungsten, -2, { 1.0313, 1, 1.0313, 0 } }, + { "SONY", "DSLR-A330", Tungsten, -1, { 1.0039, 1, 3.5625, 0 } }, + { "SONY", "DSLR-A330", Tungsten, 0, { 1.0352, 1, 3.4219, 0 } }, + { "SONY", "DSLR-A330", Tungsten, 1, { 1.0703, 1, 3.2812, 0 } }, + { "SONY", "DSLR-A330", Tungsten, 2, { 1.1055, 1, 3.1602, 0 } }, + { "SONY", "DSLR-A330", Tungsten, 3, { 1.1484, 1, 3.0313, 0 } }, + { "SONY", "DSLR-A330", Fluorescent, -2, { 1.0312, 1, 1.0312, 0 } }, + { "SONY", "DSLR-A330", Fluorescent, -1, { 1.2305, 1, 3.2383, 0 } }, + { "SONY", "DSLR-A330", Fluorescent, 0, { 1.6172, 1, 2.4648, 0 } }, + { "SONY", "DSLR-A330", Fluorescent, 1, { 1.8242, 1, 2.0508, 0 } }, + { "SONY", "DSLR-A330", Fluorescent, 2, { 1.7305, 1, 1.7695, 0 } }, + { "SONY", "DSLR-A330", Fluorescent, 3, { 2.2227, 1, 1.7695, 0 } }, + { "SONY", "DSLR-A330", Fluorescent, 4, { 1.9805, 1, 1.5586, 0 } }, + { "SONY", "DSLR-A330", Flash, -3, { 1.7656, 1, 1.7500, 0 } }, + { "SONY", "DSLR-A330", Flash, -2, { 1.8203, 1, 1.6836, 0 } }, + { "SONY", "DSLR-A330", Flash, -1, { 1.8789, 1, 1.6094, 0 } }, + { "SONY", "DSLR-A330", Flash, 0, { 1.9375, 1, 1.5313, 0 } }, + { "SONY", "DSLR-A330", Flash, 1, { 2.0000, 1, 1.4648, 0 } }, + { "SONY", "DSLR-A330", Flash, 2, { 2.0625, 1, 1.3945, 0 } }, + { "SONY", "DSLR-A330", Flash, 3, { 2.1250, 1, 1.3359, 0 } }, + + { "SONY", "DSLR-A350", Daylight, -3, { 2.316406, 1, 1.886719, 0 } }, + { "SONY", "DSLR-A350", Daylight, 0, { 2.531250, 1, 1.648437, 0 } }, + { "SONY", "DSLR-A350", Daylight, 3, { 2.750000, 1, 1.437500, 0 } }, + { "SONY", "DSLR-A350", Shade, -3, { 2.722656, 1, 1.468750, 0 } }, + { "SONY", "DSLR-A350", Shade, 0, { 2.960937, 1, 1.281250, 0 } }, + { "SONY", "DSLR-A350", Shade, 3, { 3.222656, 1, 1.109375, 0 } }, + { "SONY", "DSLR-A350", Cloudy, -3, { 2.496094, 1, 1.691406, 0 } }, + { "SONY", "DSLR-A350", Cloudy, 0, { 2.722656, 1, 1.476562, 0 } }, + { "SONY", "DSLR-A350", Cloudy, 3, { 2.960937, 1, 1.281250, 0 } }, + { "SONY", "DSLR-A350", Tungsten, -3, { 1.445313, 1, 3.722656, 0 } }, + { "SONY", "DSLR-A350", Tungsten, 0, { 1.578125, 1, 3.289062, 0 } }, + { "SONY", "DSLR-A350", Tungsten, 3, { 1.726562, 1, 2.910156, 0 } }, + { "SONY", "DSLR-A350", Flash, -3, { 2.644531, 1, 1.558594, 0 } }, + { "SONY", "DSLR-A350", Flash, 0, { 2.875000, 1, 1.355469, 0 } }, + { "SONY", "DSLR-A350", Flash, 3, { 3.136719, 1, 1.175781, 0 } }, + { "SONY", "DSLR-A350", CoolWhiteFluorescent, 0, { 2.226563, 1, 2.355469, 0 } }, + { "SONY", "DSLR-A350", Fluorescent, 0, { 1.554687, 1, 3.984375, 0 } }, + { "SONY", "DSLR-A350", WarmWhiteFluorescent, 0, { 1.816406, 1, 3.207031, 0 } }, + { "SONY", "DSLR-A350", DayWhiteFluorescent, 0, { 2.511719, 1, 1.957031, 0 } }, +// { "SONY", "DSLR-A350", DayWhiteFluorescent, 0, { 2.484375, 1, 1.683594, 0 } }, + { "SONY", "DSLR-A350", DaylightFluorescent, 0, { 3.023437, 1, 1.671875, 0 } }, +// { "SONY", "DSLR-A350", DaylightFluorescent, 0, { 2.773438, 1, 1.441406, 0 } }, + + { "SONY", "DSLR-A380", Daylight, -3, { 2.335938, 1, 1.875000, 0 } }, + { "SONY", "DSLR-A380", Daylight, 0, { 2.562500, 1, 1.648438, 0 } }, + { "SONY", "DSLR-A380", Daylight, 3, { 2.796875, 1, 1.445312, 0 } }, + { "SONY", "DSLR-A380", Shade, -3, { 2.765625, 1, 1.472656, 0 } }, + { "SONY", "DSLR-A380", Shade, 0, { 3.019531, 1, 1.292969, 0 } }, + { "SONY", "DSLR-A380", Shade, 3, { 3.296875, 1, 1.128906, 0 } }, + { "SONY", "DSLR-A380", Cloudy, -3, { 2.527344, 1, 1.687500, 0 } }, + { "SONY", "DSLR-A380", Cloudy, 0, { 2.765625, 1, 1.480469, 0 } }, + { "SONY", "DSLR-A380", Cloudy, 3, { 3.019531, 1, 1.292969, 0 } }, + { "SONY", "DSLR-A380", Tungsten, -3, { 1.410156, 1, 3.636719, 0 } }, + { "SONY", "DSLR-A380", Tungsten, 0, { 1.550781, 1, 3.222656, 0 } }, + { "SONY", "DSLR-A380", Tungsten, 3, { 1.710938, 1, 2.859375, 0 } }, + { "SONY", "DSLR-A380", Fluorescent, -2, { 1.429687, 1, 3.906250, 0 } }, + { "SONY", "DSLR-A380", Fluorescent, 0, { 2.234375, 1, 2.335938, 0 } }, + { "SONY", "DSLR-A380", Fluorescent, 4, { 2.792969, 1, 1.445312, 0 } }, + { "SONY", "DSLR-A380", Flash, -3, { 2.574219, 1, 1.664063, 0 } }, + { "SONY", "DSLR-A380", Flash, 0, { 2.816406, 1, 1.453125, 0 } }, + { "SONY", "DSLR-A380", Flash, 3, { 3.070312, 1, 1.273437, 0 } }, + + { "SONY", "DSLR-A390", Daylight, -3, { 2.0273, 1, 1.5820, 0 } }, + { "SONY", "DSLR-A390", Daylight, 0, { 2.2188, 1, 1.3711, 0 } }, + { "SONY", "DSLR-A390", Daylight, 3, { 2.4180, 1, 1.1836, 0 } }, + { "SONY", "DSLR-A390", Shade, -3, { 2.3906, 1, 1.2148, 0 } }, + { "SONY", "DSLR-A390", Shade, 0, { 2.6055, 1, 1.0469, 0 } }, + { "SONY", "DSLR-A390", Shade, 3, { 2.8392, 1, 1.0000, 0 } }, + { "SONY", "DSLR-A390", Cloudy, -3, { 2.1875, 1, 1.4062, 0 } }, + { "SONY", "DSLR-A390", Cloudy, 0, { 2.3906, 1, 1.2227, 0 } }, + { "SONY", "DSLR-A390", Cloudy, 3, { 2.6055, 1, 1.0469, 0 } }, + { "SONY", "DSLR-A390", Tungsten, -3, { 1.2461, 1, 3.1992, 0 } }, + { "SONY", "DSLR-A390", Tungsten, 0, { 1.3633, 1, 2.8164, 0 } }, + { "SONY", "DSLR-A390", Tungsten, 3, { 1.4961, 1, 2.4844, 0 } }, + { "SONY", "DSLR-A390", Fluorescent, -2, { 1.2617, 1, 3.4453, 0 } }, + { "SONY", "DSLR-A390", Fluorescent, 0, { 1.9414, 1, 2.0039, 0 } }, + { "SONY", "DSLR-A390", Fluorescent, 4, { 2.4102, 1, 1.1836, 0 } }, + { "SONY", "DSLR-A390", Flash, -3, { 2.2305, 1, 1.3867, 0 } }, + { "SONY", "DSLR-A390", Flash, 0, { 2.4336, 1, 1.1953, 0 } }, + { "SONY", "DSLR-A390", Flash, 3, { 2.6484, 1, 1.0313, 0 } }, + + /* SONY DSLR-A450 presets */ + { "SONY", "DSLR-A450", Daylight, -3, { 2.109375, 1, 1.593750, 0 } }, + { "SONY", "DSLR-A450", Daylight, 0, { 2.296875, 1, 1.445312, 0 } }, + { "SONY", "DSLR-A450", Daylight, 3, { 2.503906, 1, 1.312500, 0 } }, + { "SONY", "DSLR-A450", Shade, -3, { 2.468750, 1, 1.332031, 0 } }, + { "SONY", "DSLR-A450", Shade, 0, { 2.691406, 1, 1.214844, 0 } }, + { "SONY", "DSLR-A450", Shade, 3, { 2.925781, 1, 1.105469, 0 } }, + { "SONY", "DSLR-A450", Cloudy, -3, { 2.261719, 1, 1.468750, 0 } }, + { "SONY", "DSLR-A450", Cloudy, 0, { 2.464844, 1, 1.335938, 0 } }, + { "SONY", "DSLR-A450", Cloudy, 3, { 2.683594, 1, 1.214844, 0 } }, + { "SONY", "DSLR-A450", Tungsten, -3, { 1.312500, 1, 2.734375, 0 } }, + { "SONY", "DSLR-A450", Tungsten, 0, { 1.437500, 1, 2.468750, 0 } }, + { "SONY", "DSLR-A450", Tungsten, 3, { 1.566406, 1, 2.234375, 0 } }, + { "SONY", "DSLR-A450", Fluorescent, -1, { 1.636719, 1, 2.507812, 0 } }, + { "SONY", "DSLR-A450", Fluorescent, 0, { 2.019531, 1, 2.003906, 0 } }, + { "SONY", "DSLR-A450", Fluorescent, 3, { 2.507812, 1, 1.355469, 0 } }, + { "SONY", "DSLR-A450", Flash, -3, { 2.339844, 1, 1.433594, 0 } }, + { "SONY", "DSLR-A450", Flash, 0, { 2.550781, 1, 1.304688, 0 } }, + { "SONY", "DSLR-A450", Flash, 3, { 2.777344, 1, 1.183594, 0 } }, + + { "SONY", "DSLR-A500", Daylight, 0, { 2.242188, 1, 1.300781, 0 } }, + { "SONY", "DSLR-A500", Shade, 0, { 2.609375, 1, 1.066406, 0 } }, + { "SONY", "DSLR-A500", Cloudy, 0, { 2.398438, 1, 1.191406, 0 } }, + { "SONY", "DSLR-A500", Tungsten, 0, { 1.433594, 1, 2.328125, 0 } }, + { "SONY", "DSLR-A500", WarmWhiteFluorescent, 0, { 1.679688, 1, 2.351563, 0 } }, + { "SONY", "DSLR-A500", CoolWhiteFluorescent, 0, { 2.000000, 1, 1.878906, 0 } }, + { "SONY", "DSLR-A500", DayWhiteFluorescent, 0, { 2.222656, 1, 1.359375, 0 } }, + { "SONY", "DSLR-A500", DaylightFluorescent, 0, { 2.484375, 1, 1.199219, 0 } }, + { "SONY", "DSLR-A500", Flash, 0, { 2.453125, 1, 1.152344, 0 } }, + { "SONY", "DSLR-A500", "2500K", 0, { 1.250000, 1, 2.781250, 0 } }, + { "SONY", "DSLR-A500", "3200K", 0, { 1.589844, 1, 2.027344, 0 } }, + { "SONY", "DSLR-A500", "4500K", 0, { 2.039063, 1, 1.464844, 0 } }, + { "SONY", "DSLR-A500", "6000K", 0, { 2.378906, 1, 1.199219, 0 } }, + { "SONY", "DSLR-A500", "8500K", 0, { 2.726563, 1, 1.007813, 0 } }, + + { "SONY", "DSLR-A550", Daylight, 0, { 2.160156, 1, 1.496094, 0 } }, + { "SONY", "DSLR-A550", Shade, 0, { 2.519531, 1, 1.234375, 0 } }, + { "SONY", "DSLR-A550", Cloudy, 0, { 2.312500, 1, 1.375000, 0 } }, + { "SONY", "DSLR-A550", Tungsten, 0, { 1.367188, 1, 2.632813, 0 } }, + { "SONY", "DSLR-A550", Fluorescent, 0, { 1.902344, 1, 2.117188, 0 } }, + { "SONY", "DSLR-A550", Flash, 0, { 2.390625, 1, 1.335938, 0 } }, + + { "SONY", "DSLR-A580", Daylight, 0, { 2.570313, 1, 1.578125, 0 } }, + { "SONY", "DSLR-A580", Shade, 0, { 3.015625, 1, 1.304688, 0 } }, + { "SONY", "DSLR-A580", Cloudy, 0, { 2.757813, 1, 1.453125, 0 } }, + { "SONY", "DSLR-A580", Tungsten, 0, { 1.593750, 1, 2.781250, 0 } }, + { "SONY", "DSLR-A580", WarmWhiteFluorescent, 0, { 1.824219, 1, 2.785156, 0 } }, + { "SONY", "DSLR-A580", CoolWhiteFluorescent, 0, { 2.253906, 1, 2.210938, 0 } }, + { "SONY", "DSLR-A580", DayWhiteFluorescent, 0, { 2.488281, 1, 1.621094, 0 } }, + { "SONY", "DSLR-A580", DaylightFluorescent, 0, { 2.820313, 1, 1.445313, 0 } }, + { "SONY", "DSLR-A580", Flash, 0, { 2.867188, 1, 1.394531, 0 } }, + { "SONY", "DSLR-A580", "2500K", 0, { 1.375000, 1, 3.308594, 0 } }, + { "SONY", "DSLR-A580", "3200K", 0, { 1.781250, 1, 2.429688, 0 } }, + { "SONY", "DSLR-A580", "4500K", 0, { 2.324219, 1, 1.769531, 0 } }, + { "SONY", "DSLR-A580", "6000K", 0, { 2.734375, 1, 1.464844, 0 } }, + { "SONY", "DSLR-A580", "8500K", 0, { 3.156250, 1, 1.238281, 0 } }, + + /* SONY DSLR-A700 presets - firmware v4 */ + { "SONY", "DSLR-A700", Daylight, -3, { 1.972656, 1, 1.777344, 0 } }, + { "SONY", "DSLR-A700", Daylight, -2, { 2.027344, 1, 1.718750, 0 } }, + { "SONY", "DSLR-A700", Daylight, -1, { 2.089844, 1, 1.664063, 0 } }, + { "SONY", "DSLR-A700", Daylight, 0, { 2.140625, 1, 1.605469, 0 } }, + { "SONY", "DSLR-A700", Daylight, 1, { 2.195313, 1, 1.550781, 0 } }, + { "SONY", "DSLR-A700", Daylight, 2, { 2.257813, 1, 1.500000, 0 } }, + { "SONY", "DSLR-A700", Daylight, 3, { 2.320313, 1, 1.449219, 0 } }, + { "SONY", "DSLR-A700", Shade, -3, { 2.304688, 1, 1.464844, 0 } }, + { "SONY", "DSLR-A700", Shade, -2, { 2.359375, 1, 1.414063, 0 } }, + { "SONY", "DSLR-A700", Shade, -1, { 2.429688, 1, 1.367188, 0 } }, + { "SONY", "DSLR-A700", Shade, 0, { 2.500000, 1, 1.320313, 0 } }, + { "SONY", "DSLR-A700", Shade, 1, { 2.570313, 1, 1.277344, 0 } }, + { "SONY", "DSLR-A700", Shade, 2, { 2.636719, 1, 1.234375, 0 } }, + { "SONY", "DSLR-A700", Shade, 3, { 2.714844, 1, 1.191406, 0 } }, + { "SONY", "DSLR-A700", Cloudy, -3, { 2.109375, 1, 1.632813, 0 } }, + { "SONY", "DSLR-A700", Cloudy, -2, { 2.171875, 1, 1.578125, 0 } }, + { "SONY", "DSLR-A700", Cloudy, -1, { 2.234375, 1, 1.527344, 0 } }, + { "SONY", "DSLR-A700", Cloudy, 0, { 2.296875, 1, 1.472656, 0 } }, + { "SONY", "DSLR-A700", Cloudy, 1, { 2.359375, 1, 1.421875, 0 } }, + { "SONY", "DSLR-A700", Cloudy, 2, { 2.429688, 1, 1.375000, 0 } }, + { "SONY", "DSLR-A700", Cloudy, 3, { 2.484375, 1, 1.328125, 0 } }, + { "SONY", "DSLR-A700", Tungsten, -3, { 1.238281, 1, 3.140625, 0 } }, + { "SONY", "DSLR-A700", Tungsten, -2, { 1.273438, 1, 3.035156, 0 } }, + { "SONY", "DSLR-A700", Tungsten, -1, { 1.312500, 1, 2.933594, 0 } }, + { "SONY", "DSLR-A700", Tungsten, 0, { 1.347656, 1, 2.847656, 0 } }, + { "SONY", "DSLR-A700", Tungsten, 1, { 1.390625, 1, 2.746094, 0 } }, + { "SONY", "DSLR-A700", Tungsten, 2, { 1.425781, 1, 2.660156, 0 } }, + { "SONY", "DSLR-A700", Tungsten, 3, { 1.464844, 1, 2.562500, 0 } }, + { "SONY", "DSLR-A700", Fluorescent, -2, { 1.304688, 1, 3.515625, 0 } }, + { "SONY", "DSLR-A700", Fluorescent, -1, { 1.535156, 1, 2.878906, 0 } }, + { "SONY", "DSLR-A700", Fluorescent, 0, { 1.910156, 1, 2.351563, 0 } }, + { "SONY", "DSLR-A700", Fluorescent, 1, { 2.132813, 1, 1.949219, 0 } }, + { "SONY", "DSLR-A700", Fluorescent, 2, { 2.058594, 1, 1.675781, 0 } }, + { "SONY", "DSLR-A700", Fluorescent, 3, { 2.488281, 1, 1.667969, 0 } }, + { "SONY", "DSLR-A700", Fluorescent, 4, { 2.320313, 1, 1.453125, 0 } }, + { "SONY", "DSLR-A700", Flash, -3, { 2.171875, 1, 1.578125, 0 } }, + { "SONY", "DSLR-A700", Flash, -2, { 2.234375, 1, 1.527344, 0 } }, + { "SONY", "DSLR-A700", Flash, -1, { 2.281250, 1, 1.472656, 0 } }, + { "SONY", "DSLR-A700", Flash, 0, { 2.324219, 1, 1.414063, 0 } }, + { "SONY", "DSLR-A700", Flash, 1, { 2.414063, 1, 1.375000, 0 } }, + { "SONY", "DSLR-A700", Flash, 2, { 2.484375, 1, 1.328125, 0 } }, + { "SONY", "DSLR-A700", Flash, 3, { 2.554688, 1, 1.285156, 0 } }, + + /* SONY DSLR-A850 presets - firmware v1.00 */ + { "SONY", "DSLR-A850", Daylight, -3, { 2.445313, 1, 1.515625, 0 } }, + { "SONY", "DSLR-A850", Daylight, 0, { 2.683594, 1, 1.359375, 0 } }, + { "SONY", "DSLR-A850", Daylight, 3, { 2.929688, 1, 1.222656, 0 } }, + { "SONY", "DSLR-A850", Shade, -3, { 2.898438, 1, 1.242188, 0 } }, + { "SONY", "DSLR-A850", Shade, 0, { 3.164062, 1, 1.121094, 0 } }, + { "SONY", "DSLR-A850", Shade, 3, { 3.457031, 1, 1.011719, 0 } }, + { "SONY", "DSLR-A850", Cloudy, -3, { 2.644531, 1, 1.386719, 0 } }, + { "SONY", "DSLR-A850", Cloudy, 0, { 2.898438, 1, 1.250000, 0 } }, + { "SONY", "DSLR-A850", Cloudy, 3, { 3.164062, 1, 1.121094, 0 } }, + { "SONY", "DSLR-A850", Tungsten, -3, { 1.468750, 1, 2.703125, 0 } }, + { "SONY", "DSLR-A850", Tungsten, 0, { 1.617188, 1, 2.421875, 0 } }, + { "SONY", "DSLR-A850", Tungsten, 3, { 1.785156, 1, 2.175781, 0 } }, + { "SONY", "DSLR-A850", Fluorescent, -2, { 1.531250, 1, 2.925781, 0 } }, + { "SONY", "DSLR-A850", Fluorescent, 0, { 2.324219, 1, 1.882813, 0 } }, + { "SONY", "DSLR-A850", Fluorescent, 4, { 2.945313, 1, 1.238281, 0 } }, + { "SONY", "DSLR-A850", Flash, -3, { 2.757813, 1, 1.324219, 0 } }, + { "SONY", "DSLR-A850", Flash, 0, { 3.015625, 1, 1.191406, 0 } }, + { "SONY", "DSLR-A850", Flash, 3, { 3.296875, 1, 1.070312, 0 } }, + + { "SONY", "DSLR-A900", Daylight, -3, { 2.351563, 1, 1.511719, 0 } }, + { "SONY", "DSLR-A900", Daylight, 0, { 2.585938, 1, 1.355469, 0 } }, + { "SONY", "DSLR-A900", Daylight, 3, { 2.824219, 1, 1.218750, 0 } }, + { "SONY", "DSLR-A900", Shade, -3, { 2.792969, 1, 1.238281, 0 } }, + { "SONY", "DSLR-A900", Shade, 0, { 3.054688, 1, 1.113281, 0 } }, + { "SONY", "DSLR-A900", Shade, 3, { 3.339844, 1, 1.003906, 0 } }, + { "SONY", "DSLR-A900", Cloudy, -3, { 2.546875, 1, 1.382813, 0 } }, + { "SONY", "DSLR-A900", Cloudy, 0, { 2.792969, 1, 1.242187, 0 } }, + { "SONY", "DSLR-A900", Cloudy, 3, { 3.054688, 1, 1.113281, 0 } }, + { "SONY", "DSLR-A900", Tungsten, -3, { 1.402344, 1, 2.707031, 0 } }, + { "SONY", "DSLR-A900", Tungsten, 0, { 1.546875, 1, 2.425781, 0 } }, + { "SONY", "DSLR-A900", Tungsten, 3, { 1.710938, 1, 2.179688, 0 } }, + { "SONY", "DSLR-A900", Fluorescent, -2, { 1.460938, 1, 2.933594, 0 } }, + { "SONY", "DSLR-A900", Fluorescent, 0, { 2.234375, 1, 1.882812, 0 } }, + { "SONY", "DSLR-A900", Fluorescent, 4, { 2.839844, 1, 1.230469, 0 } }, + { "SONY", "DSLR-A900", Flash, -3, { 2.656250, 1, 1.316406, 0 } }, + { "SONY", "DSLR-A900", Flash, 0, { 2.910156, 1, 1.183594, 0 } }, + { "SONY", "DSLR-A900", Flash, 3, { 3.183594, 1, 1.062500, 0 } }, + + { "SONY", "ILCA-68", Daylight, 0, { 2.503906, 1, 1.597656, 0 } }, + { "SONY", "ILCA-68", Shade, 0, { 2.992188, 1, 1.316406, 0 } }, + { "SONY", "ILCA-68", Cloudy, 0, { 2.710938, 1, 1.464844, 0 } }, + { "SONY", "ILCA-68", Tungsten, 0, { 1.535156, 1, 2.890625, 0 } }, + { "SONY", "ILCA-68", WarmWhiteFluorescent, 0, { 1.761719, 1, 2.843750, 0 } }, + { "SONY", "ILCA-68", CoolWhiteFluorescent, 0, { 2.234375, 1, 2.300781, 0 } }, + { "SONY", "ILCA-68", DayWhiteFluorescent, 0, { 2.386719, 1, 1.687500, 0 } }, + { "SONY", "ILCA-68", DaylightFluorescent, 0, { 2.660156, 1, 1.542969, 0 } }, + { "SONY", "ILCA-68", Flash, 0, { 2.875000, 1, 1.386719, 0 } }, + { "SONY", "ILCA-68", "2500K", 0, { 1.335938, 1, 3.492188, 0 } }, + { "SONY", "ILCA-68", "3200K", 0, { 1.718750, 1, 2.500000, 0 } }, + { "SONY", "ILCA-68", "4500K", 0, { 2.257812, 1, 1.800781, 0 } }, + { "SONY", "ILCA-68", "6000K", 0, { 2.687500, 1, 1.476562, 0 } }, + { "SONY", "ILCA-68", "8500K", 0, { 3.148438, 1, 1.246094, 0 } }, + + { "SONY", "ILCA-77M2", Daylight, 0, { 2.785156, 1, 1.679688, 0 } }, + { "SONY", "ILCA-77M2", Shade, 0, { 3.285156, 1, 1.386719, 0 } }, + { "SONY", "ILCA-77M2", Cloudy, 0, { 2.996094, 1, 1.542969, 0 } }, + { "SONY", "ILCA-77M2", Incandescent, 0, { 1.750000, 1, 3.015625, 0 } }, + { "SONY", "ILCA-77M2", WarmWhiteFluorescent, 0, { 2.019531, 1, 2.976563, 0 } }, + { "SONY", "ILCA-77M2", CoolWhiteFluorescent, 0, { 2.531250, 1, 2.472656, 0 } }, + { "SONY", "ILCA-77M2", DayWhiteFluorescent, 0, { 2.683594, 1, 1.781250, 0 } }, + { "SONY", "ILCA-77M2", DaylightFluorescent, 0, { 3.003906, 1, 1.609375, 0 } }, + { "SONY", "ILCA-77M2", Flash, 0, { 3.203125, 1, 1.433594, 0 } }, + + // firmware ILCE-7 (A7) Ver 1.0.1 + { "SONY", "ILCE-7", Daylight, 0, { 2.398438, 1, 1.464844, 0 } }, + { "SONY", "ILCE-7", Shade, 0, { 2.871094, 1, 1.210938, 0 } }, + { "SONY", "ILCE-7", Cloudy, 0, { 2.597656, 1, 1.347656, 0 } }, + { "SONY", "ILCE-7", Incandescent, 0, { 1.464844, 1, 2.621094, 0 } }, + { "SONY", "ILCE-7", WarmWhiteFluorescent, 0, { 1.703125, 1, 2.605469, 0 } }, + { "SONY", "ILCE-7", CoolWhiteFluorescent, 0, { 2.246094, 1, 2.117188, 0 } }, + { "SONY", "ILCE-7", DayWhiteFluorescent, 0, { 2.296875, 1, 1.589844, 0 } }, + { "SONY", "ILCE-7", DaylightFluorescent, 0, { 2.578125, 1, 1.382813, 0 } }, + { "SONY", "ILCE-7", Flash, 0, { 2.648438, 1, 1.324219, 0 } }, + { "SONY", "ILCE-7", "5500K", 0, { 2.214844, 1, 1.406250, 0 } }, + + { "SONY", "ILCE-7M2", Daylight, 0, { 2.277344, 1, 1.488281, 0 } }, + { "SONY", "ILCE-7M2", Shade, 0, { 2.714844, 1, 1.234375, 0 } }, + { "SONY", "ILCE-7M2", Cloudy, 0, { 2.460938, 1, 1.367188, 0 } }, + { "SONY", "ILCE-7M2", Incandescent, 0, { 1.398438, 1, 2.625000, 0 } }, + { "SONY", "ILCE-7M2", WarmWhiteFluorescent, 0, { 1.625000, 1, 2.609375, 0 } }, + { "SONY", "ILCE-7M2", CoolWhiteFluorescent, 0, { 2.132813, 1, 2.132813, 0 } }, + { "SONY", "ILCE-7M2", DayWhiteFluorescent, 0, { 2.179688, 1, 1.613281, 0 } }, + { "SONY", "ILCE-7M2", DaylightFluorescent, 0, { 2.445313, 1, 1.406250, 0 } }, + { "SONY", "ILCE-7M2", Flash, 0, { 2.507813, 1, 1.347656, 0 } }, + + // firmware ILCE-7R (A7R) Ver 1.0.1 + { "SONY", "ILCE-7R", Daylight, 0, { 2.507813, 1, 1.492188, 0 } }, + { "SONY", "ILCE-7R", Shade, 0, { 2.964844, 1, 1.226563, 0 } }, + { "SONY", "ILCE-7R", Cloudy, 0, { 2.699219, 1, 1.367188, 0 } }, + { "SONY", "ILCE-7R", Incandescent, 0, { 1.566406, 1, 2.695313, 0 } }, + { "SONY", "ILCE-7R", WarmWhiteFluorescent, 0, { 1.808594, 1, 2.679688, 0 } }, + { "SONY", "ILCE-7R", CoolWhiteFluorescent, 0, { 2.355469, 1, 2.164063, 0 } }, + { "SONY", "ILCE-7R", DayWhiteFluorescent, 0, { 2.406250, 1, 1.617188, 0 } }, + { "SONY", "ILCE-7R", DaylightFluorescent, 0, { 2.683594, 1, 1.406250, 0 } }, + { "SONY", "ILCE-7R", Flash, 0, { 2.750000, 1, 1.343750, 0 } }, + { "SONY", "ILCE-7R", "5500K", 0, { 2.558594, 1, 1.457031, 0 } }, + + // firmware ILCE-7RM2 (A7R II) Ver 1.0 + { "SONY", "ILCE-7RM2", Daylight, 0, { 2.402344, 1, 1.566406, 0 } }, + { "SONY", "ILCE-7RM2", Shade, 0, { 2.878906, 1, 1.289063, 0 } }, + { "SONY", "ILCE-7RM2", Cloudy, 0, { 2.601563, 1, 1.433594, 0 } }, + { "SONY", "ILCE-7RM2", Incandescent, 0, { 1.464844, 1, 2.847656, 0 } }, + { "SONY", "ILCE-7RM2", WarmWhiteFluorescent, 0, { 1.730469, 1, 2.734375, 0 } }, + { "SONY", "ILCE-7RM2", CoolWhiteFluorescent, 0, { 2.187500, 1, 2.226563, 0 } }, + { "SONY", "ILCE-7RM2", DayWhiteFluorescent, 0, { 2.328125, 1, 1.644531, 0 } }, + { "SONY", "ILCE-7RM2", DaylightFluorescent, 0, { 2.617188, 1, 1.515625, 0 } }, + { "SONY", "ILCE-7RM2", Flash, 0, { 2.656250, 1, 1.410156, 0 } }, + { "SONY", "ILCE-7RM2", "5500K", 0, { 2.457031, 1, 1.527344, 0 } }, + + { "SONY", "ILCE-7S", Daylight, 0, { 2.402344, 1, 1.609375, 0 } }, + { "SONY", "ILCE-7S", Shade, 0, { 2.742188, 1, 1.347656, 0 } }, + { "SONY", "ILCE-7S", Cloudy, 0, { 2.546875, 1, 1.484375, 0 } }, + { "SONY", "ILCE-7S", Tungsten, 0, { 1.617188, 1, 2.710938, 0 } }, + { "SONY", "ILCE-7S", WarmWhiteFluorescent, 0, { 1.835938, 1, 2.660156, 0 } }, + { "SONY", "ILCE-7S", CoolWhiteFluorescent, 0, { 2.250000, 1, 2.320313, 0 } }, + { "SONY", "ILCE-7S", DayWhiteFluorescent, 0, { 2.355469, 1, 1.687500, 0 } }, + { "SONY", "ILCE-7S", DaylightFluorescent, 0, { 2.574219, 1, 1.558594, 0 } }, + { "SONY", "ILCE-7S", Flash, 0, { 2.664063, 1, 1.488281, 0 } }, + { "SONY", "ILCE-7S", "2500K", 0, { 1.433594, 1, 3.175781, 0 } }, + { "SONY", "ILCE-7S", "3200K", 0, { 1.777344, 1, 2.394531, 0 } }, + { "SONY", "ILCE-7S", "4500K", 0, { 2.210938, 1, 1.792969, 0 } }, + { "SONY", "ILCE-7S", "6000K", 0, { 2.531250, 1, 1.500000, 0 } }, + { "SONY", "ILCE-7S", "8500K", 0, { 2.847656, 1, 1.281250, 0 } }, + + { "SONY", "ILCE-7SM2", Daylight, 0, { 2.480469, 1, 1.609375, 0 } }, + { "SONY", "ILCE-7SM2", Shade, 0, { 2.824219, 1, 1.351563, 0 } }, + { "SONY", "ILCE-7SM2", Cloudy, 0, { 2.628906, 1, 1.488281, 0 } }, + { "SONY", "ILCE-7SM2", Tungsten, 0, { 1.683594, 1, 2.691406, 0 } }, + { "SONY", "ILCE-7SM2", WarmWhiteFluorescent, 0, { 1.906250, 1, 2.640625, 0 } }, + { "SONY", "ILCE-7SM2", CoolWhiteFluorescent, 0, { 2.324219, 1, 2.308594, 0 } }, + { "SONY", "ILCE-7SM2", DayWhiteFluorescent, 0, { 2.433594, 1, 1.687500, 0 } }, + { "SONY", "ILCE-7SM2", DaylightFluorescent, 0, { 2.656250, 1, 1.562500, 0 } }, + { "SONY", "ILCE-7SM2", Flash, 0, { 2.746094, 1, 1.488281, 0 } }, + { "SONY", "ILCE-7SM2", "2500K", 0, { 1.492188, 1, 3.140625, 0 } }, + { "SONY", "ILCE-7SM2", "3200K", 0, { 1.843750, 1, 2.382813, 0 } }, + { "SONY", "ILCE-7SM2", "4500K", 0, { 2.289063, 1, 1.789063, 0 } }, + { "SONY", "ILCE-7SM2", "6000K", 0, { 2.613281, 1, 1.500000, 0 } }, + { "SONY", "ILCE-7SM2", "8500K", 0, { 2.933594, 1, 1.285156, 0 } }, + + { "SONY", "ILCE-3000", Daylight, 0, { 2.597656, 1, 1.613281, 0 } }, + { "SONY", "ILCE-3000", Shade, 0, { 3.136719, 1, 1.324219, 0 } }, + { "SONY", "ILCE-3000", Cloudy, 0, { 2.824219, 1, 1.476563, 0 } }, + { "SONY", "ILCE-3000", Tungsten, 0, { 1.562500, 1, 2.953125, 0 } }, + { "SONY", "ILCE-3000", WarmWhiteFluorescent, 0, { 1.835938, 1, 2.902344, 0 } }, + { "SONY", "ILCE-3000", CoolWhiteFluorescent, 0, { 2.332031, 1, 2.328125, 0 } }, + { "SONY", "ILCE-3000", DayWhiteFluorescent, 0, { 2.507813, 1, 1.761719, 0 } }, + { "SONY", "ILCE-3000", DaylightFluorescent, 0, { 2.847656, 1, 1.535156, 0 } }, + { "SONY", "ILCE-3000", Flash, 0, { 3.042969, 1, 1.363281, 0 } }, + { "SONY", "ILCE-3000", "2500K", 0, { 1.347656, 1, 3.585938, 0 } }, + { "SONY", "ILCE-3000", "3200K", 0, { 1.753906, 1, 2.546875, 0 } }, + { "SONY", "ILCE-3000", "4500K", 0, { 2.328125, 1, 1.820313, 0 } }, + { "SONY", "ILCE-3000", "6000K", 0, { 2.796875, 1, 1.492188, 0 } }, + { "SONY", "ILCE-3000", "8500K", 0, { 3.316406, 1, 1.253906, 0 } }, + + { "SONY", "ILCE-5000", Daylight, 0, { 2.746094, 1, 1.656250, 0 } }, + { "SONY", "ILCE-5000", Shade, 0, { 3.328125, 1, 1.359375, 0 } }, + { "SONY", "ILCE-5000", Cloudy, 0, { 2.988281, 1, 1.515625, 0 } }, + { "SONY", "ILCE-5000", Tungsten, 0, { 1.632813, 1, 3.035156, 0 } }, + { "SONY", "ILCE-5000", WarmWhiteFluorescent, 0, { 1.925781, 1, 2.980469, 0 } }, + { "SONY", "ILCE-5000", CoolWhiteFluorescent, 0, { 2.457031, 1, 2.390625, 0 } }, + { "SONY", "ILCE-5000", DayWhiteFluorescent, 0, { 2.648438, 1, 1.808594, 0 } }, + { "SONY", "ILCE-5000", DaylightFluorescent, 0, { 3.015625, 1, 1.574219, 0 } }, + { "SONY", "ILCE-5000", Flash, 0, { 3.121094, 1, 1.507813, 0 } }, + { "SONY", "ILCE-5000", "2500K", 0, { 1.406250, 1, 3.691406, 0 } }, + { "SONY", "ILCE-5000", "3200K", 0, { 1.835938, 1, 2.617188, 0 } }, + { "SONY", "ILCE-5000", "4500K", 0, { 2.453125, 1, 1.867188, 0 } }, + { "SONY", "ILCE-5000", "6000K", 0, { 2.960938, 1, 1.531250, 0 } }, + { "SONY", "ILCE-5000", "8500K", 0, { 3.523438, 1, 1.285156, 0 } }, + + { "SONY", "ILCE-5100", Daylight, 0, { 2.695313, 1, 1.671875, 0 } }, + { "SONY", "ILCE-5100", Shade, 0, { 3.164063, 1, 1.378906, 0 } }, + { "SONY", "ILCE-5100", Cloudy, 0, { 2.894531, 1, 1.531250, 0 } }, + { "SONY", "ILCE-5100", Tungsten, 0, { 1.710938, 1, 3.023438, 0 } }, + { "SONY", "ILCE-5100", WarmWhiteFluorescent, 0, { 1.968750, 1, 2.984375, 0 } }, + { "SONY", "ILCE-5100", CoolWhiteFluorescent, 0, { 2.453125, 1, 2.472656, 0 } }, + { "SONY", "ILCE-5100", DayWhiteFluorescent, 0, { 2.597656, 1, 1.773438, 0 } }, + { "SONY", "ILCE-5100", DaylightFluorescent, 0, { 2.902344, 1, 1.601563, 0 } }, + { "SONY", "ILCE-5100", Flash, 0, { 3.039063, 1, 1.550781, 0 } }, + { "SONY", "ILCE-5100", "2500K", 0, { 1.496094, 1, 3.648438, 0 } }, + { "SONY", "ILCE-5100", "3200K", 0, { 1.902344, 1, 2.617188, 0 } }, + { "SONY", "ILCE-5100", "4500K", 0, { 2.449219, 1, 1.882813, 0 } }, + { "SONY", "ILCE-5100", "6000K", 0, { 2.871094, 1, 1.546875, 0 } }, + { "SONY", "ILCE-5100", "8500K", 0, { 3.316406, 1, 1.304688, 0 } }, + + { "SONY", "ILCE-6000", Daylight, 0, { 2.800781, 1, 1.671875, 0 } }, + { "SONY", "ILCE-6000", Shade, 0, { 3.296875, 1, 1.382813, 0 } }, + { "SONY", "ILCE-6000", Cloudy, 0, { 3.011719, 1, 1.535156, 0 } }, + { "SONY", "ILCE-6000", Tungsten, 0, { 1.769531, 1, 2.957031, 0 } }, + { "SONY", "ILCE-6000", WarmWhiteFluorescent, 0, { 2.039063, 1, 2.921875, 0 } }, + { "SONY", "ILCE-6000", CoolWhiteFluorescent, 0, { 2.550781, 1, 2.437500, 0 } }, + { "SONY", "ILCE-6000", DayWhiteFluorescent, 0, { 2.699219, 1, 1.765625, 0 } }, + { "SONY", "ILCE-6000", DaylightFluorescent, 0, { 3.019531, 1, 1.601563, 0 } }, + { "SONY", "ILCE-6000", Flash, 0, { 3.183594, 1, 1.535156, 0 } }, + { "SONY", "ILCE-6000", "2500K", 0, { 1.546875, 1, 3.542969, 0 } }, + { "SONY", "ILCE-6000", "3200K", 0, { 1.968750, 1, 2.578125, 0 } }, + { "SONY", "ILCE-6000", "4500K", 0, { 2.542969, 1, 1.875000, 0 } }, + { "SONY", "ILCE-6000", "6000K", 0, { 2.988281, 1, 1.546875, 0 } }, + { "SONY", "ILCE-6000", "8500K", 0, { 3.453125, 1, 1.308594, 0 } }, + + { "SONY", "ILCE-6300", Daylight, 0, { 2.601563, 1, 1.785156, 0 } }, + { "SONY", "ILCE-6300", Shade, 0, { 3.058594, 1, 1.472656, 0 } }, + { "SONY", "ILCE-6300", Cloudy, 0, { 2.792969, 1, 1.636719, 0 } }, + { "SONY", "ILCE-6300", Tungsten, 0, { 1.644531, 1, 3.226563, 0 } }, + { "SONY", "ILCE-6300", WarmWhiteFluorescent, 0, { 1.910156, 1, 3.179688, 0 } }, + { "SONY", "ILCE-6300", CoolWhiteFluorescent, 0, { 2.429688, 1, 2.625000, 0 } }, + { "SONY", "ILCE-6300", DayWhiteFluorescent, 0, { 2.531250, 1, 1.886719, 0 } }, + { "SONY", "ILCE-6300", DaylightFluorescent, 0, { 2.812500, 1, 1.710938, 0 } }, + { "SONY", "ILCE-6300", Flash, 0, { 2.914063, 1, 1.636719, 0 } }, + { "SONY", "ILCE-6300", Underwater, 0, { 2.812500, 1, 1.875000, 0 } }, + { "SONY", "ILCE-6300", "5500k", 0, { 2.652344, 1, 1.746094, 0 } }, + + { "SONY", "NEX-3", Daylight, -3, { 2.0742, 1, 1.6289, 0 } }, + { "SONY", "NEX-3", Daylight, -2, { 2.1328, 1, 1.5742, 0 } }, + { "SONY", "NEX-3", Daylight, -1, { 2.1914, 1, 1.5195, 0 } }, + { "SONY", "NEX-3", Daylight, 0, { 2.2539, 1, 1.4727, 0 } }, + { "SONY", "NEX-3", Daylight, 1, { 2.3164, 1, 1.4219, 0 } }, + { "SONY", "NEX-3", Daylight, 2, { 2.3828, 1, 1.3750, 0 } }, + { "SONY", "NEX-3", Daylight, 3, { 2.4492, 1, 1.3281, 0 } }, + { "SONY", "NEX-3", Shade, -3, { 2.4180, 1, 1.3516, 0 } }, + { "SONY", "NEX-3", Shade, -2, { 2.4844, 1, 1.3047, 0 } }, + { "SONY", "NEX-3", Shade, -1, { 2.5508, 1, 1.2617, 0 } }, + { "SONY", "NEX-3", Shade, 0, { 2.6289, 1, 1.2188, 0 } }, + { "SONY", "NEX-3", Shade, 1, { 2.6992, 1, 1.1797, 0 } }, + { "SONY", "NEX-3", Shade, 2, { 2.7773, 1, 1.1445, 0 } }, + { "SONY", "NEX-3", Shade, 3, { 2.8555, 1, 1.1055, 0 } }, + { "SONY", "NEX-3", Cloudy, -3, { 2.2188, 1, 1.4961, 0 } }, + { "SONY", "NEX-3", Cloudy, -2, { 2.2813, 1, 1.4453, 0 } }, + { "SONY", "NEX-3", Cloudy, -1, { 2.3477, 1, 1.3984, 0 } }, + { "SONY", "NEX-3", Cloudy, 0, { 2.4141, 1, 1.3516, 0 } }, + { "SONY", "NEX-3", Cloudy, 1, { 2.4805, 1, 1.3086, 0 } }, + { "SONY", "NEX-3", Cloudy, 2, { 2.5508, 1, 1.2656, 0 } }, + { "SONY", "NEX-3", Cloudy, 3, { 2.6250, 1, 1.2227, 0 } }, + { "SONY", "NEX-3", Incandescent, -3, { 1.3164, 1, 2.8594, 0 } }, + { "SONY", "NEX-3", Incandescent, -2, { 1.3516, 1, 2.7617, 0 } }, + { "SONY", "NEX-3", Incandescent, -1, { 1.3906, 1, 2.6641, 0 } }, + { "SONY", "NEX-3", Incandescent, 0, { 1.4336, 1, 2.5742, 0 } }, + { "SONY", "NEX-3", Incandescent, 1, { 1.4766, 1, 2.4883, 0 } }, + { "SONY", "NEX-3", Incandescent, 2, { 1.5156, 1, 2.4023, 0 } }, + { "SONY", "NEX-3", Incandescent, 3, { 1.5586, 1, 2.3203, 0 } }, + { "SONY", "NEX-3", Fluorescent, -1, { 1.6250, 1, 2.6172, 0 } }, + { "SONY", "NEX-3", Fluorescent, 0, { 1.9883, 1, 2.0742, 0 } }, + { "SONY", "NEX-3", Fluorescent, 1, { 2.1875, 1, 1.5273, 0 } }, + { "SONY", "NEX-3", Fluorescent, 2, { 2.4531, 1, 1.3711, 0 } }, + { "SONY", "NEX-3", Flash, -3, { 2.5352, 1, 1.3633, 0 } }, + { "SONY", "NEX-3", Flash, -2, { 2.6016, 1, 1.3242, 0 } }, + { "SONY", "NEX-3", Flash, -1, { 2.6758, 1, 1.2773, 0 } }, + { "SONY", "NEX-3", Flash, 0, { 2.7500, 1, 1.2383, 0 } }, + { "SONY", "NEX-3", Flash, 1, { 2.8281, 1, 1.1953, 0 } }, + { "SONY", "NEX-3", Flash, 2, { 2.9063, 1, 1.1602, 0 } }, + { "SONY", "NEX-3", Flash, 3, { 2.9883, 1, 1.1211, 0 } }, + + { "SONY", "NEX-3N", Daylight, 0, { 2.617188, 1, 1.601563, 0 } }, + { "SONY", "NEX-3N", Shade, 0, { 3.144531, 1, 1.316406, 0 } }, + { "SONY", "NEX-3N", Cloudy, 0, { 2.835938, 1, 1.464844, 0 } }, + { "SONY", "NEX-3N", Tungsten, 0, { 1.578125, 1, 2.945313, 0 } }, + { "SONY", "NEX-3N", WarmWhiteFluorescent, 0, { 1.855469, 1, 2.894531, 0 } }, + { "SONY", "NEX-3N", CoolWhiteFluorescent, 0, { 2.347656, 1, 2.320313, 0 } }, + { "SONY", "NEX-3N", DayWhiteFluorescent, 0, { 2.527344, 1, 1.753906, 0 } }, + { "SONY", "NEX-3N", DaylightFluorescent, 0, { 2.863281, 1, 1.523438, 0 } }, + { "SONY", "NEX-3N", Flash, 0, { 2.941406, 1, 1.476563, 0 } }, + { "SONY", "NEX-3N", "2500K", 0, { 1.367188, 1, 3.589844, 0 } }, + { "SONY", "NEX-3N", "3200K", 0, { 1.773438, 1, 2.539063, 0 } }, + { "SONY", "NEX-3N", "4500K", 0, { 2.347656, 1, 1.808594, 0 } }, + { "SONY", "NEX-3N", "6000K", 0, { 2.812500, 1, 1.480469, 0 } }, + { "SONY", "NEX-3N", "8500K", 0, { 3.324219, 1, 1.246094, 0 } }, + + { "SONY", "NEX-5", Daylight, -3, { 2.1250, 1, 1.6055, 0 } }, + { "SONY", "NEX-5", Daylight, -2, { 2.1836, 1, 1.5508, 0 } }, + { "SONY", "NEX-5", Daylight, -1, { 2.2500, 1, 1.4961, 0 } }, + { "SONY", "NEX-5", Daylight, 0, { 2.3125, 1, 1.4453, 0 } }, + { "SONY", "NEX-5", Daylight, 1, { 2.3750, 1, 1.3984, 0 } }, + { "SONY", "NEX-5", Daylight, 2, { 2.4453, 1, 1.3477, 0 } }, + { "SONY", "NEX-5", Daylight, 3, { 2.5156, 1, 1.3008, 0 } }, + { "SONY", "NEX-5", Shade, -3, { 2.4805, 1, 1.3242, 0 } }, + { "SONY", "NEX-5", Shade, -2, { 2.5508, 1, 1.2773, 0 } }, + { "SONY", "NEX-5", Shade, -1, { 2.6211, 1, 1.2344, 0 } }, + { "SONY", "NEX-5", Shade, 0, { 2.6992, 1, 1.1914, 0 } }, + { "SONY", "NEX-5", Shade, 1, { 2.7734, 1, 1.1523, 0 } }, + { "SONY", "NEX-5", Shade, 2, { 2.8555, 1, 1.1133, 0 } }, + { "SONY", "NEX-5", Shade, 3, { 2.9336, 1, 1.0742, 0 } }, + { "SONY", "NEX-5", Cloudy, -3, { 2.2734, 1, 1.4727, 0 } }, + { "SONY", "NEX-5", Cloudy, -2, { 2.3398, 1, 1.4219, 0 } }, + { "SONY", "NEX-5", Cloudy, -1, { 2.4063, 1, 1.3711, 0 } }, + { "SONY", "NEX-5", Cloudy, 0, { 2.4766, 1, 1.3281, 0 } }, + { "SONY", "NEX-5", Cloudy, 1, { 2.5469, 1, 1.2813, 0 } }, + { "SONY", "NEX-5", Cloudy, 2, { 2.6211, 1, 1.2383, 0 } }, + { "SONY", "NEX-5", Cloudy, 3, { 2.6953, 1, 1.1953, 0 } }, + { "SONY", "NEX-5", Incandescent, -3, { 1.3398, 1, 2.8594, 0 } }, + { "SONY", "NEX-5", Incandescent, -2, { 1.3750, 1, 2.7617, 0 } }, + { "SONY", "NEX-5", Incandescent, -1, { 1.4180, 1, 2.6641, 0 } }, + { "SONY", "NEX-5", Incandescent, 0, { 1.4609, 1, 2.5703, 0 } }, + { "SONY", "NEX-5", Incandescent, 1, { 1.5039, 1, 2.4805, 0 } }, + { "SONY", "NEX-5", Incandescent, 2, { 1.5469, 1, 2.3945, 0 } }, + { "SONY", "NEX-5", Incandescent, 3, { 1.5898, 1, 2.3125, 0 } }, + { "SONY", "NEX-5", Fluorescent, -1, { 1.6563, 1, 2.6133, 0 } }, + { "SONY", "NEX-5", Fluorescent, 0, { 2.0352, 1, 2.0625, 0 } }, + { "SONY", "NEX-5", Fluorescent, 1, { 2.2422, 1, 1.5039, 0 } }, + { "SONY", "NEX-5", Fluorescent, 2, { 2.5195, 1, 1.3438, 0 } }, + { "SONY", "NEX-5", Flash, -3, { 2.6055, 1, 1.3398, 0 } }, + { "SONY", "NEX-5", Flash, -2, { 2.6719, 1, 1.2969, 0 } }, + { "SONY", "NEX-5", Flash, -1, { 2.7500, 1, 1.2500, 0 } }, + { "SONY", "NEX-5", Flash, 0, { 2.8281, 1, 1.2109, 0 } }, + { "SONY", "NEX-5", Flash, 1, { 2.9063, 1, 1.1641, 0 } }, + { "SONY", "NEX-5", Flash, 2, { 2.9883, 1, 1.1289, 0 } }, + { "SONY", "NEX-5", Flash, 3, { 3.0742, 1, 1.0938, 0 } }, + + { "SONY", "NEX-5N", Daylight, -7, { 2.023438, 1, 1.964844, 0 } }, + { "SONY", "NEX-5N", Daylight, -6, { 2.085938, 1, 1.898438, 0 } }, + { "SONY", "NEX-5N", Daylight, -5, { 2.148438, 1, 1.832031, 0 } }, + { "SONY", "NEX-5N", Daylight, -4, { 2.210938, 1, 1.769531, 0 } }, + { "SONY", "NEX-5N", Daylight, -3, { 2.277344, 1, 1.710938, 0 } }, + { "SONY", "NEX-5N", Daylight, -2, { 2.347656, 1, 1.652344, 0 } }, + { "SONY", "NEX-5N", Daylight, -1, { 2.417969, 1, 1.597656, 0 } }, + { "SONY", "NEX-5N", Daylight, 0, { 2.492188, 1, 1.542969, 0 } }, + { "SONY", "NEX-5N", Daylight, 1, { 2.566406, 1, 1.492188, 0 } }, + { "SONY", "NEX-5N", Daylight, 2, { 2.644531, 1, 1.441406, 0 } }, + { "SONY", "NEX-5N", Daylight, 3, { 2.726563, 1, 1.394531, 0 } }, + { "SONY", "NEX-5N", Daylight, 4, { 2.808594, 1, 1.347656, 0 } }, + { "SONY", "NEX-5N", Daylight, 5, { 2.898438, 1, 1.300781, 0 } }, + { "SONY", "NEX-5N", Daylight, 6, { 2.988281, 1, 1.257813, 0 } }, + { "SONY", "NEX-5N", Daylight, 7, { 3.082031, 1, 1.218750, 0 } }, + { "SONY", "NEX-5N", Shade, -7, { 2.382813, 1, 1.621094, 0 } }, + { "SONY", "NEX-5N", Shade, -6, { 2.457031, 1, 1.566406, 0 } }, + { "SONY", "NEX-5N", Shade, -5, { 2.531250, 1, 1.515625, 0 } }, + { "SONY", "NEX-5N", Shade, -4, { 2.609375, 1, 1.464844, 0 } }, + { "SONY", "NEX-5N", Shade, -3, { 2.687500, 1, 1.414063, 0 } }, + { "SONY", "NEX-5N", Shade, -2, { 2.769531, 1, 1.367188, 0 } }, + { "SONY", "NEX-5N", Shade, -1, { 2.855469, 1, 1.324219, 0 } }, + { "SONY", "NEX-5N", Shade, 0, { 2.945313, 1, 1.277344, 0 } }, + { "SONY", "NEX-5N", Shade, 1, { 3.039063, 1, 1.234375, 0 } }, + { "SONY", "NEX-5N", Shade, 2, { 3.136719, 1, 1.195313, 0 } }, + { "SONY", "NEX-5N", Shade, 3, { 3.234375, 1, 1.156250, 0 } }, + { "SONY", "NEX-5N", Shade, 4, { 3.339844, 1, 1.117188, 0 } }, + { "SONY", "NEX-5N", Shade, 5, { 3.445313, 1, 1.082031, 0 } }, + { "SONY", "NEX-5N", Shade, 6, { 3.558594, 1, 1.046875, 0 } }, + { "SONY", "NEX-5N", Shade, 7, { 3.675781, 1, 1.011719, 0 } }, + { "SONY", "NEX-5N", Cloudy, -7, { 2.175781, 1, 1.804688, 0 } }, + { "SONY", "NEX-5N", Cloudy, -6, { 2.242188, 1, 1.742188, 0 } }, + { "SONY", "NEX-5N", Cloudy, -5, { 2.308594, 1, 1.683594, 0 } }, + { "SONY", "NEX-5N", Cloudy, -4, { 2.378906, 1, 1.625000, 0 } }, + { "SONY", "NEX-5N", Cloudy, -3, { 2.449219, 1, 1.570313, 0 } }, + { "SONY", "NEX-5N", Cloudy, -2, { 2.527344, 1, 1.519531, 0 } }, + { "SONY", "NEX-5N", Cloudy, -1, { 2.601563, 1, 1.468750, 0 } }, + { "SONY", "NEX-5N", Cloudy, 0, { 2.683594, 1, 1.417969, 0 } }, + { "SONY", "NEX-5N", Cloudy, 1, { 2.765625, 1, 1.371094, 0 } }, + { "SONY", "NEX-5N", Cloudy, 2, { 2.851563, 1, 1.324219, 0 } }, + { "SONY", "NEX-5N", Cloudy, 3, { 2.941406, 1, 1.281250, 0 } }, + { "SONY", "NEX-5N", Cloudy, 4, { 3.035156, 1, 1.238281, 0 } }, + { "SONY", "NEX-5N", Cloudy, 5, { 3.128906, 1, 1.199219, 0 } }, + { "SONY", "NEX-5N", Cloudy, 6, { 3.226563, 1, 1.156250, 0 } }, + { "SONY", "NEX-5N", Cloudy, 7, { 3.332031, 1, 1.121094, 0 } }, + { "SONY", "NEX-5N", Incandescent, -7, { 1.277344, 1, 3.503906, 0 } }, + { "SONY", "NEX-5N", Incandescent, -6, { 1.316406, 1, 3.378906, 0 } }, + { "SONY", "NEX-5N", Incandescent, -5, { 1.351563, 1, 3.257813, 0 } }, + { "SONY", "NEX-5N", Incandescent, -4, { 1.390625, 1, 3.140625, 0 } }, + { "SONY", "NEX-5N", Incandescent, -3, { 1.429688, 1, 3.027344, 0 } }, + { "SONY", "NEX-5N", Incandescent, -2, { 1.468750, 1, 2.917969, 0 } }, + { "SONY", "NEX-5N", Incandescent, -1, { 1.511719, 1, 2.816406, 0 } }, + { "SONY", "NEX-5N", Incandescent, 0, { 1.554688, 1, 2.718750, 0 } }, + { "SONY", "NEX-5N", Incandescent, 1, { 1.601563, 1, 2.621094, 0 } }, + { "SONY", "NEX-5N", Incandescent, 2, { 1.644531, 1, 2.531250, 0 } }, + { "SONY", "NEX-5N", Incandescent, 3, { 1.695313, 1, 2.441406, 0 } }, + { "SONY", "NEX-5N", Incandescent, 4, { 1.742188, 1, 2.359375, 0 } }, + { "SONY", "NEX-5N", Incandescent, 5, { 1.792969, 1, 2.277344, 0 } }, + { "SONY", "NEX-5N", Incandescent, 6, { 1.843750, 1, 2.199219, 0 } }, + { "SONY", "NEX-5N", Incandescent, 7, { 1.898438, 1, 2.121094, 0 } }, + { "SONY", "NEX-5N", WarmWhiteFluorescent, -7, { 1.503906, 1, 3.433594, 0 } }, + { "SONY", "NEX-5N", WarmWhiteFluorescent, -6, { 1.542969, 1, 3.320313, 0 } }, + { "SONY", "NEX-5N", WarmWhiteFluorescent, -5, { 1.585938, 1, 3.203125, 0 } }, + { "SONY", "NEX-5N", WarmWhiteFluorescent, -4, { 1.628906, 1, 3.097656, 0 } }, + { "SONY", "NEX-5N", WarmWhiteFluorescent, -3, { 1.671875, 1, 2.992188, 0 } }, + { "SONY", "NEX-5N", WarmWhiteFluorescent, -2, { 1.718750, 1, 2.894531, 0 } }, + { "SONY", "NEX-5N", WarmWhiteFluorescent, -1, { 1.765625, 1, 2.792969, 0 } }, + { "SONY", "NEX-5N", WarmWhiteFluorescent, 0, { 1.816406, 1, 2.703125, 0 } }, + { "SONY", "NEX-5N", WarmWhiteFluorescent, 1, { 1.863281, 1, 2.613281, 0 } }, + { "SONY", "NEX-5N", WarmWhiteFluorescent, 2, { 1.914063, 1, 2.527344, 0 } }, + { "SONY", "NEX-5N", WarmWhiteFluorescent, 3, { 1.968750, 1, 2.445313, 0 } }, + { "SONY", "NEX-5N", WarmWhiteFluorescent, 4, { 2.023438, 1, 2.363281, 0 } }, + { "SONY", "NEX-5N", WarmWhiteFluorescent, 5, { 2.078125, 1, 2.285156, 0 } }, + { "SONY", "NEX-5N", WarmWhiteFluorescent, 6, { 2.136719, 1, 2.210938, 0 } }, + { "SONY", "NEX-5N", WarmWhiteFluorescent, 7, { 2.199219, 1, 2.140625, 0 } }, + { "SONY", "NEX-5N", CoolWhiteFluorescent, -7, { 1.878906, 1, 2.734375, 0 } }, + { "SONY", "NEX-5N", CoolWhiteFluorescent, -6, { 1.929688, 1, 2.648438, 0 } }, + { "SONY", "NEX-5N", CoolWhiteFluorescent, -5, { 1.980469, 1, 2.558594, 0 } }, + { "SONY", "NEX-5N", CoolWhiteFluorescent, -4, { 2.035156, 1, 2.476563, 0 } }, + { "SONY", "NEX-5N", CoolWhiteFluorescent, -3, { 2.093750, 1, 2.398438, 0 } }, + { "SONY", "NEX-5N", CoolWhiteFluorescent, -2, { 2.148438, 1, 2.320313, 0 } }, + { "SONY", "NEX-5N", CoolWhiteFluorescent, -1, { 2.210938, 1, 2.246094, 0 } }, + { "SONY", "NEX-5N", CoolWhiteFluorescent, 0, { 2.269531, 1, 2.175781, 0 } }, + { "SONY", "NEX-5N", CoolWhiteFluorescent, 1, { 2.332031, 1, 2.105469, 0 } }, + { "SONY", "NEX-5N", CoolWhiteFluorescent, 2, { 2.398438, 1, 2.039063, 0 } }, + { "SONY", "NEX-5N", CoolWhiteFluorescent, 3, { 2.468750, 1, 1.972656, 0 } }, + { "SONY", "NEX-5N", CoolWhiteFluorescent, 4, { 2.535156, 1, 1.910156, 0 } }, + { "SONY", "NEX-5N", CoolWhiteFluorescent, 5, { 2.609375, 1, 1.851563, 0 } }, + { "SONY", "NEX-5N", CoolWhiteFluorescent, 6, { 2.683594, 1, 1.792969, 0 } }, + { "SONY", "NEX-5N", CoolWhiteFluorescent, 7, { 2.757813, 1, 1.734375, 0 } }, + { "SONY", "NEX-5N", DayWhiteFluorescent, -7, { 1.992188, 1, 2.062500, 0 } }, + { "SONY", "NEX-5N", DayWhiteFluorescent, -6, { 2.050781, 1, 1.992188, 0 } }, + { "SONY", "NEX-5N", DayWhiteFluorescent, -5, { 2.109375, 1, 1.921875, 0 } }, + { "SONY", "NEX-5N", DayWhiteFluorescent, -4, { 2.175781, 1, 1.859375, 0 } }, + { "SONY", "NEX-5N", DayWhiteFluorescent, -3, { 2.238281, 1, 1.796875, 0 } }, + { "SONY", "NEX-5N", DayWhiteFluorescent, -2, { 2.304688, 1, 1.734375, 0 } }, + { "SONY", "NEX-5N", DayWhiteFluorescent, -1, { 2.375000, 1, 1.679688, 0 } }, + { "SONY", "NEX-5N", DayWhiteFluorescent, 0, { 2.445313, 1, 1.621094, 0 } }, + { "SONY", "NEX-5N", DayWhiteFluorescent, 1, { 2.519531, 1, 1.566406, 0 } }, + { "SONY", "NEX-5N", DayWhiteFluorescent, 2, { 2.593750, 1, 1.515625, 0 } }, + { "SONY", "NEX-5N", DayWhiteFluorescent, 3, { 2.671875, 1, 1.464844, 0 } }, + { "SONY", "NEX-5N", DayWhiteFluorescent, 4, { 2.753906, 1, 1.417969, 0 } }, + { "SONY", "NEX-5N", DayWhiteFluorescent, 5, { 2.839844, 1, 1.371094, 0 } }, + { "SONY", "NEX-5N", DayWhiteFluorescent, 6, { 2.929688, 1, 1.324219, 0 } }, + { "SONY", "NEX-5N", DayWhiteFluorescent, 7, { 3.019531, 1, 1.281250, 0 } }, + { "SONY", "NEX-5N", DaylightFluorescent, -7, { 2.253906, 1, 1.800781, 0 } }, + { "SONY", "NEX-5N", DaylightFluorescent, -6, { 2.320313, 1, 1.742188, 0 } }, + { "SONY", "NEX-5N", DaylightFluorescent, -5, { 2.390625, 1, 1.683594, 0 } }, + { "SONY", "NEX-5N", DaylightFluorescent, -4, { 2.460938, 1, 1.628906, 0 } }, + { "SONY", "NEX-5N", DaylightFluorescent, -3, { 2.535156, 1, 1.574219, 0 } }, + { "SONY", "NEX-5N", DaylightFluorescent, -2, { 2.613281, 1, 1.519531, 0 } }, + { "SONY", "NEX-5N", DaylightFluorescent, -1, { 2.691406, 1, 1.472656, 0 } }, + { "SONY", "NEX-5N", DaylightFluorescent, 0, { 2.773438, 1, 1.421875, 0 } }, + { "SONY", "NEX-5N", DaylightFluorescent, 1, { 2.859375, 1, 1.375000, 0 } }, + { "SONY", "NEX-5N", DaylightFluorescent, 2, { 2.945313, 1, 1.332031, 0 } }, + { "SONY", "NEX-5N", DaylightFluorescent, 3, { 3.039063, 1, 1.285156, 0 } }, + { "SONY", "NEX-5N", DaylightFluorescent, 4, { 3.132813, 1, 1.246094, 0 } }, + { "SONY", "NEX-5N", DaylightFluorescent, 5, { 3.230469, 1, 1.203125, 0 } }, + { "SONY", "NEX-5N", DaylightFluorescent, 6, { 3.335938, 1, 1.164063, 0 } }, + { "SONY", "NEX-5N", DaylightFluorescent, 7, { 3.441406, 1, 1.125000, 0 } }, + { "SONY", "NEX-5N", Flash, -7, { 2.265625, 1, 1.726563, 0 } }, + { "SONY", "NEX-5N", Flash, -6, { 2.332031, 1, 1.667969, 0 } }, + { "SONY", "NEX-5N", Flash, -5, { 2.402344, 1, 1.613281, 0 } }, + { "SONY", "NEX-5N", Flash, -4, { 2.476563, 1, 1.558594, 0 } }, + { "SONY", "NEX-5N", Flash, -3, { 2.550781, 1, 1.507813, 0 } }, + { "SONY", "NEX-5N", Flash, -2, { 2.628906, 1, 1.457031, 0 } }, + { "SONY", "NEX-5N", Flash, -1, { 2.710938, 1, 1.406250, 0 } }, + { "SONY", "NEX-5N", Flash, 0, { 2.792969, 1, 1.359375, 0 } }, + { "SONY", "NEX-5N", Flash, 1, { 2.878906, 1, 1.316406, 0 } }, + { "SONY", "NEX-5N", Flash, 2, { 2.972656, 1, 1.273438, 0 } }, + { "SONY", "NEX-5N", Flash, 3, { 3.062500, 1, 1.230469, 0 } }, + { "SONY", "NEX-5N", Flash, 4, { 3.164063, 1, 1.187500, 0 } }, + { "SONY", "NEX-5N", Flash, 5, { 3.261719, 1, 1.148438, 0 } }, + { "SONY", "NEX-5N", Flash, 6, { 3.367188, 1, 1.113281, 0 } }, + { "SONY", "NEX-5N", Flash, 7, { 3.476563, 1, 1.074219, 0 } }, + + { "SONY", "NEX-5R", Daylight, 0, { 2.5000, 1, 1.5117, 0 } }, + { "SONY", "NEX-5R", Shade, 0, { 3.0156, 1, 1.2422, 0 } }, + { "SONY", "NEX-5R", Cloudy, 0, { 2.7188, 1, 1.3828, 0 } }, + { "SONY", "NEX-5R", Tungsten, 0, { 1.5039, 1, 2.7695, 0 } }, + { "SONY", "NEX-5R", WarmWhiteFluorescent, 0, { 1.8164, 1, 2.7305, 0 } }, + { "SONY", "NEX-5R", CoolWhiteFluorescent, 0, { 2.3086, 1, 2.1758, 0 } }, + { "SONY", "NEX-5R", DayWhiteFluorescent, 0, { 2.4844, 1, 1.5703, 0 } }, + { "SONY", "NEX-5R", DaylightFluorescent, 0, { 2.8555, 1, 1.4648, 0 } }, + { "SONY", "NEX-5R", Flash, 0, { 2.8828, 1, 1.3906, 0 } }, + + { "SONY", "NEX-5T", Daylight, 0, { 2.441406, 1, 1.550781, 0 } }, + { "SONY", "NEX-5T", Shade, 0, { 2.941406, 1, 1.273438, 0 } }, + { "SONY", "NEX-5T", Cloudy, 0, { 2.648438, 1, 1.421875, 0 } }, + { "SONY", "NEX-5T", Tungsten, 0, { 1.468750, 1, 2.835938, 0 } }, + { "SONY", "NEX-5T", WarmWhiteFluorescent, 0, { 1.773438, 1, 2.800781, 0 } }, + { "SONY", "NEX-5T", CoolWhiteFluorescent, 0, { 2.253906, 1, 2.230469, 0 } }, + { "SONY", "NEX-5T", DayWhiteFluorescent, 0, { 2.421875, 1, 1.609375, 0 } }, + { "SONY", "NEX-5T", DaylightFluorescent, 0, { 2.785156, 1, 1.503906, 0 } }, + { "SONY", "NEX-5T", Flash, 0, { 2.812500, 1, 1.429688, 0 } }, + { "SONY", "NEX-5T", "2500K", 0, { 1.269531, 1, 3.445313, 0 } }, + { "SONY", "NEX-5T", "3200K", 0, { 1.648438, 1, 2.449219, 0 } }, + { "SONY", "NEX-5T", "4500K", 0, { 2.187500, 1, 1.750000, 0 } }, + { "SONY", "NEX-5T", "6000K", 0, { 2.625000, 1, 1.433594, 0 } }, + { "SONY", "NEX-5T", "8500K", 0, { 3.105469, 1, 1.207031, 0 } }, + + // firmware NEX-6 1.03 + { "SONY", "NEX-6", Daylight, 0, { 2.6250, 1, 1.4765, 0 } }, + { "SONY", "NEX-6", Shade, 0, { 3.1718, 1, 1.2109, 0 } }, + { "SONY", "NEX-6", Cloudy, 0, { 2.8515, 1, 1.3515, 0 } }, + { "SONY", "NEX-6", Tungsten, 0, { 1.5742, 1, 2.7148, 0 } }, + { "SONY", "NEX-6", WarmWhiteFluorescent, 0, { 1.9023, 1, 2.6796, 0 } }, + { "SONY", "NEX-6", CoolWhiteFluorescent, 0, { 2.4218, 1, 2.1289, 0 } }, + { "SONY", "NEX-6", DayWhiteFluorescent, 0, { 2.6054, 1, 1.5312, 0 } }, + { "SONY", "NEX-6", DaylightFluorescent, 0, { 3.0000, 1, 1.4296, 0 } }, + { "SONY", "NEX-6", Flash, 0, { 3.0312, 1, 1.3554, 0 } }, + + { "SONY", "NEX-7", Daylight, 0, { 2.5820, 1, 1.5273, 0 } }, + { "SONY", "NEX-7", Shade, 0, { 3.0781, 1, 1.2734, 0 } }, + { "SONY", "NEX-7", Cloudy, 0, { 2.7930, 1, 1.4102, 0 } }, + { "SONY", "NEX-7", Tungsten, 0, { 1.5859, 1, 2.6133, 0 } }, + { "SONY", "NEX-7", WarmWhiteFluorescent, 0, { 1.8203, 1, 2.5703, 0 } }, + { "SONY", "NEX-7", CoolWhiteFluorescent, 0, { 2.3164, 1, 2.0937, 0 } }, + { "SONY", "NEX-7", DayWhiteFluorescent, 0, { 2.4570, 1, 1.6055, 0 } }, + { "SONY", "NEX-7", DaylightFluorescent, 0, { 2.7734, 1, 1.4258, 0 } }, + { "SONY", "NEX-7", Flash, 0, { 2.9219, 1, 1.4453, 0 } }, + + // firmware NEX-C3 Ver.02 + { "SONY", "NEX-C3", Daylight, 0, { 2.699219, 1, 1.527344, 0 } }, + { "SONY", "NEX-C3", Shade, 0, { 3.191406, 1, 1.257813, 0 } }, + { "SONY", "NEX-C3", Cloudy, 0, { 2.906250, 1, 1.402344, 0 } }, + { "SONY", "NEX-C3", Tungsten, 0, { 1.617188, 1, 2.718750, 0 } }, + { "SONY", "NEX-C3", Fluorescent, 0, { 2.359375, 1, 2.136719, 0 } }, + { "SONY", "NEX-C3", Flash, 0, { 3.015625, 1, 1.335938, 0 } }, + { "SONY", "NEX-C3", "5000K", 0, { 2.605469, 1, 1.589844, 0 } }, + { "SONY", "NEX-C3", "5500K", 0, { 2.753906, 1, 1.492188, 0 } }, + { "SONY", "NEX-C3", "6500K", 0, { 2.996094, 1, 1.351563, 0 } }, + + { "SONY", "NEX-F3", Daylight, 0, { 2.613281, 1, 1.542969, 0 } }, + { "SONY", "NEX-F3", Shade, 0, { 3.121094, 1, 1.277344, 0 } }, + { "SONY", "NEX-F3", Cloudy, 0, { 2.824219, 1, 1.417969, 0 } }, + { "SONY", "NEX-F3", Tungsten, 0, { 1.601563, 1, 2.703125, 0 } }, + { "SONY", "NEX-F3", WarmWhiteFluorescent, 0, { 1.878906, 1, 2.687500, 0 } }, + { "SONY", "NEX-F3", CoolWhiteFluorescent, 0, { 2.371094, 1, 2.167969, 0 } }, + { "SONY", "NEX-F3", DayWhiteFluorescent, 0, { 2.562500, 1, 1.621094, 0 } }, + { "SONY", "NEX-F3", DaylightFluorescent, 0, { 2.929688, 1, 1.421875, 0 } }, + { "SONY", "NEX-F3", Flash, 0, { 3.105469, 1, 1.394531, 0 } }, + { "SONY", "NEX-F3", "2500K", 0, { 1.390625, 1, 3.222656, 0 } }, + { "SONY", "NEX-F3", "3200K", 0, { 1.792969, 1, 2.363281, 0 } }, + { "SONY", "NEX-F3", "4500K", 0, { 2.351563, 1, 1.726563, 0 } }, + { "SONY", "NEX-F3", "6000K", 0, { 2.800781, 1, 1.429688, 0 } }, + { "SONY", "NEX-F3", "8500K", 0, { 3.285156, 1, 1.210938, 0 } }, + + { "SONY", "SLT-A33", Daylight, 0, { 2.406250, 1, 1.425781, 0 } }, + { "SONY", "SLT-A33", Shade, 0, { 2.832031, 1, 1.164063, 0 } }, + { "SONY", "SLT-A33", Cloudy, 0, { 2.585938, 1, 1.300781, 0 } }, + { "SONY", "SLT-A33", Tungsten, 0, { 1.468750, 1, 2.585938, 0 } }, + { "SONY", "SLT-A33", WarmWhiteFluorescent, 0, { 1.683594, 1, 2.628906, 0 } }, + { "SONY", "SLT-A33", CoolWhiteFluorescent, 0, { 2.101563, 1, 2.058594, 0 } }, + { "SONY", "SLT-A33", DayWhiteFluorescent, 0, { 2.328125, 1, 1.488281, 0 } }, + { "SONY", "SLT-A33", DaylightFluorescent, 0, { 2.632813, 1, 1.320313, 0 } }, + { "SONY", "SLT-A33", Flash, 0, { 2.691406, 1, 1.234375, 0 } }, + { "SONY", "SLT-A33", "2500K", 0, { 1.257813, 1, 3.093750, 0 } }, + { "SONY", "SLT-A33", "3200K", 0, { 1.648438, 1, 2.246094, 0 } }, + { "SONY", "SLT-A33", "4500K", 0, { 2.171875, 1, 1.613281, 0 } }, + { "SONY", "SLT-A33", "6000K", 0, { 2.562500, 1, 1.316406, 0 } }, + { "SONY", "SLT-A33", "8500K", 0, { 2.964844, 1, 1.097656, 0 } }, + + { "SONY", "SLT-A35", Daylight, 0, { 2.710938, 1, 1.585938, 0 } }, + { "SONY", "SLT-A35", Shade, 0, { 3.207031, 1, 1.292969, 0 } }, + { "SONY", "SLT-A35", Cloudy, 0, { 2.921875, 1, 1.449219, 0 } }, + { "SONY", "SLT-A35", Tungsten, 0, { 1.621094, 1, 2.863281, 0 } }, + { "SONY", "SLT-A35", WarmWhiteFluorescent, 0, { 1.878906, 1, 2.769531, 0 } }, + { "SONY", "SLT-A35", CoolWhiteFluorescent, 0, { 2.371094, 1, 2.238281, 0 } }, + { "SONY", "SLT-A35", DayWhiteFluorescent, 0, { 2.613281, 1, 1.636719, 0 } }, + { "SONY", "SLT-A35", DaylightFluorescent, 0, { 2.941406, 1, 1.460938, 0 } }, + { "SONY", "SLT-A35", Flash, 0, { 3.042969, 1, 1.390625, 0 } }, + { "SONY", "SLT-A35", "2500K", 0, { 1.375000, 1, 3.425781, 0 } }, + { "SONY", "SLT-A35", "3200K", 0, { 1.832031, 1, 2.488281, 0 } }, + { "SONY", "SLT-A35", "4500K", 0, { 2.437500, 1, 1.789063, 0 } }, + { "SONY", "SLT-A35", "6000K", 0, { 2.894531, 1, 1.464844, 0 } }, + { "SONY", "SLT-A35", "8500K", 0, { 3.363281, 1, 1.226563, 0 } }, + + { "SONY", "SLT-A37", Daylight, 0, { 2.6641, 1, 1.5156, 0 } }, + { "SONY", "SLT-A37", Shade, 0, { 3.1836, 1, 1.2539, 0 } }, + { "SONY", "SLT-A37", Cloudy, 0, { 2.8828, 1, 1.3906, 0 } }, + { "SONY", "SLT-A37", Incandescent, 0, { 1.6367, 1, 2.7070, 0 } }, + { "SONY", "SLT-A37", WarmWhiteFluorescent, 0, { 1.9180, 1, 2.6914, 0 } }, + { "SONY", "SLT-A37", CoolWhiteFluorescent, 0, { 2.4219, 1, 2.1523, 0 } }, + { "SONY", "SLT-A37", DayWhiteFluorescent, 0, { 2.6172, 1, 1.5977, 0 } }, + { "SONY", "SLT-A37", DaylightFluorescent, 0, { 2.9883, 1, 1.3984, 0 } }, + { "SONY", "SLT-A37", Flash, 0, { 3.0859, 1, 1.3008, 0 } }, + { "SONY", "SLT-A37", "5500K", 0, { 2.7227, 1, 1.4805, 0 } }, + { "SONY", "SLT-A37", "9200K", 0, { 1.8945, 1, 2.4492, 0 } }, + + { "SONY", "SLT-A55", Daylight, -3, { 2.3320, 1, 1.6758, 0 } }, + { "SONY", "SLT-A55", Daylight, -2, { 2.3984, 1, 1.6172, 0 } }, + { "SONY", "SLT-A55", Daylight, -1, { 2.4727, 1, 1.5625, 0 } }, + { "SONY", "SLT-A55", Daylight, 0, { 2.5469, 1, 1.5117, 0 } }, + { "SONY", "SLT-A55", Daylight, 1, { 2.6172, 1, 1.4609, 0 } }, + { "SONY", "SLT-A55", Daylight, 2, { 2.6992, 1, 1.4102, 0 } }, + { "SONY", "SLT-A55", Daylight, 3, { 2.7773, 1, 1.3633, 0 } }, + { "SONY", "SLT-A55", Shade, -3, { 2.7422, 1, 1.3867, 0 } }, + { "SONY", "SLT-A55", Shade, -2, { 2.8203, 1, 1.3398, 0 } }, + { "SONY", "SLT-A55", Shade, -1, { 2.8984, 1, 1.2969, 0 } }, + { "SONY", "SLT-A55", Shade, 0, { 2.9922, 1, 1.2500, 0 } }, + { "SONY", "SLT-A55", Shade, 1, { 3.0781, 1, 1.2109, 0 } }, + { "SONY", "SLT-A55", Shade, 2, { 3.1680, 1, 1.1719, 0 } }, + { "SONY", "SLT-A55", Shade, 3, { 3.2578, 1, 1.1328, 0 } }, + { "SONY", "SLT-A55", Cloudy, -3, { 2.5039, 1, 1.5352, 0 } }, + { "SONY", "SLT-A55", Cloudy, -2, { 2.5781, 1, 1.4844, 0 } }, + { "SONY", "SLT-A55", Cloudy, -1, { 2.6562, 1, 1.4375, 0 } }, + { "SONY", "SLT-A55", Cloudy, 0, { 2.7344, 1, 1.3906, 0 } }, + { "SONY", "SLT-A55", Cloudy, 1, { 2.8125, 1, 1.3437, 0 } }, + { "SONY", "SLT-A55", Cloudy, 2, { 2.8984, 1, 1.2969, 0 } }, + { "SONY", "SLT-A55", Cloudy, 3, { 2.9844, 1, 1.2539, 0 } }, + { "SONY", "SLT-A55", Incandescent, -3, { 1.4297, 1, 2.9453, 0 } }, + { "SONY", "SLT-A55", Incandescent, -2, { 1.4727, 1, 2.8477, 0 } }, + { "SONY", "SLT-A55", Incandescent, -1, { 1.5234, 1, 2.7461, 0 } }, + { "SONY", "SLT-A55", Incandescent, 0, { 1.5703, 1, 2.6523, 0 } }, + { "SONY", "SLT-A55", Incandescent, 1, { 1.6172, 1, 2.5625, 0 } }, + { "SONY", "SLT-A55", Incandescent, 2, { 1.6680, 1, 2.4727, 0 } }, + { "SONY", "SLT-A55", Incandescent, 3, { 1.7148, 1, 2.3906, 0 } }, + { "SONY", "SLT-A55", Fluorescent, -1, { 1.8008, 1, 2.6562, 0 } }, + { "SONY", "SLT-A55", Fluorescent, 0, { 2.2305, 1, 2.1094, 0 } }, + { "SONY", "SLT-A55", Fluorescent, 1, { 2.4648, 1, 1.5508, 0 } }, + { "SONY", "SLT-A55", Fluorescent, 2, { 2.7969, 1, 1.3828, 0 } }, + { "SONY", "SLT-A55", Flash, -3, { 2.6055, 1, 1.4805, 0 } }, + { "SONY", "SLT-A55", Flash, -2, { 2.6797, 1, 1.4297, 0 } }, + { "SONY", "SLT-A55", Flash, -1, { 2.7578, 1, 1.3828, 0 } }, + { "SONY", "SLT-A55", Flash, 0, { 2.8437, 1, 1.3359, 0 } }, + { "SONY", "SLT-A55", Flash, 1, { 2.9258, 1, 1.2930, 0 } }, + { "SONY", "SLT-A55", Flash, 2, { 3.0156, 1, 1.2461, 0 } }, + { "SONY", "SLT-A55", Flash, 3, { 3.1016, 1, 1.2070, 0 } }, + + { "SONY", "SLT-A55V", Daylight, -3, { 2.3320, 1, 1.6758, 0 } }, + { "SONY", "SLT-A55V", Daylight, -2, { 2.3984, 1, 1.6172, 0 } }, + { "SONY", "SLT-A55V", Daylight, -1, { 2.4727, 1, 1.5625, 0 } }, + { "SONY", "SLT-A55V", Daylight, 0, { 2.5469, 1, 1.5117, 0 } }, + { "SONY", "SLT-A55V", Daylight, 1, { 2.6172, 1, 1.4609, 0 } }, + { "SONY", "SLT-A55V", Daylight, 2, { 2.6992, 1, 1.4102, 0 } }, + { "SONY", "SLT-A55V", Daylight, 3, { 2.7773, 1, 1.3633, 0 } }, + { "SONY", "SLT-A55V", Shade, -3, { 2.7422, 1, 1.3867, 0 } }, + { "SONY", "SLT-A55V", Shade, -2, { 2.8203, 1, 1.3398, 0 } }, + { "SONY", "SLT-A55V", Shade, -1, { 2.8984, 1, 1.2969, 0 } }, + { "SONY", "SLT-A55V", Shade, 0, { 2.9922, 1, 1.2500, 0 } }, + { "SONY", "SLT-A55V", Shade, 1, { 3.0781, 1, 1.2109, 0 } }, + { "SONY", "SLT-A55V", Shade, 2, { 3.1680, 1, 1.1719, 0 } }, + { "SONY", "SLT-A55V", Shade, 3, { 3.2578, 1, 1.1328, 0 } }, + { "SONY", "SLT-A55V", Cloudy, -3, { 2.5039, 1, 1.5352, 0 } }, + { "SONY", "SLT-A55V", Cloudy, -2, { 2.5781, 1, 1.4844, 0 } }, + { "SONY", "SLT-A55V", Cloudy, -1, { 2.6562, 1, 1.4375, 0 } }, + { "SONY", "SLT-A55V", Cloudy, 0, { 2.7344, 1, 1.3906, 0 } }, + { "SONY", "SLT-A55V", Cloudy, 1, { 2.8125, 1, 1.3437, 0 } }, + { "SONY", "SLT-A55V", Cloudy, 2, { 2.8984, 1, 1.2969, 0 } }, + { "SONY", "SLT-A55V", Cloudy, 3, { 2.9844, 1, 1.2539, 0 } }, + { "SONY", "SLT-A55V", Incandescent, -3, { 1.4297, 1, 2.9453, 0 } }, + { "SONY", "SLT-A55V", Incandescent, -2, { 1.4727, 1, 2.8477, 0 } }, + { "SONY", "SLT-A55V", Incandescent, -1, { 1.5234, 1, 2.7461, 0 } }, + { "SONY", "SLT-A55V", Incandescent, 0, { 1.5703, 1, 2.6523, 0 } }, + { "SONY", "SLT-A55V", Incandescent, 1, { 1.6172, 1, 2.5625, 0 } }, + { "SONY", "SLT-A55V", Incandescent, 2, { 1.6680, 1, 2.4727, 0 } }, + { "SONY", "SLT-A55V", Incandescent, 3, { 1.7148, 1, 2.3906, 0 } }, + { "SONY", "SLT-A55V", Fluorescent, -1, { 1.8008, 1, 2.6562, 0 } }, + { "SONY", "SLT-A55V", Fluorescent, 0, { 2.2305, 1, 2.1094, 0 } }, + { "SONY", "SLT-A55V", Fluorescent, 1, { 2.4648, 1, 1.5508, 0 } }, + { "SONY", "SLT-A55V", Fluorescent, 2, { 2.7969, 1, 1.3828, 0 } }, + { "SONY", "SLT-A55V", Flash, -3, { 2.6055, 1, 1.4805, 0 } }, + { "SONY", "SLT-A55V", Flash, -2, { 2.6797, 1, 1.4297, 0 } }, + { "SONY", "SLT-A55V", Flash, -1, { 2.7578, 1, 1.3828, 0 } }, + { "SONY", "SLT-A55V", Flash, 0, { 2.8437, 1, 1.3359, 0 } }, + { "SONY", "SLT-A55V", Flash, 1, { 2.9258, 1, 1.2930, 0 } }, + { "SONY", "SLT-A55V", Flash, 2, { 3.0156, 1, 1.2461, 0 } }, + { "SONY", "SLT-A55V", Flash, 3, { 3.1016, 1, 1.2070, 0 } }, + + { "SONY", "SLT-A57", Daylight, -7, { 2.160156, 1, 2.000000, 0 } }, + { "SONY", "SLT-A57", Daylight, -6, { 2.226563, 1, 1.929688, 0 } }, + { "SONY", "SLT-A57", Daylight, -5, { 2.296875, 1, 1.863281, 0 } }, + { "SONY", "SLT-A57", Daylight, -4, { 2.367188, 1, 1.800781, 0 } }, + { "SONY", "SLT-A57", Daylight, -3, { 2.437500, 1, 1.738281, 0 } }, + { "SONY", "SLT-A57", Daylight, -2, { 2.515625, 1, 1.679688, 0 } }, + { "SONY", "SLT-A57", Daylight, -1, { 2.593750, 1, 1.621094, 0 } }, + { "SONY", "SLT-A57", Daylight, 0, { 2.671875, 1, 1.566406, 0 } }, + { "SONY", "SLT-A57", Daylight, 1, { 2.757813, 1, 1.511719, 0 } }, + { "SONY", "SLT-A57", Daylight, 2, { 2.843750, 1, 1.460938, 0 } }, + { "SONY", "SLT-A57", Daylight, 3, { 2.937500, 1, 1.414063, 0 } }, + { "SONY", "SLT-A57", Daylight, 4, { 3.031250, 1, 1.363281, 0 } }, + { "SONY", "SLT-A57", Daylight, 5, { 3.128906, 1, 1.320313, 0 } }, + { "SONY", "SLT-A57", Daylight, 6, { 3.230469, 1, 1.273438, 0 } }, + { "SONY", "SLT-A57", Daylight, 7, { 3.335938, 1, 1.230469, 0 } }, + { "SONY", "SLT-A57", Shade, -7, { 2.554688, 1, 1.648438, 0 } }, + { "SONY", "SLT-A57", Shade, -6, { 2.636719, 1, 1.593750, 0 } }, + { "SONY", "SLT-A57", Shade, -5, { 2.718750, 1, 1.539063, 0 } }, + { "SONY", "SLT-A57", Shade, -4, { 2.804688, 1, 1.484375, 0 } }, + { "SONY", "SLT-A57", Shade, -3, { 2.894531, 1, 1.433594, 0 } }, + { "SONY", "SLT-A57", Shade, -2, { 2.988281, 1, 1.386719, 0 } }, + { "SONY", "SLT-A57", Shade, -1, { 3.082031, 1, 1.339844, 0 } }, + { "SONY", "SLT-A57", Shade, 0, { 3.183594, 1, 1.296875, 0 } }, + { "SONY", "SLT-A57", Shade, 1, { 3.285156, 1, 1.250000, 0 } }, + { "SONY", "SLT-A57", Shade, 2, { 3.394531, 1, 1.210938, 0 } }, + { "SONY", "SLT-A57", Shade, 3, { 3.507813, 1, 1.167969, 0 } }, + { "SONY", "SLT-A57", Shade, 4, { 3.625000, 1, 1.128906, 0 } }, + { "SONY", "SLT-A57", Shade, 5, { 3.746094, 1, 1.093750, 0 } }, + { "SONY", "SLT-A57", Shade, 6, { 3.875000, 1, 1.054688, 0 } }, + { "SONY", "SLT-A57", Shade, 7, { 4.007813, 1, 1.019531, 0 } }, + { "SONY", "SLT-A57", Cloudy, -7, { 2.328125, 1, 1.832031, 0 } }, + { "SONY", "SLT-A57", Cloudy, -6, { 2.402344, 1, 1.769531, 0 } }, + { "SONY", "SLT-A57", Cloudy, -5, { 2.472656, 1, 1.710938, 0 } }, + { "SONY", "SLT-A57", Cloudy, -4, { 2.550781, 1, 1.652344, 0 } }, + { "SONY", "SLT-A57", Cloudy, -3, { 2.628906, 1, 1.593750, 0 } }, + { "SONY", "SLT-A57", Cloudy, -2, { 2.714844, 1, 1.542969, 0 } }, + { "SONY", "SLT-A57", Cloudy, -1, { 2.796875, 1, 1.488281, 0 } }, + { "SONY", "SLT-A57", Cloudy, 0, { 2.886719, 1, 1.437500, 0 } }, + { "SONY", "SLT-A57", Cloudy, 1, { 2.980469, 1, 1.390625, 0 } }, + { "SONY", "SLT-A57", Cloudy, 2, { 3.078125, 1, 1.343750, 0 } }, + { "SONY", "SLT-A57", Cloudy, 3, { 3.175781, 1, 1.296875, 0 } }, + { "SONY", "SLT-A57", Cloudy, 4, { 3.281250, 1, 1.253906, 0 } }, + { "SONY", "SLT-A57", Cloudy, 5, { 3.386719, 1, 1.210938, 0 } }, + { "SONY", "SLT-A57", Cloudy, 6, { 3.500000, 1, 1.171875, 0 } }, + { "SONY", "SLT-A57", Cloudy, 7, { 3.617188, 1, 1.132813, 0 } }, + { "SONY", "SLT-A57", Incandescent, -7, { 1.351563, 1, 3.613281, 0 } }, + { "SONY", "SLT-A57", Incandescent, -6, { 1.390625, 1, 3.476563, 0 } }, + { "SONY", "SLT-A57", Incandescent, -5, { 1.433594, 1, 3.351563, 0 } }, + { "SONY", "SLT-A57", Incandescent, -4, { 1.472656, 1, 3.226563, 0 } }, + { "SONY", "SLT-A57", Incandescent, -3, { 1.515625, 1, 3.109375, 0 } }, + { "SONY", "SLT-A57", Incandescent, -2, { 1.558594, 1, 2.996094, 0 } }, + { "SONY", "SLT-A57", Incandescent, -1, { 1.605469, 1, 2.886719, 0 } }, + { "SONY", "SLT-A57", Incandescent, 0, { 1.652344, 1, 2.785156, 0 } }, + { "SONY", "SLT-A57", Incandescent, 1, { 1.699219, 1, 2.683594, 0 } }, + { "SONY", "SLT-A57", Incandescent, 2, { 1.750000, 1, 2.589844, 0 } }, + { "SONY", "SLT-A57", Incandescent, 3, { 1.800781, 1, 2.496094, 0 } }, + { "SONY", "SLT-A57", Incandescent, 4, { 1.855469, 1, 2.410156, 0 } }, + { "SONY", "SLT-A57", Incandescent, 5, { 1.910156, 1, 2.324219, 0 } }, + { "SONY", "SLT-A57", Incandescent, 6, { 1.964844, 1, 2.242188, 0 } }, + { "SONY", "SLT-A57", Incandescent, 7, { 2.023438, 1, 2.164063, 0 } }, + { "SONY", "SLT-A57", WarmWhiteFluorescent, -7, { 1.593750, 1, 3.539063, 0 } }, + { "SONY", "SLT-A57", WarmWhiteFluorescent, -6, { 1.640625, 1, 3.414063, 0 } }, + { "SONY", "SLT-A57", WarmWhiteFluorescent, -5, { 1.683594, 1, 3.296875, 0 } }, + { "SONY", "SLT-A57", WarmWhiteFluorescent, -4, { 1.730469, 1, 3.183594, 0 } }, + { "SONY", "SLT-A57", WarmWhiteFluorescent, -3, { 1.777344, 1, 3.074219, 0 } }, + { "SONY", "SLT-A57", WarmWhiteFluorescent, -2, { 1.828125, 1, 2.968750, 0 } }, + { "SONY", "SLT-A57", WarmWhiteFluorescent, -1, { 1.878906, 1, 2.867188, 0 } }, + { "SONY", "SLT-A57", WarmWhiteFluorescent, 0, { 1.933594, 1, 2.769531, 0 } }, + { "SONY", "SLT-A57", WarmWhiteFluorescent, 1, { 1.984375, 1, 2.675781, 0 } }, + { "SONY", "SLT-A57", WarmWhiteFluorescent, 2, { 2.042969, 1, 2.585938, 0 } }, + { "SONY", "SLT-A57", WarmWhiteFluorescent, 3, { 2.101563, 1, 2.500000, 0 } }, + { "SONY", "SLT-A57", WarmWhiteFluorescent, 4, { 2.160156, 1, 2.414063, 0 } }, + { "SONY", "SLT-A57", WarmWhiteFluorescent, 5, { 2.222656, 1, 2.335938, 0 } }, + { "SONY", "SLT-A57", WarmWhiteFluorescent, 6, { 2.285156, 1, 2.257813, 0 } }, + { "SONY", "SLT-A57", WarmWhiteFluorescent, 7, { 2.351563, 1, 2.183594, 0 } }, + { "SONY", "SLT-A57", CoolWhiteFluorescent, -7, { 2.003906, 1, 2.800781, 0 } }, + { "SONY", "SLT-A57", CoolWhiteFluorescent, -6, { 2.058594, 1, 2.710938, 0 } }, + { "SONY", "SLT-A57", CoolWhiteFluorescent, -5, { 2.113281, 1, 2.621094, 0 } }, + { "SONY", "SLT-A57", CoolWhiteFluorescent, -4, { 2.175781, 1, 2.535156, 0 } }, + { "SONY", "SLT-A57", CoolWhiteFluorescent, -3, { 2.234375, 1, 2.449219, 0 } }, + { "SONY", "SLT-A57", CoolWhiteFluorescent, -2, { 2.296875, 1, 2.371094, 0 } }, + { "SONY", "SLT-A57", CoolWhiteFluorescent, -1, { 2.363281, 1, 2.292969, 0 } }, + { "SONY", "SLT-A57", CoolWhiteFluorescent, 0, { 2.433594, 1, 2.218750, 0 } }, + { "SONY", "SLT-A57", CoolWhiteFluorescent, 1, { 2.500000, 1, 2.144531, 0 } }, + { "SONY", "SLT-A57", CoolWhiteFluorescent, 2, { 2.574219, 1, 2.078125, 0 } }, + { "SONY", "SLT-A57", CoolWhiteFluorescent, 3, { 2.648438, 1, 2.007813, 0 } }, + { "SONY", "SLT-A57", CoolWhiteFluorescent, 4, { 2.726563, 1, 1.945313, 0 } }, + { "SONY", "SLT-A57", CoolWhiteFluorescent, 5, { 2.804688, 1, 1.882813, 0 } }, + { "SONY", "SLT-A57", CoolWhiteFluorescent, 6, { 2.886719, 1, 1.820313, 0 } }, + { "SONY", "SLT-A57", CoolWhiteFluorescent, 7, { 2.972656, 1, 1.765625, 0 } }, + { "SONY", "SLT-A57", DayWhiteFluorescent, -7, { 2.125000, 1, 2.101563, 0 } }, + { "SONY", "SLT-A57", DayWhiteFluorescent, -6, { 2.191406, 1, 2.027344, 0 } }, + { "SONY", "SLT-A57", DayWhiteFluorescent, -5, { 2.257813, 1, 1.957031, 0 } }, + { "SONY", "SLT-A57", DayWhiteFluorescent, -4, { 2.324219, 1, 1.890625, 0 } }, + { "SONY", "SLT-A57", DayWhiteFluorescent, -3, { 2.394531, 1, 1.828125, 0 } }, + { "SONY", "SLT-A57", DayWhiteFluorescent, -2, { 2.468750, 1, 1.765625, 0 } }, + { "SONY", "SLT-A57", DayWhiteFluorescent, -1, { 2.542969, 1, 1.703125, 0 } }, + { "SONY", "SLT-A57", DayWhiteFluorescent, 0, { 2.625000, 1, 1.648438, 0 } }, + { "SONY", "SLT-A57", DayWhiteFluorescent, 1, { 2.707031, 1, 1.589844, 0 } }, + { "SONY", "SLT-A57", DayWhiteFluorescent, 2, { 2.789063, 1, 1.539063, 0 } }, + { "SONY", "SLT-A57", DayWhiteFluorescent, 3, { 2.878906, 1, 1.484375, 0 } }, + { "SONY", "SLT-A57", DayWhiteFluorescent, 4, { 2.968750, 1, 1.437500, 0 } }, + { "SONY", "SLT-A57", DayWhiteFluorescent, 5, { 3.062500, 1, 1.386719, 0 } }, + { "SONY", "SLT-A57", DayWhiteFluorescent, 6, { 3.164063, 1, 1.343750, 0 } }, + { "SONY", "SLT-A57", DayWhiteFluorescent, 7, { 3.265625, 1, 1.296875, 0 } }, + { "SONY", "SLT-A57", DaylightFluorescent, -7, { 2.414063, 1, 1.832031, 0 } }, + { "SONY", "SLT-A57", DaylightFluorescent, -6, { 2.488281, 1, 1.769531, 0 } }, + { "SONY", "SLT-A57", DaylightFluorescent, -5, { 2.562500, 1, 1.710938, 0 } }, + { "SONY", "SLT-A57", DaylightFluorescent, -4, { 2.640625, 1, 1.652344, 0 } }, + { "SONY", "SLT-A57", DaylightFluorescent, -3, { 2.722656, 1, 1.597656, 0 } }, + { "SONY", "SLT-A57", DaylightFluorescent, -2, { 2.808594, 1, 1.542969, 0 } }, + { "SONY", "SLT-A57", DaylightFluorescent, -1, { 2.898438, 1, 1.492188, 0 } }, + { "SONY", "SLT-A57", DaylightFluorescent, 0, { 2.988281, 1, 1.441406, 0 } }, + { "SONY", "SLT-A57", DaylightFluorescent, 1, { 3.085938, 1, 1.394531, 0 } }, + { "SONY", "SLT-A57", DaylightFluorescent, 2, { 3.183594, 1, 1.347656, 0 } }, + { "SONY", "SLT-A57", DaylightFluorescent, 3, { 3.285156, 1, 1.304688, 0 } }, + { "SONY", "SLT-A57", DaylightFluorescent, 4, { 3.394531, 1, 1.261719, 0 } }, + { "SONY", "SLT-A57", DaylightFluorescent, 5, { 3.503906, 1, 1.218750, 0 } }, + { "SONY", "SLT-A57", DaylightFluorescent, 6, { 3.621094, 1, 1.179688, 0 } }, + { "SONY", "SLT-A57", DaylightFluorescent, 7, { 3.742188, 1, 1.140625, 0 } }, + { "SONY", "SLT-A57", Flash, -7, { 2.464844, 1, 1.707031, 0 } }, + { "SONY", "SLT-A57", Flash, -6, { 2.542969, 1, 1.648438, 0 } }, + { "SONY", "SLT-A57", Flash, -5, { 2.621094, 1, 1.589844, 0 } }, + { "SONY", "SLT-A57", Flash, -4, { 2.707031, 1, 1.539063, 0 } }, + { "SONY", "SLT-A57", Flash, -3, { 2.792969, 1, 1.484375, 0 } }, + { "SONY", "SLT-A57", Flash, -2, { 2.878906, 1, 1.433594, 0 } }, + { "SONY", "SLT-A57", Flash, -1, { 2.972656, 1, 1.386719, 0 } }, + { "SONY", "SLT-A57", Flash, 0, { 3.066406, 1, 1.339844, 0 } }, + { "SONY", "SLT-A57", Flash, 1, { 3.167969, 1, 1.292969, 0 } }, + { "SONY", "SLT-A57", Flash, 2, { 3.269531, 1, 1.250000, 0 } }, + { "SONY", "SLT-A57", Flash, 3, { 3.378906, 1, 1.210938, 0 } }, + { "SONY", "SLT-A57", Flash, 4, { 3.488281, 1, 1.167969, 0 } }, + { "SONY", "SLT-A57", Flash, 5, { 3.605469, 1, 1.128906, 0 } }, + { "SONY", "SLT-A57", Flash, 6, { 3.726563, 1, 1.093750, 0 } }, + { "SONY", "SLT-A57", Flash, 7, { 3.855469, 1, 1.054688, 0 } }, + + // firmware version 1.00 + { "SONY", "SLT-A58", Daylight, 0, { 2.640625, 1, 1.546875, 0 } }, + { "SONY", "SLT-A58", Cloudy, 0, { 2.875000, 1, 1.414063, 0 } }, + { "SONY", "SLT-A58", Incandescent, 0, { 1.578125, 1, 2.843750, 0 } }, + { "SONY", "SLT-A58", WarmWhiteFluorescent, 0, { 1.859375, 1, 2.796875, 0 } }, + { "SONY", "SLT-A58", CoolWhiteFluorescent, 0, { 2.367188, 1, 2.238281, 0 } }, + { "SONY", "SLT-A58", DayWhiteFluorescent, 0, { 2.550781, 1, 1.695313, 0 } }, + { "SONY", "SLT-A58", DaylightFluorescent, 0, { 2.898438, 1, 1.472656, 0 } }, + { "SONY", "SLT-A58", Flash, 0, { 2.992188, 1, 1.355469, 0 } }, + + { "SONY", "SLT-A65", Daylight, 0, { 2.628906, 1, 1.433594, 0 } }, + { "SONY", "SLT-A65", Shade, 0, { 3.132813, 1, 1.191406, 0 } }, + { "SONY", "SLT-A65", Cloudy, 0, { 2.839844, 1, 1.316406, 0 } }, + { "SONY", "SLT-A65", Tungsten, 0, { 1.617188, 1, 2.488281, 0 } }, + { "SONY", "SLT-A65", Fluorescent, 0, { 2.363281, 1, 1.980469, 0 } }, + { "SONY", "SLT-A65", Flash, 0, { 3.070313, 1, 1.238281, 0 } }, + + { "SONY", "SLT-A65V", Daylight, 0, { 2.628906, 1, 1.433594, 0 } }, + { "SONY", "SLT-A65V", Shade, 0, { 3.132813, 1, 1.191406, 0 } }, + { "SONY", "SLT-A65V", Cloudy, 0, { 2.839844, 1, 1.316406, 0 } }, + { "SONY", "SLT-A65V", Tungsten, 0, { 1.617188, 1, 2.488281, 0 } }, + { "SONY", "SLT-A65V", Fluorescent, 0, { 2.363281, 1, 1.980469, 0 } }, + { "SONY", "SLT-A65V", Flash, 0, { 3.070313, 1, 1.238281, 0 } }, + + { "SONY", "SLT-A77", Daylight, 0, { 2.726563, 1, 1.390625, 0 } }, + { "SONY", "SLT-A77", Shade, 0, { 3.296875, 1, 1.156250, 0 } }, + { "SONY", "SLT-A77", Cloudy, 0, { 2.964844, 1, 1.281250, 0 } }, + { "SONY", "SLT-A77", Tungsten, 0, { 1.636719, 1, 2.417969, 0 } }, + { "SONY", "SLT-A77", Fluorescent, -1, { 1.886719, 1, 2.375000, 0 } }, + { "SONY", "SLT-A77", Fluorescent, 0, { 2.433594, 1, 1.925781, 0 } }, + { "SONY", "SLT-A77", Fluorescent, 1, { 2.589844, 1, 1.464844, 0 } }, + { "SONY", "SLT-A77", Fluorescent, 2, { 2.945313, 1, 1.300781, 0 } }, + { "SONY", "SLT-A77", Flash, 0, { 3.222656, 1, 1.207031, 0 } }, + + { "SONY", "SLT-A77V", Daylight, 0, { 2.726563, 1, 1.390625, 0 } }, + { "SONY", "SLT-A77V", Shade, 0, { 3.296875, 1, 1.156250, 0 } }, + { "SONY", "SLT-A77V", Cloudy, 0, { 2.964844, 1, 1.281250, 0 } }, + { "SONY", "SLT-A77V", Tungsten, 0, { 1.636719, 1, 2.417969, 0 } }, + { "SONY", "SLT-A77V", Fluorescent, -1, { 1.886719, 1, 2.375000, 0 } }, + { "SONY", "SLT-A77V", Fluorescent, 0, { 2.433594, 1, 1.925781, 0 } }, + { "SONY", "SLT-A77V", Fluorescent, 1, { 2.589844, 1, 1.464844, 0 } }, + { "SONY", "SLT-A77V", Fluorescent, 2, { 2.945313, 1, 1.300781, 0 } }, + { "SONY", "SLT-A77V", Flash, 0, { 3.222656, 1, 1.207031, 0 } }, + + { "SONY", "SLT-A99", Daylight, 0, { 2.449219, 1, 1.464844, 0 } }, + { "SONY", "SLT-A99", Shade, 0, { 2.933594, 1, 1.207031, 0 } }, + { "SONY", "SLT-A99", Cloudy, 0, { 2.652344, 1, 1.343750, 0 } }, + { "SONY", "SLT-A99", Incandescent, 0, { 1.496094, 1, 2.667969, 0 } }, + { "SONY", "SLT-A99", WarmWhiteFluorescent, 0, { 1.738281, 1, 2.652344, 0 } }, + { "SONY", "SLT-A99", CoolWhiteFluorescent, 0, { 2.292969, 1, 2.136719, 0 } }, + { "SONY", "SLT-A99", DayWhiteFluorescent, 0, { 2.343750, 1, 1.589844, 0 } }, + { "SONY", "SLT-A99", DaylightFluorescent, 0, { 2.636719, 1, 1.378906, 0 } }, + { "SONY", "SLT-A99", Flash, 0, { 2.707031, 1, 1.320313, 0 } }, + + { "SONY", "SLT-A99V", Daylight, 0, { 2.449219, 1, 1.464844, 0 } }, + { "SONY", "SLT-A99V", Shade, 0, { 2.933594, 1, 1.207031, 0 } }, + { "SONY", "SLT-A99V", Cloudy, 0, { 2.652344, 1, 1.343750, 0 } }, + { "SONY", "SLT-A99V", Incandescent, 0, { 1.496094, 1, 2.667969, 0 } }, + { "SONY", "SLT-A99V", WarmWhiteFluorescent, 0, { 1.738281, 1, 2.652344, 0 } }, + { "SONY", "SLT-A99V", CoolWhiteFluorescent, 0, { 2.292969, 1, 2.136719, 0 } }, + { "SONY", "SLT-A99V", DayWhiteFluorescent, 0, { 2.343750, 1, 1.589844, 0 } }, + { "SONY", "SLT-A99V", DaylightFluorescent, 0, { 2.636719, 1, 1.378906, 0 } }, + { "SONY", "SLT-A99V", Flash, 0, { 2.707031, 1, 1.320313, 0 } }, + +}; + +const int wb_preset_count = sizeof(wb_preset) / sizeof(wb_data);