/** * Fake a dual ISO from two bracketed shots. For research purposes. * * Input: two bracketed raw files (CR2, DNG, maybe non-Canon too) * Output: a merged DNG file */ /* * Copyright (C) 2013 a1ex * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include "../../src/raw.h" #include "optmed.h" #include "dcraw-bridge.h" #include "exiftool-bridge.h" /* here we only have a global raw_info */ #define save_dng(filename) save_dng(filename, &raw_info) #define FAIL(fmt,...) { fprintf(stderr, "Error: "); fprintf(stderr, fmt, ## __VA_ARGS__); fprintf(stderr, "\n"); exit(1); } #define CHECK(ok, fmt,...) { if (!ok) FAIL(fmt, ## __VA_ARGS__); } #define COERCE(x,lo,hi) MAX(MIN((x),(hi)),(lo)) #define COUNT(x) ((int)(sizeof(x)/sizeof((x)[0]))) #define MIN(a,b) \ ({ typeof ((a)+(b)) _a = (a); \ typeof ((a)+(b)) _b = (b); \ _a < _b ? _a : _b; }) #define MAX(a,b) \ ({ typeof ((a)+(b)) _a = (a); \ typeof ((a)+(b)) _b = (b); \ _a > _b ? _a : _b; }) #define ABS(a) \ ({ __typeof__ (a) _a = (a); \ _a > 0 ? _a : -_a; }) struct raw_info raw_info = { .api_version = 1, .bits_per_pixel = 16, .black_level = 2048, .white_level = 15000, .cfa_pattern = 0x02010100, // Red Green Green Blue .calibration_illuminant1 = 1, // Daylight }; static inline int raw_get_pixel16(int x, int y) { unsigned short * buf = raw_info.buffer; int value = buf[x + y * raw_info.width]; return value; } static inline int raw_set_pixel16(int x, int y, int value) { unsigned short * buf = raw_info.buffer; buf[x + y * raw_info.width] = value; return value; } int raw_get_pixel(int x, int y) { return raw_get_pixel16(x,y); } static int startswith(char* str, char* prefix) { char* s = str; char* p = prefix; for (; *p; s++,p++) if (*s != *p) return 0; return 1; } static void reverse_bytes_order(char* buf, int count) { unsigned short* buf16 = (unsigned short*) buf; int i; for (i = 0; i < count/2; i++) { unsigned short x = buf16[i]; buf[2*i+1] = x; buf[2*i] = x >> 8; } } static void interleave_lines(void* other_buf) { int w = raw_info.width; int h = raw_info.height; void* out_buf = raw_info.buffer; int x,y; for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { if ((y/2) % 2) continue; /* dirty switch back and forth between buffers; ugly but works */ raw_info.buffer = other_buf; int p = raw_get_pixel16(x, y); raw_info.buffer = out_buf; raw_set_pixel16(x, y, p); } } } int main(int argc, char** argv) { printf("\n"); printf("fake_dual_iso\nBuilds a fake dual ISO DNG from two bracketed shots for research purposes.\n"); printf("Usage: fake_dual_iso FOO.CR2 BAR.CR2\n"); printf("Output: out.dng\n"); printf("\n"); printf(" -- a1ex\n"); printf("\n"); if (argc != 3) return 0; void* images[2]; int k; int r; for (k = 1; k < 3; k++) { char* filename = argv[k]; printf("\nInput file : %s\n", filename); char dcraw_cmd[1000]; snprintf(dcraw_cmd, sizeof(dcraw_cmd), "dcraw -v -i -t 0 \"%s\"", filename); FILE* t = popen(dcraw_cmd, "r"); CHECK(t, "%s", filename); int raw_width = 0, raw_height = 0; int out_width = 0, out_height = 0; char line[100]; while (fgets(line, sizeof(line), t)) { if (startswith(line, "Full size: ")) { r = sscanf(line, "Full size: %d x %d\n", &raw_width, &raw_height); CHECK(r == 2, "sscanf"); } else if (startswith(line, "Output size: ")) { r = sscanf(line, "Output size: %d x %d\n", &out_width, &out_height); CHECK(r == 2, "sscanf"); } } pclose(t); printf("Full size : %d x %d\n", raw_width, raw_height); printf("Active area : %d x %d\n", out_width, out_height); int left_margin = raw_width - out_width; int top_margin = raw_height - out_height; snprintf(dcraw_cmd, sizeof(dcraw_cmd), "dcraw -4 -E -c -t 0 \"%s\"", filename); FILE* fp = popen(dcraw_cmd, "r"); CHECK(fp, "%s", filename); #ifdef _O_BINARY _setmode(_fileno(fp), _O_BINARY); #endif /* PGM read code from dcraw */ int dim[3]={0,0,0}, comment=0, number=0, error=0, nd=0, c; if (fgetc(fp) != 'P' || fgetc(fp) != '5') error = 1; while (!error && nd < 3 && (c = fgetc(fp)) != EOF) { if (c == '#') comment = 1; if (c == '\n') comment = 0; if (comment) continue; if (isdigit(c)) number = 1; if (number) { if (isdigit(c)) dim[nd] = dim[nd]*10 + c -'0'; else if (isspace(c)) { number = 0; nd++; } else error = 1; } } CHECK(!(error || nd < 3), "dcraw output is not a valid PGM file\n"); int width = dim[0]; int height = dim[1]; CHECK(width == raw_width, "pgm width"); CHECK(height == raw_height, "pgm height"); void* buf = malloc(width * (height+1) * 2); /* 1 extra line for handling GBRG easier */ int size = fread(buf, 1, width * height * 2, fp); CHECK(size == width * height * 2, "fread"); pclose(fp); /* PGM is big endian, need to reverse it */ reverse_bytes_order(buf, width * height * 2); raw_info.buffer = buf; images[k-1] = buf; /* did we read the PGM correctly? (right byte order etc) */ //~ int i; //~ for (i = 0; i < 10; i++) //~ printf("%d ", raw_get_pixel16(i, 0)); //~ printf("\n"); raw_info.black_level = 2048; raw_info.white_level = 15000; raw_info.width = width; raw_info.height = height; raw_info.pitch = width * 2; raw_info.frame_size = raw_info.height * raw_info.pitch; raw_info.active_area.x1 = left_margin; raw_info.active_area.x2 = raw_info.width; raw_info.active_area.y1 = top_margin; raw_info.active_area.y2 = raw_info.height; raw_info.jpeg.x = 0; raw_info.jpeg.y = 0; raw_info.jpeg.width = raw_info.width - left_margin; raw_info.jpeg.height = raw_info.height - top_margin; } printf("\nInterleaving lines...\n"); interleave_lines(images[0]); char* out_filename = "out.dng"; reverse_bytes_order(raw_info.buffer, raw_info.frame_size); printf("Output file : %s\n", out_filename); save_dng(out_filename); free(images[0]); free(images[1]); //~ copy_tags_from_source(filename, out_filename); return 0; }