Wait for the format change of an image - javascript

during a project I need to set up a cropper associated with a face detection. The face detection works well but the cropper modifies the format of the image with its object, the coordinates returned by the facedetector are false. Do you know how to apply the facedetector once the image has been modified with the cropper interface ?
var image = document.getElementById('img');
var cropper = new Cropper(image, {
/* aspectRatio: 9 / 16,*/
// autoCrop: true,
scalable: false,
cropBoxResizable: false,
guides: true,
dragMode: 'none',
preview: '.preview',
data:{
width: 250,
height: 325,
},
crop: function(e) {
$('#x').val(e.detail.x);
$('#y').val(e.detail.y);
$('#w').val(e.detail.width);
$('#h').val(e.detail.height);
},
});
$('#img').faceDetection({
complete: function (faces) {
console.log(faces)
initx = faces[0].x;
inity = faces[0].y;
cropper.data({x:120,y:init});
}
});

You probably need to first, get the coords, then initiate Cropper with those coordinates, like this:
const img = $('img');
img.faceDetection({
complete: function (faces) {
initCropper(faces[0]);
}
});
function initCropper(data) {
cropper = new Cropper(img[0], {
data
});
}
https://jsbin.com/keruzal/edit?js,output

Related

Paste image from clipboard to fabric.js canvas?

I'm trying to create a function that pastes an image from the user's clipboard to the canvas as a new fabric.Image(). Any search result I find either describes cloning objects already on the canvas or pasting IText data. This SO question is related to what I'm asking about, but it's 4 years old and the function in the top answer doesn't work:
How to do Copy and paste the image from User system to Canvas using fabric.js
Here's the code I'm currently trying to use. I'm trying to set up a paste function I can call later:
var $wrapper = $('#content'),
canvas = new fabric.Canvas('canvas', {
width: 400,
height: 550
}),
pasteImage = function (e) {
var items=e.originalEvent.clipboardData.items;
e.preventDefault();
e.stopPropagation();
// Fabric.js image function
function canvasImage(url) {
var img = new fabric.Image(url);
img.scale(0.75).center().setCoords();
canvas.add(img).renderAll();
}
//Loop through files
for(var i=0;i<items.length;i++){
var file = items.items[i],
type = file.type;
if (type.indexOf("image")!=-1) {
var imageData = file.getAsFile();
var imageURL=window.webkitURL.createObjectURL(imageData);
canvasImage(imageURL);
}
}
};
$wrapper.on('paste', pasteImage);
Here's a fiddle to see it in action (or inaction, I guess). This will eventually be part of a Photoshop plugin, so thankfully I only need to worry about this working in Chrome.
I couldn't get your paste event handler to trigger, because i'm not sure if div can natively take the past event unless you make it a contenteditable div, which in your use case i doubt you want to do.
I just recently implemented this in an app of my own, but i wasn't using fabric, just native canvas and js.
You're going to have to rework your code, but try changing
$wrapper.on('paste', pasteImage);
to
$(window).on('paste', pasteImage);
Regardless, I tinkered with your current code, and this is what I got to work, albeit it might not have your settings being triggered completely, but it is pasting the image in:
(function() {
var $wrapper = $('#content'),
canvas = new fabric.Canvas('canvas', {
width: 400,
height: 550
}),
txtStyles = {
top: 100,
left: 200,
padding: 6,
fill: '#d6d6d6',
fontFamily: 'sans-serif',
fontSize: '24',
originY: 'center',
originX: 'center',
borderColor: '#d6d6d6',
cornerColor: '#d6d6d6',
cornerSize: 5,
cornerStyle: 'circle',
transparentCorners: false,
lockUniScaling: true
},
imgAttrs = {
left: 200,
top: 200,
originY: 'center',
originX: 'center',
borderColor: '#d6d6d6',
cornerColor: '#d6d6d6',
cornerSize: 5,
cornerStyle: 'circle',
transparentCorners: false,
lockUniScaling: true
},
introTxt = new fabric.Text('Paste images here', txtStyles),
pasteImage = function (e) {
var items=e.originalEvent.clipboardData.items;
e.preventDefault();
e.stopPropagation();
//Loop through files
for(var i=0;i<items.length;i++){
if (items[i].type.indexOf('image')== -1) continue;
var file = items[i],
type = items[i].type;
var imageData = file.getAsFile();
var URLobj = window.URL || window.webkitURL;
var img = new Image();
img.src = URLobj.createObjectURL(imageData);
fabric.Image.fromURL(img.src, function(img){
canvas.add(img);
});
}
},
//Canvas starter text
introCanvas = function() {
canvas.add(introTxt);
};
introCanvas();
$(window).on('paste', pasteImage);
})();
fiddlers: https://jsfiddle.net/c0kw5dbu/3/

