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