Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ a package manager you might need to install an additional "-dev" packages.

### Debian

apt-get install libexiv2 libexiv2-dev
apt-get install exiv2 libexiv2-dev

### OS X

Expand Down Expand Up @@ -95,6 +95,25 @@ the tests:
}
});

### Meta Information:

var ex = require('exiv2')
ex.getImageMeta('./photo.jpg', function(err, meta){
if (err) {
console.error(err);
} else {
console.log("Meta:", meta);
}

Meta information looks as follows:

{ fileName: '/path/books.jpg',
fileSize: '993738',
mimeType: 'image/jpeg',
pixelHeight: '1200',
pixelWidth: '1600' }


Take a look at the `examples/` and `test/` directories for more.

email: dberesford at gmail
Expand Down
78 changes: 78 additions & 0 deletions exiv2node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ static void GetImagePreviewsWorker(uv_work_t* req);
static void AfterGetImagePreviews(uv_work_t* req, int status);
static void DeleteImageTagsWorker(uv_work_t *req);
static void AfterDeleteImageTags(uv_work_t* req, int status);
static void GetImageMetaWorker(uv_work_t* req);
static void AfterGetImageMeta(uv_work_t* req, int status);

static Handle<Value> GetImageTags(const Arguments& args) {
HandleScope scope;
Expand Down Expand Up @@ -195,6 +197,81 @@ static void AfterGetImageTags(uv_work_t* req, int status) {
delete thread_data;
}

static Handle<Value> GetImageMeta(const Arguments& args) {
HandleScope scope;

/* Usage arguments */
if (args.Length() <= (1) || !args[1]->IsFunction())
return ThrowException(Exception::TypeError(String::New("Usage: <filename> <callback function>")));

// Set up our thread data struct, pass off to the libuv thread pool.
Baton *thread_data = new Baton(Local<String>::Cast(args[0]), Local<Function>::Cast(args[1]));

int status = uv_queue_work(uv_default_loop(), &thread_data->request, GetImageMetaWorker, (uv_after_work_cb)AfterGetImageMeta);
assert(status == 0);

return Undefined();
}

template<class T>
std::string t_to_string(T i)
{
std::stringstream ss;
std::string s;
ss << i;
s = ss.str();

return s;
}

static void GetImageMetaWorker(uv_work_t* req) {
Baton *thread_data = static_cast<Baton *> (req->data);

try {
Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(thread_data->fileName);
assert(image.get() != 0);
image->readMetadata();

// Filesize
struct stat buf;
stat(thread_data->fileName.c_str(), &buf);
thread_data->tags->insert(std::pair<std::string, std::string> ("fileName", thread_data->fileName));
thread_data->tags->insert(std::pair<std::string, std::string> ("fileSize", t_to_string(buf.st_size)));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you pass these across as strings rather than integers?

thread_data->tags->insert(std::pair<std::string, std::string> ("mimeType", image->mimeType()));
thread_data->tags->insert(std::pair<std::string, std::string> ("pixelWidth", t_to_string(image->pixelWidth())));
thread_data->tags->insert(std::pair<std::string, std::string> ("pixelHeight", t_to_string(image->pixelHeight())));
} catch (std::exception& e) {
thread_data->exifException.append(e.what());
}
}

/* Thread complete callback.. */
static void AfterGetImageMeta(uv_work_t* req, int status) {
HandleScope scope;
Baton *thread_data = static_cast<Baton *> (req->data);

Local<Value> argv[2] = { Local<Value>::New(Null()), Local<Value>::New(Null()) };
if (!thread_data->exifException.empty()){
argv[0] = Local<String>::New(String::New(thread_data->exifException.c_str()));
} else if (!thread_data->tags->empty()) {
Local<Object> tags = Object::New();
// Copy the tags out.
for (tag_map_t::iterator i = thread_data->tags->begin(); i != thread_data->tags->end(); ++i) {
tags->Set(String::New(i->first.c_str()), String::New(i->second.c_str()), ReadOnly);
}
argv[1] = tags;
}

// Pass the argv array object to our callback function.
TryCatch try_catch;
thread_data->cb->Call(Context::GetCurrent()->Global(), 2, argv);
if (try_catch.HasCaught()) {
FatalException(try_catch);
}

delete thread_data;
}

/* Set Image Tag support.. */
static Handle<Value> SetImageTags(const Arguments& args) {
HandleScope scope;
Expand Down Expand Up @@ -456,5 +533,6 @@ void InitAll(Handle<Object> target) {
target->Set(String::NewSymbol("setImageTags"), FunctionTemplate::New(SetImageTags)->GetFunction());
target->Set(String::NewSymbol("deleteImageTags"), FunctionTemplate::New(DeleteImageTags)->GetFunction());
target->Set(String::NewSymbol("getImagePreviews"), FunctionTemplate::New(GetImagePreviews)->GetFunction());
target->Set(String::NewSymbol("getImageMeta"), FunctionTemplate::New(GetImageMeta)->GetFunction());
}
NODE_MODULE(exiv2, InitAll)
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
},
"name": "exiv2",
"description": "A native c++ extension for node.js that provides support for reading & writing image metadata via Exiv2.",
"version": "0.4.2",
"version": "0.5.0",
"homepage": "https://github.com/dberesford/exiv2node",
"repository": {
"type": "git",
Expand Down
16 changes: 15 additions & 1 deletion test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,5 +195,19 @@ describe('exiv2', function(){
var d = exiv.getDate(tags, 'Exif.Photo.DateTimeDigitized');
d.toISOString().should.equal('2012-04-14T17:08:08.880Z');
});
})
});

describe('.getMeta()', function(){
it("should callback with image's meta information", function(done) {
exiv.getImageMeta(dir + '/books.jpg', function(err, meta) {
should.not.exist(err);
meta.should.have.property('mimeType', 'image/jpeg');
meta.should.have.property('pixelHeight', '1200');
done();
})
});
});



})