I am going to start working on a new project that requires me to crop images based on poly selection. The challenge is to allow the front end user to be able to quickly select an area in an image and then crop it. To make the process easier for the user I am thinking to provide some functionality similar to magic-wand tool in photoshop.
I found this library -
This works fine, but only let me select the area once.
My question is, is it possible to add features of multiple selections and remove a selection from the area already selected.
Check this demo fiddle to see what I am referring to - jsfiddle(dot)net/Tamersoul/dr7Dw/
I am going to start working on a new project that requires me to crop images based on poly selection. The challenge is to allow the front end user to be able to quickly select an area in an image and then crop it. To make the process easier for the user I am thinking to provide some functionality similar to magic-wand tool in photoshop.
I found this library - https://github./Tamersoul/magic-wand-js
This works fine, but only let me select the area once.
My question is, is it possible to add features of multiple selections and remove a selection from the area already selected.
Check this demo fiddle to see what I am referring to - jsfiddle(dot)net/Tamersoul/dr7Dw/
Share Improve this question asked Jun 7, 2015 at 22:27 maurya8888maurya8888 2531 gold badge4 silver badges11 bronze badges 2- 1 Might be easier to start with an image editor that has already been written. See this example on MDN Demo Studio called MiniPaint. Includes image cropping and magic wand tools. – Yogi Commented Jun 7, 2015 at 22:50
- 3 "Happiness does not e from doing easy work but from the afterglow of satisfaction that es after the achievement of a difficult task that demanded our best." Theodore Isaac Rubin – rafaelcastrocouto Commented Jun 8, 2015 at 2:56
1 Answer
Reset to default 8github. Magic-Wand-js
jsbin. Demo
$(function() {
var colorThreshold = 15,
blurRadius = 5,
simplifyTolerant = 0,
simplifyCount = 30,
hatchLength = 4,
hatchOffset = 0,
imageInfo = null,
cacheInd = null,
cacheInds = [],
downPoint = null,
mask = null,
masks = [],
allowDraw = false,
currentThreshold = colorThreshold;
$('#upload').on('change', function () {
var inp = this;
if (inp.files && inp.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
var img = $('#test');
img.attr('src', e.target.result);
img.on('load', function() {
resetCache();
var canvas = $('#canvas')[0];
imageInfo = {
width: img.width(),
height: img.height(),
context: canvas.getContext("2d")
};
canvas.width = imageInfo.width;
canvas.height = imageInfo.height;
var tempCanvas = document.createElement('canvas'),
tempCtx = tempCanvas.getContext("2d");
tempCanvas.width = imageInfo.width;
tempCanvas.height = imageInfo.height;
tempCtx.drawImage(img[0], 0, 0);
imageInfo.data = tempCtx.getImageData(0, 0, imageInfo.width, imageInfo.height).data;
});
};
reader.readAsDataURL(inp.files[0]);
}
});
$('#blur').on('change keyup', function () {
blurRadius = Number($(this).val()) || 0;
magic();
});
$('#threshold').on('change keyup', function () {
currentThreshold = Number($(this).val()) || 0;
magic();
});
$('#canvas').on('click', function (e) {
var p = $(e.target).offset(),
x = Math.round((e.clientX || e.pageX) - p.left),
y = Math.round((e.clientY || e.pageY) - p.top);
downPoint = { x: x, y: y };
magic();
});
var magic = function () {
if (imageInfo) {
var image = {
data: imageInfo.data,
width: imageInfo.width,
height: imageInfo.height,
bytes: 4
};
mask = MagicWand.floodFill(image, downPoint.x, downPoint.y, currentThreshold);
mask = MagicWand.gaussBlurOnlyBorder(mask, blurRadius);
masks.push(mask);
cacheInds.push(MagicWand.getBorderIndices(mask));
drawBorder(true);
}
};
var drawBorder = function () {
if (masks.length) {
var x, y, k, i, j, m,
w = imageInfo.width,
h = imageInfo.height,
ctx = imageInfo.context,
imgData = ctx.createImageData(w, h),
res = imgData.data;
ctx.clearRect(0, 0, w, h);
for (m = 0; m < masks.length; m++) {
cacheInd = cacheInds[m];
for (j = 0; j < cacheInd.length; j++) {
i = cacheInd[j];
x = i % w; // calc x by index
y = (i - x) / w; // calc y by index
k = (y * w + x) * 4;
if ((x + y + hatchOffset) % (hatchLength * 2) < hatchLength) {
// detect hatch color
res[k + 3] = 255; // black, change only alpha
} else {
res[k] = 255; // white
res[k + 1] = 255;
res[k + 2] = 255;
res[k + 3] = 255;
}
}
}
ctx.putImageData(imgData, 0, 0);
}
};
setInterval(function () {
hatchOffset = (hatchOffset + 1) % (hatchLength * 2);
drawBorder();
}, 100);
$('#trace').on('click', function () {
var ctx = imageInfo.context;
ctx.clearRect(0, 0, imageInfo.width, imageInfo.height);
for (var m = 0; m < masks.length; m++) {
// draw contours
var i, j, ps, cs = MagicWand.traceContours(masks[m]);
cs = MagicWand.simplifyContours(cs, simplifyTolerant, simplifyCount);
//inner
ctx.beginPath();
for (i = 0; i < cs.length; i++) {
if (cs[i].inner) {
ps = cs[i].points;
ctx.moveTo(ps[0].x, ps[0].y);
for (j = 1; j < ps.length; j++) {
ctx.lineTo(ps[j].x, ps[j].y);
}
}
}
ctx.strokeStyle = 'red';
ctx.stroke();
//outer
ctx.beginPath();
for (i = 0; i < cs.length; i++) {
if (!cs[i].inner) {
ps = cs[i].points;
ctx.moveTo(ps[0].x, ps[0].y);
for (j = 1; j < ps.length; j++) {
ctx.lineTo(ps[j].x, ps[j].y);
}
}
}
ctx.strokeStyle = 'blue';
ctx.stroke();
}
resetCache();
});
var resetCache = function () {
mask = null;
masks = [];
cacheInds = [];
};
});
#display * {
cursor: crosshair;
position: absolute;
}
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.jsdelivr/npm/[email protected]/js/magic-wand.js"></script>
<script src="https://code.jquery./jquery-2.1.1.min.js"></script>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<div id="controls">
<input id="upload" type="file" accept="image/*"/>
<p>Blur radius
<input value="5" id="blur" type="number"/>
</p>
<p>Threshold
<input value="15" id="threshold" type="number"/>
</p>
<button id="trace">Trace</button>
</div>
<div id="display">
<img id="test"/>
<canvas id="canvas"></canvas>
</div>
</body>
</html>