diff --git a/README.md b/README.md index b8f13c1..d56d5eb 100644 --- a/README.md +++ b/README.md @@ -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 @@ -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 diff --git a/exiv2node.cc b/exiv2node.cc index cea6d0c..8c42b35 100644 --- a/exiv2node.cc +++ b/exiv2node.cc @@ -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 GetImageTags(const Arguments& args) { HandleScope scope; @@ -195,6 +197,81 @@ static void AfterGetImageTags(uv_work_t* req, int status) { delete thread_data; } +static Handle GetImageMeta(const Arguments& args) { + HandleScope scope; + + /* Usage arguments */ + if (args.Length() <= (1) || !args[1]->IsFunction()) + return ThrowException(Exception::TypeError(String::New("Usage: "))); + + // Set up our thread data struct, pass off to the libuv thread pool. + Baton *thread_data = new Baton(Local::Cast(args[0]), Local::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 +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 (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 ("fileName", thread_data->fileName)); + thread_data->tags->insert(std::pair ("fileSize", t_to_string(buf.st_size))); + thread_data->tags->insert(std::pair ("mimeType", image->mimeType())); + thread_data->tags->insert(std::pair ("pixelWidth", t_to_string(image->pixelWidth()))); + thread_data->tags->insert(std::pair ("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 (req->data); + + Local argv[2] = { Local::New(Null()), Local::New(Null()) }; + if (!thread_data->exifException.empty()){ + argv[0] = Local::New(String::New(thread_data->exifException.c_str())); + } else if (!thread_data->tags->empty()) { + Local 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 SetImageTags(const Arguments& args) { HandleScope scope; @@ -456,5 +533,6 @@ void InitAll(Handle 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) diff --git a/package.json b/package.json index 0ec0011..f0c0643 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/test/test.js b/test/test.js index fb4fe7a..a4e5b94 100644 --- a/test/test.js +++ b/test/test.js @@ -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(); + }) + }); + }); + + + })