Skip to content

Commit

Permalink
finished buffer support
Browse files Browse the repository at this point in the history
  • Loading branch information
dills122 committed Aug 1, 2020
1 parent 5566cb8 commit 213bce2
Show file tree
Hide file tree
Showing 6 changed files with 1,558 additions and 2,396 deletions.
57 changes: 47 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,27 @@ imageHash('./_95695590_tv039055678.jpg', 16, true, (error, data) => {
console.log(data);
// 0773063f063f36070e070a070f378e7f1f000fff0fff020103f00ffb0f810ff0
});

//Buffer
const fBuffer = fs.readFileSync(__dirname + '/example/_95695591_tv039055678.jpeg');
imageHash({
ext: 'image/jpeg',
data: fBuffer
}, 16, true, (error, data) => {
if(error) throw error;
console.log(data);
// 0773063f063f36070e070a070f378e7f1f000fff0fff020103f00ffb0f810ff0
});

//Buffer, without ext arg
const fBuffer = fs.readFileSync(__dirname + '/example/_95695591_tv039055678.jpeg');
imageHash({
data: fBuffer
}, 16, true, (error, data) => {
if(error) throw error;
console.log(data);
// 0773063f063f36070e070a070f378e7f1f000fff0fff020103f00ffb0f810ff0
});
```

## API
Expand All @@ -49,19 +70,35 @@ imageHash(string|object, int, bool, function)

### Image-Hash Arguments

Argument | Type | Description | Mandatory | Example
--- | --- | --- | --- | ---
location | `object` or `string` | A [RequestJS Object](https://github.com/request/request#requestoptions-callback) or `String` with a valid url or file location | Yes | see above
bits | `int` | The number of bits in a row. The more bits, the more unique the hash. | Yes | 8
precise | `bool` | Whether a precision algorithm is used. `true` Precise but slower, non-overlapping blocks. `false` Quick and crude, non-overlapping blocks. Method 2 is recommended as a good tradeoff between speed and good matches on any image size. The quick ones are only advisable when the image width and height are an even multiple of the number of blocks used. | Yes | `true`
callback | `function` | A function with `error` and `data` arguments - see below |
| Argument | Type | Description | Mandatory | Example |
| -------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------- | --------- |
| location | `object` or `string` | A [RequestJS Object](https://github.com/request/request#requestoptions-callback), `Buffer` object (See input types below for more details), or `String` with a valid url or file location | Yes | see above |
| bits | `int` | The number of bits in a row. The more bits, the more unique the hash. | Yes | 8 |
| precise | `bool` | Whether a precision algorithm is used. `true` Precise but slower, non-overlapping blocks. `false` Quick and crude, non-overlapping blocks. Method 2 is recommended as a good tradeoff between speed and good matches on any image size. The quick ones are only advisable when the image width and height are an even multiple of the number of blocks used. | Yes | `true` |
| callback | `function` | A function with `error` and `data` arguments - see below |

#### Location Object Types

```typescript
// Url Request Object
interface UrlRequestObject {
encoding?: string | null,
url: string | null,
};
// Buffer Object
interface BufferObject {
ext?: string, // mime type of buffered file
data: Buffer,
name?: string // file name for buffered file
};
```

### Callback Arguments

Argument | Type | Description
--- | --- | --- | --- | ---
error | `Error Object` or `null` | If a run time error is detected this will be an `Error Object`, otherwise `null`
data | `string` or `null` | If there is no run time error, this be will be your hashed result, otherwise `null`
| Argument | Type | Description |
| -------- | ------------------------ | ----------------------------------------------------------------------------------- | | |
| error | `Error Object` or `null` | If a run time error is detected this will be an `Error Object`, otherwise `null` |
| data | `string` or `null` | If there is no run time error, this be will be your hashed result, otherwise `null` |

## Development
I have made this with Typescript, ESLint, Jest, Babel and VSCode. All config files and global binaries are included. For developers using VS Code, make sure you have ESLint extension installed.
Expand Down
167 changes: 126 additions & 41 deletions __tests__/main.test.ts
Original file line number Diff line number Diff line change
@@ -1,141 +1,226 @@
import Buffer from 'buffer';
import request from 'request';
import { assert, expect } from 'chai';
import fs from 'fs';
import { imageHash } from '../src/imageHash';

jest.setTimeout(30000);
describe('hash images', () => {
test('should hash a local jpg', (done) => {
it('should hash a local jpg', (done) => {
imageHash('example/_95695590_tv039055678.jpg', 16, true, (err, res) => {
expect(res).toEqual('0773063f063f36070e070a070f378e7f1f000fff0fff020103f00ffb0f810ff0');
expect(res).to.equal('0773063f063f36070e070a070f378e7f1f000fff0fff020103f00ffb0f810ff0');
done();
});
});

test('should hash a local jpg', (done) => {
it('should hash a local jpg', (done) => {
imageHash('example/_95695591_tv039055678.jpeg', 16, true, (err, res) => {
expect(res).toEqual('0773063f063f36070e070a070f378e7f1f000fff0fff020103f00ffb0f810ff0');
expect(res).to.equal('0773063f063f36070e070a070f378e7f1f000fff0fff020103f00ffb0f810ff0');
done();
});
});

test('should hash a local png', (done) => {
it('should hash a local png', (done) => {
imageHash('example/Example.png', 16, true, (err, res) => {
expect(res).toEqual('00007ffe7c3e780e601e603e7ffe7ffe47fe020642067ff66b066a567ffe7ffe');
expect(res).to.equal('00007ffe7c3e780e601e603e7ffe7ffe47fe020642067ff66b066a567ffe7ffe');
done();
});
});

test('should hash a local PNG', (done) => {
it('should hash a local PNG', (done) => {
imageHash('example/Example2.PNG', 16, true, (err, res) => {
expect(res).toEqual('00007ffe7c3e780e601e603e7ffe7ffe47fe020642067ff66b066a567ffe7ffe');
expect(res).to.equal('00007ffe7c3e780e601e603e7ffe7ffe47fe020642067ff66b066a567ffe7ffe');
done();
});
});

test('should throw error when there is a mime type mismatch', (done) => {
it('should throw error when there is a mime type mismatch', (done) => {
imageHash('example/jpgpretendingtobeapng.png', 16, true, (err) => {
expect(err).toBeInstanceOf(Error);
expect(err).instanceOf(Error);
done();
});
});

test('should throw an error when there is no src', (done) => {
it('should throw an error when there is no src', (done) => {
const undef = {};
// @ts-ignore
imageHash(undef.some, 16, true, (err) => {
expect(err).toBeInstanceOf(Error);
expect(err).instanceOf(Error);
done();
});
});

test('Should hash remote image', (done) => {
it('Should hash remote image', (done) => {
imageHash('https://ichef.bbci.co.uk/news/800/cpsprodpb/145F4/production/_106744438_p077xzvx.jpg', 16, true, (err, res) => {
expect(res).toBe('ffffbe7ff83fc03fc43ffc17bc07f807f00ff00ff00fe00ff05fe00fe00fe00f');
done();
if (err) {
return done(err);
}
expect(res).to.equal('dfffbe3ff83fc03fc43ffc17bc07f803f00ff00ff00fe00ff05fe00fe00fe00f');
return done();
});
});

test('Should handle error when url is not found', (done) => {
it('Should handle error when url is not found', (done) => {
imageHash('https://ichef.bbo.co.uk/news/800/cpsprodpb/145F4/production/_106744438_p077xzvx.jpg', 16, true, (err) => {
expect(err).toBeInstanceOf(Error);
expect(err).instanceOf(Error);
done();
});
});

test('Should handle error when file is not found', (done) => {
it('Should handle error when file is not found', (done) => {
imageHash('example/jpgpreten.png', 16, true, (err) => {
expect(err).toBeInstanceOf(Error);
expect(err).instanceOf(Error);
done();
});
});

test('Should hash without jpg ext', (done) => {
it('Should hash without jpg ext', (done) => {
imageHash('example/Example', 16, true, (err, res) => {
expect(res).toBe('00007ffe7c3e780e601e603e7ffe7ffe47fe020642067ff66b066a567ffe7ffe');
expect(res).to.equal('00007ffe7c3e780e601e603e7ffe7ffe47fe020642067ff66b066a567ffe7ffe');
done();
});
});

test('Should handle error when unreconised mime type', (done) => {
it('Should handle error when unreconised mime type', (done) => {
imageHash('example/local-file-js', 16, true, (err) => {
expect(err).toBeInstanceOf(Error);
expect(err).instanceOf(Error);
done();
});
});

test('Should handle error when unreconised mime type', (done) => {
it('Should handle error when unreconised mime type', (done) => {
imageHash('example/giphygif', 16, true, (err) => {
expect(err).toBeInstanceOf(Error);
expect(err).instanceOf(Error);
done();
});
});

test('Should handle jpg with no file extension', (done) => {
it('Should handle jpg with no file extension', (done) => {
imageHash('example/_95695592_tv039055678jpeg', 16, true, (err, res) => {
expect(res).toBe('0773063f063f36070e070a070f378e7f1f000fff0fff020103f00ffb0f810ff0');
expect(res).to.equal('0773063f063f36070e070a070f378e7f1f000fff0fff020103f00ffb0f810ff0');
done();
});
});

test('Should handle local jpg with file extension', (done) => {
it('Should handle local jpg with file extension', (done) => {
imageHash('example/_95695591_tv039055678.jpeg', 16, true, (err, res) => {
expect(res).toBe('0773063f063f36070e070a070f378e7f1f000fff0fff020103f00ffb0f810ff0');
expect(res).to.equal('0773063f063f36070e070a070f378e7f1f000fff0fff020103f00ffb0f810ff0');
done();
});
});

test('Should handle custom request object', (done) => {
it('Should handle custom request object', (done) => {
imageHash({
url: 'https://ichef.bbci.co.uk/news/800/cpsprodpb/145F4/production/_106744438_p077xzvx.jpg',
}, 16, true, (err, res) => {
expect(res).toBe('ffffbe7ff83fc03fc43ffc17bc07f807f00ff00ff00fe00ff05fe00fe00fe00f');
done();
if (err) {
return done(err);
}
expect(res).to.equal('dfffbe3ff83fc03fc43ffc17bc07f803f00ff00ff00fe00ff05fe00fe00fe00f');
done(err);
});
});

test('Should handle url when no extenion provided (#7)', (done) => {
it('Should handle url when no extenion provided (#7)', (done) => {
imageHash({
url: 'https://falabella.scene7.com/is/image/Falabella/prod11830022_6',
}, 16, true, (err, res) => {
expect(res).toBe('80ff807f807f807fcc7fc007c067c077c8f3c183c013ccf7c823c8f3f8f7f8ff');
expect(res).to.equal('80ff807f807f807fcc7fc007c067c077c8f3c183c013ccf7c823c8f3f8f7f8ff');
done();
});
});

test('Should handle local file buffer', (done) => {
it('Should handle local file buffer', (done) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fs.readFile(`${__dirname}/../example/_95695591_tv039055678.jpeg`, (err, data) => {
if (err) {
return done(err);
}
imageHash({
ext: 'image/jpeg',
data,
}, 16, true, (error, res) => {
if (error) {
return done(error);
}
expect(res).equal('0773063f063f36070e070a070f378e7f1f000fff0fff020103f00ffb0f810ff0').and.not.length(0);
return done();
});
});
});

it('Should handle buffer with incorrect mime type', (done) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fs.readFile(`${__dirname}/../example/_95695591_tv039055678.jpeg`, (err, data) => {
if (err) {
return done(err);
}
imageHash({
ext: 'image/jpg',
data,
}, 16, true, (error) => {
expect(error).instanceOf(Error);
return done();
});
});
});

it('Should handle local file buffer, without ext arg', (done) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fs.readFile(`${__dirname}/../example/_95695591_tv039055678.jpeg`, (err, data) => {
if (err) {
return done(err);
}
imageHash({
data,
}, 16, true, (error, res) => {
if (error) {
return done(error);
}
expect(res).equal('0773063f063f36070e070a070f378e7f1f000fff0fff020103f00ffb0f810ff0').and.not.length(0);
return done();
});
});
});

it('Should handle remote file buffer', (done) => {
try {
const testUrl = 'https://ichef.bbci.co.uk/news/800/cpsprodpb/145F4/production/_106744438_p077xzvx.jpg';
// eslint-disable-next-line @typescript-eslint/no-unused-vars
request({ url: testUrl, encoding: null }, (err, _resp, buffer) => {
if (err) {
return done(err);
}
imageHash({
ext: 'image/jpeg',
data: buffer,
}, 16, true, (imgErr, res) => {
if (imgErr) {
return done(err);
}
expect(res).not.length(0).and.equal('dfffbe3ff83fc03fc43ffc17bc07f803f00ff00ff00fe00ff05fe00fe00fe00f');
return done();
});
});
} catch (err) {
return done(err);
}
});

it('Should handle remote file buffer, without ext arg', (done) => {
try {
const testUrl = 'https://www.archives.gov/files/research/american-west/images/west-cover-m.jpgg';
const testUrl = 'https://ichef.bbci.co.uk/news/800/cpsprodpb/145F4/production/_106744438_p077xzvx.jpg';
// eslint-disable-next-line @typescript-eslint/no-unused-vars
request({ url: testUrl, encoding: null }, (err, _resp, buffer) => {
if (err) {
return done(err);
}
imageHash(buffer, 16, true, (err, res) => {
if (err) {
imageHash({
data: buffer,
}, 16, true, (imgErr, res) => {
if (imgErr) {
return done(err);
}
expect(res).not.toHaveLength(0);
console.log(res);
expect(res).not.length(0).and.equal('dfffbe3ff83fc03fc43ffc17bc07f803f00ff00ff00fe00ff05fe00fe00fe00f');
return done();
});
});
Expand Down
8 changes: 0 additions & 8 deletions jest.config.js

This file was deleted.

Loading

0 comments on commit 213bce2

Please sign in to comment.