File indexing completed on 2025-01-05 03:56:49

0001 /* -*- C++ -*-
0002  * File: identify.cpp
0003  * Copyright 2008-2021 LibRaw LLC (info@libraw.org)
0004  * Created: Sat Mar  8, 2008
0005  *
0006  * LibRaw C++ demo: emulates dcraw -i [-v]
0007  *
0008 
0009 LibRaw is free software; you can redistribute it and/or modify
0010 it under the terms of the one of two licenses as you choose:
0011 
0012 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1
0013    (See file LICENSE.LGPL provided in LibRaw distribution archive for details).
0014 
0015 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
0016    (See file LICENSE.CDDL provided in LibRaw distribution archive for details).
0017 
0018 
0019  */
0020 
0021 #include <stdio.h>
0022 #include <string.h>
0023 #include <math.h>
0024 #include <time.h>
0025 #include <string>
0026 #include <list>
0027 
0028 #include "libraw/libraw.h"
0029 
0030 #ifdef LIBRAW_WIN32_CALLS
0031 #define snprintf _snprintf
0032 #define strcasecmp stricmp
0033 #define strncasecmp strnicmp
0034 #endif
0035 
0036 #ifndef LIBRAW_WIN32_CALLS
0037 #include <sys/stat.h>
0038 #include <fcntl.h>
0039 #include <unistd.h>
0040 #include <sys/mman.h>
0041 #include <sys/time.h>
0042 #ifndef MAX_PATH
0043 #ifdef PATH_MAX
0044 #define MAX_PATH PATH_MAX
0045 #else
0046 #define MAX_PATH 4096
0047 #endif
0048 #endif
0049 #endif
0050 
0051 #ifdef _MSC_VER
0052 #if _MSC_VER < 1800 /* below MSVC 2013 */
0053 float roundf(float f) { return floorf(f + 0.5); }
0054 
0055 #endif
0056 #endif
0057 
0058 #define P1 MyCoolRawProcessor.imgdata.idata
0059 #define P2 MyCoolRawProcessor.imgdata.other
0060 #define P3 MyCoolRawProcessor.imgdata.makernotes.common
0061 
0062 #define mnLens MyCoolRawProcessor.imgdata.lens.makernotes
0063 #define exifLens MyCoolRawProcessor.imgdata.lens
0064 #define ShootingInfo MyCoolRawProcessor.imgdata.shootinginfo
0065 
0066 #define S MyCoolRawProcessor.imgdata.sizes
0067 #define O MyCoolRawProcessor.imgdata.params
0068 #define C MyCoolRawProcessor.imgdata.color
0069 #define T MyCoolRawProcessor.imgdata.thumbnail
0070 
0071 void print_verbose(FILE *, LibRaw &MyCoolRawProcessor, std::string &fn);
0072 void print_wbfun(FILE *, LibRaw &MyCoolRawProcessor, std::string &fn);
0073 void print_szfun(FILE *, LibRaw &MyCoolRawProcessor, std::string &fn);
0074 void print_unpackfun(FILE *, LibRaw &MyCoolRawProcessor, int print_frame, std::string &fn);
0075 
0076 /*
0077 table of fluorescents:
0078 12 = FL-D; Daylight fluorescent (D 5700K – 7100K) (F1,F5)
0079 13 = FL-N; Day white fluorescent (N 4600K – 5400K) (F7,F8)
0080 14 = FL-W; Cool white fluorescent (W 3900K – 4500K) (F2,F6, office,
0081 store,warehouse) 15 = FL-WW; White fluorescent (WW 3200K – 3700K) (F3,
0082 residential) 16 = FL-L; Soft/Warm white fluorescent (L 2600K - 3250K) (F4,
0083 kitchen, bath)
0084 */
0085 
0086 static const struct
0087 {
0088   const int NumId;
0089   const char *StrId;
0090   const char *hrStrId; // human-readable
0091   const int aux_setting;
0092 } WBToStr[] = {
0093     {LIBRAW_WBI_Unknown, "WBI_Unknown", "Unknown", 0},
0094     {LIBRAW_WBI_Daylight, "WBI_Daylight", "Daylight", 0},
0095     {LIBRAW_WBI_Fluorescent, "WBI_Fluorescent", "Fluorescent", 0},
0096     {LIBRAW_WBI_Tungsten, "WBI_Tungsten", "Tungsten (Incandescent)", 0},
0097     {LIBRAW_WBI_Flash, "WBI_Flash", "Flash", 0},
0098     {LIBRAW_WBI_FineWeather, "WBI_FineWeather", "Fine Weather", 0},
0099     {LIBRAW_WBI_Cloudy, "WBI_Cloudy", "Cloudy", 0},
0100     {LIBRAW_WBI_Shade, "WBI_Shade", "Shade", 0},
0101     {LIBRAW_WBI_FL_D, "WBI_FL_D", "Daylight Fluorescent", 0},
0102     {LIBRAW_WBI_FL_N, "WBI_FL_N", "Day White Fluorescent", 0},
0103     {LIBRAW_WBI_FL_W, "WBI_FL_W", "Cool White Fluorescent", 0},
0104     {LIBRAW_WBI_FL_WW, "WBI_FL_WW", "White Fluorescent", 0},
0105     {LIBRAW_WBI_FL_L, "WBI_FL_L", "Warm White Fluorescent", 0},
0106     {LIBRAW_WBI_Ill_A, "WBI_Ill_A", "Illuminant A", 0},
0107     {LIBRAW_WBI_Ill_B, "WBI_Ill_B", "Illuminant B", 0},
0108     {LIBRAW_WBI_Ill_C, "WBI_Ill_C", "Illuminant C", 0},
0109     {LIBRAW_WBI_D55, "WBI_D55", "D55", 0},
0110     {LIBRAW_WBI_D65, "WBI_D65", "D65", 0},
0111     {LIBRAW_WBI_D75, "WBI_D75", "D75", 0},
0112     {LIBRAW_WBI_D50, "WBI_D50", "D50", 0},
0113     {LIBRAW_WBI_StudioTungsten, "WBI_StudioTungsten", "ISO Studio Tungsten", 0},
0114     {LIBRAW_WBI_BW, "WBI_BW", "BW", 0},
0115     {LIBRAW_WBI_Other, "WBI_Other", "Other", 0},
0116     {LIBRAW_WBI_Sunset, "WBI_Sunset", "Sunset", 1},
0117     {LIBRAW_WBI_Underwater, "WBI_Underwater", "Underwater", 1},
0118     {LIBRAW_WBI_FluorescentHigh, "WBI_FluorescentHigh", "Fluorescent High", 1},
0119     {LIBRAW_WBI_HT_Mercury, "WBI_HT_Mercury", "HT Mercury", 1},
0120     {LIBRAW_WBI_AsShot, "WBI_AsShot", "As Shot", 1},
0121     {LIBRAW_WBI_Measured, "WBI_Measured", "Camera Measured", 1},
0122     {LIBRAW_WBI_Auto, "WBI_Auto", "Camera Auto", 1},
0123     {LIBRAW_WBI_Auto1, "WBI_Auto1", "Camera Auto 1", 1},
0124     {LIBRAW_WBI_Auto2, "WBI_Auto2", "Camera Auto 2", 1},
0125     {LIBRAW_WBI_Auto3, "WBI_Auto3", "Camera Auto 3", 1},
0126     {LIBRAW_WBI_Auto4, "WBI_Auto4", "Camera Auto 4", 1},
0127     {LIBRAW_WBI_Custom, "WBI_Custom", "Custom", 1},
0128     {LIBRAW_WBI_Custom1, "WBI_Custom1", "Custom 1", 1},
0129     {LIBRAW_WBI_Custom2, "WBI_Custom2", "Custom 2", 1},
0130     {LIBRAW_WBI_Custom3, "WBI_Custom3", "Custom 3", 1},
0131     {LIBRAW_WBI_Custom4, "WBI_Custom4", "Custom 4", 1},
0132     {LIBRAW_WBI_Custom5, "WBI_Custom5", "Custom 5", 1},
0133     {LIBRAW_WBI_Custom6, "WBI_Custom6", "Custom 6", 1},
0134     {LIBRAW_WBI_PC_Set1, "WBI_PC_Set1", "PC Set 1", 1},
0135     {LIBRAW_WBI_PC_Set2, "WBI_PC_Set2", "PC Set 2", 1},
0136     {LIBRAW_WBI_PC_Set3, "WBI_PC_Set3", "PC Set 3", 1},
0137     {LIBRAW_WBI_PC_Set4, "WBI_PC_Set4", "PC Set 4", 1},
0138     {LIBRAW_WBI_PC_Set5, "WBI_PC_Set5", "PC Set 5", 1},
0139     {LIBRAW_WBI_Kelvin, "WBI_Kelvin", "Kelvin", 1},
0140 };
0141 
0142 const char *WB_idx2str(unsigned WBi)
0143 {
0144   for (int i = 0; i < int(sizeof WBToStr / sizeof *WBToStr); i++)
0145     if (WBToStr[i].NumId == (int)WBi)
0146       return WBToStr[i].StrId;
0147   return 0;
0148 }
0149 
0150 const char *WB_idx2hrstr(unsigned WBi)
0151 {
0152   for (int i = 0; i < int(sizeof WBToStr / sizeof *WBToStr); i++)
0153     if (WBToStr[i].NumId == (int)WBi)
0154       return WBToStr[i].hrStrId;
0155   return 0;
0156 }
0157 
0158 double _log2(double a)
0159 {
0160   if(a > 0.00000000001) return log(a)/log(2.0);
0161   return -1000;
0162 }
0163 
0164 void trimSpaces(char *s)
0165 {
0166   char *p = s;
0167   if (!strncasecmp(p, "NO=", 3))
0168     p = p + 3; /* fix for Nikon D70, D70s */
0169   int l = strlen(p);
0170   if (!l)
0171     return;
0172   while (isspace(p[l - 1]))
0173     p[--l] = 0; /* trim trailing spaces */
0174   while (*p && isspace(*p))
0175     ++p, --l; /* trim leading spaces */
0176   memmove(s, p, l + 1);
0177 }
0178 
0179 void print_usage(const char *pname)
0180 {
0181   printf("Usage: %s [options] inputfiles\n", pname);
0182   printf("Options:\n"
0183          "\t-v\tverbose output\n"
0184          "\t-w\tprint white balance\n"
0185          "\t-u\tprint unpack function\n"
0186          "\t-f\tprint frame size (only w/ -u)\n"
0187          "\t-s\tprint output image size\n"
0188          "\t-h\tforce half-size mode (only for -s)\n"
0189          "\t-M\tdisable use of raw-embedded color data\n"
0190          "\t+M\tforce use of raw-embedded color data\n"
0191          "\t-L filename\tread input files list from filename\n"
0192          "\t-o filename\toutput to filename\n");
0193 }
0194 
0195 int main(int ac, char *av[])
0196 {
0197   int ret;
0198   int verbose = 0, print_sz = 0, print_unpack = 0, print_frame = 0, print_wb = 0;
0199   LibRaw MyCoolRawProcessor;
0200   char *filelistfile = NULL;
0201   char *outputfilename = NULL;
0202   FILE *outfile = stdout;
0203   std::vector<std::string> filelist;
0204 
0205   filelist.reserve(ac - 1);
0206 
0207   for (int i = 1; i < ac; i++)
0208   {
0209     if (av[i][0] == '-')
0210     {
0211       if (!strcmp(av[i], "-v"))
0212         verbose++;
0213       if (!strcmp(av[i], "-w"))
0214         print_wb++;
0215       if (!strcmp(av[i], "-u"))
0216         print_unpack++;
0217       if (!strcmp(av[i], "-s"))
0218         print_sz++;
0219       if (!strcmp(av[i], "-h"))
0220         O.half_size = 1;
0221       if (!strcmp(av[i], "-f"))
0222         print_frame++;
0223       if (!strcmp(av[i], "-M"))
0224         MyCoolRawProcessor.imgdata.params.use_camera_matrix = 0;
0225       if (!strcmp(av[i], "-L") && i < ac - 1)
0226       {
0227         filelistfile = av[i + 1];
0228         i++;
0229       }
0230       if (!strcmp(av[i], "-o") && i < ac - 1)
0231       {
0232         outputfilename = av[i + 1];
0233         i++;
0234       }
0235       continue;
0236     }
0237     else if (!strcmp(av[i], "+M"))
0238     {
0239       MyCoolRawProcessor.imgdata.params.use_camera_matrix = 3;
0240       continue;
0241     }
0242     filelist.push_back(av[i]);
0243   }
0244   if (filelistfile)
0245   {
0246     char *p;
0247     char path[MAX_PATH + 1];
0248     FILE *f = fopen(filelistfile, "r");
0249     if (f)
0250     {
0251       while (fgets(path, MAX_PATH, f))
0252       {
0253         if ((p = strchr(path, '\n')))
0254           *p = 0;
0255         if ((p = strchr(path, '\r')))
0256           *p = 0;
0257         filelist.push_back(path);
0258       }
0259       fclose(f);
0260     }
0261   }
0262   if (filelist.size() < 1)
0263   {
0264     print_usage(av[0]);
0265     return 1;
0266   }
0267   if (outputfilename)
0268     outfile = fopen(outputfilename, "wt");
0269 
0270   for (int i = 0; i < (int)filelist.size(); i++)
0271   {
0272     if ((ret = MyCoolRawProcessor.open_file(filelist[i].c_str())) != LIBRAW_SUCCESS)
0273     {
0274       fprintf(stderr, "Cannot decode %s: %s\n", filelist[i].c_str(), libraw_strerror(ret));
0275       continue; // no recycle, open_file will recycle
0276     }
0277 
0278     if (print_sz)
0279       print_szfun(outfile, MyCoolRawProcessor, filelist[i]);
0280     else if (verbose)
0281       print_verbose(outfile, MyCoolRawProcessor, filelist[i]);
0282     else if (print_unpack)
0283       print_unpackfun(outfile, MyCoolRawProcessor, print_frame, filelist[i]);
0284     else if (print_wb)
0285       print_wbfun(outfile, MyCoolRawProcessor, filelist[i]);
0286     else
0287       fprintf(outfile, "%s is a %s %s image.\n", filelist[i].c_str(), P1.make, P1.model);
0288 
0289     MyCoolRawProcessor.recycle();
0290   } // endfor
0291   return 0;
0292 }
0293 
0294 #define PRINTMATRIX3x4(of, mat, clrs)                                                                                  \
0295   do                                                                                                                   \
0296   {                                                                                                                    \
0297     for (int r = 0; r < 3; r++)                                                                                        \
0298       if (clrs == 4)                                                                                                   \
0299         fprintf(of, "%6.4f\t%6.4f\t%6.4f\t%6.4f\n", mat[r][0], mat[r][1], mat[r][2], mat[r][3]);                       \
0300       else                                                                                                             \
0301         fprintf(of, "%6.4f\t%6.4f\t%6.4f\n", mat[r][0], mat[r][1], mat[r][2]);                                         \
0302   } while (0)
0303 
0304 #define PRINTMATRIX4x3(of, mat, clrs)                                                                                  \
0305   do                                                                                                                   \
0306   {                                                                                                                    \
0307     for (int r = 0; r < clrs && r < 4; r++)                                                                            \
0308       fprintf(of, "%6.4f\t%6.4f\t%6.4f\n", mat[r][0], mat[r][1], mat[r][2]);                                           \
0309   } while (0)
0310 
0311 void print_verbose(FILE *outfile, LibRaw &MyCoolRawProcessor, std::string &fn)
0312 {
0313   int WBi;
0314   float denom;
0315   int ret;
0316 
0317   if ((ret = MyCoolRawProcessor.adjust_sizes_info_only()))
0318   {
0319     fprintf(outfile, "Cannot decode %s: %s\n", fn.c_str(), libraw_strerror(ret));
0320     return; // no recycle, open_file will recycle
0321   }
0322 
0323   fprintf(outfile, "\nFilename: %s\n", fn.c_str());
0324   if (C.OriginalRawFileName[0])
0325     fprintf(outfile, "OriginalRawFileName: =%s=\n", C.OriginalRawFileName);
0326   fprintf(outfile, "Timestamp: %s", ctime(&(P2.timestamp)));
0327   fprintf(outfile, "Camera: %s %s ID: 0x%llx\n", P1.make, P1.model, mnLens.CamID);
0328   fprintf(outfile, "Normalized Make/Model: =%s/%s= ", P1.normalized_make, P1.normalized_model);
0329   fprintf(outfile, "CamMaker ID: %d\n", P1.maker_index);
0330 
0331   {
0332     int i = 0;
0333     char sep[] = ", ";
0334     if (C.UniqueCameraModel[0])
0335     {
0336       i++;
0337       fprintf(outfile, "UniqueCameraModel: =%s=", C.UniqueCameraModel);
0338     }
0339     if (C.LocalizedCameraModel[0])
0340     {
0341       if (i)
0342       {
0343         fprintf(outfile, "%s", sep);
0344         i++;
0345       }
0346       fprintf(outfile, "LocalizedCameraModel: =%s=", C.LocalizedCameraModel);
0347     }
0348     if (i)
0349     {
0350       fprintf(outfile, "\n");
0351       i = 0;
0352     }
0353     if (C.ImageUniqueID[0])
0354     {
0355       if (i)
0356         fprintf(outfile, "%s", sep);
0357       i++;
0358       fprintf(outfile, "ImageUniqueID: =%s=", C.ImageUniqueID);
0359     }
0360     if (C.RawDataUniqueID[0])
0361     {
0362       if (i)
0363         fprintf(outfile, "%s", sep);
0364       i++;
0365       fprintf(outfile, "RawDataUniqueID: =%s=", C.RawDataUniqueID);
0366     }
0367     if (i)
0368       fprintf(outfile, "\n");
0369   }
0370 
0371   if (ShootingInfo.BodySerial[0] && strcmp(ShootingInfo.BodySerial, "0"))
0372   {
0373     trimSpaces(ShootingInfo.BodySerial);
0374     fprintf(outfile, "Body#: %s", ShootingInfo.BodySerial);
0375   }
0376   else if (C.model2[0] && (!strncasecmp(P1.normalized_make, "Kodak", 5)))
0377   {
0378     trimSpaces(C.model2);
0379     fprintf(outfile, "Body#: %s", C.model2);
0380   }
0381   if (ShootingInfo.InternalBodySerial[0])
0382   {
0383     trimSpaces(ShootingInfo.InternalBodySerial);
0384     fprintf(outfile, " BodyAssy#: %s", ShootingInfo.InternalBodySerial);
0385   }
0386   if (exifLens.LensSerial[0])
0387   {
0388     trimSpaces(exifLens.LensSerial);
0389     fprintf(outfile, " Lens#: %s", exifLens.LensSerial);
0390   }
0391   if (exifLens.InternalLensSerial[0])
0392   {
0393     trimSpaces(exifLens.InternalLensSerial);
0394     fprintf(outfile, " LensAssy#: %s", exifLens.InternalLensSerial);
0395   }
0396   if (P2.artist[0])
0397     fprintf(outfile, " Owner: %s\n", P2.artist);
0398   if (P1.dng_version)
0399   {
0400     fprintf(outfile, " DNG Version: ");
0401     for (int i = 24; i >= 0; i -= 8)
0402       fprintf(outfile, "%d%c", P1.dng_version >> i & 255, i ? '.' : '\n');
0403   }
0404   fprintf(outfile, "\nEXIF:\n");
0405   fprintf(outfile, "\tMinFocal: %0.1f mm\n", exifLens.MinFocal);
0406   fprintf(outfile, "\tMaxFocal: %0.1f mm\n", exifLens.MaxFocal);
0407   fprintf(outfile, "\tMaxAp @MinFocal: f/%0.1f\n", exifLens.MaxAp4MinFocal);
0408   fprintf(outfile, "\tMaxAp @MaxFocal: f/%0.1f\n", exifLens.MaxAp4MaxFocal);
0409   fprintf(outfile, "\tCurFocal: %0.1f mm\n", P2.focal_len);
0410   fprintf(outfile, "\tMaxAperture @CurFocal: f/%0.1f\n", exifLens.EXIF_MaxAp);
0411   fprintf(outfile, "\tFocalLengthIn35mmFormat: %d mm\n", exifLens.FocalLengthIn35mmFormat);
0412   fprintf(outfile, "\tLensMake: %s\n", exifLens.LensMake);
0413   fprintf(outfile, "\tLens: %s\n", exifLens.Lens);
0414   fprintf(outfile, "\n");
0415 
0416   fprintf(outfile, "\nMakernotes:\n");
0417   fprintf(outfile, "\tDriveMode: %d\n", ShootingInfo.DriveMode);
0418   fprintf(outfile, "\tFocusMode: %d\n", ShootingInfo.FocusMode);
0419   fprintf(outfile, "\tMeteringMode: %d\n", ShootingInfo.MeteringMode);
0420   fprintf(outfile, "\tAFPoint: %d\n", ShootingInfo.AFPoint);
0421   fprintf(outfile, "\tExposureMode: %d\n", ShootingInfo.ExposureMode);
0422   fprintf(outfile, "\tExposureProgram: %d\n", ShootingInfo.ExposureProgram);
0423   fprintf(outfile, "\tImageStabilization: %d\n", ShootingInfo.ImageStabilization);
0424 
0425   fprintf(outfile, "\tLens: %s\n", mnLens.Lens);
0426   fprintf(outfile, "\tLensFormat: %d, ", mnLens.LensFormat);
0427 
0428   fprintf(outfile, "\tLensMount: %d, ", mnLens.LensMount);
0429   fprintf(outfile, "\tFocalType: %d, ", mnLens.FocalType);
0430   switch (mnLens.FocalType)
0431   {
0432   case LIBRAW_FT_UNDEFINED:
0433     fprintf(outfile, "Undefined\n");
0434     break;
0435   case LIBRAW_FT_PRIME_LENS:
0436     fprintf(outfile, "Prime lens\n");
0437     break;
0438   case LIBRAW_FT_ZOOM_LENS:
0439     fprintf(outfile, "Zoom lens\n");
0440     break;
0441   default:
0442     fprintf(outfile, "Unknown\n");
0443     break;
0444   }
0445   fprintf(outfile, "\tLensFeatures_pre: %s\n", mnLens.LensFeatures_pre);
0446   fprintf(outfile, "\tLensFeatures_suf: %s\n", mnLens.LensFeatures_suf);
0447   fprintf(outfile, "\tMinFocal: %0.1f mm\n", mnLens.MinFocal);
0448   fprintf(outfile, "\tMaxFocal: %0.1f mm\n", mnLens.MaxFocal);
0449   fprintf(outfile, "\tMaxAp @MinFocal: f/%0.1f\n", mnLens.MaxAp4MinFocal);
0450   fprintf(outfile, "\tMaxAp @MaxFocal: f/%0.1f\n", mnLens.MaxAp4MaxFocal);
0451   fprintf(outfile, "\tMinAp @MinFocal: f/%0.1f\n", mnLens.MinAp4MinFocal);
0452   fprintf(outfile, "\tMinAp @MaxFocal: f/%0.1f\n", mnLens.MinAp4MaxFocal);
0453   fprintf(outfile, "\tMaxAp: f/%0.1f\n", mnLens.MaxAp);
0454   fprintf(outfile, "\tMinAp: f/%0.1f\n", mnLens.MinAp);
0455   fprintf(outfile, "\tCurFocal: %0.1f mm\n", mnLens.CurFocal);
0456   fprintf(outfile, "\tCurAp: f/%0.1f\n", mnLens.CurAp);
0457   fprintf(outfile, "\tMaxAp @CurFocal: f/%0.1f\n", mnLens.MaxAp4CurFocal);
0458   fprintf(outfile, "\tMinAp @CurFocal: f/%0.1f\n", mnLens.MinAp4CurFocal);
0459 
0460   if (exifLens.makernotes.FocalLengthIn35mmFormat > 1.0f)
0461     fprintf(outfile, "\tFocalLengthIn35mmFormat: %0.1f mm\n", exifLens.makernotes.FocalLengthIn35mmFormat);
0462 
0463   if (exifLens.nikon.EffectiveMaxAp > 0.1f)
0464     fprintf(outfile, "\tEffectiveMaxAp: f/%0.1f\n", exifLens.nikon.EffectiveMaxAp);
0465 
0466   if (exifLens.makernotes.LensFStops > 0.1f)
0467     fprintf(outfile, "\tLensFStops @CurFocal: %0.2f\n", exifLens.makernotes.LensFStops);
0468 
0469   fprintf(outfile, "\tTeleconverterID: %lld\n", mnLens.TeleconverterID);
0470   fprintf(outfile, "\tTeleconverter: %s\n", mnLens.Teleconverter);
0471   fprintf(outfile, "\tAdapterID: %lld\n", mnLens.AdapterID);
0472   fprintf(outfile, "\tAdapter: %s\n", mnLens.Adapter);
0473   fprintf(outfile, "\tAttachmentID: %lld\n", mnLens.AttachmentID);
0474   fprintf(outfile, "\tAttachment: %s\n", mnLens.Attachment);
0475   fprintf(outfile, "\n");
0476 
0477   fprintf(outfile, "ISO speed: %d\n", (int)P2.iso_speed);
0478   if (P3.real_ISO > 0.1f)
0479     fprintf(outfile, "real ISO speed: %d\n", (int)P3.real_ISO);
0480   fprintf(outfile, "Shutter: ");
0481   if (P2.shutter > 0 && P2.shutter < 1)
0482     P2.shutter = fprintf(outfile, "1/%0.1f\n", 1.0f / P2.shutter);
0483   else if (P2.shutter >= 1)
0484     fprintf(outfile, "%0.1f sec\n", P2.shutter);
0485   else /* negative*/
0486     fprintf(outfile, " negative value\n");
0487   fprintf(outfile, "Aperture: f/%0.1f\n", P2.aperture);
0488   fprintf(outfile, "Focal length: %0.1f mm\n", P2.focal_len);
0489   if (P3.exifAmbientTemperature > -273.15f)
0490     fprintf(outfile, "Ambient temperature (exif data): %6.2f° C\n", P3.exifAmbientTemperature);
0491   if (P3.CameraTemperature > -273.15f)
0492     fprintf(outfile, "Camera temperature: %6.2f° C\n", P3.CameraTemperature);
0493   if (P3.SensorTemperature > -273.15f)
0494     fprintf(outfile, "Sensor temperature: %6.2f° C\n", P3.SensorTemperature);
0495   if (P3.SensorTemperature2 > -273.15f)
0496     fprintf(outfile, "Sensor temperature2: %6.2f° C\n", P3.SensorTemperature2);
0497   if (P3.LensTemperature > -273.15f)
0498     fprintf(outfile, "Lens temperature: %6.2f° C\n", P3.LensTemperature);
0499   if (P3.AmbientTemperature > -273.15f)
0500     fprintf(outfile, "Ambient temperature: %6.2f° C\n", P3.AmbientTemperature);
0501   if (P3.BatteryTemperature > -273.15f)
0502     fprintf(outfile, "Battery temperature: %6.2f° C\n", P3.BatteryTemperature);
0503   if (P3.FlashGN > 1.0f)
0504     fprintf(outfile, "Flash Guide Number: %6.2f\n", P3.FlashGN);
0505   fprintf(outfile, "Flash exposure compensation: %0.2f EV\n", P3.FlashEC);
0506   if (C.profile)
0507     fprintf(outfile, "Embedded ICC profile: yes, %d bytes\n", C.profile_length);
0508   else
0509     fprintf(outfile, "Embedded ICC profile: no\n");
0510 
0511   if (C.dng_levels.baseline_exposure > -999.f)
0512     fprintf(outfile, "Baseline exposure: %04.3f\n", C.dng_levels.baseline_exposure);
0513 
0514   fprintf(outfile, "Number of raw images: %d\n", P1.raw_count);
0515 
0516   if (S.pixel_aspect != 1)
0517     fprintf(outfile, "Pixel Aspect Ratio: %0.6f\n", S.pixel_aspect);
0518   if (T.tlength)
0519     fprintf(outfile, "Thumb size:  %4d x %d\n", T.twidth, T.theight);
0520   fprintf(outfile, "Full size:   %4d x %d\n", S.raw_width, S.raw_height);
0521 
0522   if (S.raw_inset_crops[0].cwidth)
0523   {
0524     fprintf(outfile, "Raw inset, width x height: %4d x %d ", S.raw_inset_crops[0].cwidth, S.raw_inset_crops[0].cheight);
0525     if (S.raw_inset_crops[0].cleft != 0xffff)
0526       fprintf(outfile, "left: %d ", S.raw_inset_crops[0].cleft);
0527     if (S.raw_inset_crops[0].ctop != 0xffff)
0528       fprintf(outfile, "top: %d", S.raw_inset_crops[0].ctop);
0529     fprintf(outfile, "\n");
0530   }
0531 
0532   fprintf(outfile, "Image size:  %4d x %d\n", S.width, S.height);
0533   fprintf(outfile, "Output size: %4d x %d\n", S.iwidth, S.iheight);
0534   fprintf(outfile, "Image flip: %d\n", S.flip);
0535 
0536   fprintf(outfile, "Raw colors: %d", P1.colors);
0537   if (P1.filters)
0538   {
0539     fprintf(outfile, "\nFilter pattern: ");
0540     if (!P1.cdesc[3])
0541       P1.cdesc[3] = 'G';
0542     for (int i = 0; i < 16; i++)
0543       putchar(P1.cdesc[MyCoolRawProcessor.fcol(i >> 1, i & 1)]);
0544   }
0545 
0546   if (C.black)
0547   {
0548     fprintf(outfile, "\nblack: %d", C.black);
0549   }
0550   if (C.cblack[0] != 0)
0551   {
0552     fprintf(outfile, "\ncblack[0 .. 3]:");
0553     for (int c = 0; c < 4; c++)
0554       fprintf(outfile, " %d", C.cblack[c]);
0555   }
0556   if ((C.cblack[4] * C.cblack[5]) > 0)
0557   {
0558     fprintf(outfile, "\nBlackLevelRepeatDim: %d x %d\n", C.cblack[4], C.cblack[5]);
0559     int n = C.cblack[4] * C.cblack[5];
0560     fprintf(outfile, "cblack[6 .. %d]:", 6 + n - 1);
0561     for (int c = 6; c < 6 + n; c++)
0562       fprintf(outfile, " %d", C.cblack[c]);
0563   }
0564 
0565   if (C.linear_max[0] != 0)
0566   {
0567     fprintf(outfile, "\nHighlight linearity limits:");
0568     for (int c = 0; c < 4; c++)
0569       fprintf(outfile, " %ld", C.linear_max[c]);
0570   }
0571 
0572   if (P1.colors > 1)
0573   {
0574     fprintf(outfile, "\nMakernotes WB data:               coeffs                  EVs");
0575     if ((C.cam_mul[0] > 0) && (C.cam_mul[1] > 0))
0576     {
0577       fprintf(outfile, "\n  %-23s   %g %g %g %g   %5.2f %5.2f %5.2f %5.2f", "As shot", C.cam_mul[0], C.cam_mul[1],
0578               C.cam_mul[2], C.cam_mul[3], roundf(_log2(C.cam_mul[0] / C.cam_mul[1]) * 100.0f) / 100.0f, 0.0f,
0579               roundf(_log2(C.cam_mul[2] / C.cam_mul[1]) * 100.0f) / 100.0f,
0580               C.cam_mul[3] ? roundf(_log2(C.cam_mul[3] / C.cam_mul[1]) * 100.0f) / 100.0f : 0.0f);
0581     }
0582 
0583     for (int cnt = 0; cnt < int(sizeof WBToStr / sizeof *WBToStr); cnt++)
0584     {
0585       WBi = WBToStr[cnt].NumId;
0586       if ((C.WB_Coeffs[WBi][0] > 0) && (C.WB_Coeffs[WBi][1] > 0))
0587       {
0588         denom = (float)C.WB_Coeffs[WBi][1];
0589         fprintf(outfile, "\n  %-23s   %4d %4d %4d %4d   %5.2f %5.2f %5.2f %5.2f", WBToStr[cnt].hrStrId,
0590                 C.WB_Coeffs[WBi][0], C.WB_Coeffs[WBi][1], C.WB_Coeffs[WBi][2], C.WB_Coeffs[WBi][3],
0591                 roundf(_log2((float)C.WB_Coeffs[WBi][0] / denom) * 100.0f) / 100.0f, 0.0f,
0592                 roundf(_log2((float)C.WB_Coeffs[WBi][2] / denom) * 100.0f) / 100.0f,
0593                 C.WB_Coeffs[3] ? roundf(_log2((float)C.WB_Coeffs[WBi][3] / denom) * 100.0f) / 100.0f : 0.0f);
0594       }
0595     }
0596 
0597     if (C.rgb_cam[0][0] > 0.0001)
0598     {
0599       fprintf(outfile, "\n\nCamera2RGB matrix (mode: %d):\n", MyCoolRawProcessor.imgdata.params.use_camera_matrix);
0600       PRINTMATRIX3x4(outfile, C.rgb_cam, P1.colors);
0601     }
0602 
0603     fprintf(outfile, "\nXYZ->CamRGB matrix:\n");
0604     PRINTMATRIX4x3(outfile, C.cam_xyz, P1.colors);
0605 
0606     for (int cnt = 0; cnt < 2; cnt++)
0607     {
0608       if (fabsf(C.P1_color[cnt].romm_cam[0]) > 0)
0609       {
0610         fprintf(outfile, "\nPhaseOne Matrix %d:\n", cnt + 1);
0611         for (int i = 0; i < 3; i++)
0612           fprintf(outfile, "%6.4f\t%6.4f\t%6.4f\n", C.P1_color[cnt].romm_cam[i * 3],
0613                   C.P1_color[cnt].romm_cam[i * 3 + 1], C.P1_color[cnt].romm_cam[i * 3 + 2]);
0614       }
0615     }
0616 
0617     if (fabsf(C.cmatrix[0][0]) > 0)
0618     {
0619       fprintf(outfile, "\ncamRGB -> sRGB Matrix:\n");
0620       PRINTMATRIX3x4(outfile, C.cmatrix, P1.colors);
0621     }
0622 
0623     if (fabsf(C.ccm[0][0]) > 0)
0624     {
0625       fprintf(outfile, "\nColor Correction Matrix:\n");
0626       PRINTMATRIX3x4(outfile, C.ccm, P1.colors);
0627     }
0628 
0629     for (int cnt = 0; cnt < 2; cnt++)
0630     {
0631       if (C.dng_color[cnt].illuminant != LIBRAW_WBI_None)
0632       {
0633         if (C.dng_color[cnt].illuminant <= LIBRAW_WBI_StudioTungsten)
0634         {
0635           fprintf(outfile, "\nDNG Illuminant %d: %s", cnt + 1, WB_idx2hrstr(C.dng_color[cnt].illuminant));
0636         }
0637         else if (C.dng_color[cnt].illuminant == LIBRAW_WBI_Other)
0638         {
0639           fprintf(outfile, "\nDNG Illuminant %d: Other", cnt + 1);
0640         }
0641         else
0642         {
0643           fprintf(outfile,
0644                   "\nDNG Illuminant %d is out of EXIF LightSources range "
0645                   "[0:24, 255]: %d",
0646                   cnt + 1, C.dng_color[cnt].illuminant);
0647         }
0648       }
0649     }
0650 
0651     for (int n = 0; n < 2; n++)
0652     {
0653       if (fabsf(C.dng_color[n].colormatrix[0][0]) > 0)
0654       {
0655         fprintf(outfile, "\nDNG color matrix %d:\n", n + 1);
0656         PRINTMATRIX4x3(outfile, C.dng_color[n].colormatrix, P1.colors);
0657       }
0658     }
0659 
0660     for (int n = 0; n < 2; n++)
0661     {
0662       if (fabsf(C.dng_color[n].calibration[0][0]) > 0)
0663       {
0664         fprintf(outfile, "\nDNG calibration matrix %d:\n", n + 1);
0665         for (int i = 0; i < P1.colors && i < 4; i++)
0666         {
0667           for (int j = 0; j < P1.colors && j < 4; j++)
0668             fprintf(outfile, "%6.4f\t", C.dng_color[n].calibration[j][i]);
0669           fprintf(outfile, "\n");
0670         }
0671       }
0672     }
0673 
0674     for (int n = 0; n < 2; n++)
0675     {
0676       if (fabsf(C.dng_color[n].forwardmatrix[0][0]) > 0)
0677       {
0678         fprintf(outfile, "\nDNG forward matrix %d:\n", n + 1);
0679         PRINTMATRIX3x4(outfile, C.dng_color[n].forwardmatrix, P1.colors);
0680       }
0681     }
0682 
0683     fprintf(outfile, "\nDerived D65 multipliers:");
0684     for (int c = 0; c < P1.colors; c++)
0685       fprintf(outfile, " %f", C.pre_mul[c]);
0686     fprintf(outfile, "\n");
0687   }
0688 }
0689 
0690 void print_wbfun(FILE *outfile, LibRaw &MyCoolRawProcessor, std::string &fn)
0691 {
0692   int WBi;
0693   float denom;
0694   fprintf(outfile, "// %s %s\n", P1.make, P1.model);
0695   for (int cnt = 0; cnt < int(sizeof WBToStr / sizeof *WBToStr); cnt++)
0696   {
0697     WBi = WBToStr[cnt].NumId;
0698     if (C.WB_Coeffs[WBi][0] && C.WB_Coeffs[WBi][1] && !WBToStr[cnt].aux_setting)
0699     {
0700       denom = (float)C.WB_Coeffs[WBi][1];
0701       fprintf(outfile, "{\"%s\", \"%s\", %s, {%6.5ff, 1.0f, %6.5ff, ", P1.normalized_make, P1.normalized_model,
0702               WBToStr[cnt].StrId, C.WB_Coeffs[WBi][0] / denom, C.WB_Coeffs[WBi][2] / denom);
0703       if (C.WB_Coeffs[WBi][1] == C.WB_Coeffs[WBi][3])
0704         fprintf(outfile, "1.0f}},\n");
0705       else
0706         fprintf(outfile, "%6.5ff}},\n", C.WB_Coeffs[WBi][3] / denom);
0707     }
0708   }
0709 
0710   for (int cnt = 0; cnt < 64; cnt++)
0711     if (C.WBCT_Coeffs[cnt][0])
0712     {
0713       fprintf(outfile, "{\"%s\", \"%s\", %d, {%6.5ff, 1.0f, %6.5ff, ", P1.normalized_make, P1.normalized_model,
0714               (int)C.WBCT_Coeffs[cnt][0], C.WBCT_Coeffs[cnt][1] / C.WBCT_Coeffs[cnt][2],
0715               C.WBCT_Coeffs[cnt][3] / C.WBCT_Coeffs[cnt][2]);
0716       if (C.WBCT_Coeffs[cnt][2] == C.WBCT_Coeffs[cnt][4])
0717         fprintf(outfile, "1.0f}},\n");
0718       else
0719         fprintf(outfile, "%6.5ff}},\n", C.WBCT_Coeffs[cnt][4] / C.WBCT_Coeffs[cnt][2]);
0720     }
0721     else
0722       break;
0723   fprintf(outfile, "\n");
0724 }
0725 
0726 void print_szfun(FILE *outfile, LibRaw &MyCoolRawProcessor, std::string &fn)
0727 {
0728   fprintf(outfile, "%s\t%s\t%s\t%d\t%d\n", fn.c_str(), P1.make, P1.model, S.width, S.height);
0729 }
0730 
0731 void print_unpackfun(FILE *outfile, LibRaw &MyCoolRawProcessor, int print_frame, std::string &fn)
0732 {
0733   char frame[48] = "";
0734   if (print_frame)
0735   {
0736     ushort right_margin = S.raw_width - S.width - S.left_margin;
0737     ushort bottom_margin = S.raw_height - S.height - S.top_margin;
0738     snprintf(frame, 48, "F=%dx%dx%dx%d RS=%dx%d", S.left_margin, S.top_margin, right_margin, bottom_margin, S.raw_width,
0739              S.raw_height);
0740   }
0741   fprintf(outfile, "%s\t%s\t%s\t%s/%s\n", fn.c_str(), MyCoolRawProcessor.unpack_function_name(), frame, P1.make,
0742           P1.model);
0743 }