Resizing image with canvas and Javascript

Asked

Viewed 3,254 times

2

How to reduce the size of an image with JavaScript? I’m using canvas to resize, reduce the size in proportion and convert to jpeg.

The problem occurs when I try to save the image, since I cannot download it converted to jpeg.

Follow the code on JsFidle.

http://jsfiddle.net/x4gvgnwn/3/

Obs: the console.log() returns what type is jpeg, but by right clicking the mouse try to save it, is in png.

Any suggestions on how to solve the problem?

  • I think you forgot to join jsFiddle...

  • nusss q mess...kk

  • For me it’s in jpeg.

  • I have just hidden the image and left only the canvas, so just try to save it to see it saved in png http://jsfiddle.net/x4gvgnwn/3/

  • This is what you are looking for -> http://jsfiddle.net/x4gvgnwn/4/ ?

  • Sergio, right click on the image and try to save, you will see that in your script it also saves in png...

Show 1 more comment

2 answers

0


According to this documentation there is a kind of "fault", or rather, this is the canvas feature in obtaining jpeg:

http://zapone.org/blaine/2015/01/03/save-html-canvas-drawing-as-jpg-error/

There is already a topic about this:

https://stackoverflow.com/questions/17397319/save-canvas-as-jpg-to-desktop?answertab=active#tab-top

According to these two surveys your solution would create a link type or force download when clicking on the image. This is very simple. An example with link:

/**
 *    Ken Fyrstenberg Nilsen
 *    Abidas Software
 */
var canvas = document.getElementById('canvas'),
    ctx = canvas.getContext('2d');

/**
 * Functions for demo
 */
function doCanvas() {

    //some background
    var s = canvas.width / 5;
    var i = 0;
    var r = Math.random;


    var txt = 'Normal text';
    var itxt = 'Inversed text';

    ctx.fillStyle = '#fff';
    
    ctx.textBaseline = 'top';
    ctx.font = '80px impact'
    ctx.fillText(txt, 30, 20);

    ctx.fillInversedText(itxt, 30, 100);
    
    requestAnimationFrame(doCanvas);
}

/**
 * Canvas extension: fillInversedText
 * By Ken Fyrstenberg Nilsen 2013. Beta 1.
*/
CanvasRenderingContext2D.prototype.fillInversedText = function (txt, x, y) {

    //measure
    var tw = this.measureText(txt).width;
    var th = parseInt(ctx.font, '10');
    th = (th === 0) ? 16 : th;

    //setupp off-screen canvas
    var co = document.createElement('canvas');
    co.width = tw;
    co.height = th;

    //fill text
    var octx = co.getContext('2d');
    octx.font = this.font;
    octx.textBaseline = 'top';
    octx.fillText(txt, 0, 0);

    //get pixel buffers
    var ddata = this.getImageData(x, y, tw, th);
    var sdata = octx.getImageData(0, 0, tw, th);

    var dd = ddata.data;
    var ds = sdata.data;
    var len = ds.length;
    
    //invert
    for (var i = 0; i < len; i += 4) {
        if (ds[i + 3] > 0) {
            dd[i] = (255 - dd[i]);
            dd[i + 1] = (255 - dd[i + 1]);
            dd[i + 2] = (255 - dd[i + 2]);
        }
    }

    //result at x/y
    this.putImageData(ddata, x, y);
}

/**
 * Init generals
 */
ctx.fillStyle = '#000';
ctx.fillRect(0, 0, canvas.width, canvas.height);

function download() {
    var dt = canvas.toDataURL();
    this.href = dt; //this may not work in the future..
}
document.getElementById('download').addEventListener('click', download, false);

/**
 * Monkey patches
 */
window.requestAnimationFrame = (function () {
    return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function (callback) {
        window.setTimeout(callback, 1000 / 60);
    };
})();

window.cancelAnimationFrame = (function () {
    return window.cancelAnimationFrame || window.webkitCancelAnimationFrame || window.mozCancelAnimationFrame || function (timPtr) {
        window.clearTimeout(timPtr);
    };
})();

/**
 * START
 */
