Skip to content

Commit

Permalink
Merge pull request #1240 from stephenplusplus/spp--1239
Browse files Browse the repository at this point in the history
vision: support image URLs
  • Loading branch information
callmehiphop committed May 2, 2016
2 parents eeafb33 + 25f56bf commit 7a508f6
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 3 deletions.
36 changes: 33 additions & 3 deletions lib/vision/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ var fs = require('fs');
var is = require('is');
var nodeutil = require('util');
var prop = require('propprop');
var request = require('request');

/**
* @type {module:storage/file}
Expand Down Expand Up @@ -183,7 +184,7 @@ Vision.prototype.annotate = function(requests, callback) {
*
* @param {string|string[]|module:storage/file|module:storage/file[]} images -
* The source image(s) to run the detection on. It can be either a local
* image path or a gcloud File object.
* image path, a remote image URL, or a gcloud File object.
* @param {string[]|object=} options - An array of types or a configuration
* object.
* @param {number} options.maxResults - The maximum number of results, per type,
Expand Down Expand Up @@ -218,6 +219,16 @@ Vision.prototype.annotate = function(requests, callback) {
* });
*
* //-
* // Run feature detection over a remote image.
* //
* // *Note: This is not an officially supported feature of the Vision API. Our
* // library will make a request to the URL given, convert it to base64, and
* // send that upstream.*
* //-
* var img = 'https://upload.wikimedia.org/wikipedia/commons/5/51/Google.png';
* vision.detect(img, types, function(err, detection, apiResponse) {});
*
* //-
* // Supply multiple images for feature detection.
* //-
* var images = [
Expand Down Expand Up @@ -1155,8 +1166,9 @@ Vision.convertToBoolean_ = function(baseLikelihood, object) {

/**
* Determine the type of image the user is asking to be annotated. If a
* {module:storage/file}, convert to its "gs://{bucket}/{file}" URL. If a file
* path, convert to a base64 string.
* {module:storage/file}, convert to its "gs://{bucket}/{file}" URL. If a remote
* URL, read the contents and convert to a base64 string. If a file path to a
* local file, convert to a base64 string.
*
* @private
*/
Expand All @@ -1178,6 +1190,24 @@ Vision.findImages_ = function(images, callback) {
return;
}

// File is a URL.
if (/^http/.test(image)) {
request({
method: 'GET',
uri: image,
encoding: 'base64'
}, function(err, resp, body) {
if (err) {
callback(err);
return;
}

callback(null, { content: body });
});

return;
}

// File exists on disk.
fs.readFile(image, { encoding: 'base64' }, function(err, contents) {
if (err) {
Expand Down
25 changes: 25 additions & 0 deletions system-test/vision.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
'use strict';

var assert = require('assert');
var fs = require('fs');
var http = require('http');
var is = require('is');
var multiline = require('multiline');
var normalizeNewline = require('normalize-newline');
Expand All @@ -37,6 +39,29 @@ describe('Vision', function() {
vision = new Vision(env);
});

it('should detect from a URL', function(done) {
var server = http.createServer(function(req, res) {
fs.readFile(IMAGES.logo, function(err, resp) {
assert.ifError(err);
res.end(resp);
});
});

server.listen(8800, function(err) {
assert.ifError(err);

var url = 'http://localhost:8800/logo.png';

vision.detect(url, ['logos'], function(err, logos) {
assert.ifError(err);

assert.deepEqual(logos, ['Google']);

done();
});
});
});

it('should perform multiple detections', function(done) {
var detectionTypes = ['faces', 'labels', 'safeSearch'];

Expand Down
46 changes: 46 additions & 0 deletions test/vision/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ function FakeFile() {
this.calledWith_ = arguments;
}

var requestOverride = null;
var fakeRequest = function() {
return (requestOverride || util.noop).apply(this, arguments);
};

describe('Vision', function() {
var IMAGE = './image.jpg';
var PROJECT_ID = 'project-id';
Expand All @@ -50,6 +55,7 @@ describe('Vision', function() {
var vision;

before(function() {
mockery.registerMock('request', fakeRequest);
mockery.registerMock('../../lib/storage/file.js', FakeFile);
mockery.registerMock('../../lib/common/service.js', FakeService);
mockery.registerMock('../../lib/common/util.js', fakeUtil);
Expand All @@ -68,6 +74,8 @@ describe('Vision', function() {
});

beforeEach(function() {
requestOverride = null;

vision = new Vision({
projectId: PROJECT_ID
});
Expand Down Expand Up @@ -766,6 +774,44 @@ describe('Vision', function() {
});
});

it('should get a file from a URL', function(done) {
var imageUri = 'http://www.google.com/logo.png';
var body = 'body';

requestOverride = function(reqOpts, callback) {
assert.strictEqual(reqOpts.method, 'GET');
assert.strictEqual(reqOpts.uri, imageUri);
assert.strictEqual(reqOpts.encoding, 'base64');

callback(null, {}, body);
};

Vision.findImages_(imageUri, function(err, images) {
assert.ifError(err);
assert.deepEqual(images, [
{
content: body
}
]);
done();
});
});

it('should return an error from reading a URL', function(done) {
var imageUri = 'http://www.google.com/logo.png';

var error = new Error('Error.');

requestOverride = function(reqOpts, callback) {
callback(error);
};

Vision.findImages_(imageUri, function(err) {
assert.strictEqual(err, error);
done();
});
});

it('should read from a file path', function(done) {
tmp.setGracefulCleanup();

Expand Down

0 comments on commit 7a508f6

Please sign in to comment.