jQuery Cropper, cropbox goes outside my canvas

I'm using jQuery cropper to crop my images. Perfect plugin but I have 1 big issue...
When I set the dimensions to 1920/1080 my Cropbox goes outside my canvas. Is it possible to keep the cropbox inside the canvas and scale the image instead?
Here's my current code:
var cropImgData;
$('#edit-image-' + $id).cropper({
// aspectRatio: $width / $height,
crop: function(data) {
cropImgData = data;
},
cropBoxMovable: false,
cropBoxResizable: false,
dragMode: 'move',
guides: false,
autoCropArea: 0.5,
built: function() {
// $('#edit-image-' + $id).cropper('setData', {"width": 5000, "height": 1000});
$('#edit-image-' + $id).cropper('setCropBoxData', {"width": 1920, "height": 1080})
}
});

Is it possible to make a dynamic mask/crop system via fabric.js that behaves like canva.com?

edit 2016, Oct 24
I've an idea about this feature by using 'pattern' which seems to be a good idea.
I tried to prove my thoughts with this pen, its still buggy but at least we can set the image(pattern) position and keep the original image when double click.
I'am not very good at javascript, So if you are interest in this please help to make this more useable, any discussions/thoughts or code correction is welcome.
http://codepen.io/wushan/pen/LRrQEL?editors=1010
// Create Canvas
var canvas = this.__canvas = new fabric.CanvasEx('c', {
preserveObjectStacking: true
});
fabric.Object.prototype.transparentCorners = false;
// Global Settings
var url = "http://fabricjs.com/assets/pug.jpg";
//Make the Pattern by url
function createMaskedImage(url) {
//Load Image
fabric.Image.fromURL(url, function(img) {
img.scaleToWidth(300);
//Make a Pattern
var patternSourceCanvas = new fabric.StaticCanvas();
patternSourceCanvas.add(img);
var pattern = new fabric.Pattern({
source: function() {
patternSourceCanvas.setDimensions({
width: img.getWidth(),
height: img.getHeight()
});
return patternSourceCanvas.getElement();
},
repeat: 'no-repeat'
});
console.log(pattern.offsetX)
console.log(pattern.offsetY)
console.log(img.getWidth()) // 縮小後 (*scale)
console.log(img.width) // 原尺寸
//Mask (can be any shape ex: Polygon, Circles....)
var rect = new fabric.Rect({
width: 200,
height: 200,
left: 150,
top: 100,
fill: pattern
})
//Bind Double Click Event from fabric.ext
//https://github.com/mazong1123/fabric.ext
rect.on('object:dblclick', function (options) {
//Pass pattern out
enterEditMode(rect, img);
});
canvas.add(rect);
canvas.setActiveObject(rect);
});
}
function enterEditMode(mask, image) {
image.left = mask.left;
image.top = mask.top;
// New Image
// Fake Crop Area (fixed)
var rect = new fabric.Rect({
width: mask.width,
height: mask.height,
left: mask.left,
top: mask.top,
fill: '#000000',
opacity: 0.8,
selectable: false
})
canvas.remove(mask);
canvas.add(image);
image.on('object:dblclick', function (options) {
//Flatten
flatten(rect, image);
});
canvas.add(rect);
// console.log(JSON.stringify(canvas));
}
function flatten(mask, image) {
//Make a Pattern
var patternSourceCanvas = new fabric.StaticCanvas();
patternSourceCanvas.add(image);
var pattern = new fabric.Pattern({
source: function() {
patternSourceCanvas.setDimensions({
width: image.getWidth(),
height: image.getHeight()
});
return patternSourceCanvas.getElement();
},
repeat: 'no-repeat'
});
//Offsets
pattern.offsetX = image.left - mask.left - image.left;
pattern.offsetY = image.top - mask.top - image.top;
var rect = new fabric.Rect({
width: mask.width,
height: mask.height,
left: mask.left,
top: mask.top,
fill: pattern
})
//Bind Double Click Event from fabric.ext
//https://github.com/mazong1123/fabric.ext
rect.on('object:dblclick', function (options) {
//Pass pattern out
enterEditMode(rect, image);
});
canvas.remove(mask);
canvas.remove(image);
canvas.add(rect);
canvas.setActiveObject(rect);
canvas.renderAll();
}
//Button Events
//Create
document.getElementById('createMaskedImage').addEventListener('click', function () {
createMaskedImage(url);
});
Test this :
click 'create'
double click on the image object
move/scale the image
double click the image to flatten the obejct.
Know issue:
when cutting the image without scale, the image position looks correct but there is a wired transparent space.
It generates a lot duplicate objects on the scene...
Original Post
I've been working with fabric.js for a few month, haven't seen any example or discussions about a mask/crop system which is behaves like canva.com ( which is way easy to understand for users. )
the object looks like this:
when double clicked on a group/mask, it shows the original image with an unselectable mask, you can move/scale the image whatever you need and click 'OK' to made the change without modifying the original image.
I'd like to know if there is any possible solutions about making this in fabricjs, or maybe some thoughts about this issue is welcome.
Thank you a lot !

