How to compress image size in JavaScript? - javascript

I am trying to compress image size using JavaScript. but it returns canvas error.
below is my code.
var reader = new FileReader();
reader.readAsDataURL(fileItem._file);
reader.onload = function (event) {
var base64 = event.target.result.substring(event.target.result.indexOf(',') + 1, event.target.result.length);
var cvs = document.createElement('canvas');
var source_img_obj = event.target.result;
cvs.width = source_img_obj.naturalWidth;
cvs.height = source_img_obj.naturalHeight;
var ctx = cvs.getContext("2d").drawImage(source_img_obj, 0, 0);
var newImageData = cvs.toDataURL(type, 70 / 100);
var result_image_obj = new Image();
result_image_obj.src = newImageData;
console.log(result_image_obj);
};
Error:

I think you are looking something like this~
This implementation has two methods to reduce the size of the image. One method resize the image while the other compress it maintaining the same size but it reduces the quality.
This implementation is based on FileReader() to read the contents of files (or raw data buffers for Blob objects) stored on the user's computer.
// Console logging (html)
if (!window.console) console = {}
const consoleOut = document.getElementById('console-out')
console.log = message => {
consoleOut.innerHTML += message + '<br />'
consoleOut.scrollTop = consoleOut.scrollHeight
}
const outputFormat = 'jpg'
const encodeButton = document.getElementById('jpeg-encode-button')
const encodeQuality = document.getElementById('jpeg-encode-quality')
function previewFile() {
const preview = document.getElementById('source-image')
const previewResize = document.getElementById('result-resize-image')
const previewCompress = document.getElementById('result-compress-image')
const file = document.querySelector('input[type=file]').files[0]
const reader = new FileReader()
reader.onload = e => {
preview.onload = () => {
resizeFile(preview, previewResize)
compressFile(preview, previewCompress)
}
preview.src = e.target.result
// preview.src = reader.result
}
if (file) {
reader.readAsDataURL(file)
}
}
function resizeFile(loadedData, preview) {
console.log('Image resizing:')
console.log(`Resolution: ${loadedData.width}x${loadedData.height}`)
const canvas = document.createElement('canvas')
canvas.width = Math.round(loadedData.width / 2)
canvas.height = Math.round(loadedData.height / 2)
preview.appendChild(canvas)
// document.body.appendChild(canvas)
const ctx = canvas.getContext('2d')
ctx.drawImage(loadedData, 0, 0, canvas.width, canvas.height)
console.log(`New resolution: ${canvas.width}x${canvas.height}`)
console.log('---')
}
function compressFile(loadedData, preview) {
console.log('Image compressing:')
console.log(`width: ${loadedData.width} | height: ${loadedData.height}`)
const quality = parseInt(encodeQuality.value)
console.log(`Quality >> ${quality}`)
const timeStart = performance.now()
console.log('process started...')
const mimeType = typeof outputFormat !== 'undefined' && outputFormat === 'png' ? 'image/png' : 'image/jpeg'
const canvas = document.createElement('canvas')
canvas.width = loadedData.width;
canvas.height = loadedData.height;
const ctx = canvas.getContext('2d').drawImage(loadedData, 0, 0)
const newImageData = canvas.toDataURL(mimeType, quality / 100)
const img = new Image()
img.src = newImageData
preview.src = img.src
preview.onload = () => {}
const duration = performance.now() - timeStart;
console.log('process finished...')
console.log(`Processed in: ${duration}ms`)
console.log('---')
}
<input type="file" onchange="previewFile()"><br>
<div>
<h3>Original Image</h3>
<img id="source-image" />
</div>
<div>
<h3>Resized Image</h3>
<div id="result-resize-image">
</div>
</div>
<div>
<h3>Compressed Image</h3>
<img id="result-compress-image" class='img-container' />
</div>
<br><br>
<div>
<fieldset>
<legend>Compressor settings</legend>
<div id='controls-wrapper'>
Compression ratio : <input id="jpeg-encode-quality" size='3' readonly='true' type="text" value="30" /> %
</div>
</fieldset>
</div>
<div>
<fieldset>
<legend>Console output</legend>
<div id='console-out'></div>
</fieldset>
</div>

You might have to resize the canvas size
refer the following example
here
function resizeImg(base, width, height) {
var canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
var context = canvas.getContext("2d");
var deferred = $.Deferred();
$("<img/>").attr("src", "data:image/gif;base," + base).load(function() {
context.scale(width/this.width, height/this.height);
context.drawImage(this, 0, 0);
deferred.resolve($("<img/>").attr("src", canvas.toDataURL()));
});
return deferred.promise();
}

