rawstudio/rawstudio-2.0+20210602git.c140a5e-load-dcraw_9.28.patch

38525 lines
1.7 MiB

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 <omp.h>
+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 <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <float.h>
+#include <limits.h>
+#include <math.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+
+#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 <io.h>
+#endif
+#ifdef _WIN32
+#include <sys/utime.h>
+#include <winsock2.h>
+#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 <unistd.h>
+#include <utime.h>
+#include <netinet/in.h>
+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 <jasper/jasper.h> /* Decode Red camera movies */
+#endif
+#ifdef HAVE_LIBJPEG
+extern "C" {
+#include <jpeglib.h> /* Decode compressed Kodak DC120 photos */
+}
+#endif /* and Adobe Lossy DNGs */
+#ifndef NO_LCMS
+#include <lcms2.h> /* Support color profiles */
+#endif
+#ifndef DCRAW_NOMAIN
+#ifdef LOCALEDIR
+#include <libintl.h>
+#define _(String) gettext(String)
+#else
+#define _(String) (String)
+#endif
+#else
+#include <glib/gi18n.h> /*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 <stdarg.h>
+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<signed char>(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<signed char>(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<signed char>(0x80), +0,-1,+0,+1,1,static_cast<signed char>(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<signed char>(0x80),
+ +1,-1,+1,+1,0,static_cast<signed char>(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<<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(row,col);
+ if (fcol(row+y,col+x) != color && fcol(row+y*2,col+x*2) == color)
+ *ip++ = (y*width + x) * 8 + color;
+ else
+ *ip++ = 0;
+ }
+ }
+ brow[4] = (ushort (*)[4]) calloc (width*3, sizeof **brow);
+ merror (brow[4], "vng_interpolate()");
+ for (row=0; row < 3; row++)
+ brow[row] = brow[4] + row*width;
+ for (row=2; row < height-2; row++) { /* Do VNG interpolation */
+ 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(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<<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(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<unsigned>(-1),static_cast<unsigned>(-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 (&timestamp));
+#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 (&timestamp));
+#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 <lcms2.h>. */
+ (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 (&timestamp);
+ 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 <x y w h> Average a grey box for white balance"));
+ puts(_("-r <r g b g> Set custom white balance"));
+ puts(_("+M/-M Use/don't use an embedded color matrix"));
+ puts(_("-C <r b> Correct chromatic aberration"));
+ puts(_("-P <file> Fix the dead pixels listed in this file"));
+ puts(_("-K <file> Subtract dark frame (16-bit raw PGM)"));
+ puts(_("-k <num> Set the darkness level"));
+ puts(_("-S <num> Set the saturation level"));
+ puts(_("-n <num> 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 <file> Apply output ICC profile from file"));
+ puts(_("-p <file> 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 <num> Adjust brightness (default = 1.0)"));
+ puts(_("-g <p ts> 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 <num> 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<char *>(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(&timestamp));
+ 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 <glib.h>
+extern "C" {
+#include <glib/gstdio.h>
+}
+#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 <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <math.h> /* for sqrt() */
+#include <setjmp.h>
+#include <errno.h>
+#include <float.h>
+#include "uf_glib.h"
+#include <glib/gi18n.h> /*For _(String) definition - NKBJ*/
+#include <sys/types.h>
+#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<char *>("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 <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <glib.h>
+#include <glib/gi18n.h> /*For _(String) definition - NKBJ*/
+#include "dcraw_api.h"
+#include "uf_progress.h"
+
+#ifdef _OPENMP
+#include <omp.h>
+#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@brander.dk>,
+ * * Anders Kvist <akv@lnxbx.dk> and Klaus Post <klauspost@gmail.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 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 <rawstudio.h>
+#include <math.h>
+#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<<shift;
+
+ /* Advance output by one pixel */
+ output++;
+ }
+ }
+ }
+ else if (raw->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;i<rawsize;i++)
+ max = MAX(((gushort *)raw->raw.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@brander.dk>,
+ * * Anders Kvist <akv@lnxbx.dk> and Klaus Post <klauspost@gmail.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 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 <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <string.h>
+#include "mmap-hack.h"
+#include <unistd.h>
+
+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@brander.dk>,
+ * * Anders Kvist <akv@lnxbx.dk> and Klaus Post <klauspost@gmail.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 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 <stdio.h>
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define g_fopen fopen
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <errno.h>
+#include <stdarg.h> /* 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 <glib.h>
+#include <glib/gstdio.h>
+
+#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 <glib.h>
+#include <glib/gi18n.h>
+#include <string.h> // for strcmp
+#include <stdio.h> // for sscanf
+#include <math.h> // for pow, log, floor
+#include <algorithm> // for std::max
+#include <map> // for std::map
+#include <stdexcept> // for std::logic_error
+#include <typeinfo> // for std::bad_cast
+#include <limits> // for std::numeric_limits<double>::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<UFNumber &>(*this);
+}
+
+UFObject::operator const class UFNumber&() const
+{
+ return dynamic_cast<const UFNumber &>(*this);
+}
+
+UFObject::operator class UFNumberArray&()
+{
+ return dynamic_cast<UFNumberArray &>(*this);
+}
+
+UFObject::operator const class UFNumberArray&() const
+{
+ return dynamic_cast<const UFNumberArray &>(*this);
+}
+
+UFObject::operator class UFString&()
+{
+ return dynamic_cast<UFString &>(*this);
+}
+
+UFObject::operator const class UFString&() const
+{
+ return dynamic_cast<const UFString &>(*this);
+}
+
+UFObject::operator class UFGroup&()
+{
+ return dynamic_cast<UFGroup &>(*this);
+}
+
+UFObject::operator const class UFGroup&() const
+{
+ return dynamic_cast<const UFGroup &>(*this);
+}
+
+UFObject::operator class UFArray&()
+{
+ return dynamic_cast<UFArray &>(*this);
+}
+
+UFObject::operator const class UFArray&() const
+{
+ return dynamic_cast<const UFArray &>(*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 + "</" + Name() + ">\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<const char *, UFObject *, _UFNameCompare> _UFGroupMap;
+typedef std::pair<const char *, UFObject *> _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 <UFObject *> and generally not a <UFGroup *>.
+// The cast to <UFGroup *> is needed for accessing ufobject.
+#define _UFGROUP_PARENT(object) static_cast<UFGroup*>(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 + "</" + group.Name() + ">\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<char *>(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 + "</" + group.Name() + ">\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 <UFObject *> and generally not a <UFArray *>.
+// The cast to <UFArray *> is needed for accessing ufobject.
+#define _UFARRAY_PARENT(object) static_cast<UFArray *>(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<UFArray *>(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<UFNumber &>(*object).DoubleValue();
+ } catch (std::bad_cast &e) {
+ object->Message(e.what());
+ return std::numeric_limits<double>::quiet_NaN();
+ }
+ }
+
+ UFBoolean ufnumber_set(UFObject *object, double number)
+ {
+ try {
+ dynamic_cast<UFNumber *>(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<UFNumberArray &>(*object).DoubleValue(index);
+ } catch (UFException &e) {
+ object->Message(e.what());
+ return std::numeric_limits<double>::quiet_NaN();
+ } catch (std::bad_cast &e) {
+ object->Message(e.what());
+ return std::numeric_limits<double>::quiet_NaN();
+ }
+ }
+
+ UFBoolean ufnumber_array_set(UFObject *object, const double array[])
+ {
+ try {
+ dynamic_cast<UFNumberArray &>(*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<UFString *>(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<UFGroup *>(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<UFGroup &>(*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<UFGroup &>(*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<UFGroup *>(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<UFArray *>(object)->SetIndex(index);
+ } catch (std::bad_cast &e) {
+ object->Message(e.what());
+ return false;
+ }
+ }
+
+ int ufarray_index(UFObject *object)
+ {
+ try {
+ return dynamic_cast<UFArray *>(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<UFArray *>(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 <string>
+#include <list>
+#include <stdexcept> // 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 <tt>object.Set(1.0/3.0)</tt> command, the result of the condition
+ /// <tt>(obj.DoubleValue() == 1.0/3.0)</tt> 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<UFObject *> 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 <stdlib.h> /* for exit */
+#include <errno.h> /* for errno */
+#include <string.h>
+#include <glib/gi18n.h>
+
+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 <inttypes.h>
+#include <glib.h>
+#include <lcms2.h>
+
+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 <string.h>
+#include <errno.h>
+#include <math.h>
+#include <sys/stat.h> /* needed for fstat() */
+#include <getopt.h>
+#include <glib/gi18n.h>
+
+#ifdef HAVE_EXIV2
+#include <exiv2/exv_conf.h>
+#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, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
+ buf = uf_markup_buf(buf, "<UFRaw Version='%d'>\n", c->version);
+ if (strlen(c->inputFilename) > 0 && IDFilename != NULL) {
+ char *utf8 = g_filename_display_name(c->inputFilename);
+ buf = uf_markup_buf(buf, "<InputFilename>%s</InputFilename>\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, "<OutputFilename>%s</OutputFilename>\n", utf8);
+ g_free(utf8);
+ }
+ if (strlen(c->outputPath) > 0) {
+ char *utf8 = g_filename_display_name(c->outputPath);
+ buf = uf_markup_buf(buf, "<OutputPath>%s</OutputPath>\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,
+ "<SaveConfiguration>%d</SaveConfiguration>\n",
+ c->saveConfiguration);
+ if (c->expander[raw_expander] != conf_default.expander[raw_expander])
+ buf = uf_markup_buf(buf, "<RawExpander>%d</RawExpander>\n",
+ c->expander[raw_expander]);
+ if (c->expander[live_expander] != conf_default.expander[live_expander])
+ buf = uf_markup_buf(buf, "<LiveExpander>%d</LiveExpander>\n",
+ c->expander[live_expander]);
+ if (c->histogram != conf_default.histogram)
+ buf = uf_markup_buf(buf,
+ "<Histogram>%d</Histogram>\n", c->histogram);
+ if (c->liveHistogramScale != conf_default.liveHistogramScale)
+ buf = uf_markup_buf(buf,
+ "<LiveHistogramScale>%d</LiveHistogramScale>\n",
+ c->liveHistogramScale);
+ if (c->rawHistogramScale != conf_default.rawHistogramScale)
+ buf = uf_markup_buf(buf,
+ "<RawHistogramScale>%d</RawHistogramScale>\n",
+ c->rawHistogramScale);
+ if (c->LockAspect != conf_default.LockAspect)
+ buf = uf_markup_buf(buf,
+ "<LockAspectRatio>%d</LockAspectRatio>\n", c->LockAspect);
+ if (c->overExp != conf_default.overExp)
+ buf = uf_markup_buf(buf,
+ "<OverExposure>%d</OverExposure>\n", c->overExp);
+ if (c->underExp != conf_default.underExp)
+ buf = uf_markup_buf(buf,
+ "<UnderExposure>%d</UnderExposure>\n", c->underExp);
+ if (c->blinkOverUnder != conf_default.blinkOverUnder)
+ buf = uf_markup_buf(buf,
+ "<BlinkOverUnder>%d</BlinkOverUnder>\n", c->blinkOverUnder);
+ if (c->drawLines != conf_default.drawLines)
+ buf = uf_markup_buf(buf,
+ "<DrawLines>%d</DrawLines>\n", c->drawLines);
+ if (c->RememberOutputPath != conf_default.RememberOutputPath)
+ buf = uf_markup_buf(buf,
+ "<RememberOutputPath>%d</RememberOutputPath>\n",
+ c->RememberOutputPath);
+ if (c->WindowMaximized != conf_default.WindowMaximized)
+ buf = uf_markup_buf(buf,
+ "<WindowMaximized>%d</WindowMaximized>\n",
+ c->WindowMaximized);
+ if (strcmp(c->remoteGimpCommand, conf_default.remoteGimpCommand) != 0)
+ buf = uf_markup_buf(buf,
+ "<RemoteGimpCommand>%s</RemoteGimpCommand>\n",
+ c->remoteGimpCommand);
+ if (strlen(c->curvePath) > 0) {
+ char *utf8 = g_filename_display_name(c->curvePath);
+ buf = uf_markup_buf(buf, "<CurvePath>%s</CurvePath>\n", utf8);
+ g_free(utf8);
+ }
+ if (strlen(c->profilePath) > 0) {
+ char *utf8 = g_filename_display_name(c->profilePath);
+ buf = uf_markup_buf(buf, "<ProfilePath>%s</ProfilePath>\n", utf8);
+ g_free(utf8);
+ }
+ }
+ if (c->interpolation != conf_default.interpolation)
+ buf = uf_markup_buf(buf, "<Interpolation>%s</Interpolation>\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, "<ColorSmoothing>%d</ColorSmoothing>\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,
+ "<WaveletDenoisingThreshold>%d</WaveletDenoisingThreshold>\n",
+ (int)floor(c->threshold));
+ if (c->hotpixel != conf_default.hotpixel)
+ buf = uf_markup_buf(buf,
+ "<HotpixelSensitivity>%f</HotpixelSensitivity>\n",
+ c->hotpixel);
+#ifdef UFRAW_CONTRAST
+ if (c->contrast != conf_default.contrast)
+ buf = uf_markup_buf(buf,
+ "<Contrast>%f</Contrast>\n", c->contrast);
+#endif
+ if (c->exposure != conf_default.exposure)
+ buf = uf_markup_buf(buf, "<Exposure>%lf</Exposure>\n", c->exposure);
+ if (c->ExposureNorm != conf_default.ExposureNorm)
+ buf = uf_markup_buf(buf, "<ExposureNorm>%d</ExposureNorm>\n",
+ c->ExposureNorm);
+ if (c->restoreDetails != conf_default.restoreDetails)
+ buf = uf_markup_buf(buf, "<RestoreDetails>%s</RestoreDetails>\n",
+ conf_get_name(restoreDetailsNames, c->restoreDetails));
+ if (c->clipHighlights != conf_default.clipHighlights)
+ buf = uf_markup_buf(buf, "<ClipHighlights>%s</ClipHighlights>\n",
+ conf_get_name(clipHighlightsNames, c->clipHighlights));
+ if (c->autoExposure != conf_default.autoExposure)
+ buf = uf_markup_buf(buf,
+ "<AutoExposure>%d</AutoExposure>\n", c->autoExposure);
+ if (c->autoBlack != conf_default.autoBlack)
+ buf = uf_markup_buf(buf, "<AutoBlack>%d</AutoBlack>\n", c->autoBlack);
+ if (c->autoCrop != conf_default.autoCrop)
+ buf = uf_markup_buf(buf, "<AutoCrop>%d</AutoCrop>\n", c->autoCrop);
+ if (c->saturation != conf_default.saturation)
+ buf = uf_markup_buf(buf,
+ "<Saturation>%lf</Saturation>\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, "<LightnessAdjustment>%f %f %f</LightnessAdjustment>\n",
+ a->adjustment, a->hue, a->hueWidth);
+ }
+ }
+ if (c->grayscaleMode != grayscale_invalid &&
+ c->grayscaleMode != conf_default.grayscaleMode)
+ buf = uf_markup_buf(buf,
+ "<GrayscaleMode>%s</GrayscaleMode>\n",
+ grayscaleModeNames[c->grayscaleMode]);
+ if (c->grayscaleMode == grayscale_mixer) {
+ buf = uf_markup_buf(buf,
+ "<GrayscaleMixer>%f %f %f</GrayscaleMixer>\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, "<DespeckleWindow>%f %f %f</DespeckleWindow>\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, "<DespeckleDecay>%f %f %f</DespeckleDecay>\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, "<DespecklePasses>%f %f %f</DespecklePasses>\n",
+ c->despecklePasses[0], c->despecklePasses[1], c->despecklePasses[2]);
+ }
+ if (c->size != conf_default.size)
+ buf = uf_markup_buf(buf, "<Size>%d</Size>\n", c->size);
+ if (c->shrink != conf_default.shrink)
+ buf = uf_markup_buf(buf, "<Shrink>%d</Shrink>\n", c->shrink);
+ if (c->type != conf_default.type)
+ buf = uf_markup_buf(buf, "<OutputType>%d</OutputType>\n", c->type);
+ if (c->createID != conf_default.createID)
+ buf = uf_markup_buf(buf, "<CreateID>%d</CreateID>\n", c->createID);
+ if (c->embedExif != conf_default.embedExif)
+ buf = uf_markup_buf(buf, "<EmbedExif>%d</EmbedExif>\n", c->embedExif);
+ if (c->progressiveJPEG != conf_default.progressiveJPEG)
+ buf = uf_markup_buf(buf, "<ProgressiveJPEG>%d</ProgressiveJPEG>\n", c->progressiveJPEG);
+ if (c->compression != conf_default.compression)
+ buf = uf_markup_buf(buf,
+ "<Compression>%d</Compression>\n", c->compression);
+ if (c->overwrite != conf_default.overwrite)
+ buf = uf_markup_buf(buf, "<Overwrite>%d</Overwrite>\n", c->overwrite);
+ if (c->losslessCompress != conf_default.losslessCompress)
+ buf = uf_markup_buf(buf,
+ "<LosslessCompression>%d</LosslessCompression>\n",
+ c->losslessCompress);
+ if (c->noExit != conf_default.noExit)
+ buf = uf_markup_buf(buf, "<NoExit>%d</NoExit>\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,
+ "<BaseManualCurve Current='%s'>\n", current);
+ buf = uf_markup_buf(buf, curveBuf);
+ buf = uf_markup_buf(buf, "</BaseManualCurve>\n");
+ break;
+ case linear_curve:
+ buf = uf_markup_buf(buf,
+ "<BaseLinearCurve Current='%s'>\n", current);
+ buf = uf_markup_buf(buf, curveBuf);
+ buf = uf_markup_buf(buf, "</BaseLinearCurve>\n");
+ break;
+ case custom_curve:
+ buf = uf_markup_buf(buf,
+ "<BaseCustomCurve Current='%s'>\n", current);
+ buf = uf_markup_buf(buf, curveBuf);
+ buf = uf_markup_buf(buf, "</BaseCustomCurve>\n");
+ break;
+ case camera_curve:
+ buf = uf_markup_buf(buf,
+ "<BaseCameraCurve Current='%s'>\n", current);
+ buf = uf_markup_buf(buf, curveBuf);
+ buf = uf_markup_buf(buf, "</BaseCameraCurve>\n");
+ break;
+ default:
+ buf = uf_markup_buf(buf,
+ "<BaseCurve Current='%s'>%s\n", current,
+ c->BaseCurve[i].name);
+ buf = uf_markup_buf(buf, curveBuf);
+ buf = uf_markup_buf(buf, "</BaseCurve>\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,
+ "<ManualCurve Current='%s'>\n", current);
+ buf = uf_markup_buf(buf, curveBuf);
+ buf = uf_markup_buf(buf, "</ManualCurve>\n");
+ break;
+ case linear_curve:
+ buf = uf_markup_buf(buf,
+ "<LinearCurve Current='%s'>\n", current);
+ buf = uf_markup_buf(buf, curveBuf);
+ buf = uf_markup_buf(buf, "</LinearCurve>\n");
+ break;
+ default:
+ buf = uf_markup_buf(buf,
+ "<Curve Current='%s'>%s\n", current,
+ c->curve[i].name);
+ buf = uf_markup_buf(buf, curveBuf);
+ buf = uf_markup_buf(buf, "</Curve>\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<File>%s</File>\n", utf8);
+ g_free(utf8);
+ buf = uf_markup_buf(buf, "\t<ProductName>%s</ProductName>\n",
+ c->profile[j][i].productName);
+ }
+ if (c->profile[j][i].gamma != conf_default.profile[j][1].gamma)
+ buf = uf_markup_buf(buf,
+ "\t<Gamma>%lf</Gamma>\n", c->profile[j][i].gamma);
+ if (c->profile[j][i].linear != conf_default.profile[j][1].linear)
+ buf = uf_markup_buf(buf, "\t<Linearity>%lf</Linearity>\n",
+ c->profile[j][i].linear);
+ if (c->profile[j][i].BitDepth != conf_default.profile[j][1].BitDepth)
+ buf = uf_markup_buf(buf, "\t<BitDepth>%d</BitDepth>\n",
+ c->profile[j][i].BitDepth);
+ buf = uf_markup_buf(buf, "</%s%s>\n", profile, type);
+ }
+ }
+ if (c->intent[out_profile] != conf_default.intent[out_profile])
+ buf = uf_markup_buf(buf, "<OutputIntent>%s</OutputIntent>\n",
+ conf_get_name(intentNames, c->intent[out_profile]));
+ if (c->intent[display_profile] != conf_default.intent[display_profile])
+ buf = uf_markup_buf(buf, "<DisplayIntent>%s</DisplayIntent>\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, "<Make>%s</Make>\n", c->make);
+ buf = uf_markup_buf(buf, "<Model>%s</Model>\n", c->model);
+ if (IDFilename != NULL) {
+ if (strcmp(c->darkframeFile, conf_default.darkframeFile) != 0)
+ buf = uf_markup_buf(buf,
+ "<DarkframeFile>%s</DarkframeFile>\n", c->darkframeFile);
+ buf = uf_markup_buf(buf, "<Timestamp>%s</Timestamp>\n",
+ c->timestampText);
+ buf = uf_markup_buf(buf, "<Orientation>%d</Orientation>\n",
+ c->orientation);
+ buf = uf_markup_buf(buf, "<ISOSpeed>%s</ISOSpeed>\n", c->isoText);
+ buf = uf_markup_buf(buf, "<Shutter>%s</Shutter>\n", c->shutterText);
+ buf = uf_markup_buf(buf, "<Aperture>%s</Aperture>\n", c->apertureText);
+ buf = uf_markup_buf(buf, "<FocalLength>%s</FocalLength>\n",
+ c->focalLenText);
+ buf = uf_markup_buf(buf, "<FocalLength35>%s</FocalLength35>\n",
+ c->focalLen35Text);
+ if (strlen(c->lensText) > 0)
+ buf = uf_markup_buf(buf, "<Lens>%s</Lens>\n", c->lensText);
+ buf = uf_markup_buf(buf, "<EXIFSource>%s</EXIFSource>\n",
+ c->exifSource);
+ buf = uf_markup_buf(buf, "<Crop>%d %d %d %d</Crop>\n",
+ c->CropX1, c->CropY1, c->CropX2, c->CropY2);
+ if (c->aspectRatio != 0.0)
+ buf = uf_markup_buf(buf, "<AspectRatio>%lf</AspectRatio>\n", c->aspectRatio);
+ buf = uf_markup_buf(buf, "<Rotation>%lf</Rotation>\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, "<Log>\n%s</Log>\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, "</UFRaw>\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 <omp.h>
+#endif
+#include <math.h>
+#include <string.h>
+#include <lcms2.h>
+#include <lcms2_plugin.h>
+#include "ufraw_colorspaces.h"
+
+static void lcms_message(cmsContext ContextID,
+ cmsUInt32Number ErrorCode,
+ const char *ErrorText)
+{
+ (void) ContextID;
+ /* Possible ErrorCode: see cmsERROR_* in <lcms2.h>. */
+ (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 <errno.h> /* for errno */
+#include <string.h>
+#include <glib/gi18n.h>
+#ifdef HAVE_LIBJPEG
+#include <jpeglib.h>
+#include <jerror.h>
+#endif
+#ifdef HAVE_LIBPNG
+#include <png.h>
+#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 <exiv2/exiv2.hpp>
+#include <sstream>
+#include <cassert>
+#include <iostream>
+
+/*
+ * 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 <string.h>
+
+/*
+ * 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 <glib/gi18n.h>
+#include <errno.h>
+#include <locale.h>
+#include <stdlib.h> /* needed for canonicalize_file_name() */
+#include <string.h>
+
+/* 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, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
+ char *base = g_path_get_basename(filename);
+ char *name = uf_file_set_type(base, "");
+ char *utf8 = g_filename_display_name(name);
+ fprintf(out, "<Curve Version='%d'>%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, "</Curve>\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<MinXY>%lf %lf</MinXY>\n", c->m_min_x, c->m_min_y);
+ buf = uf_markup_buf(buf,
+ "\t<MaxXY>%lf %lf</MaxXY>\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<AnchorXY>%lf %lf</AnchorXY>\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 <glib/gi18n.h>
+#include <string.h>
+#include <assert.h>
+
+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 <const char *name>
+ class UF_STRING : public UFString {
+ public:
+ UF_STRING() : UFString(name) { }
+ };
+
+typedef UF_STRING<ufCameraMake> 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<Image *>(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<Image &>(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 + "</" + Name() + ">\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 + "</" + Name() + ">\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 + "</" + Name() + ">\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<dcraw_data *>(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<UFRaw::Image *>(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 <lensfun.h>
+#endif
+#include <glib/gi18n.h>
+#include <string.h>
+#include <sys/stat.h> /* for fstat() */
+#include <math.h>
+#include <errno.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_LIBZ
+#include <zlib.h>
+#endif
+#ifdef HAVE_LIBBZ2
+#include <bzlib.h>
+#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 <glib/gi18n.h>
+#include <errno.h> /* for errno */
+#include <string.h>
+#include <lcms2.h>
+#include "ufraw_colorspaces.h"
+#ifdef HAVE_LIBTIFF
+#include <tiffio.h>
+#endif
+#ifdef HAVE_LIBJPEG
+#include <jerror.h>
+#include "iccjpeg.h"
+#endif
+#ifdef HAVE_LIBPNG
+#include <png.h>
+#ifdef HAVE_LIBZ
+#include <zlib.h> /* 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 <omp.h>
+#define uf_omp_get_thread_num() omp_get_thread_num()
+#else
+#define uf_omp_get_thread_num() 0
+#endif
+
+#ifdef HAVE_LIBCFITSIO
+#include <fitsio.h>
+#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 <glib/gi18n.h>
+
+/* 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);