KineticJS dragBoundFunc not working

I've got this calling function
$(document).ready(function(){
$('#change-background').click(function(){
layers['map'] = new Kinetic.Layer();
buildMap(layers['map'],'img/test.png');
stage.add(layers['map']);
});
});
And, I've got this function to display the image
function buildMap(layer, img_src){
var img = new Image();
img.src = img_src;
img.onload = function(e) {
var map = new Kinetic.Image({
id: 'map_img',
x: 0,
y: 0,
image: img,
draggable: true,
dragBoundFunc: function(pos) {
// THIS SHOULD EXECUTE
console.log('hahaha');
return { x:0, y:0 };
}
});
layer.add(map);
layer.draw();
};
}
I have a similar code on a separate project of mine, and it works like a charm.. But its quite awkward that it does not work well here. The image showed up in the canvas, and its draggable, which in this case it should not be because I explicitly returned { x:0, y:0 }(the return values is for my testing only). I also looked at the console logs the 'hahaha' text never appears.. It did not call the function when the image has been dragged. Both of these are inside a <script> tags and in one html document.
Fixed this: http://jsfiddle.net/xpLPT/2/
try :
dragBoundFunc: function(pos) {
console.log('hahaha'); //check the jsfiddle, this does work.
return {
x: this.getAbsolutePosition().x, //constrain vertically
y: this.getAbsolutePosition().y //constrain horizontally
}
}
also change your click function by adding stage.draw();:
$(document).ready(function(){
$('#change-background').click(function(){
//if(layers['map'])
// layers['map'].remove(); // this is optional, but recommended, as it removes the current map layer before adding a new one
layers['map'] = new Kinetic.Layer();
buildMap(layers['map'],'img/test.png');
stage.add(layers['map']);
stage.draw();
});
});
try using a newer version of kinetics:
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.3.0.min.js"></script>

ExtJS4 DragDrop Proxy positioning

In ExtJS 4, by default, the dragdrop proxy is displayed to the right bottom position of the mouse position during drag operation. Let say I click into the center of my target and move my mouse by 1 px. I would like the proxy to itself over the original element, shifted by 1 px.
Basically, I need proxy to behave like the example at http://jqueryui.com/demos/draggable/#sortable. In this example the proxy is over the original element and then moves around when the mouse is dragged.
How can I achieve this?
Here is sample code illustrating the problem when dragging a custom widget.
Ext.onReady(function(){
var hewgt = Ext.define('Demo.widget.Complex', {
extend: 'Ext.panel.Panel',
alias: 'widget.complex',
frameHeader: false,
draggable: false,
layout: 'table',
initComponent: function() {
this.callParent(arguments);
var txtFld;
this.superclass.add.call(this, txtFld = new Ext.form.field.Text({fieldLabel:'test'}));
this.superclass.add.call(this, new Ext.button.Button({text:'Save'}));
}
});
Ext.define('Demo.dd.DragSource', {
extend: 'Ext.dd.DragSource',
b4MouseDown: function(e) {
this.diffX = e.getX() - this.el.getX();
this.diffY = e.getY() - this.el.getY();
this.superclass.setDelta.call(this, 0, 0);
},
getTargetCoord: function(iPageX, iPageY) {
return {x: iPageX - this.diffX, y: iPageY - this.diffY};
}
});
var panel = Ext.create('Ext.panel.Panel', {
layout: 'absolute',
title: 'Navigation'
});
var vp = Ext.create('Ext.container.Viewport', {
layout: 'fit',
items: [panel]
});
var img = Ext.create('Demo.widget.Complex', { width: 400, height:100, x:20, y:20 });
panel.add(img);
new Demo.dd.DragSource(img.getEl());
img = Ext.create('Demo.widget.Complex', { width: 400, height:100, x:20, y:150 });
panel.add(img);
new Demo.dd.DragSource(img.getEl());
});
I am new to Ext JS.
Please let me know how can the dragged proxy be positioned correctly?
Thanks

Categories

Resources