3

I have a canvas element CA where I'm drawing some fancy stuff on. Then I run kind of a filter over the ImageData IDA from canvas CA and create new, modified ImageData IDB. Now, I want this IDB to be converted to a base64 string without the need of a second helper canvas CB.

Everything I've found on this topic shows a whole canvas being converted to a dataURL. Is it possible without CB? How?

var CA = document.getElementById("CA");
var ctx = CA.getContext("2d");

ctx.beginPath();
ctx.fillRect(100, 100, 100, 100);
ctx.stroke();
ctx.closePath();

var srcImg = ctx.getImageData(0, 0, CA.width, CA.height),
    srcData = srcImg.data,
    dstImg = ctx.createImageData(srcImg),
    dstData = dstImg.data;

for (var i=0, maxI=srcData.length; i<maxI; i+=4) {
  //invert
  if (srcData[i+3] > 0) {    
    dstData[i] = dstData[i+1] = dstData[i+2] = 255;
    dstData[i+3] = 0;
  }
  else {
    dstData[i] = dstData[i+1] = dstData[i+2] = 0;         
    dstData[i+3] = 255;
  }
}

//how to create base64 from dstImg??
//...

//just for visualization
document.getElementById("CB").getContext("2d").putImageData(dstImg, 0, 0);
canvas {
  border : 1px solid;
}
<canvas id="CA" width="400" height="300"></canvas>
<!-- I'd like to avoid this helper canvas CB -->
<canvas id="CB" width="400" height="300"></canvas>
Fidel90
  • 1,828
  • 6
  • 27
  • 63
  • 1
    You could clone the original `` element, call `.clearRect()`, `.putImageData()`, `clone.toDataURL()` – guest271314 Aug 05 '16 at 06:13
  • @guest271314: Hey, thanks for your help. This indeed works nicely. I'm using `CA.cloneNode(false);` for this. If you could create an answer I'll accept it :) – Fidel90 Aug 05 '16 at 06:55

1 Answers1

2

You could clone the original <canvas> element, .putImageData(), clone.toDataURL()

var CA = document.getElementById("CA");
var ctx = CA.getContext("2d");

ctx.beginPath();
ctx.fillRect(100, 100, 100, 100);
ctx.stroke();
ctx.closePath();

var srcImg = ctx.getImageData(0, 0, CA.width, CA.height),
  srcData = srcImg.data,
  dstImg = ctx.createImageData(srcImg),
  dstData = dstImg.data;

for (var i = 0, maxI = srcData.length; i < maxI; i += 4) {
  //invert
  if (srcData[i + 3] > 0) {
    dstData[i] = dstData[i + 1] = dstData[i + 2] = 255;
    dstData[i + 3] = 0;
  } else {
    dstData[i] = dstData[i + 1] = dstData[i + 2] = 0;
    dstData[i + 3] = 255;
  }
}

var clone = document.getElementById("CA").cloneNode();
var ctx = clone.getContext("2d");
ctx.putImageData(dstImg, 0, 0);
var url = clone.toDataURL();
var img = document.createElement("img");
img.onload = function() {
  document.body.appendChild(this);
  console.log(url);
}
img.src = url;
canvas {
  border: 1px solid;
}
<canvas id="CA" width="400" height="300"></canvas>
guest271314
  • 1
  • 15
  • 104
  • 177
  • 1
    Btw: Is `clearRect()` really needed or does `putImageData()` replace the whole content as I would expect? – Fidel90 Aug 05 '16 at 07:06
  • That makes it even better. Thanks again :) – Fidel90 Aug 05 '16 at 07:10
  • 3
    Even if it does solve OP's issue that unfortunately doesn't answer the title question, since `clone` is a canvas element. The question title should be reformulated to ...without a visble canvas element. (I say that because I know [someone](http://stackoverflow.com/q/38781413/3702797) will be looking for a standalone png encoder) – Kaiido Aug 05 '16 at 15:12
  • @Kaiido Tried, though not certain how to create a `File` object from `ImagData` object, though that could also be another variation of a Question. At linked post, it should be possible to use `canvas.toBlob()`, then use `FileReader` to create `data URL`. An alternative approach would be to send a `FormData` object including `Blob` as `File` object, use `FileReader` at `message` event. Another approach could use `SharedWorker` to send, receive image as `File` object or `data URL` – guest271314 Aug 06 '16 at 03:05
  • For linked question in my comment he needs to get rid of canvas entirely, thus he has to generate the png file in js from scratch. His problem is not in the base64 encoding, but in the png decoding/encoding being different in every implementation. He could not even use an imageData. – Kaiido Aug 06 '16 at 03:17
  • @Kaiido Interesting links. – guest271314 Aug 06 '16 at 04:03