# HG changeset patch # User nadvornik # Date 1203879319 0 # Node ID bd3fc1aa7fe939d8e985ee7d653241d3e5146dd2 # Parent 354da67a7ca2abfc9215d3ba86c875cbd5e3b559 a hack to read raw previews with exiv2 0.16, however it should be fixed in the library diff -r 354da67a7ca2 -r bd3fc1aa7fe9 src/exiv2.cc --- a/src/exiv2.cc Fri Feb 15 10:48:09 2008 +0000 +++ b/src/exiv2.cc Sun Feb 24 18:55:19 2008 +0000 @@ -9,8 +9,24 @@ #include #include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + + extern "C" { - #include #include "exif.h" @@ -284,7 +300,8 @@ { try { if (!item) return 0; - return ((Exiv2::Metadatum *)item)->toLong(); + *value = ((Exiv2::Metadatum *)item)->toLong(); + return 1; } catch (Exiv2::AnyError& e) { std::cout << "Caught Exiv2 exception '" << e << "'\n"; @@ -320,14 +337,197 @@ } } -gint format_raw_img_exif_offsets_fd(int fd, const gchar *path, + +} + +/* This is a dirty hack to support raw file preview, bassed on +tiffparse.cpp from Exiv2 examples */ + +class RawFile { + public: + + RawFile(int fd); + ~RawFile(); + + const Exiv2::Value *find(uint16_t tag, uint16_t group); + + unsigned long preview_offset(); + + private: + int type; + Exiv2::TiffComponent::AutoPtr rootDir; + Exiv2::byte *map_data; + size_t map_len; + unsigned long offset; +}; + +using namespace Exiv2; + +RawFile::RawFile(int fd) : map_data(NULL), map_len(0), offset(0) +{ + struct stat st; + if (fstat(fd, &st) == -1) + { + throw Error(14); + } + map_len = st.st_size; + map_data = (Exiv2::byte *) mmap(0, map_len, PROT_READ, MAP_PRIVATE, fd, 0); + if (map_data == MAP_FAILED) + { + throw Error(14); + } + type = Exiv2::ImageFactory::getType(map_data, map_len); + + TiffHeaderBase *tiffHeader; + switch (type) { + case Exiv2::ImageType::tiff: + tiffHeader = new TiffHeade2(); + break; + case Exiv2::ImageType::cr2: + tiffHeader = new Cr2Header(); + break; + case Exiv2::ImageType::orf: + tiffHeader = new OrfHeader(); + break; + case Exiv2::ImageType::raf: + if (map_len < 84 + 4) throw Error(14); + offset = getULong(map_data + 84, bigEndian); + return; + + default: + throw Error(3, "RAW"); + } + + // process tiff-like formats + if (!tiffHeader->read(map_data, map_len)) throw Error(3, "TIFF"); + + TiffCompFactoryFct createFct = TiffCreator::create; + + rootDir = createFct(Tag::root, Group::none); + if (0 == rootDir.get()) { + throw Error(1, "No root element defined in TIFF structure"); + } + rootDir->setStart(map_data + tiffHeader->offset()); + + TiffRwState::AutoPtr state( + new TiffRwState(tiffHeader->byteOrder(), 0, createFct)); + + TiffReader reader(map_data, + map_len, + rootDir.get(), + state); + + rootDir->accept(reader); + + delete tiffHeader; +} + +RawFile::~RawFile() +{ + if (map_data && munmap(map_data, map_len) == -1) + { + printf("Failed to unmap file \n"); + } +} + +const Value * RawFile::find(uint16_t tag, uint16_t group) +{ + printf("%04x %04x\n", tag, group); + TiffFinder finder(tag, group); + rootDir->accept(finder); + TiffEntryBase* te = dynamic_cast(finder.result()); + if (te) + return te->pValue(); + else + return NULL; +} + +unsigned long RawFile::preview_offset() +{ + const Value *val; + if (offset) return offset; + + if (type == Exiv2::ImageType::cr2) + { + val = find(0x111, Group::ifd0); + if (val) return val->toLong(); + + return 0; + } + + val = find(0x201, Group::sub0_0); + if (val) return val->toLong(); + + val = find(0x201, Group::ifd0); + if (val) return val->toLong(); + + val = find(0x201, Group::ignr); // for PEF files, originally it was probably ifd2 + if (val) return val->toLong(); + + val = find(0x111, Group::sub0_1); // dng + if (val) return val->toLong(); + + return 0; +} + + +const static char *raw_ext_list[] = { ".cr2", ".nef", ".pef", ".arw", NULL }; + +extern "C" gint format_raw_img_exif_offsets_fd(int fd, const gchar *path, unsigned char *header_data, const guint header_len, guint *image_offset, guint *exif_offset) { - return 0; + int success; + unsigned long offset; + + /* given image pathname, first do simple (and fast) file extension test */ +/* if (path) + { + const gchar *ext; + gint match = FALSE; + gint i; + + ext = strrchr(path, '.'); + if (!ext) return FALSE; + + for (i = 0; raw_ext_list[i]; i++) + { + if (strcasecmp(raw_ext_list[i], ext) == 0) + { + match = TRUE; + break; + } + } + + if (!match) return FALSE; + + } +*/ + try { + RawFile rf(fd); + offset = rf.preview_offset(); + } + catch (Exiv2::AnyError& e) { + std::cout << "Caught Exiv2 exception '" << e << "'\n"; + return 0; + } + + if (image_offset) + { + *image_offset = offset; + if (lseek(fd, *image_offset, SEEK_SET) != *image_offset) + { + printf("Failed to seek to embedded image\n"); + + *image_offset = 0; + if (*exif_offset) *exif_offset = 0; + success = FALSE; + } + } + + return offset > 0; } -} #endif /* HAVE_EXIV2 */