Created
January 13, 2021 17:29
-
-
Save pete-rai/35e728c2ac55cc8356661881b71d8188 to your computer and use it in GitHub Desktop.
Find an image within another image using nodejs, using the node sharp library (https://www.npmjs.com/package/sharp). Note: This does not handle PNG transparencies - I may add that next - let me know if you need it.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const sharp = require('sharp'); | |
async function findImageWithinImage(outer, inner, max = 1) // max is the maximum occurences to find | |
{ | |
let file_o = sharp(outer); | |
let file_i = sharp(inner); | |
let buff_o = await file_o.raw().toBuffer(); | |
let buff_i = await file_i.raw().toBuffer(); | |
let meta_o = await file_o.metadata(); | |
let meta_i = await file_i.metadata(); | |
let size_o = meta_o.width * meta_o.channels; | |
let size_i = meta_i.width * meta_i.channels; | |
let upper = buff_i.slice(0, size_i); // upper row of inner | |
let found = -1; | |
let finds = []; | |
if (meta_i.width <= meta_o.width && meta_i.height <= meta_o.height) { // must be containable within | |
do { | |
found = buff_o.indexOf(upper, found + 1); // upper row is present, so its another candidate | |
if (found != -1) { | |
let matches = true; | |
let oy = Math.floor(found / size_o); | |
let ox = Math.floor((found - size_o * oy) / meta_o.channels); | |
for (let y = 1; matches && y < meta_i.height; y++) { // start from one as upper row is already matched | |
let pos_i = y * size_i; | |
let pos_o = y * size_o + found; | |
let slice_i = buff_i.slice(pos_i, pos_i + size_i); | |
let slice_o = buff_o.slice(pos_o, pos_o + size_i); | |
matches &= slice_o.equals(slice_i); // does next row also match? | |
} | |
if (matches) { | |
finds.push({ x: ox, y: oy, w: meta_i.width, h: meta_i.height }); | |
/* await sharp(outer) // uncomment this to see the extracted images - which are the same as inner | |
.extract({ left: finds[finds.length - 1].x, | |
top: finds[finds.length - 1].y, | |
width: finds[finds.length - 1].w, | |
height: finds[finds.length - 1].h }) | |
.toBuffer() | |
.then(buffer => sharp(buffer).toFile(`found_${finds.length}.png`)); */ | |
} | |
} | |
} | |
while (found != -1 && finds.length < max); | |
} | |
return finds; | |
} | |
/* | |
An example output would look like the object below. Here there are three | |
occurences of 'inner' inside 'outer', each at the specified (x, y) position | |
in outer: | |
[ | |
{ x: 42, y: 157, w: 107, h: 109 }, | |
{ x: 1131, y: 1015, w: 107, h: 109 }, | |
{ x: 122, y: 1656, w: 107, h: 109 } | |
] | |
An example call would be: | |
let finds = await findImageWithinImage('screen.png', 'sprite.png', 99); | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment