I am currently trying to create a web app to be able to upload images on a canvas using fabric.js. I am able to upload the images but have been unable to retrieve the dimensions of the image when I resize the image inside the canvas. Is there a way, that can be solved? Also, how do I handle it when multiple images are uploaded in realtime?
<!DOCTYPE html>
<html>
<head>
<title>Test Project</title>
</head>
<body>
<style>
canvas{
border: 1px solid black;
position: absolute;
top: 0px;
left: 0px;
}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.min.js"></script>
<input type="file" id="file"><br />
<canvas id="canvas" width="1000" height="1000"></canvas>
<script>
var canvas = new fabric.Canvas('canvas');
document.getElementById('file').addEventListener("change", function (e) {
var file = e.target.files[0];
var reader = new FileReader();
reader.onload = function (f) {
var data = f.target.result;
fabric.Image.fromURL(data, function (img) {
var oImg = img.set({left: 0, top: 0, angle: 0}).scale(0.2);
console.log(oImg.height)
console.log(oImg.width)
canvas.add(oImg).renderAll();
var a = canvas.setActiveObject(oImg);
var dataURL = canvas.toDataURL({format: 'png', quality: 1});
oImg.setControlsVisibility({ mtr: false })
});
};
reader.readAsDataURL(file);
});
</script>
</body>
</html>
In Fabric.js, an image's scaled width/height values can be obtained with the getScaledWidth() and getScaledHeight() methods.
<!DOCTYPE html>
<html>
<head>
<title>Test Project</title>
</head>
<body>
<style>
canvas{
border: 1px solid black;
position: absolute;
top: 0px;
left: 0px;
}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.min.js"></script>
<input type="file" id="file"><br />
<canvas id="canvas" width="1000" height="1000"></canvas>
<script>
var canvas = new fabric.Canvas('canvas');
document.getElementById('file').addEventListener("change", function (e) {
var file = e.target.files[0];
var reader = new FileReader();
reader.onload = function (f) {
var data = f.target.result;
fabric.Image.fromURL(data, function (img) {
var oImg = img.set({left: 0, top: 0, angle: 0}).scale(0.2);
console.log(oImg.getScaledWidth())
console.log(oImg.getScaledHeight())
canvas.add(oImg).renderAll();
var a = canvas.setActiveObject(oImg);
var dataURL = canvas.toDataURL({format: 'png', quality: 1});
oImg.setControlsVisibility({ mtr: false })
});
};
reader.readAsDataURL(file);
});
</script>
</body>
</html>
Related
Sorry if this is a duplicate I'm new to JS and HTML and I can't figure out what else to do.
I am trying to make (mostly from JS) a way to upload images onto any background you like, then saving them as one image. For now, I am experimenting by putting an image of the scream onto a canvas and then trying to upload an image of my choosing. Currently when I press save image, it saves ONLY the background. Also the background and uploaded image both overflow out of the card, but removing position:absolute in css stops them from overlaying. I've tried stuff with MarvinJ or even just trying to not use canvas, but can't get it to work.
Sorry for the big question, how do I merge an uploaded image and an image of my choosing onto a card and save them as one file?
HTML:
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<meta name = "viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type = "text/css" href="blank.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<title> Petra image </title>
</head>
<body>
<div class = "wrap">
<div class = "card-container">
<input type="file" onchange="previewFile()"><br>
<img src="" height="200" class = "Card_Image" alt="Image preview...">
</div>
<div class="card_main">
<div id="picHolder">
<img src="" id = "pic" class = "test" height="300" alt="Image preview2" object-fit: cover;>
<img id="scream" class = "scream" width="300" height="480" src="img_the_scream.jpg" alt="The Scream" object-fit: cover;>
</div>
</div>
</div>
</div>
<script src="blank.js"></script>
</body>
CSS:
html, body {
margin: 0;
width:100%;
padding:0;
}
.wrap {
display: flex;
flex-direction: column;
}
.card-container {
display: flex;
flex-wrap: wrap;
justify-content: space-evenly;
}
.card_main {
width: 300px;
height: 420px;
margin: 12px;
background-color: rgb(0, 0, 0);
padding: 10px;
overflow: hidden;
}
.scream{
position: absolute;
opacity: 0.2;
border: 1px solid #000000;
z-index: 1;
}
Javascript:
function previewFile() {
var preview = document.querySelector('img');
var preview2 = document.querySelector('.test')
var file = document.querySelector('input[type=file]').files[0];
var reader = new FileReader();
reader.onloadend = function () {
preview.src = reader.result;
preview2.src = reader.result;
}
if (file) {
reader.readAsDataURL(file);
} else {
preview.src = "";
}
}
window.onload = function() {
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var img = document.getElementById("pic");
var img2 = document.getElementById("scream2");
ctx.drawImage(img, 10, 10);
ctx.globalAlpha = 0.5;
ctx.drawImage(img2, 10, 10);
}
I put an image and a textbox on a FabricJS canvas, but only the textbox is rendered. I also tried to export the whole canvas as an image, but still, only the textbox showed up. If I print out all objects on canvas in the console, the image instance is there, but why it's not rendered? Here is the JS Fiddle,
Here is the full HTML file
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.3.1/fabric.min.js"></script>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
</head>
<style>
#c {
border: 2px solid black;
}
#render {
border: 2px solid red;
}
</style>
<body>
<h2>This is the test image</h2>
<img id='testImg' src="https://picsum.photos/seed/123/50/50" crossorigin="anonymous">
<h2>Fabric canvas</h2>
<canvas id='c'></canvas>
<h2>Save canvas as an image</h2>
<div id='render'></div>
<script>
var canvas = new fabric.Canvas('c');
canvas.setHeight(200);
canvas.setWidth(200);
//add image
var imgEle = $("#testImg")[0];
var newImg = new fabric.Image(imgEle, {
left: 0,
top:0
});
canvas.add(newImg);
canvas.renderAll();
//add new textbox
var newTextBox = new fabric.Textbox("Hello text box", {
left: 0,
top: 100,
width: 200
});
canvas.add(newTextBox);
canvas.renderAll();
//two objects are stored in canvas
console.log(JSON.stringify(canvas));
//show the canvas image, only one object shows
var canvasUrl = canvas.toDataURL('png');
var canvasImg = $("<img id=canvasImg>");
canvasImg.attr('src', canvasUrl);
canvasImg.appendTo("#render");
</script>
</body>
</html>
In your code you are not waiting for the image to load, so what happens is that the new fabric.Image executes before the image has fully loaded, that is why you only see the text.
We need an onload on the image.
See the code below:
var canvas = new fabric.Canvas('c');
canvas.setHeight(120);
canvas.setWidth(200);
$("#testImg")[0].onload = function () {
var newImg = new fabric.Image(this, { left: 10, top: 10 });
canvas.add(newImg);
canvas.renderAll();
}
var newTextBox = new fabric.Textbox("Hello", { left: 0, top: 70, width: 90 });
canvas.add(newTextBox);
canvas.renderAll();
#c {
border: 2px solid black;
}
#render {
border: 2px solid red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.6.2/fabric.min.js"></script>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
This is the test image
<img id='testImg' src="https://picsum.photos/seed/123/50/50" crossorigin="anonymous">
<canvas id='c'></canvas>
I'm going to make a twibbon-like website using Fabric.js for my school so students can post a picture and download it with my school campaign image on it and share it to Instagram.
to download the image in high resolution and maintain the canvas to be small enough to fit the screen, I'm using this solution I found from another stackoverflow question here
the problem is the canvas is still small but it push my div or buttons
away by the value of canvas.setWidth or setHeigth.
here's my page looks like.
how can i fix this and bring back my buttons?
here's my code :
.canvas-container canvas {
width: 400px !important;
height: 500px !important;
border: 1px solid blue;
}
body{
font-family: 'Helvetica', Tahoma, Geneva, Verdana, sans-serif;
}
h1{
color: rgb(119, 214, 124);
}
.site{
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-gap: 1em;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="cssTest.css">
<title>Twibbon</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.3.3/fabric.min.js"></script>
<script src="FileSaver.js"></script>
<script src="canvas-toBlob.js"></script>
</head>
<body>
<div class="site">
<h1 class="title">Fortafaste Campaign</h1>
<canvas id="c"></canvas>
<input type="file" id="d" class="button">
<input id="download" type="button" value="download" />
<h2 class="contact">instagram</h2>
</div>
<script>
var canvas = new fabric.Canvas('c');
canvas.setWidth(1080);
canvas.setHeight(1350);
var canvasWrapper = document.getElementById('c');
var canvasWrapperWidth = canvasWrapper.clientWidth;
$(function () {
$(":file").change(function () {
if (this.files && this.files[0]) {
var reader = new FileReader();
reader.onload = imageIsLoaded;
reader.readAsDataURL(this.files[0]);
}
});
});
fabric.Image.fromURL('twibbon2 fortafaste.png',function(img){
img.scaleToWidth(canvas.getWidth());
canvas.setOverlayImage(img, canvas.renderAll.bind(canvas));
});
function imageIsLoaded(e) {
fabric.Image.fromURL(e.target.result,function(img){
var aspectRatio = 1350/1080;
var factor = 1080 / img.width;
img.set({
scaleX: factor,
scaleY: factor
});
canvas.add(img);
canvas.sendToBack(img);
});
};
$("#download").click(function(){
$("#c").get(0).toBlob(function(blob){
saveAs(blob, "myIMG.png");
});
});
</script>
</body>
</html>
I recommend you to simplify your design...
Keep all the information and action buttons on top and the canvas below, here is an example:
.canvas-container canvas {
width: 400px !important;
height: 500px !important;
border: 1px solid blue;
}
body{
font-family: 'Helvetica', Tahoma, Geneva, Verdana, sans-serif;
}
h1{
color: rgb(119, 214, 124);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="cssTest.css">
<title>Twibbon</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.3.3/fabric.min.js"></script>
<script src="FileSaver.js"></script>
<script src="canvas-toBlob.js"></script>
</head>
<body>
<div class="site">
<div>
<h1 class="title">Fortafaste Campaign</h1>
<input type="file" id="d" class="button">
<input id="download" type="button" value="download" />
<h2 class="contact">instagram</h2>
</div>
<canvas id="c"></canvas>
</div>
<script>
var canvas = new fabric.Canvas('c');
canvas.setWidth(1080);
canvas.setHeight(1350);
var canvasWrapper = document.getElementById('c');
var canvasWrapperWidth = canvasWrapper.clientWidth;
$(function () {
$(":file").change(function () {
if (this.files && this.files[0]) {
var reader = new FileReader();
reader.onload = imageIsLoaded;
reader.readAsDataURL(this.files[0]);
}
});
});
fabric.Image.fromURL('twibbon2 fortafaste.png',function(img){
img.scaleToWidth(canvas.getWidth());
canvas.setOverlayImage(img, canvas.renderAll.bind(canvas));
});
function imageIsLoaded(e) {
fabric.Image.fromURL(e.target.result,function(img){
var aspectRatio = 1350/1080;
var factor = 1080 / img.width;
img.set({
scaleX: factor,
scaleY: factor
});
canvas.add(img);
canvas.sendToBack(img);
});
};
$("#download").click(function(){
$("#c").get(0).toBlob(function(blob){
saveAs(blob, "myIMG.png");
});
});
</script>
</body>
</html>
So when I try to draw image on canvas like this (it works fine):
<html>
<head>
<title>HTML5 canvas</title>
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
<script>
$(document).ready(start);
var image1;
function start() {
var ctx = $('#canvas').get(0).getContext('2d');
image1 = new Image;
image1.src = "/arenag/arenagimg/BeastBear.jpg";
image1.onload = function () {
ctx.drawImage(image1.src,200, 200, 100, 100);
};
}
</script>
<style type="text/css">
#framework {
border: 2px solid #000;
width: 100%;
text-align: center;
}
#canvas {
background-color: #00FFE2;
margin-right: auto;
margin-left: auto;
}
</style>
</head>
<body>
<div id="framework">
<canvas id="canvas" width="1024" height="768"></canvas>
</div>
</body>
</html>
Then i add a folder called imagefactory.js and create a class ImageFactory,and create function in that class called drawImage:
var ImageFactory = function (ctx) {
this.ctx = ctx;
this.drawImage = function (image_arg, image_x, image_y, image_w, image_h) {
var _this = this;
var image = new Image;
image.src = image_arg;
image.onload = function () {
_this.ctx.drawImage(image.src, image_x, image_y, image_w, image_h);
};
};
};
Then I simply try to call that function in my main file:
<html>
<head>
<title>HTML5 canvas</title>
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
<script>
$(document).ready(start);
var image;
function start() {
image = '/arenag/arenagimg/BeastBear.jpg';
var ctx = $('#canvas').get(0).getContext('2d');
var imageFactory=new ImageFactory(ctx);
imageFactory.drawImage(image,200, 200, 100, 100);
}
</script>
<style type="text/css">
#framework {
border: 2px solid #000;
width: 100%;
text-align: center;
}
#canvas {
background-color: #00FFE2;
margin-right: auto;
margin-left: auto;
}
</style>
</head>
<body>
<div id="framework">
<canvas id="canvas" width="1024" height="768"></canvas>
</div>
</body>
</html>
I get this error(on 36 line in my main (HTML) file where the canvas is) :
Uncaught TypeError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The provided value is not of type '(HTMLImageElement or HTMLVideoElement or HTMLCanvasElement or ImageBitmap)'
And also this bug which is connected to the other one(i mean when there is no this bug then there is no the first bug too):
[object%20HTMLImageElement]:1 GET http://phpcasovi.dev/arenag/klase/[object%20HTMLImageElement] 404 (Not Found)
And i wanted to just give you a help to solve this : When i change var image = new Image;to var image = {};in JS file.Then there is no bug but becuase var image is not equal to new Image well then there is no images at all.So i think bug is at that line where i say var image = new Image; but i dont know why there is a bug (why should it be)??
First argument for context.drawImage should be Image-Object not image.src
From docs, ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);, image, An element to draw into the context. The specification permits any canvas image source (CanvasImageSource), such as an HTMLImageElement, an HTMLVideoElement, an HTMLCanvasElement or an ImageBitmap.
var ImageFactory = function(ctx) {
this.ctx = ctx;
this.drawImage = function(image_arg, image_x, image_y, image_w, image_h) {
var _this = this;
var image = new Image();
image.src = image_arg;
image.onload = function() {
_this.ctx.drawImage(image, image_x, image_y, image_w, image_h);
};
};
};
$(document).ready(start);
function start() {
var image = 'https://www.google.com/images/branding/googlelogo/1x/googlelogo_white_background_color_272x92dp.png';
var ctx = $('#canvas').get(0).getContext('2d');
var imageFactory = new ImageFactory(ctx);
imageFactory.drawImage(image, 200, 200, 100, 100);
}
#framework {
border: 2px solid #000;
width: 100%;
text-align: center;
}
#canvas {
background-color: #00FFE2;
margin-right: auto;
margin-left: auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div id="framework">
<canvas id="canvas" width="1024" height="768"></canvas>
</div>
Fiddle Demo
Here simple code1 which work fine Demo jsFiddle ,I want the same result in code2
Here the code2 Demo jsfiddle which have two problems.
The scale is not correct to 1400x700 pix
I can only successes to draw from inside function loadImage()
function loadImage(){
oG.width = 1400;
oG.height = 700;
oG.drawImage(scrollImg,0,0);
}
I want to draw from scrollObject.draw()
var scrollObject = {
draw : function() {
oG.drawImage(scrollImg,0,0);
}
};
How can I do that ?
Many thanks.
code1;
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#mycanvas{
border: 1px solid #9C9898;
}
</style>
</head>
<body >
<canvas id="mycanvas" width="1400" height="700" ></canvas>
<script type="text/javascript">
// get the canvas element using the DOM http://jsfiddle.net/centerwow/Z2UzF/show/
var context = document.getElementById('mycanvas').getContext("2d");
context.width = 1400 ;
context.height = 700 ;
var img = new Image();
img.src = "http://s9.postimage.org/433ecr79b/grid.png";
img.onload = function () {
context.clearRect(0,0,1400,700);
context.drawImage(img, 0, 0);
}
</script>
</body>
</html>
code2:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title> image not display correct</title>
<style type='text/css'>
body {
background-color:black;
}
.Container {
position: relative;
margin-left:auto;
margin-right:auto;
top:10px;
background-image:url('http://s8.postimage.org/jnu65wk2d/Box_Grass200x100.jpg');
background-repeat:repeat;
width:1000px;
height:500px;
z-index:0;
overflow:hidden;
}
#layer1{
position:absolute;
padding:0;
margin: 0px;
z-index:2;
top:-100px;
left:-200px;
width:1400px;
height:700px;
}
</style>
</head>
<body >
<div class="Container">
<canvas id="layer1">LAYER1</canvas>
</div>
<script type='text/javascript'>//http://jsfiddle.net/centerwow/Z2UzF/1/show/
function loadImage(){
oG.width = 1400;
oG.height = 700;
oG.drawImage(scrollImg,0,0);
}
//layer 1 image then will be object objectGame = oG
var oG = document.getElementById('layer1').getContext("2d");
scrollImg = new Image();
scrollImg.src = "http://s9.postimage.org/433ecr79b/grid.png"; //image size 1400x700px
scrollImg.onload = loadImage;
var scrollObject = {
// Basic attributes
draw : function() {
oG.drawImage(scrollImg,0,0);
}
};
// Now moving it
function move() {
//handle with object background
//clearRect(x, y, width, height)
oG.clearRect(0,0,1400,700);
scrollObject.draw();
}
move();
</script>
</body>
</html>
You can only draw on loadImage(), because when you trigger move() the image have not been loaded yet. You can use a assetmanager to download your assets like images, sounds etc. Here is a great guide to build one - http://www.html5rocks.com/en/tutorials/games/assetmanager/
And for the scale, you can pass a width and height argument to the drawImage function.
context.drawImage(image, x, y, width, height);
You are also setting the height and width of the 2d-context, that you cannot do. Set the width and height in the <canvas> attributes. I once had problems with height/width when I used css, so I would not recommend setting the width/height there.