To compress a File (got from input type file) you can use this function. Just call it with the file, and it will return the same file but compressed:
const compressImage = (imageFile, quality) => {
return new Promise((resolve, reject) => {
const $canvas = document.createElement("canvas");
const image = new Image();
image.onload = () => {
$canvas.width = image.width;
$canvas.height = image.height;
$canvas.getContext("2d").drawImage(image, 0, 0);
$canvas.toBlob(
(blob) => {
if (blob === null) {
return reject(blob);
} else {
resolve(blob);
}
},
"image/jpeg",
quality / 100
);
};
image.src = URL.createObjectURL(imageFile);
});
};
Usage is:
<input type="file" id="my_input">
And JS:
const $inputFile = document.querySelector("#my_input");
$inputFile.addEventListener("change", async () => {
const file = $inputFile.files[0];
const blob = await compressImage(file, 50);
// Upload the blob with FormData or something similar
console.log({ blob });
});

Related

compress multiple images before upload javascript and php

<input id="upload" type="file" accept=".jpg, .jpeg, .png, .webp" />
<script>
var fileInput = document.querySelector("#upload");
var originalImage = document.querySelector("#originalImage");
var compressedImage = document.querySelector("#compressedImage");
var resizingElement = document.querySelector("#resizingRange");
var qualityElement = document.querySelector("#qualityRange");
var uploadButton = document.querySelector("#uploadButton");
var compressedImageBlob;
var resizingFactor = 0.8;
var quality = 0.5;
// initializing the compressed image
compressImage(originalImage, resizingFactor, quality);
fileInput.addEventListener("change", async (e) => {
var [file] = fileInput.files;
// storing the original image
originalImage.src = await fileToDataUri(file);
// compressing the uplodaded image
originalImage.addEventListener("load", () => {
compressImage(originalImage, resizingFactor, quality);
});
return false;
});
resizingElement.oninput = (e) => {
resizingFactor = parseInt(e.target.value) / 100;
compressImage(originalImage, resizingFactor, quality);
};
qualityElement.oninput = (e) => {
quality = parseInt(e.target.value) / 100;
compressImage(originalImage, resizingFactor, quality);
};
function compressImage(imgToCompress, resizingFactor, quality) {
// showing the compressed image
var canvas = document.createElement("canvas");
var context = canvas.getContext("2d");
var originalWidth = imgToCompress.width;
var originalHeight = imgToCompress.height;
var obtainedHeight = (originalHeight / originalWidth) * 420;
var canvasWidth = originalWidth * (420/originalWidth);
var canvasHeight = originalHeight * (obtainedHeight/originalHeight);
canvas.width = canvasWidth;
canvas.height = canvasHeight;
context.drawImage(
imgToCompress,
0,
0,
originalWidth * (420/originalWidth),
originalHeight * (obtainedHeight/originalHeight)
);
// reducing the quality of the image
canvas.toBlob(
(blob) => {
if (blob) {
compressedImageBlob = blob;
compressedImage.src = URL.createObjectURL(compressedImageBlob);
document.querySelector("#size").innerHTML = bytesToSize(blob.size);
var reader = new FileReader();
reader.readAsDataURL(compressedImageBlob);
reader.onloadend = function() {
var base64data = reader.result;
document.querySelector("#image").value = base64data;
}
}
},
"image/jpeg",
quality
);
}
function fileToDataUri(field) {
return new Promise((resolve) => {
var reader = new FileReader();
reader.addEventListener("load", () => {
resolve(reader.result);
});
reader.readAsDataURL(field);
});
}
// source: https://stackoverflow.com/a/18650828
function bytesToSize(bytes) {
var sizes = ["Bytes", "KB", "MB", "GB", "TB"];
if (bytes === 0) {
return "0 Byte";
}
var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
return Math.round(bytes / Math.pow(1024, i), 2) + " " + sizes[i];
}
</script>
With the javascript functions above I am able to select a big image, compress the size on client-side and upload to the server. This works perfectly for a single image upload. I was wondering if it is possible to modify this code to convert all selected images in a multiple file upload scenario.
so instead of doing it for
<input id="upload" type="file" accept=".jpg, .jpeg, .png, .webp" />
it will be for
<input id="uploads" type="file" accept=".jpg, .jpeg, .png, .webp" multiple>

How to draw a dragged and droppped image on to a canvas

