Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dsteele/buffer support #25

Merged
merged 4 commits into from
Aug 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
183 changes: 146 additions & 37 deletions __tests__/main.test.ts
Original file line number Diff line number Diff line change
@@ -1,122 +1,231 @@
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');
done();
});
expect(res).to.equal('80ff807f807f807fcc7fc007c067c077c8f3c183c013ccf7c823c8f3f8f7f8ff');
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://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({
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);
}
});
});
8 changes: 0 additions & 8 deletions jest.config.js

This file was deleted.

Loading