# HG changeset patch # User nadvornik # Date 1219962369 0 # Node ID 68b0cb6ca8f0593bb1aa482de87bee81200b6767 # Parent 4303ee1e88ec1747a48d10e71b26855f590d5e6f use mmaped files image loader implemented new interface for extracting raw previews experiments with previews support in SVN version of Exiv2 diff -r 4303ee1e88ec -r 68b0cb6ca8f0 src/exif.h --- a/src/exif.h Thu Aug 28 12:51:02 2008 +0000 +++ b/src/exif.h Thu Aug 28 22:26:09 2008 +0000 @@ -158,10 +158,8 @@ gint exif_jpeg_parse_color(ExifData *exif, guchar *data, guint size); /*raw support */ -gint format_raw_img_exif_offsets_fd(gint fd, const gchar *path, - guchar *header_data, const guint header_len, - guint *image_offset, guint *exif_offset); - +guchar *exif_get_preview(ExifData *exif, guint *data_len); +void exif_free_preview(guchar *buf); #endif diff -r 4303ee1e88ec -r 68b0cb6ca8f0 src/exiv2.cc --- a/src/exiv2.cc Thu Aug 28 12:51:02 2008 +0000 +++ b/src/exiv2.cc Thu Aug 28 22:26:09 2008 +0000 @@ -30,6 +30,7 @@ #include #include +#if !EXIV2_TEST_VERSION(0,17,90) #include #include #include @@ -43,7 +44,9 @@ #include #endif #include - +#else +#include +#endif extern "C" { @@ -544,7 +547,7 @@ if (!item) return 0; ((Exiv2::Metadatum *)item)->setValue(std::string(str)); return 1; - } + } catch (Exiv2::AnyError& e) { return 0; } @@ -588,7 +591,7 @@ exif->cp_length =cp_length; } -unsigned char *exif_get_color_profile(ExifData *exif, guint *data_len) +guchar *exif_get_color_profile(ExifData *exif, guint *data_len) { if (exif->cp_data) { @@ -601,9 +604,41 @@ return NULL; } +#if EXIV2_TEST_VERSION(0,17,90) +guchar *exif_get_preview(ExifData *exif, guint *data_len) +{ + if (!exif) return NULL; + try { + + Exiv2::PreviewImageList list(*exif->image); + list.read(); + + Exiv2::PreviewImageList::iterator pos = list.begin(); + if (pos != list.end()) + { + Exiv2::DataBuf buf = pos->copy(); + std::pair p = buf.release(); + + *data_len = p.second; + return p.first; + } + return NULL; + } + catch (Exiv2::AnyError& e) { + std::cout << "Caught Exiv2 exception '" << e << "'\n"; + return NULL; + } +} + +void exif_free_preview(guchar *buf) +{ + delete[] (Exiv2::byte*)buf; +} +#endif } +#if !EXIV2_TEST_VERSION(0,17,90) /* This is a dirty hack to support raw file preview, bassed on tiffparse.cpp from Exiv2 examples */ @@ -611,7 +646,7 @@ class RawFile { public: - RawFile(int fd); + RawFile(Exiv2::BasicIo &io); ~RawFile(); const Exiv2::Value *find(uint16_t tag, uint16_t group); @@ -621,15 +656,102 @@ private: int type; Exiv2::TiffComponent::AutoPtr rootDir; - Exiv2::byte *map_data; + Exiv2::BasicIo &io_; + const Exiv2::byte *map_data; size_t map_len; unsigned long offset; }; +typedef struct _UnmapData UnmapData; +struct _UnmapData +{ + guchar *ptr; + guchar *map_data; + size_t map_len; +}; + +static GList *exif_unmap_list = 0; + +extern "C" guchar *exif_get_preview(ExifData *exif, guint *data_len) +{ + int success; + unsigned long offset; + + if (!exif) return NULL; + const char* path = exif->image->io().path().c_str(); + + /* given image pathname, first do simple (and fast) file extension test */ + if (!filter_file_class(path, FORMAT_CLASS_RAWIMAGE)) return 0; + + try { + struct stat st; + guchar *map_data; + size_t map_len; + UnmapData *ud; + int fd; + + RawFile rf(exif->image->io()); + offset = rf.preview_offset(); + DEBUG_1("%s: offset %lu", path, offset); + + fd = open(path, O_RDONLY); + if (fd == -1) + { + return 0; + } + + if (fstat(fd, &st) == -1) + { + close(fd); + return 0; + } + map_len = st.st_size; + map_data = (guchar *) mmap(0, map_len, PROT_READ, MAP_PRIVATE, fd, 0); + close(fd); + if (map_data == MAP_FAILED) + { + return 0; + } + *data_len = map_len - offset; + ud = g_new(UnmapData, 1); + ud->ptr = map_data + offset; + ud->map_data = map_data; + ud->map_len = map_len; + + exif_unmap_list = g_list_prepend(exif_unmap_list, ud); + return ud->ptr; + + } + catch (Exiv2::AnyError& e) { + std::cout << "Caught Exiv2 exception '" << e << "'\n"; + } + return NULL; + +} + +void exif_free_preview(guchar *buf) +{ + GList *work = exif_unmap_list; + + while (work) + { + UnmapData *ud = (UnmapData *)work->data; + if (ud->ptr == buf) + { + munmap(ud->map_data, ud->map_len); + exif_unmap_list = g_list_remove_link(exif_unmap_list, work); + g_free(ud); + return; + } + } + g_assert_not_reached(); +} + using namespace Exiv2; -RawFile::RawFile(int fd) : map_data(NULL), map_len(0), offset(0) +RawFile::RawFile(BasicIo &io) : io_(io), map_data(NULL), map_len(0), offset(0) { +/* struct stat st; if (fstat(fd, &st) == -1) { @@ -641,6 +763,15 @@ { throw Error(14); } +*/ + if (io.open() != 0) { + throw Error(9, io.path(), strError()); + } + + map_data = io.mmap(); + map_len = io.size(); + + type = Exiv2::ImageFactory::getType(map_data, map_len); #if EXIV2_TEST_VERSION(0,16,0) @@ -723,10 +854,8 @@ RawFile::~RawFile(void) { - if (map_data && munmap(map_data, map_len) == -1) - { - log_printf("Failed to unmap file \n"); - } + io_.munmap(); + io_.close(); } const Value * RawFile::find(uint16_t tag, uint16_t group) @@ -772,41 +901,7 @@ } -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) -{ - int success; - unsigned long offset; - - /* given image pathname, first do simple (and fast) file extension test */ - if (!filter_file_class(path, FORMAT_CLASS_RAWIMAGE)) return 0; - - try { - RawFile rf(fd); - offset = rf.preview_offset(); - DEBUG_1("%s: offset %lu", path, offset); - } - catch (Exiv2::AnyError& e) { - std::cout << "Caught Exiv2 exception '" << e << "'\n"; - return 0; - } - - if (image_offset && offset > 0) - { - *image_offset = offset; - if ((unsigned long) lseek(fd, *image_offset, SEEK_SET) != *image_offset) - { - log_printf("Failed to seek to embedded image\n"); - - *image_offset = 0; - if (*exif_offset) *exif_offset = 0; - success = FALSE; - } - } - - return offset > 0; -} +#endif #endif diff -r 4303ee1e88ec -r 68b0cb6ca8f0 src/image-load.c --- a/src/image-load.c Thu Aug 28 12:51:02 2008 +0000 +++ b/src/image-load.c Thu Aug 28 22:26:09 2008 +0000 @@ -19,6 +19,7 @@ #include "ui_fileops.h" #include +#include static const gchar *image_loader_path(ImageLoader *il) @@ -155,10 +156,17 @@ il->loader = NULL; } - if (il->load_fd != -1) + if (il->mapped_file) { - close(il->load_fd); - il->load_fd = -1; + if (il->preview) + { + exif_free_preview(il->mapped_file); + } + else + { + munmap(il->mapped_file, il->bytes_total); + } + il->mapped_file = NULL; } il->done = TRUE; @@ -208,7 +216,7 @@ c = il->idle_read_loop_count ? il->idle_read_loop_count : 1; while (c > 0) { - b = read(il->load_fd, il->read_buffer, il->read_buffer_size); + b = MIN(il->read_buffer_size, il->bytes_total - il->bytes_read); if (b == 0) { @@ -216,7 +224,7 @@ return FALSE; } - if (b < 0 || (b > 0 && !gdk_pixbuf_loader_write(il->loader, il->read_buffer, b, NULL))) + if (b < 0 || (b > 0 && !gdk_pixbuf_loader_write(il->loader, il->mapped_file + il->bytes_read, b, NULL))) { image_loader_error(il); return FALSE; @@ -238,19 +246,10 @@ static gint image_loader_begin(ImageLoader *il) { gint b; - guint offset = 0; if (!il->loader || il->pixbuf) return FALSE; - b = read(il->load_fd, il->read_buffer, il->read_buffer_size); - - if (b > 0 && - format_raw_img_exif_offsets_fd(il->load_fd, image_loader_path(il), il->read_buffer, b, &offset, NULL)) - { - DEBUG_1("Raw file %s contains embedded image", image_loader_path(il)); - - b = read(il->load_fd, il->read_buffer, il->read_buffer_size); - } + b = MIN(il->read_buffer_size, il->bytes_total - il->bytes_read); if (b < 1) { @@ -258,19 +257,19 @@ return FALSE; } - if (!gdk_pixbuf_loader_write(il->loader, il->read_buffer, b, NULL)) + if (!gdk_pixbuf_loader_write(il->loader, il->mapped_file + il->bytes_read, b, NULL)) { image_loader_stop(il); return FALSE; } - il->bytes_read += b + offset; + il->bytes_read += b; /* read until size is known */ while (il->loader && !gdk_pixbuf_loader_get_pixbuf(il->loader) && b > 0) { - b = read(il->load_fd, il->read_buffer, il->read_buffer_size); - if (b < 0 || (b > 0 && !gdk_pixbuf_loader_write(il->loader, il->read_buffer, b, NULL))) + b = MIN(il->read_buffer_size, il->bytes_total - il->bytes_read); + if (b < 0 || (b > 0 && !gdk_pixbuf_loader_write(il->loader, il->mapped_file + il->bytes_read, b, NULL))) { image_loader_stop(il); return FALSE; @@ -307,18 +306,56 @@ struct stat st; gchar *pathl; - if (!il || il->load_fd != -1 || il->loader) return FALSE; + if (!il || il->loader || il->mapped_file) return FALSE; + + il->mapped_file = NULL; + + if (il->fd) + { + ExifData *exif = exif_read_fd(il->fd); + + il->mapped_file = exif_get_preview(exif, &il->bytes_total); + + if (il->mapped_file) + { + il->preview = TRUE; + DEBUG_1("Raw file %s contains embedded image", image_loader_path(il)); + } + exif_free_fd(il->fd, exif); + } - pathl = path_from_utf8(image_loader_path(il)); - il->load_fd = open(pathl, O_RDONLY | O_NONBLOCK); - g_free(pathl); - if (il->load_fd == -1) return FALSE; + + if (!il->mapped_file) + { + /* normal file */ + gint load_fd; + + pathl = path_from_utf8(image_loader_path(il)); + load_fd = open(pathl, O_RDONLY | O_NONBLOCK); + g_free(pathl); + if (load_fd == -1) return FALSE; - if (fstat(il->load_fd, &st) == 0) - { - il->bytes_total = st.st_size; + if (fstat(load_fd, &st) == 0) + { + il->bytes_total = st.st_size; + } + else + { + close(load_fd); + return FALSE; + } + + il->mapped_file = mmap(0, il->bytes_total, PROT_READ|PROT_WRITE, MAP_PRIVATE, load_fd, 0); + close(load_fd); + if (il->mapped_file == MAP_FAILED) + { + il->mapped_file = 0; + return FALSE; + } + il->preview = FALSE; } + il->loader = gdk_pixbuf_loader_new(); g_signal_connect(G_OBJECT(il->loader), "area_updated", G_CALLBACK(image_loader_area_updated_cb), il); @@ -346,7 +383,6 @@ il->idle_priority = G_PRIORITY_DEFAULT_IDLE; il->done = FALSE; il->loader = NULL; - il->load_fd = -1; il->bytes_read = 0; il->bytes_total = 0; @@ -355,7 +391,7 @@ il->idle_read_loop_count = options->image.idle_read_loop_count; il->read_buffer_size = options->image.read_buffer_size; - il->read_buffer = g_new(guchar, il->read_buffer_size); + il->mapped_file = NULL; il->requested_width = 0; il->requested_height = 0; @@ -383,7 +419,6 @@ if (il->pixbuf) gdk_pixbuf_unref(il->pixbuf); if (il->fd) file_data_unref(il->fd); if (il->path) g_free(il->path); - if (il->read_buffer) g_free(il->read_buffer); DEBUG_1("freeing image loader %p bytes_read=%d", il, il->bytes_read); g_free(il); } diff -r 4303ee1e88ec -r 68b0cb6ca8f0 src/typedefs.h --- a/src/typedefs.h Thu Aug 28 12:51:02 2008 +0000 +++ b/src/typedefs.h Thu Aug 28 22:26:09 2008 +0000 @@ -216,6 +216,8 @@ gint bytes_read; gint bytes_total; + gint preview; + gint requested_width; gint requested_height; gint shrunk; @@ -225,7 +227,6 @@ gint idle_priority; GdkPixbufLoader *loader; - gint load_fd; void (*func_area_ready)(ImageLoader *, guint x, guint y, guint w, guint h, gpointer); void (*func_error)(ImageLoader *, gpointer); @@ -239,7 +240,7 @@ gint idle_done_id; - guchar *read_buffer; + guchar *mapped_file; gint read_buffer_size; gint idle_read_loop_count; };