671 lines
19 KiB
C++
671 lines
19 KiB
C++
/* -*- C++ -*-
|
|
* File: dcraw_emu.cpp
|
|
* Copyright 2008-2024 LibRaw LLC (info@libraw.org)
|
|
* Created: Sun Mar 23, 2008
|
|
*
|
|
* LibRaw simple C++ API sample: almost complete dcraw emulator
|
|
*
|
|
|
|
LibRaw is free software; you can redistribute it and/or modify
|
|
it under the terms of the one of two licenses as you choose:
|
|
|
|
1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1
|
|
(See file LICENSE.LGPL provided in LibRaw distribution archive for details).
|
|
|
|
2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
|
|
(See file LICENSE.CDDL provided in LibRaw distribution archive for details).
|
|
|
|
|
|
*/
|
|
#ifdef _MSC_VER
|
|
// suppress sprintf-related warning. sprintf() is permitted in sample code
|
|
#define _CRT_SECURE_NO_WARNINGS
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#include <ctype.h>
|
|
|
|
#include "libraw/libraw.h"
|
|
|
|
#ifndef LIBRAW_WIN32_CALLS
|
|
#include <sys/mman.h>
|
|
#include <sys/time.h>
|
|
#include <unistd.h>
|
|
#else
|
|
#include <io.h>
|
|
#endif
|
|
#include <fcntl.h>
|
|
#include <sys/stat.h>
|
|
|
|
#ifdef LIBRAW_WIN32_CALLS
|
|
#define snprintf _snprintf
|
|
#include <windows.h>
|
|
#else
|
|
#define O_BINARY 0
|
|
#endif
|
|
|
|
#ifdef USE_DNGSDK
|
|
#include "dng_host.h"
|
|
#include "dng_negative.h"
|
|
#include "dng_simple_image.h"
|
|
#include "dng_info.h"
|
|
#endif
|
|
|
|
void usage(const char *prog)
|
|
{
|
|
printf("dcraw_emu: almost complete dcraw emulator\n");
|
|
printf("Usage: %s [OPTION]... [FILE]...\n", prog);
|
|
printf("-c float-num Set adjust maximum threshold (default 0.75)\n"
|
|
"-v Verbose: print progress messages (repeated -v will add "
|
|
"verbosity)\n"
|
|
"-w Use camera white balance, if possible\n"
|
|
"-a Average the whole image for white balance\n"
|
|
"-A <x y w h> Average a grey box for white balance\n"
|
|
"-r <r g b g> Set custom white balance\n"
|
|
"+M/-M Use/don't use an embedded color matrix\n"
|
|
"-C <r b> Correct chromatic aberration\n"
|
|
"-P <file> Fix the dead pixels listed in this file\n"
|
|
"-K <file> Subtract dark frame (16-bit raw PGM)\n"
|
|
"-k <num> Set the darkness level\n"
|
|
"-S <num> Set the saturation level\n"
|
|
"-R <num> Set raw processing options to num\n"
|
|
"-n <num> Set threshold for wavelet denoising\n"
|
|
"-H [0-9] Highlight mode (0=clip, 1=unclip, 2=blend, 3+=rebuild)\n"
|
|
"-t [0-7] Flip image (0=none, 3=180, 5=90CCW, 6=90CW)\n"
|
|
"-o [0-8] Output colorspace (raw,sRGB,Adobe,Wide,ProPhoto,XYZ,ACES,\n"
|
|
" DCI-P3,Rec2020)\n"
|
|
#ifndef NO_LCMS
|
|
"-o file Output ICC profile\n"
|
|
"-p file Camera input profile (use \'embed\' for embedded profile)\n"
|
|
#endif
|
|
"-j Don't stretch or rotate raw pixels\n"
|
|
"-W Don't automatically brighten the image\n"
|
|
"-b <num> Adjust brightness (default = 1.0)\n"
|
|
"-q N Set the interpolation quality:\n"
|
|
" 0 - linear, 1 - VNG, 2 - PPG, 3 - AHD, 4 - DCB\n"
|
|
" 11 - DHT, 12 - AAHD\n"
|
|
"-h Half-size color image (twice as fast as \"-q 0\")\n"
|
|
"-f Interpolate RGGB as four colors\n"
|
|
"-m <num> Apply a 3x3 median filter to R-G and B-G\n"
|
|
"-s [0..N-1] Select one raw image from input file\n"
|
|
"-4 Linear 16-bit, same as \"-6 -W -g 1 1\n"
|
|
"-6 Write 16-bit output\n"
|
|
"-g pow ts Set gamma curve to gamma pow and toe slope ts (default = "
|
|
"2.222 4.5)\n"
|
|
"-T Write TIFF instead of PPM\n"
|
|
"-G Use green_matching() filter\n"
|
|
"-B <x y w h> use cropbox\n"
|
|
"-F Use FILE I/O instead of streambuf API\n"
|
|
"-Z <suf> Output filename generation rules\n"
|
|
" .suf => append .suf to input name, keeping existing suffix "
|
|
"too\n"
|
|
" suf => replace input filename last extension\n"
|
|
" - => output to stdout\n"
|
|
" filename.suf => output to filename.suf\n"
|
|
"-timing Detailed timing report\n"
|
|
"-fbdd N 0 - disable FBDD noise reduction (default), 1 - light "
|
|
"FBDD, 2 - full\n"
|
|
"-dcbi N Number of extra DCD iterations (default - 0)\n"
|
|
"-dcbe DCB color enhance\n"
|
|
"-aexpo <e p> exposure correction\n"
|
|
"-apentax4shot enables merge of 4-shot pentax files\n"
|
|
"-apentax4shotorder 3102 sets pentax 4-shot alignment order\n"
|
|
#ifdef USE_RAWSPEED_BITS
|
|
"-arsbits V Set use_rawspeed to V\n"
|
|
#endif
|
|
"-mmap Use memory mmaped buffer instead of plain FILE I/O\n"
|
|
"-mem Use memory buffer instead of FILE I/O\n"
|
|
"-disars Do not use RawSpeed library\n"
|
|
"-disinterp Do not run interpolation step\n"
|
|
"-dsrawrgb1 Disable YCbCr to RGB conversion for sRAW (Cb/Cr "
|
|
"interpolation enabled)\n"
|
|
"-dsrawrgb2 Disable YCbCr to RGB conversion for sRAW (Cb/Cr "
|
|
"interpolation disabled)\n"
|
|
#ifdef USE_DNGSDK
|
|
"-dngsdk Use Adobe DNG SDK for DNG decode\n"
|
|
"-dngflags N set DNG decoding options to value N\n"
|
|
#endif
|
|
"-doutputflags N set params.output_flags to N\n"
|
|
);
|
|
exit(1);
|
|
}
|
|
|
|
static int verbosity = 0;
|
|
int cnt = 0;
|
|
int my_progress_callback(void *d, enum LibRaw_progress p, int iteration,
|
|
int expected)
|
|
{
|
|
char *passed = (char *)(d ? d : "default string"); // data passed to callback
|
|
// at set_callback stage
|
|
|
|
if (verbosity > 2) // verbosity set by repeat -v switches
|
|
{
|
|
printf("CB: %s pass %d of %d (data passed=%s)\n", libraw_strprogress(p),
|
|
iteration, expected, passed);
|
|
}
|
|
else if (iteration == 0) // 1st iteration of each step
|
|
printf("Starting %s (expecting %d iterations)\n", libraw_strprogress(p),
|
|
expected);
|
|
else if (iteration == expected - 1)
|
|
printf("%s finished\n", libraw_strprogress(p));
|
|
|
|
/// if(++cnt>10) return 1; // emulate user termination on 10-th callback
|
|
/// call
|
|
|
|
return 0; // always return 0 to continue processing
|
|
}
|
|
|
|
// timer
|
|
#ifndef LIBRAW_WIN32_CALLS
|
|
static struct timeval start, end;
|
|
void timerstart(void) { gettimeofday(&start, NULL); }
|
|
void timerprint(const char *msg, const char *filename)
|
|
{
|
|
gettimeofday(&end, NULL);
|
|
float msec = (end.tv_sec - start.tv_sec) * 1000.0f +
|
|
(end.tv_usec - start.tv_usec) / 1000.0f;
|
|
printf("Timing: %s/%s: %6.3f msec\n", filename, msg, msec);
|
|
}
|
|
#else
|
|
LARGE_INTEGER start;
|
|
void timerstart(void) { QueryPerformanceCounter(&start); }
|
|
void timerprint(const char *msg, const char *filename)
|
|
{
|
|
LARGE_INTEGER unit, end;
|
|
QueryPerformanceCounter(&end);
|
|
QueryPerformanceFrequency(&unit);
|
|
float msec = (float)(end.QuadPart - start.QuadPart);
|
|
msec /= (float)unit.QuadPart / 1000.0f;
|
|
printf("Timing: %s/%s: %6.3f msec\n", filename, msg, msec);
|
|
}
|
|
|
|
#endif
|
|
|
|
struct file_mapping
|
|
{
|
|
void *map;
|
|
INT64 fsize;
|
|
#ifdef LIBRAW_WIN32_CALLS
|
|
HANDLE fd, fd_map;
|
|
file_mapping() : map(0), fsize(0), fd(INVALID_HANDLE_VALUE), fd_map(INVALID_HANDLE_VALUE){}
|
|
#else
|
|
int fd;
|
|
file_mapping() : map(0), fsize(0), fd(-1){}
|
|
#endif
|
|
};
|
|
|
|
void create_mapping(struct file_mapping& data, const std::string& fn)
|
|
{
|
|
#ifdef LIBRAW_WIN32_CALLS
|
|
std::wstring fpath(fn.begin(), fn.end());
|
|
if ((data.fd = CreateFileW(fpath.c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)) == INVALID_HANDLE_VALUE) return;
|
|
LARGE_INTEGER fs;
|
|
if (!GetFileSizeEx(data.fd, &fs)) return;
|
|
data.fsize = fs.QuadPart;
|
|
if ((data.fd_map = ::CreateFileMapping(data.fd, 0, PAGE_READONLY, fs.HighPart, fs.LowPart, 0)) == INVALID_HANDLE_VALUE) return;
|
|
data.map = MapViewOfFile(data.fd_map, FILE_MAP_READ, 0, 0, data.fsize);
|
|
#else
|
|
struct stat stt;
|
|
if ((data.fd = open(fn.c_str(), O_RDONLY)) < 0) return;
|
|
if (fstat(data.fd, &stt) != 0) return;
|
|
data.fsize = stt.st_size;
|
|
data.map = mmap(0, data.fsize, PROT_READ | PROT_WRITE, MAP_PRIVATE, data.fd, 0);
|
|
return;
|
|
#endif
|
|
}
|
|
|
|
void close_mapping(struct file_mapping& data)
|
|
{
|
|
#ifdef LIBRAW_WIN32_CALLS
|
|
if (data.map) UnmapViewOfFile(data.map);
|
|
if (data.fd_map != INVALID_HANDLE_VALUE) CloseHandle(data.fd_map);
|
|
if (data.fd != INVALID_HANDLE_VALUE) CloseHandle(data.fd);
|
|
data.map = 0;
|
|
data.fsize = 0;
|
|
data.fd = data.fd_map = INVALID_HANDLE_VALUE;
|
|
#else
|
|
if (data.map)
|
|
munmap(data.map, data.fsize);
|
|
if (data.fd >= 0)
|
|
close(data.fd);
|
|
data.map = 0;
|
|
data.fsize = 0;
|
|
data.fd = -1;
|
|
#endif
|
|
}
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
if (argc == 1)
|
|
usage(argv[0]);
|
|
|
|
LibRaw RawProcessor;
|
|
int i, arg, c, ret;
|
|
char opm, opt, *cp, *sp;
|
|
int use_timing = 0, use_mem = 0, use_mmap = 0;
|
|
char *outext = NULL;
|
|
#ifdef USE_DNGSDK
|
|
dng_host *dnghost = NULL;
|
|
#endif
|
|
struct file_mapping mapping;
|
|
void *iobuffer = 0;
|
|
#ifdef OUT
|
|
#undef OUT
|
|
#endif
|
|
#define OUT RawProcessor.imgdata.params
|
|
#define OUTR RawProcessor.imgdata.rawparams
|
|
|
|
argv[argc] = (char *)"";
|
|
for (arg = 1; (((opm = argv[arg][0]) - 2) | 2) == '+';)
|
|
{
|
|
char *optstr = argv[arg];
|
|
opt = argv[arg++][1];
|
|
if ((cp = strchr(sp = (char *)"cnbrkStqmHABCgU", opt)) != 0)
|
|
for (i = 0; i < "111411111144221"[cp - sp] - '0'; i++)
|
|
if (!isdigit(argv[arg + i][0]) && !optstr[2])
|
|
{
|
|
fprintf(stderr, "Non-numeric argument to \"-%c\"\n", opt);
|
|
return 1;
|
|
}
|
|
if (!strchr("ftdeam", opt) && argv[arg - 1][2]) {
|
|
fprintf(stderr, "Unknown option \"%s\".\n", argv[arg - 1]);
|
|
continue;
|
|
}
|
|
switch (opt)
|
|
{
|
|
case 'v':
|
|
verbosity++;
|
|
break;
|
|
case 'G':
|
|
OUT.green_matching = 1;
|
|
break;
|
|
case 'c':
|
|
OUT.adjust_maximum_thr = (float)atof(argv[arg++]);
|
|
break;
|
|
case 'U':
|
|
OUT.auto_bright_thr = (float)atof(argv[arg++]);
|
|
break;
|
|
case 'n':
|
|
OUT.threshold = (float)atof(argv[arg++]);
|
|
break;
|
|
case 'b':
|
|
OUT.bright = (float)atof(argv[arg++]);
|
|
break;
|
|
case 'P':
|
|
OUT.bad_pixels = argv[arg++];
|
|
break;
|
|
case 'K':
|
|
OUT.dark_frame = argv[arg++];
|
|
break;
|
|
case 'r':
|
|
for (c = 0; c < 4; c++)
|
|
OUT.user_mul[c] = (float)atof(argv[arg++]);
|
|
break;
|
|
case 'C':
|
|
OUT.aber[0] = 1 / atof(argv[arg++]);
|
|
OUT.aber[2] = 1 / atof(argv[arg++]);
|
|
break;
|
|
case 'g':
|
|
OUT.gamm[0] = 1 / atof(argv[arg++]);
|
|
OUT.gamm[1] = atof(argv[arg++]);
|
|
break;
|
|
case 'k':
|
|
OUT.user_black = atoi(argv[arg++]);
|
|
break;
|
|
case 'S':
|
|
OUT.user_sat = atoi(argv[arg++]);
|
|
break;
|
|
case 'R':
|
|
OUTR.options = atoi(argv[arg++]);
|
|
break;
|
|
case 't':
|
|
if (!strcmp(optstr, "-timing"))
|
|
use_timing = 1;
|
|
else if (!argv[arg - 1][2])
|
|
OUT.user_flip = atoi(argv[arg++]);
|
|
else
|
|
fprintf(stderr, "Unknown option \"%s\".\n", argv[arg - 1]);
|
|
break;
|
|
case 'q':
|
|
OUT.user_qual = atoi(argv[arg++]);
|
|
break;
|
|
case 'm':
|
|
if (!strcmp(optstr, "-mmap"))
|
|
use_mmap = 1;
|
|
else
|
|
if (!strcmp(optstr, "-mem"))
|
|
use_mem = 1;
|
|
else
|
|
{
|
|
if (!argv[arg - 1][2])
|
|
OUT.med_passes = atoi(argv[arg++]);
|
|
else
|
|
fprintf(stderr, "Unknown option \"%s\".\n", argv[arg - 1]);
|
|
}
|
|
break;
|
|
case 'H':
|
|
OUT.highlight = atoi(argv[arg++]);
|
|
break;
|
|
case 's':
|
|
OUTR.shot_select = abs(atoi(argv[arg++]));
|
|
break;
|
|
case 'o':
|
|
if (isdigit(argv[arg][0]) && !isdigit(argv[arg][1]))
|
|
OUT.output_color = atoi(argv[arg++]);
|
|
#ifndef NO_LCMS
|
|
else
|
|
OUT.output_profile = argv[arg++];
|
|
break;
|
|
case 'p':
|
|
OUT.camera_profile = argv[arg++];
|
|
#endif
|
|
break;
|
|
case 'h':
|
|
OUT.half_size = 1;
|
|
break;
|
|
case 'f':
|
|
if (!strcmp(optstr, "-fbdd"))
|
|
OUT.fbdd_noiserd = atoi(argv[arg++]);
|
|
else
|
|
{
|
|
if (!argv[arg - 1][2])
|
|
OUT.four_color_rgb = 1;
|
|
else
|
|
fprintf(stderr, "Unknown option \"%s\".\n", argv[arg - 1]);
|
|
}
|
|
break;
|
|
case 'A':
|
|
for (c = 0; c < 4; c++)
|
|
OUT.greybox[c] = atoi(argv[arg++]);
|
|
break;
|
|
case 'B':
|
|
for (c = 0; c < 4; c++)
|
|
OUT.cropbox[c] = atoi(argv[arg++]);
|
|
break;
|
|
case 'a':
|
|
if (!strcmp(optstr, "-aexpo"))
|
|
{
|
|
OUT.exp_correc = 1;
|
|
OUT.exp_shift = (float)atof(argv[arg++]);
|
|
OUT.exp_preser = (float)atof(argv[arg++]);
|
|
}
|
|
#ifdef USE_RAWSPEED_BITS
|
|
else if (!strcmp(optstr, "-arsbits"))
|
|
{
|
|
OUTR.use_rawspeed = atoi(argv[arg++]);
|
|
}
|
|
#endif
|
|
else if (!strcmp(optstr, "-apentax4shot"))
|
|
{
|
|
OUTR.options |= LIBRAW_RAWOPTIONS_PENTAX_PS_ALLFRAMES;
|
|
}
|
|
else if (!strcmp(optstr, "-apentax4shotorder"))
|
|
{
|
|
strncpy(OUTR.p4shot_order, argv[arg++], 5);
|
|
}
|
|
else if (!argv[arg - 1][2])
|
|
OUT.use_auto_wb = 1;
|
|
else
|
|
fprintf(stderr, "Unknown option \"%s\".\n", argv[arg - 1]);
|
|
break;
|
|
case 'w':
|
|
OUT.use_camera_wb = 1;
|
|
break;
|
|
case 'M':
|
|
OUT.use_camera_matrix = (opm == '+')?3:0;
|
|
break;
|
|
case 'j':
|
|
OUT.use_fuji_rotate = 0;
|
|
break;
|
|
case 'W':
|
|
OUT.no_auto_bright = 1;
|
|
break;
|
|
case 'T':
|
|
OUT.output_tiff = 1;
|
|
break;
|
|
case '4':
|
|
OUT.gamm[0] = OUT.gamm[1] = OUT.no_auto_bright = 1; /* no break here! */
|
|
case '6':
|
|
OUT.output_bps = 16;
|
|
break;
|
|
case 'Z':
|
|
outext = strdup(argv[arg++]);
|
|
break;
|
|
case 'd':
|
|
if (!strcmp(optstr, "-dcbi"))
|
|
OUT.dcb_iterations = atoi(argv[arg++]);
|
|
else if (!strcmp(optstr, "-doutputflags"))
|
|
OUT.output_flags = atoi(argv[arg++]);
|
|
else if (!strcmp(optstr, "-disars"))
|
|
OUTR.use_rawspeed = 0;
|
|
else if (!strcmp(optstr, "-disinterp"))
|
|
OUT.no_interpolation = 1;
|
|
else if (!strcmp(optstr, "-dcbe"))
|
|
OUT.dcb_enhance_fl = 1;
|
|
else if (!strcmp(optstr, "-dsrawrgb1"))
|
|
{
|
|
OUTR.specials |= LIBRAW_RAWSPECIAL_SRAW_NO_RGB;
|
|
OUTR.specials &= ~LIBRAW_RAWSPECIAL_SRAW_NO_INTERPOLATE;
|
|
}
|
|
else if (!strcmp(optstr, "-dsrawrgb2"))
|
|
{
|
|
OUTR.specials &= ~LIBRAW_RAWSPECIAL_SRAW_NO_RGB;
|
|
OUTR.specials |= LIBRAW_RAWSPECIAL_SRAW_NO_INTERPOLATE;
|
|
}
|
|
#ifdef USE_DNGSDK
|
|
else if (!strcmp(optstr, "-dngsdk"))
|
|
{
|
|
dnghost = new dng_host;
|
|
RawProcessor.set_dng_host(dnghost);
|
|
}
|
|
else if (!strcmp(optstr, "-dngflags"))
|
|
{
|
|
OUTR.use_dngsdk = atoi(argv[arg++]);
|
|
}
|
|
#endif
|
|
else
|
|
fprintf(stderr, "Unknown option \"%s\".\n", argv[arg - 1]);
|
|
break;
|
|
default:
|
|
fprintf(stderr, "Unknown option \"-%c\".\n", opt);
|
|
break;
|
|
}
|
|
}
|
|
#ifndef LIBRAW_WIN32_CALLS
|
|
putenv((char *)"TZ=UTC"); // dcraw compatibility, affects TIFF datestamp field
|
|
#else
|
|
_putenv(
|
|
(char *)"TZ=UTC"); // dcraw compatibility, affects TIFF datestamp field
|
|
#endif
|
|
#define P1 RawProcessor.imgdata.idata
|
|
#define S RawProcessor.imgdata.sizes
|
|
#define C RawProcessor.imgdata.color
|
|
#define T RawProcessor.imgdata.thumbnail
|
|
#define P2 RawProcessor.imgdata.other
|
|
|
|
if (outext && !strcmp(outext, "-"))
|
|
use_timing = verbosity = 0;
|
|
|
|
if (verbosity > 1)
|
|
RawProcessor.set_progress_handler(my_progress_callback,
|
|
(void *)"Sample data passed");
|
|
#ifdef LIBRAW_USE_OPENMP
|
|
if (verbosity)
|
|
printf("Using %d threads\n", omp_get_max_threads());
|
|
#endif
|
|
|
|
int done = 0;
|
|
int total = argc - arg;
|
|
for (; arg < argc; arg++)
|
|
{
|
|
char outfn[1024];
|
|
|
|
if (verbosity)
|
|
printf("Processing file %s\n", argv[arg]);
|
|
|
|
timerstart();
|
|
|
|
if (use_mmap)
|
|
{
|
|
create_mapping(mapping, argv[arg]);
|
|
if (!mapping.map)
|
|
{
|
|
fprintf(stderr, "Cannot map %s\n", argv[arg]);
|
|
close_mapping(mapping);
|
|
continue;
|
|
}
|
|
if ((ret = RawProcessor.open_buffer(mapping.map,mapping.fsize) !=
|
|
LIBRAW_SUCCESS))
|
|
{
|
|
fprintf(stderr, "Cannot open_buffer %s: %s\n", argv[arg], libraw_strerror(ret));
|
|
close_mapping(mapping);
|
|
continue; // no recycle b/c open file will recycle itself
|
|
}
|
|
}
|
|
else if (use_mem)
|
|
{
|
|
int file = open(argv[arg], O_RDONLY | O_BINARY);
|
|
struct stat st;
|
|
if (file < 0)
|
|
{
|
|
fprintf(stderr, "Cannot open %s: %s\n", argv[arg], strerror(errno));
|
|
continue;
|
|
}
|
|
if (fstat(file, &st))
|
|
{
|
|
fprintf(stderr, "Cannot stat %s: %s\n", argv[arg], strerror(errno));
|
|
close(file);
|
|
continue;
|
|
}
|
|
if (!(iobuffer = malloc(st.st_size)))
|
|
{
|
|
fprintf(stderr, "Cannot allocate %d kbytes for memory buffer\n",
|
|
(int)(st.st_size / 1024));
|
|
close(file);
|
|
continue;
|
|
}
|
|
int rd;
|
|
if (st.st_size != (rd = read(file, iobuffer, st.st_size)))
|
|
{
|
|
fprintf(stderr,
|
|
"Cannot read %d bytes instead of %d to memory buffer\n",
|
|
(int)rd, (int)st.st_size);
|
|
close(file);
|
|
free(iobuffer);
|
|
continue;
|
|
}
|
|
close(file);
|
|
if ((ret = RawProcessor.open_buffer(iobuffer, st.st_size)) !=
|
|
LIBRAW_SUCCESS)
|
|
{
|
|
fprintf(stderr, "Cannot open_buffer %s: %s\n", argv[arg],
|
|
libraw_strerror(ret));
|
|
free(iobuffer);
|
|
continue; // no recycle b/c open file will recycle itself
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ret = RawProcessor.open_file(argv[arg]);
|
|
|
|
if (ret != LIBRAW_SUCCESS)
|
|
{
|
|
fprintf(stderr, "Cannot open %s: %s\n", argv[arg],
|
|
libraw_strerror(ret));
|
|
continue; // no recycle b/c open_file will recycle itself
|
|
}
|
|
}
|
|
|
|
if (use_timing)
|
|
timerprint("LibRaw::open_file()", argv[arg]);
|
|
|
|
timerstart();
|
|
if ((ret = RawProcessor.unpack()) != LIBRAW_SUCCESS)
|
|
{
|
|
fprintf(stderr, "Cannot unpack %s: %s\n", argv[arg],
|
|
libraw_strerror(ret));
|
|
continue;
|
|
}
|
|
|
|
if (use_timing)
|
|
timerprint("LibRaw::unpack()", argv[arg]);
|
|
|
|
timerstart();
|
|
if (LIBRAW_SUCCESS != (ret = RawProcessor.dcraw_process()))
|
|
{
|
|
fprintf(stderr, "Cannot do postprocessing on %s: %s\n", argv[arg],
|
|
libraw_strerror(ret));
|
|
if (LIBRAW_FATAL_ERROR(ret))
|
|
continue;
|
|
}
|
|
if (use_timing)
|
|
timerprint("LibRaw::dcraw_process()", argv[arg]);
|
|
|
|
if (!outext)
|
|
snprintf(outfn, sizeof(outfn), "%s.%s", argv[arg],
|
|
OUT.output_tiff ? "tiff" : (P1.colors > 1 ? "ppm" : "pgm"));
|
|
else if (!strcmp(outext, "-"))
|
|
snprintf(outfn, sizeof(outfn), "-");
|
|
else
|
|
{
|
|
if (*outext == '.') // append
|
|
snprintf(outfn, sizeof(outfn), "%s%s", argv[arg], outext);
|
|
else if (strchr(outext, '.') && *outext != '.') // dot is not 1st char
|
|
strncpy(outfn, outext, sizeof(outfn));
|
|
else
|
|
{
|
|
strncpy(outfn, argv[arg], sizeof(outfn));
|
|
if (strlen(outfn) > 0)
|
|
{
|
|
char *lastchar = outfn + strlen(outfn); // points to term 0
|
|
while (--lastchar > outfn)
|
|
{
|
|
if (*lastchar == '/' || *lastchar == '\\')
|
|
break;
|
|
if (*lastchar == '.')
|
|
{
|
|
*lastchar = 0;
|
|
break;
|
|
};
|
|
}
|
|
}
|
|
strncat(outfn, ".", sizeof(outfn) - strlen(outfn) - 1);
|
|
strncat(outfn, outext, sizeof(outfn) - strlen(outfn) - 1);
|
|
}
|
|
}
|
|
|
|
if (verbosity)
|
|
{
|
|
printf("Writing file %s\n", outfn);
|
|
}
|
|
|
|
if (LIBRAW_SUCCESS != (ret = RawProcessor.dcraw_ppm_tiff_writer(outfn)))
|
|
fprintf(stderr, "Cannot write %s: %s\n", outfn, libraw_strerror(ret));
|
|
else
|
|
done++;
|
|
|
|
RawProcessor.recycle(); // just for show this call
|
|
|
|
if (use_mmap && mapping.map)
|
|
close_mapping(mapping);
|
|
else if (use_mem && iobuffer)
|
|
{
|
|
free(iobuffer);
|
|
iobuffer = 0;
|
|
}
|
|
}
|
|
#ifdef USE_DNGSDK
|
|
if (dnghost)
|
|
delete dnghost;
|
|
#endif
|
|
if (total == 0)
|
|
return 1;
|
|
if (done < total)
|
|
return 2;
|
|
return 0;
|
|
}
|