Skip to content

Commit 05ec3dc

Browse files
authored
Merge pull request #1 from imagekit-developer/feature/phash-distance
Created phash distance function and setup test framework
2 parents d282831 + 9da6685 commit 05ec3dc

File tree

13 files changed

+1828
-23
lines changed

13 files changed

+1828
-23
lines changed

.eslintrc.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
module.exports = {
2+
env: {
3+
browser: true,
4+
commonjs: true,
5+
es6: true,
6+
mocha: true,
7+
},
8+
extends: [
9+
'eslint:recommended',
10+
'airbnb-base',
11+
],
12+
globals: {},
13+
parserOptions: {
14+
ecmaVersion: 2018,
15+
},
16+
rules: {
17+
'max-len': [2, { code: 120 }], // allow line length upto 120 characters (airbnb default is 100)
18+
'no-underscore-dangle': [2, { "allow": ["_id"] }]
19+
},
20+
};

.github/workflows/nodejs.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99

1010
strategy:
1111
matrix:
12-
node-version: [8.x]
12+
node-version: [8.x, 10.x, 12.x]
1313

1414
steps:
1515
- uses: actions/checkout@v1
@@ -19,7 +19,7 @@ jobs:
1919
node-version: ${{ matrix.node-version }}
2020
- name: npm install, build, and test
2121
run: |
22-
npm i -g yarn mocha
22+
npm i -g yarn
2323
yarn install
2424
yarn test
2525
env:

README.md

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,24 @@
1+
12
# NodeJS SDK v2.x for ImageKit
23