I drag and drop images on to a canvas using below code . Can someone please tell me how to draw it on a canvas? Thanks in advance.Earlier my canvas used to be a div and I used to append img to that div and it worked.But now I want it to be drawn to a canvas.
function dropb(ev) {
ev.preventDefault();
const dt = ev.dataTransfer;
const files = dt.files;
handleFilesb(files);
}
function handleFilesb(files) {
for (let i = 0; i < files.length; i++) {
const file = files[i];
if (!file.type.startsWith('image/')) {
continue
}
const img = document.createElement("img");
img.className = "my_image";
img.setAttribute("width", "300px");
img.setAttribute("height", "300px");
img.classList.add("obj");
img.file = file;
document.getElementById("area_c"); // canvas
var ctx = c.getContext("2d");
ctx.drawImage(img, 10, 10); // this line is not working
const reader = new FileReader();
reader.onload = (function(aImg) {
return function(e) {
aImg.src = e.target.result;
};
})(img);
reader.readAsDataURL(file);
}
}
<div style="display:flex">
<canvas id ="area_c" style="width:300px;height:300px;border:3px solid black;z-index:1" ondrop="dropb(event)" ondragover="myfkb(event)" >
</canvas>
<div id ="area_c2" style="width:300px;height:300px;border:3px solid black;z-index:1" >
</div>
<div >
<input type="button" value="Crop"
onclick="crop()">
</div>
</div>
ctx.drawImage(img) comes before img.src... There is no way your image gets drawn.
You need to wait until it loads, and that will be only after the FileReader onload event fired, and even after the img's onload fires:
img.onload = e => {
ctx.drawImage(img, 10, 10);
};
const reader = new FileReader();
reader.onload = (function(aImg) {
return function(e) {
aImg.src = e.target.result;
};
})(img);
reader.readAsDataURL(file);
But you don't need the FileReader here, use a blob URL instead:
img.onload = e => {
ctx.drawImage(img, 10, 10);
};
img.src = URL.createObjetURL(file);
const c = document.getElementById("area_c");
c.ondragover = e => {
e.preventDefault();
}
c.ondrop = dropb;
const ctx = c.getContext("2d");
function dropb(ev) {
ev.preventDefault();
const dt = ev.dataTransfer;
const files = dt.files;
handleFilesb(files);
}
function handleFilesb(files) {
for (let i = 0; i < files.length; i++) {
const file = files[i];
if (!file.type.startsWith('image/')) {
continue
}
const img = document.createElement("img");
img.className = "my_image";
img.setAttribute("width", "300px");
img.setAttribute("height", "300px");
img.classList.add("obj");
img.file = file;
img.onload = e => {
ctx.drawImage(img, 10, 10);
};
img.src = URL.createObjectURL(file);
}
}
canvas {
border: 1px solid
}
<canvas id="area_c">
</canvas>

Canvas doesn't save as image properly, just blank transparent image

I'm looping through an array of image elements (from a local folder) and attaching them to a canvas and at the end I would like to save the canvas as an image but it is not being saved properly. The resulting image matches the dimensions of the canvas but it is just a blank transparent image.
If in test.js I don't save the canvas to an image and I instead use resolve(canvas) I can display it perfectly in index.html so I know that the canvas is being written properly.
There are also no error messages displayed in the Google Chrome console.
Test.js
class Test {
constructor() {}
createPoster(images) {
return new Promise((resolve, reject) => {
let canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d');
let locX = 0;
for (let i = 0, len = images.length; i < len; ++i) {
let image = images[i];
image.onload = () => {
ctx.drawImage(image, locX, 0);
locX += image.width;
};
}
let poster = new Image();
poster.crossOrigin = 'anonymous';
poster.onload = () => {
resolve(poster);
};
poster.src = canvas.toDataURL('image/png').replace('image/png', 'image/octet-stream');
});
}
}
Index.html
<script type="module">
const Test = require('./test.js');
let test = new Test();
async function main() {
// let images = Get array of image elements from another library.
let poster = await test.createPoster(images).catch((err) => console.log(err));
document.body.appendChild(poster); // Displays just a transparent image with the same dimensions as the canvas.
}
</script>
You need to check for all image loaded before you create your poster image.
createPoster(images) {
return new Promise((resolve, reject) => {
let canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d');
let locX = 0;
let imageLoaded = 0;
for (let i = 0, len = images.length; i < len; ++i) {
let image = images[i];
image.onload = () => {
ctx.drawImage(image, locX, 0);
locX += image.width;
imageLoaded++;
if (imageLoaded == len) {
let poster = new Image();
poster.crossOrigin = 'anonymous';
poster.onload = () => {
resolve(poster);
};
poster.src = canvas.toDataURL('image/png').replace('image/png', 'image/octet-stream');
}
};
// image.src = ..
}
});
}

WinJS Low Memory issue with ZXing

