I am uploading an image and i expect base64 data of that image.I am trying below code that works to get image data as base64.
1) function getImage(file,count) //file is files[i] of input:file passed from for()
{
if(file)
{
var reader = new FileReader();
reader.onload = function(event)
{
var data = event.target.result;
var image = document.createElement("img");
image.id = 'img'+count;
image.class = 'edit';
image.src = data;
console.log('width:'+this.width);//not working value is undefined
console.log('height:'+this.height);//not working value is undefined
//image.title = 'click to edit';
image.data = count;
data = image.dataset;
data.ref=count;
document.getElementById('image'+count).appendChild(image);
jQuery(document.getElementById('image'+count)).removeClass('disable');
jQuery(document.getElementById('img'+count)).addClass('action editable img ');
}
reader.readAsDataURL(file);
}
}
This works fine and it creates an img tag with image loaded correctly.
But I want to know the image width and height before creating img element, so i tried below code,
2) function getImage(file,count)
{
if(file)
{
var reader = new FileReader();
reader.onload = function(event)
{
var img = new Image();
var data = event.target.result;
img.onload = function(){
console.log(img.width);
var image = document.createElement("img");
image.id = 'img'+count;
image.class = 'edit';
image.src = data;
console.log('width:'+this.width);
console.log('height:'+this.height);
image.data = count;
data = image.dataset;
data.ref=count;
document.getElementById('image'+count).appendChild(image);
jQuery(document.getElementById('image'+count)).removeClass('disable');
jQuery(document.getElementById('img'+count)).addClass('action editable img ');
};
}
reader.readAsDataURL(file);
}
}
But the second code does not prints log and img tag is not created. so what is the problem?What wrong in my code?Any better way to achieve this?.
just single line makes my problem null,
Thanks to this.
function getImage(file,count)
{
if(file)
{
var reader = new FileReader();
reader.onload = function(event)
{
var img = new Image();
var data = event.target.result;
img.src = data; //this line solved my problem..
img.onload = function(){
var image = document.createElement("img");
image.id = 'img'+count;
image.class = 'edit';
image.src = data;
console.log('width:'+this.width);
console.log('height:'+this.height);
image.data = count;
data = image.dataset;
data.ref=count;
document.getElementById('image'+count).appendChild(image);
jQuery(document.getElementById('image'+count)).removeClass('disable');
jQuery(document.getElementById('img'+count)).addClass('action editable img ');
};
}
reader.readAsDataURL(file);
}
}
Waiting for any better answer..
Related
I have converted a pdf to image format using PDF.JS and rendered that to the canvas. While that process the rendered pdf image is showing blurred in the canvas.
I have no idea how to scale the image to some viewable format rather than being so blurred.
Image of the pdf in canvas:
Here in the image you can clearly see that the rendered image is not in readable format!
Here is the fiddle link: https://jsfiddle.net/kjxes63f/
var fabricCanvas;
fabricCanvas = new fabric.Canvas('firtcanvas');
document.querySelector("#pdf-upload").addEventListener("change", function (e) {
var file = e.target.files[0]
console.log("pdf evente");
console.log(e);
if (file.type != "application/pdf") {
console.error(file.name, "is not a pdf file.")
return
}
var fileReader = new FileReader();
fileReader.onload = function () {
var typedarray = new Uint8Array(this.result);
console.log("typedarray");
console.log(typedarray);
console.log("this.result");
console.log(this.result);
PDFJS.getDocument(typedarray).then(function (pdf) {
// you can now use *pdf* here
console.log("the pdf has ", pdf.numPages, "page(s).")
pdf.getPage(pdf.numPages).then(function (page) {
// you can now use *page* here
var viewport = page.getViewport(2.0);
var fabricCanvas = document.querySelector("#firtcanvas")
fabricCanvas.height = viewport.height;
fabricCanvas.width = viewport.width;
page.render({
canvasContext: fabricCanvas.getContext('2d'),
viewport: viewport
}).then(function () {
bg = fabricCanvas.toDataURL("image/png");
fabric.Image.fromURL(bg, function (img) {
img.scaleToHeight(800);
img.scaleToWidth(600);
console.log("img");
console.log(img);
console.log(bg);
var imgCanvas = img.set({ left: 0, top: 0, width: 150, height: 150 });
fabricCanvas.add(imgCanvas);
});
});
});
});
};
fileReader.readAsArrayBuffer(file);
});
Construction drawings are often wide-format and hard to read onscreen without zoom. As a work-around I'd suggest adding a zoom function to your canvas like below.
var canvas = new fabric.Canvas('pdfcanvas');
canvas.selection = false;
canvas.setHeight(450);
canvas.setWidth(636);
//zoom function
canvas.on('mouse:wheel', function(opt) {
var delta = opt.e.deltaY;
var pointer = canvas.getPointer(opt.e);
var zoom = canvas.getZoom();
zoom = zoom - delta / 200;
if (zoom > 10) zoom = 10;
if (zoom < 1) {
zoom = 1;
canvas.setViewportTransform([1, 0, 0, 1, 0, 0]);
}
canvas.zoomToPoint({
'x': opt.e.offsetX,
'y': opt.e.offsetY
}, zoom);
opt.e.preventDefault();
opt.e.stopPropagation();
});
//pdf load
document.querySelector('#pdf-upload').addEventListener('change', function(e) {
var pageEl = document.getElementById('page-container');
var file = e.target.files[0];
if (file.type == 'application/pdf') {
var fileReader = new FileReader();
fileReader.onload = function() {
var typedarray = new Uint8Array(this.result);
PDFJS.getDocument(typedarray).then(function(pdf) {
//console.log('the pdf has ', pdf.numPages, 'page(s).');
pdf.getPage(pdf.numPages).then(function(pageEl) {
var viewport = pageEl.getViewport(2.0);
var canvasEl = document.querySelector('canvas');
canvasEl.height = viewport.height;
canvasEl.width = viewport.width;
pageEl.render({
'canvasContext': canvasEl.getContext('2d'),
'viewport': viewport
}).then(function() {
var bg = canvasEl.toDataURL('image/png');
fabric.Image.fromURL(bg, function(img) {
canvas.setBackgroundImage(img);
});
});
});
});
};
fileReader.readAsArrayBuffer(file);
};
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.4.0/fabric.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/1.8.349/pdf.min.js"></script>
<input id="pdf-upload" type="file">
<div id="page-container">
<canvas id="pdfcanvas"></canvas>
</div>
I want original image size in offline mode also as shown in online mode in image 2.
My problem is that when i gone in app without internet connection, i loss full quality and size of images, because of i am using convertToDataURLviaCanvas().
so, please give here solution as soon as possible.
My code is:
I am using this function to convert all images:
convertToDataURLviaCanvas(url, outputFormat) {
return new Promise((resolve, reject) =>
{
let img = new Image();
img.crossOrigin = 'Anonymous';
img.onload = function () {
let canvas = <HTMLCanvasElement>document.createElement('CANVAS'),
ctx = canvas.getContext('2d'),
dataURL;
canvas.height = 1000;
canvas.width = 1000;
ctx.drawImage(img, 0, 0);
dataURL = canvas.toDataURL();
//callback(dataURL);
canvas = null;
resolve(dataURL);
};
img.src = url;
});
}
getTravelAdviceData() {
if(this.restProvider.getNetworkType() == 'none') {
// this.onlineGrid = false;
// this.offlineGrid = true;
this.storage.get('companyLogoOffline').then((data) => {
// Do something with latitude value
// console.log("offline data", data);
this.getcompanyLogo = data;
});
this.storage.get('travelTips64Image').then((data) => {
// Do something with latitude value
// console.log("offline data", data);
this.adviceArray = data;
// console.log("offline this.adviceArray", this.adviceArray);
});
} else {
// this.offlineGrid = false;
// this.onlineGrid = true;
this.restProvider.getTravelAdvice()
.then(data => {
let serviceData : any = data['consejosviaje'];
// this.adviceArray = serviceData;
let base64Image;
for (let i in serviceData) {
this.imagen = serviceData[i].imagen;
this.convertToDataURLviaCanvas(this.imagen, "image/jpeg").then(base64 => {
base64Image = base64;
this.texto = serviceData[i].texto;
this.adviceArrays64.push({'texto': this.texto, 'imagen': base64Image});
this.storage.set("travelTips64Image", this.adviceArrays64);
this.adviceArray = this.adviceArrays64;
});
}
});
}
}
I am trying to create a Chrome extension that looks like the image below.
I want to save the Name and Id when clicking "+" button and I want to load all saved data int the onLoad event as seen in the upper section of image. I would also like to delete a particular row of data when clicking corresponding delete button.
Saved data should persist when closing Chrome.
document.body.onload = function() {
chrome.storage.sync.get(["id","name"], function(items) {
if (!chrome.runtime.error) {
console.log(items);
document.getElementById("lsid").innerText = items.id;
document.getElementById("lsname").innerText = items.name;
}
});
}
document.getElementById("set").onclick = function() {
var d = document.getElementById("name").value;
var x = document.getElementById("id").value;
d=String(d);
chrome.storage.sync.set({"name":d,"id" : x}, function() {
if (chrome.runtime.error) {
console.log("Runtime error.");
}
});
window.close();
}
document.body.onload = function Load() {
for(var i=0;i<localStorage.length;i++){
var row = document.createElement("TR");
var col1 = document.createElement("TD");
var col2 = document.createElement("TD");
var col3 = document.createElement("TD");
var del = document.createElement("BUTTON");
var id=localStorage.key(i);
col1.innerHTML=localStorage.getItem(id);
col2.innerHTML=id;
del.innerHTML="delete";
del.id=id;
del.className ="delete";
col3.appendChild(del);
row.appendChild(col1);
row.appendChild(col2);
document.getElementById("list_table").appendChild(row);
}
}
document.form_save.onsubmit = function() {
var newName = document.form_save.name.value;
var newId = document.form_save.id.value;
window.localStorage.setItem(newId, newName);
location.reload();
}
document.getElementById("list_table").onclick=function(e){
if(e.target.className=="delete"){
var result = confirm("Want to delete?");
if (result) {
window.localStorage.removeItem(e.target.id);
location.reload();
}
}
}
How to render an image blob to a canvas element?
So far i have these two (simplified) functions to capture an image, transform it to a blob and eventually render the blob on a canvas
in this codepen, it just returns the default black image.
var canvas = document.getElementById('canvas');
var input = document.getElementById('input');
var ctx = canvas.getContext('2d');
var photo;
function picToBlob() {
var file = input.files[0];
canvas.toBlob(function(blob) {
var newImg = document.createElement("img"),
url = URL.createObjectURL(blob);
newImg.onload = function() {
ctx.drawImage(this, 0, 0);
photo = blob;
URL.revokeObjectURL(url);
};
newImg.src = url;
}, file.type, 0.5);
canvas.renderImage(photo);
}
HTMLCanvasElement.prototype.renderImage = function(blob) {
var canvas = this;
var ctx = canvas.getContext('2d');
var img = new Image();
img.onload = function() {
ctx.drawImage(img, 0, 0)
}
img.src = URL.createObjectURL(blob);
}
input.addEventListener('change', picToBlob, false);
I think you need to tidy up your code a bit. It's hard to know what you are trying to achieve because there are many unnecessary lines of code. The main problem is that blob is coming undefined here
HTMLCanvasElement.prototype.renderImage = function(blob){
because photo never gets initialized here inside the toBlob function...which is unnecessary for what you are trying to achieve.
Here's a simplified working version of your code snippet
var canvas = document.getElementById('canvas');
var input = document.getElementById('input');
function picToBlob() {
canvas.renderImage(input.files[0]);
}
HTMLCanvasElement.prototype.renderImage = function(blob){
var ctx = this.getContext('2d');
var img = new Image();
img.onload = function(){
ctx.drawImage(img, 0, 0)
}
img.src = URL.createObjectURL(blob);
};
input.addEventListener('change', picToBlob, false);
<input type='file' accept='image' capture='camera' id='input'>
<canvas id = 'canvas'></canvas>
You can also use createImageBitmap to directly render a blob into the canvas:
createImageBitmap(blob).then(imageBitmap=>{ctx.drawImage(imageBitmap,0,0)})
var canvas = document.getElementById('canvas');
var input = document.getElementById('input');
function blobToCanvas() {
createImageBitmap(input.files[0]).then(imageBitmap => {
console.log(imageBitmap);
canvas.getContext('2d').drawImage(imageBitmap, 0, 0)
})
}
input.addEventListener('change', blobToCanvas, false);
<input type='file' accept='image' capture='camera' id='input'>
<canvas id='canvas'></canvas>
You can use it as below
function renderImage(canvas, blob) {
const ctx = canvas.getContext('2d')
const img = new Image()
img.onload = (event) => {
URL.revokeObjectURL(event.target.src) // 👈 This is important. If you are not using the blob, you should release it if you don't want to reuse it. It's good for memory.
ctx.drawImage(event.target, 0, 0)
}
img.src = URL.createObjectURL(blob)
}
below is an example
/**
* #param {HTMLCanvasElement} canvas: https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API
* #param {Blob} blob: https://developer.mozilla.org/en-US/docs/Web/API/Blob
* */
function renderImage(canvas, blob) {
const ctx = canvas.getContext('2d')
switch (blob.type) {
case "image/jpeg": // Normally, you don't need it (switch), but if you have a special case, then you can consider it.
case "image/png":
const img = new Image()
img.onload = (event) => {
URL.revokeObjectURL(event.target.src) // Once it loaded the resource, then you can free it at the beginning.
ctx.drawImage(event.target, 0, 0)
}
img.src = URL.createObjectURL(blob)
break
}
}
// 👇 below is test
(() => {
const canvas = document.querySelector('canvas')
const input = document.querySelector('input')
input.addEventListener('change',
(event) => {
const file = event.target.files[0]
const blob = new Blob(
[file],
{"type": file.type} // If the type is unknown, default is empty string.
)
renderImage(canvas, blob)
}
)
})()
<div><input type='file' accept='.png,.jpg'></div>
<canvas></canvas>
another example to show you What effect of the revokeObjectURL.
<div></div>
<canvas width="477" height="600"></canvas>
<script>
async function renderImage(canvas, blob, isNeedRevoke=true) {
const ctx = canvas.getContext('2d')
const img = new Image() // The upper part of the painting.
const img2 = new Image() // The lower part of the painting.
await new Promise(resolve => {
img.onload = (event) => {
if (isNeedRevoke) {
URL.revokeObjectURL(event.target.src)
}
ctx.drawImage(event.target,
0, 0, 477, 300,
0, 0, 477, 300
)
resolve()
}
img.src = URL.createObjectURL(blob)
setTimeout(resolve, 2000)
}).then(() => {
img2.onload = (event) => {
ctx.drawImage(event.target,
0, 300, 477, 300,
0, 300, 477, 300
)
}
img2.src = img.src // 👈 If URL.revokeObjectURL(img.src) happened, then img2.src can't find the resource, such that img2.onload will not happen.
})
}
function CreateTestButton(canvas, btnText, isNeedRevoke) {
const button = document.createElement("button")
button.innerText = btnText
button.onclick = async (event) => {
canvas.getContext("2d").clearRect(0, 0, canvas.width, canvas.height) // clear canvas
fetch("https://upload.wikimedia.org/wikipedia/commons/thumb/6/6a/PNG_Test.png/477px-PNG_Test.png")
.then(async response=>{
const blob = await response.blob()
renderImage(canvas, blob, isNeedRevoke)
}).catch(err=>console.error(err))
}
return button
}
(() => {
window.onload = () => {
const canvas = document.querySelector('canvas')
const div = document.querySelector('div')
const btn1 = CreateTestButton(canvas, "Without URL.revokeObjectURL", false)
const btn2 = CreateTestButton(canvas, "URL.revokeObjectURL", true)
div.append(btn1, btn2)
}
})()
</script>
In order to try and get around the odd issue in having with CORS (here) I am attempting to reload any images loaded via canvas.loadFromJSON()
But, I am experiencing weird issues. Sometimes only one image is replaced, other times I get duplicates of one image.
Here is my code:
canvas.loadFromJSON(<?php echo json_encode($objects); ?>, function() {
var objArray = canvas.getObjects();
for (var i = 0; i < objArray.length; i++) {
canvas.setActiveObject(objArray[i]);
var activeObject = canvas.getActiveObject();
if(activeObject.type === 'image') {
fabric.util.loadImage(activeObject.src, function(img) {
var object = new fabric.Image(img);
object.hasControls = true;
object.lockUniScaling = true;
object.scaleX = activeObject.scaleX;
object.scaleY = activeObject.scaleY;
object.originX = activeObject.originX;
object.originY = activeObject.originY;
object.centeredRotation = true;
object.centeredScaling = true;
canvas.add(object);
}, null, {crossOrigin: 'Anonymous'});
canvas.remove(activeObject);
}
activeObject.setCoords();
}
canvas.deactivateAll();
canvas.renderAll();
canvas.calcOffset();
});
Any ideas why I'm getting these weird issues?
First glance at your code I don't see anything wrong... But I'm also thinking the code might be a bit inefficient? Is there a need to create a new image instance?
I believe you should be able to just set the crossOrigin property on the image object.
This code is untested, but I'd try something like this:
canvas.loadFromJSON(<?php echo json_encode($objects); ?>, function() {
var objArray = canvas.getObjects();
for (var i = 0; i < objArray.length; i++) {
canvas.setActiveObject(objArray[i]);
var activeObject = canvas.getActiveObject();
if(activeObject.type === 'image') {
activeObject.crossOrigin = 'Anonymous';
}
}
canvas.deactivateAll();
canvas.renderAll();
canvas.calcOffset();
});
I had the same problem and overcome it downloading again the image then reassign it to object._element once each fabric object was created using loadFromJSON.
export const getImage = url => {
return new Promise((resolve, reject) => {
let img = new Image();
img.onload = () => resolve(img);
img.onerror = reject;
img.setAttribute('crossOrigin', 'anonymous');
img.src = url;
});
}
canvas.loadFromJSON(json, canvas.renderAll.bind(canvas), async (o, object) => {
if (object.type === "image") {
let imagecore = await getImage(object.src);
object._element = imagecore;
}
});