4+
[![npm version](https://img.shields.io/npm/v/imagekit)](https://www.npmjs.com/package/imagekit)
5+
[![Twitter Follow](https://img.shields.io/twitter/follow/imagekitio?label=Follow&style=social)](https://twitter.com/ApacheAirflow)
6+
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7+
38
New version of the NodeJS SDK for [ImageKit.io](https://imagekit.io) that implements the new APIs and interface for performing different file operations.
49

510
ImageKit is a complete image optimization and transformation solution that comes with an [image CDN](https://imagekit.io/features/imagekit-infrastructure) and media storage. It can be integrated with your existing infrastructure - storages like AWS S3, web servers, your CDN and custom domain names, allowing you to deliver optimized images in minutes with minimal code changes.
611

12+
##### Table of contents
13+
* [Installation](#installation)
14+
* [Initialization](#initialization)
15+
* [URL generation](#url-generation)
16+
* [File upload](#file-upload)
17+
* [File management](#file-management)
18+
* [Utility functions](#utility-functions)
19+
* [Support](#support)
20+
* [Links](#links)
21+
722
## Installation
823

924
Use the following command to download this module. Use the optional `--save` parameter if you wish to save the dependency in your `package.json` file.
@@ -27,7 +42,7 @@ var imagekit = new ImageKit({
2742
## Usage
2843
You can use this NodeJS SDK for 3 different kinds of functions - URL generation, file uploads and file management. The usage of the SDK has been explained below
2944

30-
### URL Generation
45+
## URL Generation
3146

3247
**1. Using image path and image hostname or endpoint**
3348

@@ -195,7 +210,7 @@ The complete list of transformations supported and their usage in ImageKit can b
195210

196211

197212

198-
### File Upload
213+
## File Upload
199214

200215
The SDK provides a simple interface using the `.upload()` method to upload files to the ImageKit Media Library. It accepts all the parameters supported by the [ImageKit Upload API](https://docs.imagekit.io/imagekit-docs/server-side-file-upload).
201216

@@ -216,7 +231,7 @@ If the upload fails, `error` will be the same as what is received from ImageKit'
216231

217232

218233

219-
### File Management
234+
## File Management
220235

221236
The SDK provides a simple interface for all the [media APIs mentioned here](https://docs.imagekit.io/imagekit-docs/media-api) to manage your files. You can use a callback function with all API interfaces. The first argument of the callback function is the error and the second is the result of the API call. Error will be `null` if the API succeeds.
222237

@@ -296,7 +311,11 @@ imagekit.getPurgeCacheStatus("cache_request_id", function(err, result) {
296311
});
297312
```
298313

299-
### Authentication Parameter Generation
314+
## Utility functions
315+
316+
We have included following commonly used utility functions in this package.
317+
318+
### Authentication parameter generation
300319

301320
In case you are looking to implement client-side file upload, you are going to need a token, expiry timestamp and a valid signature for that upload. The SDK provides a simple method that you can use in your code to generate these authentication parameters for you.
302321

@@ -317,10 +336,44 @@ Returns
317336

318337
Both the `token` and `expire` parameters are optional. If not specified the SDK uses the [uuid](https://www.npmjs.com/package/uuid) package to generate a random token and also generates a valid expiry timestamp internally. The value of the `token` and `expire` used to generate the signature are always returned in the response, no matter if they are provided as an input to this method or not.
319338

339+
### Distance calculation between two pHash values
340+
341+
Perceptual hashing allows you to constructing a hash value that uniquely identifies an input image based on the contents of an image. [ImageKit.io metadata API](https://docs.imagekit.io/imagekit-docs/metadata-api) returns the pHash value of an image in the response. You can use this value to find a duplicate (or similar) image by calculating distance between pHash value of two images.
342+
343+
This SDK exposes `pHashDistance` function to calcualte distance between two pHash values. It accepts two pHash hexadecimal strings and returns a numeric value indicative of the level of difference between the two images.
344+
345+
```
346+
const calculateDistance = () => {
347+
// asynchronously fetch metadata of two uploaded image files
348+
// ...
349+
// Extract pHash strings from both: say 'firstHash' and 'secondHash'
350+
// ...
351+
// Calculate the distance between them:
352+
const distance = imagekit.pHashDistance(firstHash, secondHash);
353+
return distance;
354+
}
355+
```
356+
#### Distance calculation examples
357+
358+
```
359+
imagekit.pHashDistance('f06830ca9f1e3e90', 'f06830ca9f1e3e90');
360+
// output: 0 (same image)
361+
362+
imagekit.pHashDistance('2d5ad3936d2e015b', '2d6ed293db36a4fb');
363+
// output: 17 (similar images)
364+
365+
imagekit.pHashDistance('a4a65595ac94518b', '7838873e791f8400');
366+
// output: 37 (dissimilar images)
367+
```
368+
320369
## Support
321370

322371
For any feedback or to report any issues or general implementation support please reach out to [[email protected]](mailto:[email protected])
323372

373+
## Links
374+
* [Documentation](https://docs.imagekit.io)
375+
* [Main website](https://imagekit.io)
376+
324377
## License
325378

326379
Released under the MIT license.

constants/errorMessages.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,9 @@ module.exports = {
1010
"LIST_FILES_INPUT_MISSING" : { message : "Missing options for list files", help : "If you do not want to pass any parameter for listing, pass an empty object" },
1111
"MISSING_UPLOAD_DATA" : { message : "Missing data for upload", help : "" },
1212
"MISSING_UPLOAD_FILE_PARAMETER" : { message : "Missing file parameter for upload", help : "" },
13-
"MISSING_UPLOAD_FILENAME_PARAMETER" : { message : "Missing fileName parameter for upload", help : "" }
14-
}
13+
"MISSING_UPLOAD_FILENAME_PARAMETER" : { message : "Missing fileName parameter for upload", help : "" },
14+
// pHash errors
15+
"INVALID_PHASH_VALUE": { message: "Invalid pHash value", help: "Both pHash strings must be valid hexadecimal numbers" },
16+
"MISSING_PHASH_VALUE": { message: "Missing pHash value", help: "Please pass two pHash values" },
17+
"UNEQUAL_STRING_LENGTH": { message: "Unequal pHash string length", help: "For distance calucation, the two pHash strings must have equal length" },
18+
};

index.js

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ var signature = require('./libs/signature');
1414
/*
1515
Utils
1616
*/
17+
var pHashUtils = require('./utils/phash');
1718
var transformationUtils = require('./utils/transformation');
1819
var errorMessages = require("./constants/errorMessages");
1920

@@ -28,11 +29,11 @@ var ImageKit = function(opts) {
2829

2930
this.options = _.extend(this.options, opts);
3031
if(!mandatoryParametersAvailable(this.options)) {
31-
throw new Error(errorMessages.MANDATORY_INITIALIZATION_MISSING);
32+
throw new Error(errorMessages.MANDATORY_INITIALIZATION_MISSING.message);
3233
}
3334

3435
if(!transformationUtils.validParameters(this.options)) {
35-
throw new Error(errorMessages.INVALID_TRANSFORMATION_POSITION);
36+
throw new Error(errorMessages.INVALID_TRANSFORMATION_POSITION.message);
3637
}
3738

3839
/*
@@ -53,46 +54,50 @@ var ImageKit = function(opts) {
5354
Image Management APIs
5455
*/
5556

56-
//List and Search Files API
57+
// List and Search Files API
5758
this.listFiles = function(listOptions, callback) {
5859
return manage.listFiles(listOptions, this.options, callback);
5960
};
6061

61-
//Get File Details API
62+
// Get File Details API
6263
this.getFileDetails = function(fileId, callback) {
6364
return manage.getFileDetails(fileId, this.options, callback);
6465
};
6566

66-
//Get File Metadata API
67+
// Get File Metadata API
6768
this.getFileMetadata = function(fileId, callback) {
6869
return manage.getFileMetadata(fileId, this.options, callback);
6970
};
7071

71-
//Update File Details API
72+
// Update File Details API
7273
this.updateFileDetails = function(fileId, updateData, callback) {
7374
return manage.updateFileDetails(fileId, updateData, this.options, callback);
7475
};
7576

76-
//Delete File API
77+
// Delete File API
7778
this.deleteFile = function(fileId, callback) {
7879
return manage.deleteFile(fileId, this.options, callback);
7980
};
8081

81-
//Purge Cache API
82+
// Purge Cache API
8283
this.purgeCache = function(url, callback) {
8384
return manage.purgeCache(url, this.options, callback);
8485
};
8586

86-
//Purge Cache Status API
87+
// Purge Cache Status API
8788
this.getPurgeCacheStatus = function(requestId, callback) {
8889
return manage.getPurgeCacheStatus(requestId, this.options, callback);
8990
};
9091

91-
//To generate Signature for upload request
92+
// To generate Signature for upload request
9293
this.getAuthenticationParameters = function(token, timestamp) {
9394
return signature.getAuthenticationParameters(token, timestamp, this.options);
9495
}
9596

97+
// To calculate distance between two pHash strings
98+
this.pHashDistance = function(firstPHash, secondPHash) {
99+
return pHashUtils.pHashDistance(firstPHash, secondPHash);
100+
}
96101
};
97102

98103
function mandatoryParametersAvailable(options) {

package.json

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,31 @@
11
{
22
"name": "imagekit",
3-
"version": "2.0.0",
3+
"version": "2.0.1",
44
"description": "Offical NodeJS SDK for ImageKit.io integration",
55
"main": "index.js",
66
"scripts": {
7-
"test": "echo \"Error: no test specified\" && exit 1"
7+
"lint": "./node_modules/eslint/bin/eslint.js tests/ utils/phash.js",
8+
"lint:fix": "./node_modules/eslint/bin/eslint.js --fix tests/ utils/phash.js",
9+
"test": "export NODE_ENV=test; ./node_modules/mocha/bin/mocha --exit -t 40000 tests/*.js;ex=$?;unset NODE_ENV; exit $ex;"
810
},
911
"author": "ImageKit Developer <[email protected]>",
1012
"homepage": "https://imagekit.io",
1113
"license": "MIT",
1214
"dependencies": {
15+
"hamming-distance": "^1.0.0",
1316
"lodash": "^4.17.15",
1417
"request": "^2.88.0",
1518
"uuid": "^3.3.3"
1619
},
1720
"engines": {
1821
"node": ">=8.0.0"
22+
},
23+
"devDependencies": {
24+
"chai": "^4.2.0",
25+
"eslint": "^6.5.1",
26+
"eslint-config-airbnb-base": "^14.0.0",
27+
"eslint-plugin-import": "^2.18.2",
28+
"mocha": "^6.2.2",
29+
"sinon": "^7.5.0"
1930
}
2031
}

tests/helpers/errors.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
const errors = require('./../../constants/errorMessages');
2+
3+
module.exports = { ...errors };

tests/helpers/spies.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// packages
2+
const sinon = require('sinon');
3+
// internal modules
4+
const pHashUtils = require('./../../utils/phash');
5+
6+
// spies
7+
const pHashDistanceSpy = sinon.spy(pHashUtils, 'pHashDistance');
8+
9+
module.exports = {
10+
pHashDistanceSpy,
11+
};

tests/index.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// import tests
2+
const phashTests = require('./utils/phash');
3+
4+
describe('ImageKit SDK tests:', () => {
5+
phashTests.run();
6+
});

tests/sdk.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// import module
2+
const ImageKit = require('./../index');
3+
4+
const config = {
5+
publicKey: 'your_public_api_key',
6+
privateKey: 'your_private_api_key',
7+
urlEndpoint: 'https://ik.imagekit.io/your_imagekit_id/',
8+
};
9+
10+
module.exports = new ImageKit(config);

0 commit comments

Comments
 (0)