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(×tamp);
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