1 /* -*- C++ -*-
2  * File: unprocessed_raw.cpp
3  * Copyright 2009-2021 LibRaw LLC (info@libraw.org)
4  * Created: Fri Jan 02, 2009
5  *
6  * LibRaw sample
7  * Generates unprocessed raw image: with masked pixels and without black
8 subtraction
9  *
10 
11 LibRaw is free software; you can redistribute it and/or modify
12 it under the terms of the one of two licenses as you choose:
13 
14 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1
15    (See file LICENSE.LGPL provided in LibRaw distribution archive for details).
16 
17 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
18    (See file LICENSE.CDDL provided in LibRaw distribution archive for details).
19 
20  */
21 #include <stdio.h>
22 #include <string.h>
23 #include <math.h>
24 #include <time.h>
25 
26 #include "libraw/libraw.h"
27 
28 #ifndef LIBRAW_WIN32_CALLS
29 #include <netinet/in.h>
30 #else
31 #include <sys/utime.h>
32 #include <winsock2.h>
33 #endif
34 
35 #ifdef LIBRAW_WIN32_CALLS
36 #define snprintf _snprintf
37 #endif
38 
39 #if !(LIBRAW_COMPILE_CHECK_VERSION_NOTLESS(0, 14))
40 #error This code is for LibRaw 0.14+ only
41 #endif
42 
43 void gamma_curve(unsigned short curve[]);
44 void write_ppm(unsigned width, unsigned height, unsigned short *bitmap,
45                const char *basename);
46 void write_tiff(int width, int height, unsigned short *bitmap,
47                 const char *basename);
48 
main(int ac,char * av[])49 int main(int ac, char *av[])
50 {
51   int i, ret;
52   int verbose = 1, autoscale = 0, use_gamma = 0, out_tiff = 0;
53   char outfn[1024];
54 
55   LibRaw RawProcessor;
56   if (ac < 2)
57   {
58   usage:
59     printf("unprocessed_raw - LibRaw %s sample. %d cameras supported\n"
60            "Usage: %s [-q] [-A] [-g] [-s N] raw-files....\n"
61            "\t-q - be quiet\n"
62            "\t-s N - select Nth image in file (default=0)\n"
63            "\t-g - use gamma correction with gamma 2.2 (not precise,use for "
64            "visual inspection only)\n"
65            "\t-A - autoscaling (by integer factor)\n"
66            "\t-T - write tiff instead of pgm\n",
67            LibRaw::version(), LibRaw::cameraCount(), av[0]);
68     return 0;
69   }
70 
71 #define S RawProcessor.imgdata.sizes
72 #define OUT RawProcessor.imgdata.params
73 #define OUTR RawProcessor.imgdata.rawparams
74 
75   for (i = 1; i < ac; i++)
76   {
77     if (av[i][0] == '-')
78     {
79       if (av[i][1] == 'q' && av[i][2] == 0)
80         verbose = 0;
81       else if (av[i][1] == 'A' && av[i][2] == 0)
82         autoscale = 1;
83       else if (av[i][1] == 'g' && av[i][2] == 0)
84         use_gamma = 1;
85       else if (av[i][1] == 'T' && av[i][2] == 0)
86         out_tiff = 1;
87       else if (av[i][1] == 's' && av[i][2] == 0)
88       {
89         i++;
90         OUTR.shot_select = av[i] ? atoi(av[i]) : 0;
91       }
92       else
93         goto usage;
94       continue;
95     }
96 
97     if (verbose)
98       printf("Processing file %s\n", av[i]);
99     if ((ret = RawProcessor.open_file(av[i])) != LIBRAW_SUCCESS)
100     {
101       fprintf(stderr, "Cannot open %s: %s\n", av[i], libraw_strerror(ret));
102       continue; // no recycle b/c open file will recycle itself
103     }
104     if (verbose)
105     {
106       printf("Image size: %dx%d\nRaw size: %dx%d\n", S.width, S.height,
107              S.raw_width, S.raw_height);
108       printf("Margins: top=%d, left=%d\n", S.top_margin, S.left_margin);
109     }
110 
111     if ((ret = RawProcessor.unpack()) != LIBRAW_SUCCESS)
112     {
113       fprintf(stderr, "Cannot unpack %s: %s\n", av[i], libraw_strerror(ret));
114       continue;
115     }
116 
117     if (verbose)
118       printf("Unpacked....\n");
119 
120     if (!(RawProcessor.imgdata.idata.filters ||
121           RawProcessor.imgdata.idata.colors == 1))
122     {
123       printf("Only Bayer-pattern RAW files supported, sorry....\n");
124       continue;
125     }
126 
127     if (autoscale)
128     {
129       unsigned max = 0, scale;
130       for (int j = 0; j < S.raw_height * S.raw_width; j++)
131         if (max < RawProcessor.imgdata.rawdata.raw_image[j])
132           max = RawProcessor.imgdata.rawdata.raw_image[j];
133       if (max > 0 && max < 1 << 15)
134       {
135         scale = (1 << 16) / max;
136         if (verbose)
137           printf("Scaling with multiplier=%d (max=%d)\n", scale, max);
138 
139         for (int j = 0; j < S.raw_height * S.raw_width; j++)
140           RawProcessor.imgdata.rawdata.raw_image[j] *= scale;
141       }
142     }
143     if (use_gamma)
144     {
145       unsigned short curve[0x10000];
146       gamma_curve(curve);
147       for (int j = 0; j < S.raw_height * S.raw_width; j++)
148         RawProcessor.imgdata.rawdata.raw_image[j] =
149             curve[RawProcessor.imgdata.rawdata.raw_image[j]];
150       if (verbose)
151         printf("Gamma-corrected....\n");
152     }
153 
154     if (OUTR.shot_select)
155       snprintf(outfn, sizeof(outfn), "%s-%d.%s", av[i], OUTR.shot_select,
156                out_tiff ? "tiff" : "pgm");
157     else
158       snprintf(outfn, sizeof(outfn), "%s.%s", av[i], out_tiff ? "tiff" : "pgm");
159 
160     if (out_tiff)
161       write_tiff(S.raw_width, S.raw_height,
162                  RawProcessor.imgdata.rawdata.raw_image, outfn);
163     else
164       write_ppm(S.raw_width, S.raw_height,
165                 RawProcessor.imgdata.rawdata.raw_image, outfn);
166 
167     if (verbose)
168       printf("Stored to file %s\n", outfn);
169   }
170   return 0;
171 }
172 
write_ppm(unsigned width,unsigned height,unsigned short * bitmap,const char * fname)173 void write_ppm(unsigned width, unsigned height, unsigned short *bitmap,
174                const char *fname)
175 {
176   if (!bitmap)
177     return;
178 
179   FILE *f = fopen(fname, "wb");
180   if (!f)
181     return;
182   int bits = 16;
183   fprintf(f, "P5\n%d %d\n%d\n", width, height, (1 << bits) - 1);
184   unsigned char *data = (unsigned char *)bitmap;
185   unsigned data_size = width * height * 2;
186 #define SWAP(a, b)                                                             \
187   {                                                                            \
188     a ^= b;                                                                    \
189     a ^= (b ^= a);                                                             \
190   }
191   for (unsigned i = 0; i < data_size; i += 2)
192     SWAP(data[i], data[i + 1]);
193 #undef SWAP
194   fwrite(data, data_size, 1, f);
195   fclose(f);
196 }
197 
198 /*  == gamma curve and tiff writer - simplified cut'n'paste from dcraw.c */
199 
200 #define SQR(x) ((x) * (x))
201 
gamma_curve(unsigned short * curve)202 void gamma_curve(unsigned short *curve)
203 {
204 
205   double pwr = 1.0 / 2.2;
206   double ts = 0.0;
207   int imax = 0xffff;
208   int mode = 2;
209   int i;
210   double g[6], bnd[2] = {0, 0}, r;
211 
212   g[0] = pwr;
213   g[1] = ts;
214   g[2] = g[3] = g[4] = 0;
215   bnd[g[1] >= 1] = 1;
216   if (g[1] && (g[1] - 1) * (g[0] - 1) <= 0)
217   {
218     for (i = 0; i < 48; i++)
219     {
220       g[2] = (bnd[0] + bnd[1]) / 2;
221       if (g[0])
222         bnd[(pow(g[2] / g[1], -g[0]) - 1) / g[0] - 1 / g[2] > -1] = g[2];
223       else
224         bnd[g[2] / exp(1 - 1 / g[2]) < g[1]] = g[2];
225     }
226     g[3] = g[2] / g[1];
227     if (g[0])
228       g[4] = g[2] * (1 / g[0] - 1);
229   }
230   if (g[0])
231     g[5] = 1 / (g[1] * SQR(g[3]) / 2 - g[4] * (1 - g[3]) +
232                 (1 - pow(g[3], 1 + g[0])) * (1 + g[4]) / (1 + g[0])) -
233            1;
234   else
235     g[5] = 1 / (g[1] * SQR(g[3]) / 2 + 1 - g[2] - g[3] -
236                 g[2] * g[3] * (log(g[3]) - 1)) -
237            1;
238   for (i = 0; i < 0x10000; i++)
239   {
240     curve[i] = 0xffff;
241     if ((r = (double)i / imax) < 1)
242       curve[i] =
243           0x10000 *
244           (mode ? (r < g[3] ? r * g[1]
245                             : (g[0] ? pow(r, g[0]) * (1 + g[4]) - g[4]
246                                     : log(r) * g[2] + 1))
247                 : (r < g[2] ? r / g[1]
248                             : (g[0] ? pow((r + g[4]) / (1 + g[4]), 1 / g[0])
249                                     : exp((r - 1) / g[2]))));
250   }
251 }
252 
tiff_set(ushort * ntag,ushort tag,ushort type,int count,int val)253 void tiff_set(ushort *ntag, ushort tag, ushort type, int count, int val)
254 {
255   struct libraw_tiff_tag *tt;
256   int c;
257 
258   tt = (struct libraw_tiff_tag *)(ntag + 1) + (*ntag)++;
259   tt->tag = tag;
260   tt->type = type;
261   tt->count = count;
262   if ((type < LIBRAW_EXIFTAG_TYPE_SHORT) && (count <= 4))
263     for (c = 0; c < 4; c++)
264       tt->val.c[c] = val >> (c << 3);
265   else if (tagtypeIs(LIBRAW_EXIFTAG_TYPE_SHORT) && (count <= 2))
266     for (c = 0; c < 2; c++)
267       tt->val.s[c] = val >> (c << 4);
268   else
269     tt->val.i = val;
270 }
271 #define TOFF(ptr) ((char *)(&(ptr)) - (char *)th)
272 
tiff_head(int width,int height,struct tiff_hdr * th)273 void tiff_head(int width, int height, struct tiff_hdr *th)
274 {
275   int c;
276   time_t timestamp = time(NULL);
277   struct tm *t;
278 
279   memset(th, 0, sizeof *th);
280   th->t_order = htonl(0x4d4d4949) >> 16;
281   th->magic = 42;
282   th->ifd = 10;
283   tiff_set(&th->ntag, 254, 4, 1, 0);
284   tiff_set(&th->ntag, 256, 4, 1, width);
285   tiff_set(&th->ntag, 257, 4, 1, height);
286   tiff_set(&th->ntag, 258, 3, 1, 16);
287   for (c = 0; c < 4; c++)
288     th->bps[c] = 16;
289   tiff_set(&th->ntag, 259, 3, 1, 1);
290   tiff_set(&th->ntag, 262, 3, 1, 1);
291   tiff_set(&th->ntag, 273, 4, 1, sizeof *th);
292   tiff_set(&th->ntag, 277, 3, 1, 1);
293   tiff_set(&th->ntag, 278, 4, 1, height);
294   tiff_set(&th->ntag, 279, 4, 1, height * width * 2);
295   tiff_set(&th->ntag, 282, 5, 1, TOFF(th->rat[0]));
296   tiff_set(&th->ntag, 283, 5, 1, TOFF(th->rat[2]));
297   tiff_set(&th->ntag, 284, 3, 1, 1);
298   tiff_set(&th->ntag, 296, 3, 1, 2);
299   tiff_set(&th->ntag, 306, 2, 20, TOFF(th->date));
300   th->rat[0] = th->rat[2] = 300;
301   th->rat[1] = th->rat[3] = 1;
302   t = localtime(&timestamp);
303   if (t)
304     sprintf(th->date, "%04d:%02d:%02d %02d:%02d:%02d", t->tm_year + 1900,
305             t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
306 }
307 
write_tiff(int width,int height,unsigned short * bitmap,const char * fn)308 void write_tiff(int width, int height, unsigned short *bitmap, const char *fn)
309 {
310   struct tiff_hdr th;
311 
312   FILE *ofp = fopen(fn, "wb");
313   if (!ofp)
314     return;
315   tiff_head(width, height, &th);
316   fwrite(&th, sizeof th, 1, ofp);
317   fwrite(bitmap, 2, width * height, ofp);
318   fclose(ofp);
319 }
320