#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"
#include <libexif/exif-loader.h>
#include <libexif/exif-data.h>
#include <libexif/exif-log.h>
#include <libexif/exif-mem.h>
#include <libexif/exif-utils.h>
/*
EXIF_FORMAT_BYTE = 1,
EXIF_FORMAT_ASCII = 2,
EXIF_FORMAT_SHORT = 3,
EXIF_FORMAT_LONG = 4,
EXIF_FORMAT_RATIONAL = 5,
EXIF_FORMAT_SBYTE = 6,
EXIF_FORMAT_UNDEFINED = 7,
EXIF_FORMAT_SSHORT = 8,
EXIF_FORMAT_SLONG = 9,
EXIF_FORMAT_SRATIONAL = 10,
EXIF_FORMAT_FLOAT = 11,
EXIF_FORMAT_DOUBLE = 12
*/
static int my_exif_get_short ( const unsigned char *b, ExifByteOrder o ) { (int) exif_get_short(b,o); }
static int my_exif_get_sshort ( const unsigned char *b, ExifByteOrder o ) { (int) exif_get_sshort(b,o); }
static int my_exif_get_long ( const unsigned char *b, ExifByteOrder o ) { (int) exif_get_long(b,o); }
static int my_exif_get_slong ( const unsigned char *b, ExifByteOrder o ) { (int) exif_get_slong(b,o); }
// TODO: Double/Rational
// TODO: unsigned long
static int ( *exif_get_by_format[] )( const unsigned char *, ExifByteOrder ) = {
0, // skip 0
my_exif_get_short,
0,
my_exif_get_short,
my_exif_get_long,
0, // Rational
my_exif_get_short,
0, // Undefined
my_exif_get_sshort,
my_exif_get_slong,
0, // SRational
0, // Float
0 // Double
};
SV *
my_exif_get_value(ExifEntry *e, ExifByteOrder o) {
int ( *extractor )( const unsigned char *, ExifByteOrder );
char value[1024];
int intval, have_intval = 0;
SV *rv;
if (extractor = exif_get_by_format[e->format]) {
intval = extractor(e->data,o);
have_intval = 1;
}
exif_entry_get_value(e, value, sizeof(value));
rv = newSVpvn(value,strlen(value));
if (have_intval) {
(void) SvUPGRADE(rv,SVt_PVNV);
SvIV_set(rv, intval);
SvIOK_on(rv);
}
return rv;
}
MODULE = Image::LibExif PACKAGE = Image::LibExif
SV *
image_exif(src)
char *src;
PROTOTYPE:$
CODE:
int k,l,m,n;
ExifLoader * loader;
ExifData * data;
ExifContent * content;
ExifEntry * entry;
loader = exif_loader_new();
exif_loader_write_file(loader, src);
data = exif_loader_get_data(loader);
exif_loader_unref(loader);
if (!data) XSRETURN_UNDEF;
exif_data_fix(data);
HV * rv = newHV();
ExifByteOrder o = exif_data_get_byte_order(data);
for (k = 0; k < EXIF_IFD_COUNT; k++) {
content = data->ifd[k];
if (!content) continue;
//warn("Reading IFD %d\n",k);
for (l = 0; l < content->count; l++) {
entry = content->entries[l];
const char *tagname = exif_tag_get_name_in_ifd(entry->tag,k);
const SV * tagval = my_exif_get_value(entry,o);
//if (memcmp(tagname,"GPS",3) == 0) {
// warn("\tStore tag %04x (%s) with value %s\n",entry->tag,tagname,SvPV_nolen(tagval));
//}
(void) hv_store(rv, tagname, strlen(tagname), tagval, 0 );
}
}
if (data->size && data->data) {
(void) hv_store(rv, "ThumbnailImage", strlen("ThumbnailImage"), newRV_noinc(newSVpvn(data->data,data->size)), 0 );
}
exif_data_unref(data);
ST(0) = sv_2mortal(newRV_noinc((SV *)rv));
XSRETURN(1);