简体   繁体   中英

JavaScript canvas image data manipulation

I want to resize image using very simple algorithm. I have something like this:

var offtx = document.createElement('canvas').getContext('2d');
offtx.drawImage(imageSource, offsetX, offsetY, width, height, 0, 0, width, height);
this.imageData = offtx.getImageData(0, 0, width, height).data;
offtx.clearRect(0, 0, width, height);

for(var x = 0; x < this.width; ++x)
{
    for(var y = 0; y < this.height; ++y)
    {
        var i = (y * this.width + x) * 4;
        var r = this.imageData[i ];
        var g = this.imageData[i+1];
        var b = this.imageData[i+2];
        var a = this.imageData[i+3];
        offtx.fillStyle = "rgba("+r+","+g+","+b+","+(a/255)+")";
        offtx.fillRect(0.5 + (x * this.zoomLevel) | 0, 0.5 + (y*this.zoomLevel) | 0, this.zoomLevel, this.zoomLevel);
    }
}

this.imageData = offtx.getImageData(0, 0, this.width * this.zoomLevel, this.height * this.zoomLevel);

However, the problem I have with this solution, is that the image looses any transparency information that way. I don't know if this happens somewere in this algorithm, or maybe putImageData that I am using later to display that image is doing this, but I can't seem to be able to preserve transparency.

Each time I do this I create a canvas, I put the image on that canvas and use getImageData to get image from that canvas as you can see in the first lines of the code. Maybe there is no other way, so I might not mind that...

But the problem is I use two for loops to draw resized image and then use getImageData to store that image information. This is a wierd way to do it. I would prefer to create empty image data and fill it with all the original image information only resized. I can't grasp that with my mind, I can't image the loop structure for this. To show what I mean:

for(var x = 0; x < this.width; ++x)
{
    for(var y = 0; y < this.height; ++y)
    {
        var i = (y * this.width + x) * 4;
        var r = this.imageData[i ];
        var g = this.imageData[i+1];
        var b = this.imageData[i+2];
        var a = this.imageData[i+3];
        //I WOULD LIKE MAGIC TO HAPPEN HERE THAT WILL
        //RESIZE THAT CURRENT PIXEL AND MOVE IT TO THE NEW IMAGE DATA RESIZED
        //SO EVERYTHING IS DONE NICE AND CLEAN IN THIS LOOP WITHOUT THE 
        //GETIMAGEDATA LATER AND MAYBE SET TRANSPARENT PIXELS WHILE I'M AT IT
    }
}

I can't figure out the MAGIC part.

Thank you for reading!

Why not just use the built-in drawImage combined with image smoothing disabled? Doing this operation in a loop is not only relative slow but also prone to errors (as you already discovered).

Doing it the following way will give you the "pixel art" look and will also preserve the alpha channel:

var factor = 4; /// will resize 4x

offtx.imageSmoothingEnabled = false; /// prefixed in some browsers
offtx.drawImage(imageSource, offsetX, offsetY, width, height,
                             0, 0, width * factor, height * factor);

Here is an online demo .

Try using this library I recently made which can load an image, resize it fixed width & height or precentage.

It does exactly what you need, and much more like converting canvas to base64, blob, etc...

var CanvaWork = new CanvaWork();
CanvaWork.canvasResizeAll(obj.canvas, function(canvases){
    // "canvases" will be an array containing 3 canvases with different sizes depending on initial options
});

https://github.com/vnbenny/canvawork.js

Hope this helps you!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM