Revision: 1103
http://geeqie.svn.sourceforge.net/geeqie/?rev=1103&view=rev
Author: nadvornik
Date: 2008-08-28 22:26:09 +0000 (Thu, 28 Aug 2008)
Log Message:
-----------
use mmaped files image loader
implemented new interface for extracting raw previews
experiments with previews support in SVN version of Exiv2
Modified Paths:
--------------
trunk/src/exif.h
trunk/src/exiv2.cc
trunk/src/image-load.c
trunk/src/typedefs.h
Modified: trunk/src/exif.h
===================================================================
--- trunk/src/exif.h 2008-08-28 12:51:02 UTC (rev 1102)
+++ trunk/src/exif.h 2008-08-28 22:26:09 UTC (rev 1103)
@@ -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
Modified: trunk/src/exiv2.cc
===================================================================
--- trunk/src/exiv2.cc 2008-08-28 12:51:02 UTC (rev 1102)
+++ trunk/src/exiv2.cc 2008-08-28 22:26:09 UTC (rev 1103)
@@ -30,6 +30,7 @@
#include <fcntl.h>
#include <sys/mman.h>
+#if !EXIV2_TEST_VERSION(0,17,90)
#include <exiv2/tiffparser.hpp>
#include <exiv2/tiffcomposite.hpp>
#include <exiv2/tiffvisitor.hpp>
@@ -43,9 +44,11 @@
#include <exiv2/rafimage.hpp>
#endif
#include <exiv2/futils.hpp>
+#else
+#include <exiv2/preview.hpp>
+#endif
-
extern "C" {
#include <glib.h>
@@ -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,17 +604,49 @@
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<Exiv2::byte*, long> 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 */
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,42 +901,8 @@
}
-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;
+#endif
- /* 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
/* HAVE_EXIV2 */
Modified: trunk/src/image-load.c
===================================================================
--- trunk/src/image-load.c 2008-08-28 12:51:02 UTC (rev 1102)
+++ trunk/src/image-load.c 2008-08-28 22:26:09 UTC (rev 1103)
@@ -19,6 +19,7 @@
#include "ui_fileops.h"
#include <fcntl.h>
+#include <sys/mman.h>
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,39 +246,30 @@
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);
+ b = MIN(il->read_buffer_size, il->bytes_total - il->bytes_read);
- 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);
- }
-
if (b < 1)
{
image_loader_stop(il);
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;
- 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;
+ il->mapped_file = NULL;
- if (fstat(il->load_fd, &st) == 0)
+ if (il->fd)
{
- il->bytes_total = st.st_size;
+ 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);
}
+
+ 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(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);
}
Modified: trunk/src/typedefs.h
===================================================================
--- trunk/src/typedefs.h 2008-08-28 12:51:02 UTC (rev 1102)
+++ trunk/src/typedefs.h 2008-08-28 22:26:09 UTC (rev 1103)
@@ -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;
};
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
Geeqie-svn mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/geeqie-svn