doCanvas();
	body {
	    background-color:#555657;
	    padding:0;
	    margin:0;
	    overflow:hidden;
	    font-family:sans-serif;
	    -webkit-user-select: none;
	    -khtml-user-select: none;
	    -moz-user-select: none;
	    -ms-user-select: none;
	    user-select: none;
	}
	canvas {
	    border:1px solid #000;
	    float:left;
	    clear:both;
	}
	#download {
	    clear:both;
	    float:left;
	    cursor:pointer;
	    color:#ccc;
	    padding:3px;
	}
	#download:hover {
	    color:#fff;
	}
	/*
	div, input {
	    font-size:16px;
	    font-family:sans-serif;
	    border:1px solid #000;
	    border-radius: 5px;
	    float:left;
	    padding:5px;
	    width:50px;
	    margin:1px 1px;
	    background-color:#bbb;
	}
	input[type='text'] {
	    font-size:16px;
	    font-weight:bold;
	    width:70px;
	    text-align:center;
	    background-color:#fff;
	    padding-bottom:4px;
	}
	input[type='button'] {
	    font-size:16px;
	    font-weight:bold;
	    width:110px;
	    text-align:center;
	    background-color:#333;
	    color:#eee;
	    padding-bottom:4px;
	}
	input[type='button']:hover {
	    background-color:#fff463;
	    color:#000;
	}
	input[type='range'] {
	    width:100px;
	    margin:0 0 0 10px;
	}
*/
	
<canvas width="500" height="210" id="canvas">Sorry, no canvas available</canvas>
<a id="download" download="AbdiasCanvasDemo.png">Download as image</a>

  • Dude, in your code too not saved in jpeg...

  • @Douglaslopes, I edited the answer.

0

There is an error in your code, as you take the image that is on the canvas without before drawing it?

var img2 = new Image();
img2.src = canvas.toDataURL("image/jpeg", 1.0);
//Exibe (desenha) a imagem na tela
ctx.drawImage(img, 0, 0, width, height);

The right thing would be:

//Exibe (desenha) a imagem na tela
ctx.drawImage(img, 0, 0, width, height);
var img2 = new Image();
img2.src = canvas.toDataURL("image/jpeg", 1.0);

With this you could already get the expected result but you really want to show your jpg image on canvas? if yes, the canvas would turn it into png again then the correct one would show it in the gift:

document.body.appendChild(img2);

This would cause if the user wanted to save the image, it would already be in jpg.

Test your edited code here:

var img = document.getElementById("preview");

var canvas = document.getElementById("canvas");

var ctx = canvas.getContext("2d");

var MAX_WIDTH = 800;
var MAX_HEIGHT = 800;

var width = img.width;
var height = img.height;

if (width > height) {
  if (width > MAX_WIDTH) {
    height *= MAX_WIDTH / width;
    width = MAX_WIDTH;
  }
} else {
  if (height > MAX_HEIGHT) {
    width *= MAX_HEIGHT / height;
    height = MAX_HEIGHT;
  }
}

canvas.width = width;
canvas.height = height;

//Exibe (desenha) a imagem na tela
ctx.drawImage(img, 0, 0, width, height);
var img2 = new Image();
img2.src = canvas.toDataURL("image/jpeg", 1.0);

document.body.appendChild(img2);

console.log(img2);
<img crossOrigin="anonymous" id="preview" style="display:none;" src="https://lh3.googleusercontent.com/-zXZsjsGeYX0/UiuAEl31SDI/AAAAAAAABYI/g77Sb8-lzbY/w1109-h633-no/15-02-2013_internet.jpg">
<canvas id="canvas" style="background-size:contain;display:none;"></canvas>

  • Vlw guy, but the new image(), does not take the image and generates a <img> tag, so no matter the order, but from what I understand, the canvas works exclusively with png is not? Anyway solved, I even knew it was possible to use the append, but I wanted to use only the same canvas, abrç!

  • You are welcome, but what I was trying to say was that the todataurl should be below drawimage because before it was returning a black image (transparent in png equal to jpg black)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.