// crwReader.C // Copyright (c) 2010 The Foundry Visionmongers Ltd. All Rights Reserved. /* Reads crw files via popen of dcraw conversion tool. (Really is reading 16bit P6 format PPM files) 04/14/03 Initial Release Charles Henrich (henrich@d2.com) 09/14/06 Indentation, removed unused variables and unnecessary knobs */ #ifdef _WIN32 #define _WINSOCKAPI_ #endif #include "DDImage/Reader.h" #include "DDImage/Row.h" #include "DDImage/Thread.h" #include "DDImage/DDString.h" #include "DDImage/MetaData.h" #include "DDImage/Knobs.h" #include #include #include #ifdef _WIN32 #include #else #include #endif #ifdef _WIN32 #define ushort unsigned short #define popen _popen #define pclose _pclose #endif using namespace DD::Image; static const char* kDefaultDcRawArgs = "-4 -c"; class crwReaderFormat : public ReaderFormat { std::string _commandArgs; public: crwReaderFormat() { _commandArgs = kDefaultDcRawArgs; } const std::string& commandArgs() const { return _commandArgs; } void knobs(Knob_Callback c) override { String_knob(c, &_commandArgs, "args", "arguments to 'dcraw'"); } void append(Hash& hash) override { hash.append(_commandArgs); } }; class crwReader : public Reader { int C_ppmwidth, C_ppmheight, C_ppmmaxval; ushort* C_image_cache; void barf(const char* command) { iop->error("\nError running %s\n" "If you have the \"dcraw\" software installed, make sure that it's in your path.\n" "If you don't have it, the latest version is available as source from:\n" " http://www.cybercom.net/~dcoffin/dcraw/\n" "where you can also find links to precompiled versions for Windows and OSX." , command); } public: MetaData::Bundle _meta; const MetaData::Bundle& fetchMetaData(const char* key) override { return _meta; } crwReader(Read*, int fd); ~crwReader() override; void engine(int y, int x, int r, ChannelMask, Row &) override; static const Description d; }; static bool test(int fd, const unsigned char* block, int length) { /* Figure out test later XXX */ return true; } static Reader* build(Read* iop, int fd, const unsigned char* b, int n) { // crwReader never accesses the opened file itself, just passes the filename to dcraw, // so we might as well close the file now rather than wait until the dtor, then pass in // -1 to the ctor to indicate an invalid value, in case that ever gets modified to use it. ::close(fd); return new crwReader(iop, -1); } static ReaderFormat* buildformat(Read* iop) { return new crwReaderFormat(); } const Reader::Description crwReader::d("crw\0cr2\0", build, test, buildformat); crwReader::crwReader(Read* r, int fd) : Reader(r) { // WARNING: This would normally only ever be called by build(), which will have closed the file // and set the file descriptor, fd, to -1. C_image_cache = nullptr; info_.ydirection(-1); std::string args = kDefaultDcRawArgs; crwReaderFormat* trf = dynamic_cast(r->handler()); if (trf) { args = trf->commandArgs(); } char command[BUFSIZ]; snprintf(command, BUFSIZ, "dcraw %s \"%s\"", args.c_str(), filename()); #ifdef _WIN32 FILE* pipe = popen(command, "rb"); #else FILE* pipe = popen(command, "r"); #endif if (!pipe) { barf(command); return; } printf("crwReader: %s\n", command); char magic[4]; magic[0] = '\0'; // put some dummy values in so if reading fails it does not crash: C_ppmwidth = 640; C_ppmheight = 480; fscanf(pipe, "%3s %d %d %d", magic, &C_ppmwidth, &C_ppmheight, &C_ppmmaxval); if (strcmp(magic, "P6") != 0) { pclose(pipe); barf(command); return; } printf("crwReader: reading pixels\n"); int numpixels = C_ppmwidth * C_ppmheight * 3; C_image_cache = new ushort[numpixels]; fgetc(pipe); /* Skip whitespace char after header */ int numread = fread(C_image_cache, 2, numpixels, pipe); if (numread < numpixels) { if (numread < 1) barf(command); else iop->error("dcraw only returned %d of the %d samples needed", numread, numpixels); } frommsb(C_image_cache, numpixels); pclose(pipe); printf("crwReader: done\n"); set_info(C_ppmwidth, C_ppmheight, 3); _meta.setData(MetaData::DEPTH, MetaData::DEPTH_16); } crwReader::~crwReader() { delete[] C_image_cache; } void crwReader::engine(int y, int x, int r, ChannelMask channels, Row& row) { int xcount; int cacheoffset = 0; float* dstpixrow; if (!C_image_cache) { row.erase(channels); return; } y = height() - 1 - y; foreach(z, channels) { dstpixrow = row.writable(z); cacheoffset = (y * C_ppmwidth + x) * 3 + (z - 1); for (xcount = x; xcount < r; xcount++) { dstpixrow[xcount] = float(C_image_cache[cacheoffset] * 1.0 / C_ppmmaxval); cacheoffset += 3; } } }