Skip to content

Commit

Permalink
make "imageHash" async, add sync function
Browse files Browse the repository at this point in the history
closes #7
  • Loading branch information
Aaron Marasco committed Jun 28, 2013
1 parent 258f592 commit e0cd3fb
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 102 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ lib-cov
*.out
*.pid
*.gz

/demo
pids
logs
results
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ To install these packages in Ubuntu:

sudo apt-get install cimg-dev libphash0-dev

On OSX:

brew install phash imagemagick

Then, install using npm:

$ npm install phash
Expand Down
38 changes: 0 additions & 38 deletions examples/test.js

This file was deleted.

20 changes: 16 additions & 4 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
var pHash = require('../build/Release/pHash');

exports.getOldHash = function(filePath) {
return pHash.oldHash(filePath);
exports.imageHashSync = function(file) {
return pHash.imageHashSync(file);
};

exports.getImageHash = function(filePath) {
return pHash.imagehash(filePath);
exports.imageHash = function(file, cb) {
return pHash.imageHash(file, cb);
};

exports.hammingDistance = function(hasha,hashb) {
return pHash.hammingDistance(hasha,hashb);
};

/*
Deprecated, use "imageHashSync"
*/
exports.getImageHash = exports.imageHashSync;

exports.getOldHash = function(filePath) {
return pHash.oldHash(filePath);
};



2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "phash",
"version": "0.0.3",
"version": "0.0.4",
"description": "Bindings for node.js to pHash",
"main": "index",
"repository": {
Expand Down
86 changes: 69 additions & 17 deletions phash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
#include <pHash.h>
#include <sstream>
#include <cstdio>

using namespace node;
using namespace v8;

const char* ToCString(const String::Utf8Value& value) {
return *value ? *value : "<string conversion failed>";
}
struct PhashRequest {
string file;
string hash;
uv_work_t request;
Persistent<Function> callback;
};

template <typename T>
string NumberToString ( T Number ) {
Expand All @@ -25,23 +27,71 @@ T StringToNumber ( const string &Text ) {
return ss >> result ? result : 0;
}

Handle<Value> ImageHash(const Arguments& args) {
HandleScope scope;
string result;
const char* ToCString(const String::Utf8Value& value) {
return *value ? *value : "<string conversion failed>";
}

const string getHash(const char* file) {
string ret;
try {
String::Utf8Value str(args[0]);
const char* file = ToCString(str);
ulong64 hash = 0;
ph_dct_imagehash(file, hash);
result = NumberToString(hash);
} catch(...) {
return NumberToString(hash);
}
catch(...) {
// something went wrong with hashing
// probably a CImg or ImageMagick IO Problem
// return -1
result = "-1";
return "0";
}
}

void HashWorker(uv_work_t* req) {
PhashRequest* request = static_cast<PhashRequest*>(req->data);
request->hash = getHash(request->file.c_str());
}

void HashAfter(uv_work_t* req, int status) {
HandleScope scope;
PhashRequest* request = static_cast<PhashRequest*>(req->data);

Handle<Value> argv[2];

if (request->hash == "0") {
argv[0] = String::New("Error getting image hash");
}
else {
argv[0] = Undefined();
}

argv[1] = String::New(request->hash.c_str());
request->callback->Call(Context::GetCurrent()->Global(), 2, argv);
request->callback.Dispose();

delete request;
}


Handle<Value> ImageHashAsync(const Arguments& args) {
if (args.Length() < 2 || !args[1]->IsFunction()) {
// no callback defined
return ThrowException(Exception::Error(String::New("Callback is required and must be an Function.")));
}

String::Utf8Value str(args[0]);
Handle<Function> cb = Handle<Function>::Cast(args[1]);

PhashRequest* request = new PhashRequest;
request->callback = Persistent<Function>::New(cb);
request->file = string(*str);
request->request.data = request;
uv_queue_work(uv_default_loop(), &request->request, HashWorker, HashAfter);
return Undefined();
}

Handle<Value> ImageHashSync(const Arguments& args) {
HandleScope scope;
String::Utf8Value str(args[0]);
string result = getHash(*str);
return scope.Close(String::New(result.c_str()));
}

Expand All @@ -50,7 +100,6 @@ Handle<Value> HammingDistance(const Arguments& args) {

String::Utf8Value arg0(args[0]);
String::Utf8Value arg1(args[1]);

string aString = string(ToCString(arg0));
string bString = string(ToCString(arg1));

Expand All @@ -76,10 +125,13 @@ Handle<Value> oldHash(const Arguments& args) {
}

void RegisterModule(Handle<Object> target) {
NODE_SET_METHOD(target, "imagehash", ImageHash);
NODE_SET_METHOD(target, "imageHash", ImageHash);
NODE_SET_METHOD(target,"hammingDistance",HammingDistance);
NODE_SET_METHOD(target, "imageHashSync", ImageHashSync);
NODE_SET_METHOD(target, "imageHash", ImageHashAsync);
NODE_SET_METHOD(target, "hammingDistance", HammingDistance);

// methods below are deprecated
NODE_SET_METHOD(target, "oldHash", oldHash);
NODE_SET_METHOD(target, "imagehash", ImageHashSync);
}

NODE_MODULE(pHash, RegisterModule);
112 changes: 71 additions & 41 deletions test/test.js
Original file line number Diff line number Diff line change
@@ -1,52 +1,82 @@
var should = require('should');

var assert = require("assert");
var pHash = require('../index');
require("should");

var examples = [
{ path: "./examples/a.jpg", hash: "2816561582497829945" },
{ path: "./examples/b.png", hash: "2816561582497829945" },
{ path: "./examples/c.png", hash: "15433968795834791622" },
{ path: "./examples/d.jpg", hash: "12040987020241900649" }
];

describe('pHash', function() {
var oldHashA = pHash.getOldHash('./examples/a.jpg');

var hashA = pHash.getImageHash("./examples/a.jpg");
var hashB = pHash.getImageHash("./examples/b.png");
var hashC = pHash.getImageHash("./examples/c.png");
var hashD = pHash.getImageHash("./examples/d.jpg");
describe("pHash", function() {
describe("sync test", function() {
it("should match", function() {
examples.forEach(function(i) {
var hash = pHash.imageHashSync(i.path);
assert.equal(i.hash, hash);
})

//not really an image attempting to create an exception
var hashF = pHash.getImageHash("./examples/f.png");
it("should fail", function() {
var hashF = pHash.imageHashSync("./examples/f.png");
hashF.should.equal('0');
});
})
});

// nonRBG image
var hashG = pHash.getImageHash("./examples/g.jpg");
describe("async test", function() {
var test = examples[0];
examples.forEach(function(i) {
it("should match", function(done) {
pHash.imageHash(i.path, function(err, hash) {
if (err) {
done(err);
}

// empty image
var hashH = pHash.getImageHash("./examples/h.jpg");
assert.equal(i.hash, hash);
done();
});
});
});

describe('getImageHash()', function() {
it('should be done', function() {
oldHashA.should.equal(2816561582497830000);

hashA.should.equal('2816561582497829945');
hashB.should.equal('2816561582497829945');
hashC.should.equal('15433968795834791622');
hashD.should.equal('12040987020241900649');
it("should fail", function(done) {
pHash.imageHash("./examples/f.png", function(err, hash) {
assert(err);
done();
});
});

hashF.should.equal('0');
hashG.should.equal('18182116099082822440');
hashF.should.equal('0');
it("should throw", function() {
assert.throws(function() {
pHash.imageHash("not enough arguments");
});
})
});
});

describe('hammingDistance()', function() {
it('should be done', function() {
var hammingAB = pHash.hammingDistance(hashA,hashB);
var hammingAC = pHash.hammingDistance(hashA,hashC);
var hammingBC = pHash.hammingDistance(hashB,hashC);
var hammingAD = pHash.hammingDistance(hashA,hashD);

hammingAB.should.equal(0);
hammingAC.should.equal(38);
hammingBC.should.equal(38);
hammingAD.should.equal(12);

describe("legacy test", function() {
it("should match", function() {
examples.forEach(function(i) {
var hash = pHash.getImageHash(i.path);
assert.equal(i.hash, hash);
});
});

it("should fail", function() {
var hashF = pHash.getImageHash("./examples/f.png");
hashF.should.equal('0');
});
});
});

});
describe('hammingDistance()', function() {
it('should be done', function() {
var hammingAB = pHash.hammingDistance(examples[0].hash,examples[1].hash);
var hammingAC = pHash.hammingDistance(examples[0].hash,examples[2].hash);
var hammingBC = pHash.hammingDistance(examples[1].hash,examples[2].hash);
var hammingAD = pHash.hammingDistance(examples[1].hash,examples[3].hash);
hammingAB.should.equal(0);
hammingAC.should.equal(38);
hammingBC.should.equal(38);
hammingAD.should.equal(12);
});
});
});

0 comments on commit e0cd3fb

Please sign in to comment.