I am creating a Barcode scanner module for Windows 8 Metro App.
I some how success with my logic but suddenly I saw my application crash due to low memory issue.
<script>
var canvas = null;
var ctx = null;
var livePreview = null;
var count = 0,rescount=0;
function takepicture() {
var Capture = Windows.Media.Capture;
livePreview = document.getElementById("live-preview");
var mediaCapture = new Capture.MediaCapture();
canvas = document.getElementById("Vcanvas");
ctx=canvas.getContext('2d');
livePreview.addEventListener('play', function () { var i = window.setInterval(function () { ctx.drawImage(livePreview, 0, 0, canvas.width, canvas.height); scanCanvasEasy(); }, 20); }, false);
livePreview.addEventListener('pause', function () { window.clearInterval(i); }, false);
livePreview.addEventListener('ended', function () { clearInterval(i); }, false);
/*
var openPicker = new Windows.Storage.Pickers.FileOpenPicker();
openPicker.viewMode = Windows.Storage.Pickers.PickerViewMode.thumbnail;
openPicker.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.videosLibrary;
openPicker.fileTypeFilter.replaceAll([".mp4", ".avi", ".ogg"]);
openPicker.pickSingleFileAsync()
.then(function (file) {
if (file) {
// draw the image
var img = new Image;
//img.onload = function () {
// canvas.width = img.width;
// canvas.height = img.height;
// ctx.drawImage(img, 0, 0, img.width, img.height);
// scanCanvasEasy();
//}
//img.src = URL.createObjectURL(file);
// open a stream from the image
livePreview.src = URL.createObjectURL(file);
livePreview.play();
}
})*/
mediaCapture.initializeAsync().then(function () {
livePreview.src = URL.createObjectURL(mediaCapture);
livePreview.play();
});
}
function scanCanvasEasy() {
var imgd = ctx.getImageData(0, 0,canvas.width,canvas.height);
var pix = imgd.data;
var reader = new ZXing.BarcodeReader();
reader.onresultpointfound = function (resultPoint) {
// do something with the resultpoint location
console.log(resultPoint.toString());
}
// try to decode the raw pixel data
var result = reader.decode(pix, canvas.width, canvas.height, ZXing.BitmapFormat.rgba32);
/*
The above line cause that memory issue, without that line there is no change in memory level.
*/
// show the result
if (result) {
document.getElementById("result").innerText ="Result(+"+rescount++ +")==>"+ result.text;
}
else {
document.getElementById("error").innerText = "no barcode found" + count++;
}
}
</script>
I posted the whole code i used here I Just called the takepicture() method from button click event.
var result = reader.decode(pix, canvas.width, canvas.height, ZXing.BitmapFormat.rgba32);
This line cause memory issue.
Thanks in advance.
var reader = new ZXing.BarcodeReader();
Multiple instance of reader cause this issue. Just created one instance of reader and use it for all subsequent scan will fixed that issue.

canvas and img working in chrome but not firefox

I have searched a few results regarding this issue but none of them works for me, so I am posting here to get some helps. Basically my issue is when I clicked on the generate button, I want the image from canvas to be displayed in a img element. However, the image will show up in chrome but not firefox! Below is my coding...
<body onload="onLoad();">
<canvas id="aimage">Your browser does not support the canvas tag.</canvas>
<input type="button" value="Generate" onclick="genImage();" />
<img id="cImg" name="cImg" src="${param.src}" />
...
</body>
And the javascript...
var tcanvas;
var scanvas;
var tcontext;
var imageURL;
function onLoad() {
tcanvas = document.getElementById("aimage");
tcontext = tcanvas.getContext("2d");
scanvas = document.getElementById("cImg");
imageURL = "${param.src}";
update();
}
function update() {
var image = new Image();
image.onload = function () {
if (image.width != tcanvas.width)
tcanvas.width = image.width;
if (image.height != tcanvas.height)
tcanvas.height = image.height;
tcontext.clearRect(0, 0, tcanvas.width, tcanvas.height);
tcontext.drawImage(image, 0, 0, tcanvas.width, tcanvas.height);
}
image.crossOrigin = 'anon';
image.src = imageURL;
}
function genImage() {
var url = tcanvas.toDataURL("image/jpeg");
scanvas.crossOrigin = 'anon';
scanvas.src = url;
if(scanvas.width > 1000){
scanvas.width = 1000;
}
if(scanvas.height > 1000){
scanvas.height = 1000;
}
}
try this:
var scanvas, tcontext, tcanvas;
function genImage() {
var url = tcanvas.toDataURL("image/jpeg");
scanvas.src = url;
if (scanvas.width > 1000) {
scanvas.width = 1000;
}
if (scanvas.height > 1000) {
scanvas.height = 1000;
}
}
window.onload = function () {
tcanvas = document.getElementById("aimage");
tcontext = tcanvas.getContext("2d");
scanvas = document.getElementById('cImg');
var img = new Image();
img.onload = function () {
tcontext.drawImage(img, 0, 0, img.width, img.height)
};
img.src = "yourImage.jpg";
}

Categories

Resources