UNPKG

imghash-turbo

Version:

Image perceptual hash calculation for node with native jpeg-turbo

129 lines (115 loc) 2.61 kB
'use strict'; const imageType = require('image-type'); const fs = require('fs'); const jpeg = require('jpeg-turbo'); const PNG = require('png-js'); const bmp = require("bmp-js"); const blockhash = require('blockhash'); function hash(filepath, bits, format) { format = format || 'hex'; if (format !== 'hex' && format !== 'binary') throw new Error('Unsupported format'); bits = bits || 8; if (bits % 4 !== 0) throw new Error('Invalid bitlength'); return new Promise((resolve, reject) => { if (Buffer.isBuffer(filepath)) { return resolve(filepath); } fs.readFile(filepath, (err, content) => { if (err) return reject(err); resolve(content); }); }) .then((fdata) => { const ftype = imageType(fdata); if (ftype.mime === 'image/bmp') { return bmp.decode(fdata); } if (ftype.mime === 'image/jpeg') { return jpeg.decompressSync(fdata, { format: jpeg.FORMAT_RGBA }); } if (ftype.mime === 'image/png') { return new Promise((resolve, reject) => { let png = new PNG(fdata); png.decode((pixels) => { resolve({ width: png.width, height: png.height, data: pixels }); }); }); } throw new Error('Unsupported image type'); }) .then((data) => hashRaw(data, bits)) .then((hexHash) => { if (format === 'hex') return hexHash; if (format === 'binary') return hexToBinary(hexHash); }); } function hashRaw(data, bits) { return blockhash.blockhashData(data, bits, 2); } function hexToBinary(s) { const lookup = { '0': '0000', '1': '0001', '2': '0010', '3': '0011', '4': '0100', '5': '0101', '6': '0110', '7': '0111', '8': '1000', '9': '1001', 'a': '1010', 'b': '1011', 'c': '1100', 'd': '1101', 'e': '1110', 'f': '1111', 'A': '1010', 'B': '1011', 'C': '1100', 'D': '1101', 'E': '1110', 'F': '1111' }; let ret = ''; for (let i = 0; i < s.length; i++) { ret += lookup[s[i]]; } return ret; } function binaryToHex(s) { const lookup = { '0000': '0', '0001': '1', '0010': '2', '0011': '3', '0100': '4', '0101': '5', '0110': '6', '0111': '7', '1000': '8', '1001': '9', '1010': 'a', '1011': 'b', '1100': 'c', '1101': 'd', '1110': 'e', '1111': 'f' }; let ret = ''; for (let i = 0; i < s.length; i += 4) { let chunk = s.slice(i, i + 4); ret += lookup[chunk]; } return ret; } module.exports = { hash, hashRaw, hexToBinary, binaryToHex };