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

0001 /* -*- C++ -*-
0002  * File: unprocessed_raw.cpp
0003  * Copyright 2009-2021 LibRaw LLC (info@libraw.org)
0004  * Created: Fri Jan 02, 2009
0005  *
0006  * LibRaw sample
0007  * Generates unprocessed raw image: with masked pixels and without black
0008 subtraction
0009  *
0010 
0011 LibRaw is free software; you can redistribute it and/or modify
0012 it under the terms of the one of two licenses as you choose:
0013 
0014 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1
0015    (See file LICENSE.LGPL provided in LibRaw distribution archive for details).
0016 
0017 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
0018    (See file LICENSE.CDDL provided in LibRaw distribution archive for details).
0019 
0020  */
0021 #include <stdio.h>
0022 #include <string.h>
0023 #include <math.h>
0024 #include <time.h>
0025 
0026 #include "libraw/libraw.h"
0027 
0028 #ifndef LIBRAW_WIN32_CALLS
0029 #include <netinet/in.h>
0030 #else
0031 #include <sys/utime.h>
0032 #include <winsock2.h>
0033 #endif
0034 
0035 #ifdef LIBRAW_WIN32_CALLS
0036 #define snprintf _snprintf
0037 #endif
0038 
0039 #if !(LIBRAW_COMPILE_CHECK_VERSION_NOTLESS(0, 14))
0040 #error This code is for LibRaw 0.14+ only
0041 #endif
0042 
0043 void gamma_curve(unsigned short curve[]);
0044 void write_ppm(unsigned width, unsigned height, unsigned short *bitmap,
0045                const char *basename);
0046 void write_tiff(int width, int height, unsigned short *bitmap,
0047                 const char *basename);
0048 
0049 int main(int ac, char *av[])
0050 {
0051   int i, ret;
0052   int verbose = 1, autoscale = 0, use_gamma = 0, out_tiff = 0;
0053   char outfn[1024];
0054 
0055   LibRaw RawProcessor;
0056   if (ac < 2)
0057   {
0058   usage:
0059     printf("unprocessed_raw - LibRaw %s sample. %d cameras supported\n"
0060            "Usage: %s [-q] [-A] [-g] [-s N] raw-files....\n"
0061            "\t-q - be quiet\n"
0062            "\t-s N - select Nth image in file (default=0)\n"
0063            "\t-g - use gamma correction with gamma 2.2 (not precise,use for "
0064            "visual inspection only)\n"
0065            "\t-A - autoscaling (by integer factor)\n"
0066            "\t-T - write tiff instead of pgm\n",
0067            LibRaw::version(), LibRaw::cameraCount(), av[0]);
0068     return 0;
0069   }
0070 
0071 #define S RawProcessor.imgdata.sizes
0072 #define OUT RawProcessor.imgdata.params
0073 #define OUTR RawProcessor.imgdata.rawparams
0074 
0075   for (i = 1; i < ac; i++)
0076   {
0077     if (av[i][0] == '-')
0078     {
0079       if (av[i][1] == 'q' && av[i][2] == 0)
0080         verbose = 0;
0081       else if (av[i][1] == 'A' && av[i][2] == 0)
0082         autoscale = 1;
0083       else if (av[i][1] == 'g' && av[i][2] == 0)
0084         use_gamma = 1;
0085       else if (av[i][1] == 'T' && av[i][2] == 0)
0086         out_tiff = 1;
0087       else if (av[i][1] == 's' && av[i][2] == 0)
0088       {
0089         i++;
0090         OUTR.shot_select = av[i] ? atoi(av[i]) : 0;
0091       }
0092       else
0093         goto usage;
0094       continue;
0095     }
0096 
0097     if (verbose)
0098       printf("Processing file %s\n", av[i]);
0099     if ((ret = RawProcessor.open_file(av[i])) != LIBRAW_SUCCESS)
0100     {
0101       fprintf(stderr, "Cannot open %s: %s\n", av[i], libraw_strerror(ret));
0102       continue; // no recycle b/c open file will recycle itself
0103     }
0104     if (verbose)
0105     {
0106       printf("Image size: %dx%d\nRaw size: %dx%d\n", S.width, S.height,
0107              S.raw_width, S.raw_height);
0108       printf("Margins: top=%d, left=%d\n", S.top_margin, S.left_margin);
0109     }
0110 
0111     if ((ret = RawProcessor.unpack()) != LIBRAW_SUCCESS)
0112     {
0113       fprintf(stderr, "Cannot unpack %s: %s\n", av[i], libraw_strerror(ret));
0114       continue;
0115     }
0116 
0117     if (verbose)
0118       printf("Unpacked....\n");
0119 
0120     if (!(RawProcessor.imgdata.idata.filters ||
0121           RawProcessor.imgdata.idata.colors == 1))
0122     {
0123       printf("Only Bayer-pattern RAW files supported, sorry....\n");
0124       continue;
0125     }
0126 
0127     if (autoscale)
0128     {
0129       unsigned max = 0, scale;
0130       for (int j = 0; j < S.raw_height * S.raw_width; j++)
0131         if (max < RawProcessor.imgdata.rawdata.raw_image[j])
0132           max = RawProcessor.imgdata.rawdata.raw_image[j];
0133       if (max > 0 && max < 1 << 15)
0134       {
0135         scale = (1 << 16) / max;
0136         if (verbose)
0137           printf("Scaling with multiplier=%d (max=%d)\n", scale, max);
0138 
0139         for (int j = 0; j < S.raw_height * S.raw_width; j++)
0140           RawProcessor.imgdata.rawdata.raw_image[j] *= scale;
0141       }
0142     }
0143     if (use_gamma)
0144     {
0145       unsigned short curve[0x10000];
0146       gamma_curve(curve);
0147       for (int j = 0; j < S.raw_height * S.raw_width; j++)
0148         RawProcessor.imgdata.rawdata.raw_image[j] =
0149             curve[RawProcessor.imgdata.rawdata.raw_image[j]];
0150       if (verbose)
0151         printf("Gamma-corrected....\n");
0152     }
0153 
0154     if (OUTR.shot_select)
0155       snprintf(outfn, sizeof(outfn), "%s-%d.%s", av[i], OUTR.shot_select,
0156                out_tiff ? "tiff" : "pgm");
0157     else
0158       snprintf(outfn, sizeof(outfn), "%s.%s", av[i], out_tiff ? "tiff" : "pgm");
0159 
0160     if (out_tiff)
0161       write_tiff(S.raw_width, S.raw_height,
0162                  RawProcessor.imgdata.rawdata.raw_image, outfn);
0163     else
0164       write_ppm(S.raw_width, S.raw_height,
0165                 RawProcessor.imgdata.rawdata.raw_image, outfn);
0166 
0167     if (verbose)
0168       printf("Stored to file %s\n", outfn);
0169   }
0170   return 0;
0171 }
0172 
0173 void write_ppm(unsigned width, unsigned height, unsigned short *bitmap,
0174                const char *fname)
0175 {
0176   if (!bitmap)
0177     return;
0178 
0179   FILE *f = fopen(fname, "wb");
0180   if (!f)
0181     return;
0182   int bits = 16;
0183   fprintf(f, "P5\n%d %d\n%d\n", width, height, (1 << bits) - 1);
0184   unsigned char *data = (unsigned char *)bitmap;
0185   unsigned data_size = width * height * 2;
0186 #define SWAP(a, b)                                                             \
0187   {                                                                            \
0188     a ^= b;                                                                    \
0189     a ^= (b ^= a);                                                             \
0190   }
0191   for (unsigned i = 0; i < data_size; i += 2)
0192     SWAP(data[i], data[i + 1]);
0193 #undef SWAP
0194   fwrite(data, data_size, 1, f);
0195   fclose(f);
0196 }
0197 
0198 /*  == gamma curve and tiff writer - simplified cut'n'paste from dcraw.c */
0199 
0200 #define SQR(x) ((x) * (x))
0201 
0202 void gamma_curve(unsigned short *curve)
0203 {
0204 
0205   double pwr = 1.0 / 2.2;
0206   double ts = 0.0;
0207   int imax = 0xffff;
0208   int mode = 2;
0209   int i;
0210   double g[6], bnd[2] = {0, 0}, r;
0211 
0212   g[0] = pwr;
0213   g[1] = ts;
0214   g[2] = g[3] = g[4] = 0;
0215   bnd[g[1] >= 1] = 1;
0216   if (g[1] && (g[1] - 1) * (g[0] - 1) <= 0)
0217   {
0218     for (i = 0; i < 48; i++)
0219     {
0220       g[2] = (bnd[0] + bnd[1]) / 2;
0221       if (g[0])
0222         bnd[(pow(g[2] / g[1], -g[0]) - 1) / g[0] - 1 / g[2] > -1] = g[2];
0223       else
0224         bnd[g[2] / exp(1 - 1 / g[2]) < g[1]] = g[2];
0225     }
0226     g[3] = g[2] / g[1];
0227     if (g[0])
0228       g[4] = g[2] * (1 / g[0] - 1);
0229   }
0230   if (g[0])
0231     g[5] = 1 / (g[1] * SQR(g[3]) / 2 - g[4] * (1 - g[3]) +
0232                 (1 - pow(g[3], 1 + g[0])) * (1 + g[4]) / (1 + g[0])) -
0233            1;
0234   else
0235     g[5] = 1 / (g[1] * SQR(g[3]) / 2 + 1 - g[2] - g[3] -
0236                 g[2] * g[3] * (log(g[3]) - 1)) -
0237            1;
0238   for (i = 0; i < 0x10000; i++)
0239   {
0240     curve[i] = 0xffff;
0241     if ((r = (double)i / imax) < 1)
0242       curve[i] =
0243           0x10000 *
0244           (mode ? (r < g[3] ? r * g[1]
0245                             : (g[0] ? pow(r, g[0]) * (1 + g[4]) - g[4]
0246                                     : log(r) * g[2] + 1))
0247                 : (r < g[2] ? r / g[1]
0248                             : (g[0] ? pow((r + g[4]) / (1 + g[4]), 1 / g[0])
0249                                     : exp((r - 1) / g[2]))));
0250   }
0251 }
0252 
0253 void tiff_set(ushort *ntag, ushort tag, ushort type, int count, int val)
0254 {
0255   struct libraw_tiff_tag *tt;
0256   int c;
0257 
0258   tt = (struct libraw_tiff_tag *)(ntag + 1) + (*ntag)++;
0259   tt->tag = tag;
0260   tt->type = type;
0261   tt->count = count;
0262   if ((type < LIBRAW_EXIFTAG_TYPE_SHORT) && (count <= 4))
0263     for (c = 0; c < 4; c++)
0264       tt->val.c[c] = val >> (c << 3);
0265   else if (tagtypeIs(LIBRAW_EXIFTAG_TYPE_SHORT) && (count <= 2))
0266     for (c = 0; c < 2; c++)
0267       tt->val.s[c] = val >> (c << 4);
0268   else
0269     tt->val.i = val;
0270 }
0271 #define TOFF(ptr) ((char *)(&(ptr)) - (char *)th)
0272 
0273 void tiff_head(int width, int height, struct tiff_hdr *th)
0274 {
0275   int c;
0276   time_t timestamp = time(NULL);
0277   struct tm *t;
0278 
0279   memset(th, 0, sizeof *th);
0280   th->t_order = htonl(0x4d4d4949) >> 16;
0281   th->magic = 42;
0282   th->ifd = 10;
0283   tiff_set(&th->ntag, 254, 4, 1, 0);
0284   tiff_set(&th->ntag, 256, 4, 1, width);
0285   tiff_set(&th->ntag, 257, 4, 1, height);
0286   tiff_set(&th->ntag, 258, 3, 1, 16);
0287   for (c = 0; c < 4; c++)
0288     th->bps[c] = 16;
0289   tiff_set(&th->ntag, 259, 3, 1, 1);
0290   tiff_set(&th->ntag, 262, 3, 1, 1);
0291   tiff_set(&th->ntag, 273, 4, 1, sizeof *th);
0292   tiff_set(&th->ntag, 277, 3, 1, 1);
0293   tiff_set(&th->ntag, 278, 4, 1, height);
0294   tiff_set(&th->ntag, 279, 4, 1, height * width * 2);
0295   tiff_set(&th->ntag, 282, 5, 1, TOFF(th->rat[0]));
0296   tiff_set(&th->ntag, 283, 5, 1, TOFF(th->rat[2]));
0297   tiff_set(&th->ntag, 284, 3, 1, 1);
0298   tiff_set(&th->ntag, 296, 3, 1, 2);
0299   tiff_set(&th->ntag, 306, 2, 20, TOFF(th->date));
0300   th->rat[0] = th->rat[2] = 300;
0301   th->rat[1] = th->rat[3] = 1;
0302   t = localtime(&timestamp);
0303   if (t)
0304     sprintf(th->date, "%04d:%02d:%02d %02d:%02d:%02d", t->tm_year + 1900,
0305             t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
0306 }
0307 
0308 void write_tiff(int width, int height, unsigned short *bitmap, const char *fn)
0309 {
0310   struct tiff_hdr th;
0311 
0312   FILE *ofp = fopen(fn, "wb");
0313   if (!ofp)
0314     return;
0315   tiff_head(width, height, &th);
0316   fwrite(&th, sizeof th, 1, ofp);
0317   fwrite(bitmap, 2, width * height, ofp);
0318   fclose(ofp);
0319 }