9

I am trying to perform simple operations on image using javascript. To get the pixels of the image, I am drawing the image on canvas and then get the ImageData from canvas. But for large images, drawing them on the canvas takes a lot of time.

Is there any other way of getting the image pixels without using the canvas element?

jopasserat
  • 5,721
  • 4
  • 31
  • 50
Pulkit Goyal
  • 5,604
  • 1
  • 32
  • 50
  • 2
    Is it really that slow? Maybe it's faster if you don't draw the image to the screen, but to the canvas only. – Harmen Jun 13 '11 at 12:22
  • I am drawing it to the canvas and not the screen. But its still lot slower than most of the image editing tools. – Pulkit Goyal Jun 13 '11 at 13:01
  • 1
    Most image editing tools are hardware accelerated; not all browsers support hardware acceleration for canvas yet. But what browser are you testing with? – Harmen Jun 13 '11 at 15:11
  • Would [$.getImageData](http://www.maxnov.com/getimagedata/) help ? – George Profenza Jun 13 '11 at 16:20
  • @Harmen, I am testing with Firefox and Chrome. – Pulkit Goyal Jun 13 '11 at 21:36
  • @George From what I've read about the plugin, it helps in obtaining the image object given a url. We would still need to get the pixels by drawing the image on canvas. – Pulkit Goyal Jun 13 '11 at 21:42
  • @Pulkit could you not use the **data** property and loop through pixel values, similar to [this post](http://stackoverflow.com/questions/667045/getpixel-from-html-canvas) ? Regarding hardware acceleration, Chrome and Firefox 4 should have support for that, but different machines support different GLSL features. Have a look at [ShaderToy](http://www.iquilezles.org/apps/shadertoy/) to see some GLSL shaders running in the browser. – George Profenza Jun 14 '11 at 07:59
  • @George I would still need to draw the image on canvas before I can get the data. Drawing on the canvas is taking time. I will take a look at hardware acceleration. Thanks. – Pulkit Goyal Jun 14 '11 at 21:20

4 Answers4

2

The example below uses MarvinJ. It takes a colored image having 2800x2053 resolution, iterate through each pixel calculating the gray value and setting it back. Above the canvas there is a div to print the processing time. On my machine, it took 115ms including image loading.

var time = new Date().getTime();

var canvas = document.getElementById("canvas");
image = new MarvinImage();
image.load("https://i.imgur.com/iuGXHFj.jpg", imageLoaded);

function imageLoaded(){
 
  for(var y=0; y<image.getHeight(); y++){
    for(var x=0; x<image.getWidth(); x++){
       var r = image.getIntComponent0(x,y);
       var g = image.getIntComponent1(x,y);
       var b = image.getIntComponent2(x,y);
       
       var gray = Math.floor(r * 0.21 + g * 0.72 + b * 0.07);
       
       image.setIntColor(x,y,255,gray,gray,gray);
     }
   }
   image.draw(canvas);
   
   $("#time").html("Processing time: "+(new Date().getTime()-time)+"ms");
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://www.marvinj.org/releases/marvinj-0.7.js"></script>
<div id="time"></div>
<canvas id="canvas" width="2800" height="2053"></canvas>
Gabriel Archanjo
  • 4,547
  • 2
  • 34
  • 41
  • What takes time is getting the image data. You are starting the timer after this operation. https://jsfiddle.net/68vppz1u/ And for something like grayscale, you can achieve the same far faster with globalCompositeOperations : https://jsfiddle.net/68vppz1u/2/ – Kaiido Nov 16 '17 at 02:47
  • I changed my answer. The timer is started at the first js line. – Gabriel Archanjo Nov 16 '17 at 02:51
2

I don't think you can have image manipulation in JavaScript with hardware acceleration, so no matter if it's canvas or other technology you won't gain much marginal benefit within JavaScript environment.

If you want your code to be hardware accelerated, your code must be compiled into something that is ran in a GPU and has access to graphics memory. Flash and Silverlight's approach is introducing shading language like AGAL and HLSL. Maybe JavaScript will have something like this in the future.

So my suggestion is to do image processing with:

  1. Server side technology
  2. Flash and Silverlight with shading language
Cat Chen
  • 2,387
  • 17
  • 12
  • Yes. Thanks for reminding. WebGL cannot do pixel manipulation, right? So it seems pixel level JavaScript still cannot be compiled to GPU accelerated code. – Cat Chen Jul 26 '11 at 09:41
  • you can run a kernel on a WebGL image using glsl, however you need to convert the image buffer to some byte array to then being able to read it using js. But the last time I did this was long time ago as well… – Flavien Volken Aug 20 '21 at 18:03
1

I don't have much experience with Javascript but Max Novakovic(@betamax) wrote a nice a tiny jQuery plugin called $.getImageData which might be helpful.

You can read more about $.getImageData on the disturb blog and the plugin page

close pixelation example

You should be able to access pixels through something like context.getImageData(x, y, width, height).data.

Also, you mentioned hardware acceleration, and that should be available in Firefox4 and Chrome. Shadertoy uses GLSL shaders in the browser:

ShaderToy preview

George Profenza
  • 50,687
  • 19
  • 144
  • 218
  • As I also mentioned above, from what I've read about the plugin, it helps in obtaining the image object given a url. We would still need to get the pixels by drawing the image on canvas – Pulkit Goyal Jun 14 '11 at 21:17
0

I'm not sure, but might it be possible to write the image data as a string, and manipulate the string, then translate it back into an image before showing the resulting image?

This wouldn't require drawing to canvas, only loading the image data as a string instead of an image. It would, however, involve some complex and possibly difficult to get right string manipulation, to make sure the image data translated correctly and moreso to manipulate the pixels.

It would also mean the string is likely to be very long for larger images, so this might take more memory than canvas would and could potentially need to be split into multiple strings. In exchange it may be faster than drawing to canvas, especially with multiple strings if you only need to manipulate part of the image.

I'm not experienced with image manipulation but theoretically there's no reason a file's data couldn't be written into a string. It is just, again, going to make a very long string and have a possible RAM impact because of it because the string could take up more RAM than the image file itself. But it will be faster loading since it doesn't have to process the data as much as it would to draw to canvas.

Raymond
  • 41
  • 1