I would like to know if there's a way to draw an image into a canvas using a CSS3 Matrix3D transformation. The used context is a 2D one used to render stacked layers and an image layer transformed with a matrix3D above it (because I didn't manage to have it drawn in the canvas).
So basically what I want to achieve is to convert transform: matrix3d(0.87, 0, 0.5, -0.00025, 0, 1, 0, 0, -0.5, 0, 0.87, 0, 0, 550, 0, 1) into a drawing canvas method in a 2D context.
Is it possible ? For now, I'm quite fine with the CSS3 layer above the canvas but the application I'm developing will have to export the canvas to an actual image file (meant to be sent to the user).
Here's a snippet illustrating my current way of displaying the transformed layer. So the goal here is to actually render the "placeholder" transformed image into the canvas
#canvas {
background: tomato;
height: 100vh;
width: 100vw;
position: relative;
}
.viewport .transformed-layer {
height: 72%;
position: absolute;
left: 35%;
top: calc(21% - 550px);
-webkit-transform: rotate(-1.5deg) matrix3d(0.87, 0, 0.5, -0.00025, 0, 1, 0, 0, -0.5, 0, 0.87, 0, 0, 550, 0, 1);
transform: rotate(-1.5deg) matrix3d(0.87, 0, 0.5, -0.00025, 0, 1, 0, 0, -0.5, 0, 0.87, 0, 0, 550, 0, 1);
opacity: .9;
}
<div class='viewport'>
<div id='canvas'>This is a div simulating the canvas element with some drawed image</div>
<img class='transformed-layer' src='http://via.placeholder.com/300x300' />
</div>
There is one heck of hack that may not fit any future-readers requirements, but which may do for you:
The canvas can draw SVG images, and SVG images can be transformed via CSS.
So you could convert your current canvas to a dataURL, set this dataURL as the href of an SVGImage element, on which you would apply the CSSTransform, before exporting all this as an svg image that you'll draw back on a canvas.
Here is a rough proof of concept:
function getTransformedCanvas(canvas, CSSTransform){
return new Promise(function(res, rej){
var dim = getTransformedDimensions(canvas, CSSTransform);
var xlinkNS = "http://www.w3.org/1999/xlink",
svgNS = 'http://www.w3.org/2000/svg';
var svg = document.createElementNS(svgNS, 'svg'),
defs = document.createElementNS(svgNS, 'defs'),
style = document.createElementNS(svgNS, 'style'),
image = document.createElementNS(svgNS, 'image');
image.setAttributeNS(xlinkNS, 'href', canvas.toDataURL());
image.setAttribute('width', canvas.width);
image.setAttribute('height', canvas.height);
style.innerHTML = 'image{transform:'+CSSTransform+';}';
svg.appendChild(defs);
defs.appendChild(style);
var rect = document.createElement('rect');
svg.appendChild(image);
svg.setAttribute('width', dim.width);
svg.setAttribute('height', dim.height);
var svgStr = new XMLSerializer().serializeToString(svg);
var img = new Image();
img.onload = function(){res(img)};
img.onerror = rej;
img.src = URL.createObjectURL(new Blob([svgStr], {type:'image/svg+xml'}));
});
}
function getTransformedDimensions(canvas, CSSTransform){
var orphan = !canvas.parentNode;
if(orphan) document.body.appendChild(canvas);
var oldTrans = getComputedStyle(canvas).transform;
canvas.style.transform = CSSTransform;
var rect = canvas.getBoundingClientRect();
canvas.style.transform = oldTrans;
if(orphan) document.body.removeChild(canvas);
return rect;
}
// create a simple checkerboard
var canvas = document.createElement('canvas');
canvas.width = canvas.height = 30;
var ctx = canvas.getContext('2d');
ctx.fillStyle = 'orange';
ctx.fillRect(0,0,15, 15);
ctx.fillRect(15,15,15, 15);
var pattern = ctx.createPattern(canvas, 'repeat');
canvas.width = canvas.height = 300;
ctx.fillStyle = pattern;
ctx.fillRect(0,0,300,300);
getTransformedCanvas(canvas,
'translateY(-540px) rotate(-1.5deg) matrix3d(0.87, 0, 0.5, -0.00025, 0, 1, 0, 0, -0.5, 0, 0.87, 0, 0, 550, 0, 1)'
)
.then(function(img){
inScreen.width = img.width;
inScreen.height = img.height;
inScreen.getContext('2d').drawImage(img, 0,0);
})
.catch(console.error);
canvas {
border:1px solid;
}
<canvas id="inScreen"></canvas>
But note that old versions of IE did taint the canvas whenever an svg iamge was drawn on it...
Related
I have an image and it doesn't recognize the new size when I do put size:
here is a fiddle I created to simulate what I'm doing: https://jsfiddle.net/lightblue/w7tq3yrc/7/
As you can see, I already set the width and height of both image and canvas yet it still doesn't "fit" the image to the given size and still follows the original image width and height.
ctx.putImageData(imgd, 20, 20);
How can I make it so it fits with the height and width?
And If you can recommend a good library (if this needs one) I'll gladly listen to that.
The image you are using is 48/48. In order to get a 20/20 image on the canvas you need to do ctx.drawImage(image, 0, 0,20,20);
Also when you get the image data you don't do this: ctx.getImageData(0, 0, 45, 45),. Since you get the image data from a 20/20 canvas you do ctx.getImageData(0, 0, 20, 20)
I hope it helps.
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
image = document.getElementById("testImage");
// Fill screen with red, green, and blue stripes.
ctx.fillStyle = "red";
ctx.fillRect(0, 0, 20, 20);
ctx.drawImage(image, 0, 0,20,20);
var imgd = ctx.getImageData(0, 0, 20, 20),
pix = imgd.data;
for (var i = 0, n = pix.length; i < n; i += 4) {
var r = pix[i],
g = pix[i + 1],
b = pix[i + 2],
a = pix[i + 3];
if (r < 60) {
pix[i + 2] = 20;
}
}
ctx.putImageData(imgd, 20, 20);
canvas {
width: 20px;
height: 20px;
}
#testImage{
width: 20px;
height: 20px;
background-color: green;
}
<h3>Original Image</h3>
<img id="testImage" src='data:;base64,
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' />
<h3>Modified Image</h3>
<canvas id="canvas" width="20" height="20"></canvas>
Why does axis label of Amchart missing, when displaying to PDF after SVG to canvas conversion using canvg parser?
var image1 = $('div.amcharts-chart-div').get(0);
var svg = image1.innerHTML;
if (svg) {
svg = svg.replace(/\r?\n|\r/g, '').trim();
}
var canvas = document.createElement('canvas');
canvg(canvas, svg, {
ignoreMouse: true,
ignoreAnimation: true
});
var ctx = canvas.getContext('2d');
ctx.globalCompositeOperation = 'destination-over'
// set the color
ctx.fillStyle = '#FFFFFF';
// draw the background
ctx.fillRect(0, 0, canvas.width, canvas.height);
var imgData = canvas.toDataURL('image/jpeg', 1.0);
pdf.addImage(imgData, 'JPEG', 15, 115, 180, 100, undefined, 'none');
How can I achieve a blur behind a transparent box (fillStyle = 'rgba(255, 255, 255, 0.2)') in JavaScript canvas? Here's what I've got so far:
var canvas = document.getElementById('draw');
var c = canvas.getContext('2d');
function main() {
c.fillStyle = '#222';
c.fillRect(0, 0, canvas.width, canvas.height);
c.fillStyle = '#000';
c.fillRect(32, 32, 64, 64);
c.fillStyle = 'rgba(255, 255, 255, 0.2)';
c.filter = 'blur(5px)';
c.fillRect(16, 16, 128, 24);
}
But what happens, is instead of blurring the background behind the rectangle, is the rectangle itself is blurred, kind of obviously.
In the final script, I will probably use paths instead of rects.
Context2D filters will be applied only on your new drawings, so to also blur the background, you would actually have to redraw the part of the background you want to be blurred.
Fortunately, canvas can drawImage itself.
var blurredRect = {
x: 80,
y: 80,
height: 200,
width: 200,
spread: 10
};
var ctx = canvas.getContext('2d');
var img = new Image();
img.onload = draw;
img.src = 'https://upload.wikimedia.org/wikipedia/commons/5/55/John_William_Waterhouse_A_Mermaid.jpg';
function draw() {
canvas.width = img.width / 2;
canvas.height = img.height / 2;
// first pass draw everything
ctx.drawImage(img, 0,0, canvas.width, canvas.height);
// next drawings will be blurred
ctx.filter = 'blur('+ blurredRect.spread +'px)';
// draw the canvas over itself, cropping to our required rect
ctx.drawImage(canvas,
blurredRect.x, blurredRect.y, blurredRect.width, blurredRect.height,
blurredRect.x, blurredRect.y, blurredRect.width, blurredRect.height
);
// draw the coloring (white-ish) layer, without blur
ctx.filter = 'none'; // remove filter
ctx.fillStyle = 'rgba(255,255,255,0.2)';
ctx.fillRect(blurredRect.x, blurredRect.y, blurredRect.width, blurredRect.height);
}
<canvas id="canvas"></canvas>
But, canvas blur filter is a bit different than CSS one in that it will make the spreading stay inside the drawn area. This means that in our case, we have a 5px border around our rectangle that is less blurred than the center.
To workaround, we can take the whole thing in a different order and play with globalCompositeOperation property*:
var blurredRect = {
x: 80,
y: 80,
height: 200,
width: 200,
spread: 10
};
var ctx = canvas.getContext('2d');
var img = new Image();
img.onload = draw;
img.src = 'https://upload.wikimedia.org/wikipedia/commons/5/55/John_William_Waterhouse_A_Mermaid.jpg';
function draw() {
var spread = blurredRect.spread,
ratio = 0.5,
// make our blurred rect spreads
x = blurredRect.x - spread,
y = blurredRect.y - spread,
w = blurredRect.width + (spread * 2),
h = blurredRect.height + (spread * 2);
canvas.width = img.width * ratio;
canvas.height = img.height * ratio;
// this time we will first draw the blurred rect
ctx.filter = 'blur('+ spread +'px)';
// this time we draw from the img directly
ctx.drawImage(img,
x / ratio, y / ratio, w / ratio, h / ratio,
x, y, w, h
);
// now we will want to crop the resulting blurred image to the required one, so we get a clear-cut
ctx.filter = 'none'; // remove filter
// with this mode, previous drawings will be kept where new drawings are made
ctx.globalCompositeOperation = 'destination-in';
ctx.fillStyle = '#000'; // make it opaque
ctx.rect(blurredRect.x, blurredRect.y, blurredRect.width, blurredRect.height);
ctx.fill(); // clear-cut done
// reuse our rect to make the white-ish overlay
ctx.fillStyle = 'rgba(255,255,255,0.2)';
// reset gCO to its default
ctx.globalCompositeOperation = 'source-over';
ctx.fill();
// now we will draw behind the our blurred rect
ctx.globalCompositeOperation = 'destination-over';
ctx.drawImage(img, 0,0, canvas.width, canvas.height);
// reset to defaults
ctx.globalCompositeOperation = 'source-over';
}
<canvas id="canvas"></canvas>
But this approach requires that we keep access to the whole background as a drawable thing, in the example above that was just an image, but in real life, this might mean you'd have to do this operation on a second offscreen canvas.
var blurredRect = {
x: 80,
y: 80,
height: 200,
width: 200,
spread: 2
};
var ctx = canvas.getContext('2d');
// create an off-screen canvas
var bCanvas = canvas.cloneNode();
var bCtx = bCanvas.getContext('2d');
var img = new Image();
img.onload = draw;
img.src = 'https://upload.wikimedia.org/wikipedia/commons/5/55/John_William_Waterhouse_A_Mermaid.jpg';
function draw() {
var spread = blurredRect.spread;
canvas.width = bCanvas.width = img.width / 2;
canvas.height = bCanvas.height = img.height / 2;
// now we have a composed background
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
ctx.font = '40px Impact';
ctx.fillStyle = 'white';
ctx.fillText('..SO BLUR ME..', 120, 282);
// make our clear-cut on the offscreen canvas
bCtx.filter = 'blur(' + spread +'px)';
bCtx.drawImage(canvas,
blurredRect.x - spread, blurredRect.y - spread, blurredRect.width + spread * 2, blurredRect.height + spread * 2,
blurredRect.x - spread, blurredRect.y - spread, blurredRect.width + spread * 2, blurredRect.height + spread * 2
);
// clear-cut
bCtx.filter = 'none';
bCtx.globalCompositeOperation = 'destination-in';
bCtx.beginPath();
bCtx.rect(blurredRect.x, blurredRect.y, blurredRect.width, blurredRect.height);
bCtx.fillStyle = '#000';
bCtx.fill();
// white-ish layer
bCtx.globalCompositeOperation = 'source-over';
bCtx.fillStyle = 'rgba(255,255,255,0.2)';
bCtx.fillRect(blurredRect.x, blurredRect.y, blurredRect.width, blurredRect.height);
// now just redraw on the visible canvas
ctx.drawImage(bCanvas, 0,0);
}
<canvas id="canvas"></canvas>
*One may say that instead of an offscreen canvas and gCO we could have used ctx.clip(), but since you said it might a more complex Path than a rect, I will not advise to do so. Indeed, while it would require less code, and maybe use less memory, clipping is just bad with antialiasing, and since you are doing blurring, that will just look plain ugly.
Is there a way to create an opacity map on a canvas element
I am trying to fade a generated image as shown below.
EXAMPLE:
I don't believe there is any way to directly draw an image with a gradiant mask, but you could pre-draw the image to a separate canvas, and use globalCompositeOperation to draw a masking linear gradient, then draw that canvas using drawImage to the main canvas.
Working Example:
var cvs = document.getElementById('cvs');
var ctx = cvs.getContext('2d');
// Draw some background colors.
ctx.fillStyle = "#FF6666";
ctx.fillRect(0, 0, 150, 200);
ctx.fillStyle = "#6666FF";
ctx.fillRect(150, 0, 150, 200);
// Load the image.
img = new Image();
img.onload = function() {
// Create a canvas in memory and draw the image to it.
var icvs = document.createElement('canvas');
icvs.width = img.width;
icvs.height = img.height;
var ictx = icvs.getContext('2d');
ictx.drawImage(img, 0, 0);
// For masking.
ictx.globalCompositeOperation = 'destination-out';
// Draw the masking gradient.
var gradient = ictx.createLinearGradient(0, 0, 0, icvs.height);
gradient.addColorStop(0, "transparent");
gradient.addColorStop(1, "white");
ictx.fillStyle = gradient;
ictx.fillRect(0, 0, icvs.width, icvs.height);
// Draw the separate canvas to the main canvas.
ctx.drawImage(icvs, 25, 25, 250, 150);
};
img.src = '//i.stack.imgur.com/dR8i9.jpg';
<canvas id="cvs" width="300" height="200"></canvas>
I have followed the answer in this post; fill image with texture pattern, and it is working perfectly.
Is there a way to do the same with KonvaJS?
AFAIK, KonvaJS does not yet support the compositing required to create your texture overlay. But a Konva.Image can take a native html5 canvas element as its image source, so just do your overlay on an html5 canvas element and then feed it to Konva: var textureImage = new Konva.Image({ image:myCanvasElement })
Example annotated code and a Demo:
About Microsoft: Requires Edge -- IE doesn't allow compositing
var stage;
// Attributions of code that applies textures using compositing:
// Indirectly from your SO Q&A: http://stackoverflow.com/questions/36097859/add-texture-to-image-object-in-konvajs
// Directly from this SO Q&A: http://stackoverflow.com/questions/28545747/fill-image-with-texture-pattern/28552076#28552076
// image loading for demo (ignore)
var img1 = new Image;
var img2 = new Image;
var cnt = 2;
img1.onload = img2.onload = function() {
if (!--cnt) go()
};
img1.src = "http://i.imgur.com/8WqH9v4.png"; // sofa
img2.src = "http://i.stack.imgur.com/sQlu8.png"; // pattern
//
function createCompositedCanvas(img1, img2) {
// create canvas
canvas = document.createElement("canvas"),
ctx = canvas.getContext("2d");
canvas.width = img1.width;
canvas.height = img1.height;
// create a pattern
ctx.fillStyle = ctx.createPattern(img2, "repeat");
// fill canvas with pattern
ctx.fillRect(0, 0, canvas.width, canvas.height);
// use blending mode multiply
ctx.globalCompositeOperation = "multiply";
// draw sofa on top
ctx.drawImage(img1, 0, 0, img1.width * .5, img1.height * .5);
// change composition mode (blending mode is automatically set to normal)
ctx.globalCompositeOperation = "destination-in";
// draw to cut-out sofa
ctx.drawImage(img1, 0, 0, img1.width * .5, img1.height * .5);
//
document.body.appendChild(canvas);
return (canvas);
}
// end attibuted code
function go() {
// create stage
stage = new Konva.Stage({
container: 'container',
width: img1.width,
height: img1.height
});
var layer = new Konva.Layer();
stage.add(layer);
// create composited canvas
var canvas = createCompositedCanvas(img1, img2);
// use the in-memory canvas as an image source for Konva.Image
var img = new Konva.Image({
x: -200,
y: -50,
image: canvas,
draggable: true
});
layer.add(img);
layer.draw();
}
body{padding:20px;}
#container{
border:solid 1px #ccc;
margin-top: 10px;
}
canvas{border:solid 1px red;}
<script src="https://cdn.rawgit.com/konvajs/konva/0.9.0/konva.min.js"></script>
<div id="container"></div>
<h4>Native canvas element used to do compositing</h4>