HTML5 canvas conversion - monitor pixel to canvas point - html5-canvas

As I haven't found anything about this I wonder if I missed a simple thing:
canvas#cvs1 {
width: 32px;
height: 32px;
}
var context = cvs1.getContext("2d");
context.beginPath();
context.moveTo(0, 0);
context.lineTo(16, 32);
context.lineTo(32, 32);
context.closePath();
If I draw a triangle onto the canvas the triangle is about 3x3 pixels (and not 32x32 like I thougth) so what do I miss that the coordinates from context.lineTo(32, 32); don't reflect the pixels from width/heigth of the canvas?

Don't use CSS to resize the canvas. Resizing with CSS "shrinks" each pixel on the canvas and results in your mini-triangle.
// the canvas is 300px by 150px size by default
// This CSS causes each pixel to be squished in size to
// 32/300 wide and 32/150 high
canvas#cvs1 { width: 32px; height: 32px; }
Instead, resize the canvas element itself:
cvs1.width=32;
cvs1.height=32;

Related

How to crop the canvas to fit a specific area size in Fabric js

Among the functions of fabric js, there is a method or property that crops objects except canvas, but I did not find a function to crop the canvas itself. I tried changing the canvas to an image in the following way, cropping it, and then inserting it back into the canvas.
fabric.Image.fromURL(canvas.toDataURL(), img => {
currentImage = img; //save current canvas as image
currentImage.set({
scaleX : canvas.width / currentImage.width,
scaleY : canvas.height / currentImage.height,
cropX: selectionRect.left,
cropY: selectionRect.top,
width: selectionRect.getScaledWidth(),
height: selectionRect.getScaledHeight(),
});
canvas.setDimensions({
width: selectionRect.getScaledWidth(),
height: selectionRect.getScaledHeight()
});
canvas.setBackgroundImage(currentImage).renderAll();
but in this case, an image with a transparent background becomes a background.
If you look at the following picture, a picture of a flower without a background is on the canvas, and What I want is to resize the canvas by the dotted rectangle area without making any objects on the canvas an image as follows.
before crop:
after crop:
Just as the starting range and area are determined with attributes such as cropX or cropY when cropping an object, I would like to know how to apply this to the canvas as well.

How to make sure image alway include entire clipping Rect inside while it's transforming (move, scale) in fabric.js?

I have a Image with a simple clipping Rect ( rotate 30 degree with size 200x200 to make a small view part of image ). My problem is how to prevent Image move or scale outside clipping rect ( that mean Image need alway include entire clipping Rect )?
Here is my code:
var canvasObject = document.getElementById("editorCanvas");
// set canvas equal size with div
$(canvasObject).width($("#canvasContainer").width());
$(canvasObject).height($("#canvasContainer").height());
var canvas = new fabric.Canvas('editorCanvas', {
backgroundColor: 'white',
selectionLineWidth: 2,
width: $("#canvasContainer").width(),
height: $("#canvasContainer").height()
});
// create a clipping path
var rectClippingPath = new fabric.Rect({
top: 100,
left: 200,
width: 200,
height: 200,
fill: 'red',
angle: 30,
absolutePositioned: true
});
// create image
var newImage = new fabric.Image();
newImage.clipPath = rectClippingPath;
canvas.add(newImage);
newImage.setSrc('http://fabricjs.com/assets/pug_small.jpg', (imageObject) => {
newImage.set({ left: 50, top: 50});
canvas.setActiveObject(newImage);
newImage.setCoords();
canvas.requestRenderAll();
})
#canvasContainer {
width: 100%;
height: 100vh;
background-color: gray;
}
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.6.6/fabric.min.js" integrity="sha512-XcwgBTqf2CXR/nsswCV1e0j9CjXo87APyBsATK2/l7MvTpcIG0QYKA87v5KIJ4RS6ytArv2pWD6UcRorKhYp1A==" crossorigin="anonymous"></script>
<div id="canvasContainer">
<canvas id="editorCanvas"></canvas>
</div>
And here are some example cases:
Here is expected result:
Thank you!
I can't see a way to achieve it based on your example. I think it needs a structural change. You can do it by having a parent element with all controls and then a child element (image object).
Whenever you move the parent frame you should force the photo to move by the same amount, whenever you scale the frame you should also proportionally scale the child photo, same with rotation.
Let's say you rotate the parent frame, now in order to manipulate the photo inside you will need some kind of activating trigger: double click or a button. That will make sure you are not moving the parent frame, but the child.
While you move the child photo you will need to force it to stay contained within the parent frame borders. This is not hard if both elements have a rotation of 0, 90, 180, 270, 360 degrees. It is much harder to make it nice and smooth for all other rotation angles. You can find a working, but not perfect solution here: Contain a rotated object inside another rotated object FabricJS. I also started working on a smoother solution for that, but it is not completed https://codesandbox.io/s/force-contain-of-object-inside-another-object-fabric-js-v3-j38sz.
Implementing this solution you will most probably encounter also an issue having with rotating. It's easy to rotate an child image and the parent if they have the same origin point, but if you move the child and try to rotate the parent, then you will need to rotate them considering a different origin point. Here is a solution to this: https://codesandbox.io/s/rotation-of-an-object-with-different-rotation-origin-fabric-js-362-8m4cb?file=/src/index.js
You can also visit this platform and have look at similar ideas https://diamondphoto.co.nz/. It is build in Fabric JS version 3.

FabricJS: How to auto-resize image to fit group or rectangle object?

Goal: I'm seeking to add an image to a FabricJS group or rectangle object, and for the image to maintain it's original aspect ratio and center fit it's parent width/height.
I don't want the image overflow to show, but will show the overflow as a less opaque green in the examples below:
Landscape Image Example:
If it was a landscape oriented image, it would scale to max height, but then center itself with regards to width placement:
Since I'm not looking for the image overflow to show, the final product should look like this:
Portrait Image Example:
Similarly, if the image was portrait oriented, the image would scale 100% in width, but center itself in height:
And then negating the overflow, this is what I'm looking for as a final product:
Here's my stackblitz so far: https://stackblitz.com/edit/angular-gpfkkw
With the base-case code as follows:
this.canvas = new fabric.Canvas('canvas');
var rect = new fabric.Rect({
left: 100,
top: 50,
width: 450,
height: 200,
fill: '#e3e3e3',
});
var rectGroup = new fabric.Group([rect], {
name: 'Rectangle',
});
this.canvas.add(rectGroup);
fabric.Image.fromURL('https://placehold.it/888x500&text=16:9', (img) => {
let bounds = rectGroup.getBoundingRect();
const scaleFactor = Math.min(
Math.min(bounds.width / img.width),
Math.min(bounds.height / img.height)
);
img.scale(scaleFactor);
img.set({
top: bounds.top + Math.max(bounds.height - img.height * scaleFactor, 0)/2,
left: bounds.left + Math.max(bounds.width - img.width * scaleFactor, 0)/2,
});
rectGroup.addWithUpdate(img);
this.canvas.renderAll();
}
This is obviously not the right solution, but a start. Any advice?
I figured it out, here's the Stackblitz: https://stackblitz.com/edit/angular-yoo8h5
First, I compared whether or not the rectangle aspect ratio is proportional to the image through an if/else statement which decides whether or not to initially scale the image to the rectangle width/height.
Then I set either the top or the left attribute of the image to the rectangle boundary point. Then calculating the center point of the rectangle and subtracting half of the image's boundary and lastly, setting the rectangle group object's clipPath to that of the rectangle, it worked!
fabric.Image.fromURL('https://placehold.it/888x500&text=16:9', (img) => {
let bounds = rectGroup.getBoundingRect();
if ((bounds.height / bounds.width) >= (img.height / img.width)) {
img.scaleToHeight(bounds.height);
img.set({
top: bounds.top,
left: (bounds.left + (bounds.width/2)) - (img.getBoundingRect().width/2)
});
}
else {
img.scaleToWidth(bounds.width);
img.set({
top: (bounds.top + (bounds.height/2)) - (img.getBoundingRect().height/2),
left: bounds.left
});
}
rectGroup.addWithUpdate(img);
rectGroup.clipPath = rect;
this.canvas.renderAll();
});
A bit late here but chipping in in case this might be helpful.
You were heading in the right direction with Math.min, but you can use Math.max instead for the side with the larger group/image ratio to scale to the full length of the side. You can then set the x y origins to center.
fabric.Image.fromURL('https://placehold.it/888x500&text=16:9', (img) => {
let bounds = rectGroup.getBoundingRect();
const scaleFactor = Math.max(bounds.width / img.width, bounds.height / img.height);
img.set({
originX: 'center',
originY: 'center',
scaleX: scaleFactor,
scaleY: scaleFactor
});
rectGroup.addWithUpdate(img);
this.canvas.renderAll();
}

Image object color change using kineticjs

I am trying to convert an image to another color using kineticjs, actually my image will be on a layer and also a png one can i change only the image objects color? any help will be very greatful
You can replace non-transparent pixels with a new color using compositing.
In particular source-atop compositing will replace all existing non-transparent pixels with any color you draw.
KineticJS does not currently offer compositing out-of-the-box, but you can easily use an html5 Canvas element to do the compositing and then use that element as an image source for a Kinetic.Image element.
Here's example code and a Demo:
var stage = new Kinetic.Stage({
container: 'container',
width: 350,
height: 350
});
var layer = new Kinetic.Layer();
stage.add(layer);
var canvas=document.createElement('canvas');
var ctx=canvas.getContext('2d');
var kImage;
var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/flower.png";
function start(){
cw=canvas.width=img.width;
ch=canvas.height=img.height;
ctx.drawImage(img,0,0);
kImage=new Kinetic.Image({
image:canvas,
width:img.width,
height:img.height,
draggable:true,
});
layer.add(kImage);
layer.draw();
document.getElementById('makeGreen').onclick=function(){
ctx.globalCompositeOperation='source-atop';
ctx.fillStyle='lightgreen';
ctx.fillRect(0,0,cw,ch);
layer.draw();
};
document.getElementById('makeOriginal').onclick=function(){
ctx.globalCompositeOperation='source-over';
ctx.drawImage(img,0,0);
layer.draw();
};
}
body{padding:20px;}
#container{
border:solid 1px #ccc;
margin-top: 10px;
width:350px;
height:350px;
}
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v5.1.0.min.js"></script>
<button id=makeGreen>Green</button>
<button id=makeOriginal>Original</button>
<div id="container"></div>

dropzone - change the thumbnail size

I want to upload one file and set the width and height to fit in a given div, depending on the file size. e.g.:
div size: width: 600px, height: 300px
img size: width: 1200px, height: 400px
the thumb gets created with width 600 and height 300 (by using thumbnailWidth and thumbnailHeight options)
on success I receive the filesize. In the example case I let the width of the image and div at 600px, but I want to change the height to 200 (So that the image doesn't get deformed)
My problem now is that the image src (data) still has a width of 300px
Any ideas how to fix that? THANKS!
Change the resize fonction like this:
https://github.com/enyo/dropzone/issues/236
,
resize: function(file) {
var info;
// drawImage(image, srcX, srcY, srcWidth, srcHeight, trgX, trgY, trgWidth, trgHeight) takes an image, clips it to
// the rectangle (srcX, srcY, srcWidth, srcHeight), scales it to dimensions (trgWidth, trgHeight), and draws it
// on the canvas at coordinates (trgX, trgY).
info = {
srcX:0,
srcY:0,
srcWidth: file.width,
srcHeight: file.height,
trgX:0,
trgY:0,
trgWidth: this.options.thumbnailWidth,
trgHeight: parseInt(this.options.thumbnailWidth * file.height / file.width)
}
return info;
},

Resources