0

I'm using the PNG library from here: http://www.xarg.org/download/pnglib.js and here's my code:

var h=20;
var w=20;
var p = new PNGlib(h, w, 256);
var background = p.color(0, 0, 0, 0); // set the background transparent
for (var i = 0; i < h; i++) {
    for (var j = 0; j < w; j++) {
        p.buffer[p.index(i, j)] = p.color(0xcc, 0xee, 0x00);
    }
}
var pngStr = p.getDump();
var target1 = document.getElementById("target1");
target1.src = 'data:image/png;base64,'+btoa(pngStr);
//var pngStr = atob(target1.src.split(',')[1]);
//if(pngStr != pngStr2) alert("string don't match");
var pngbytes = new TextEncoder().encode(pngStr);
var blob = new Blob([pngbytes],  {type: 'image/png'});
var urlCreator = window.URL || window.webkitURL;
var imageUrl = urlCreator.createObjectURL( blob );
var target2 = document.getElementById("target2");
target2.src = imageUrl;

As can be seen in this fiddle: https://jsfiddle.net/1c0ggvfy/3/

The base64 encoded version works, but the blob version doesn't. But this fiddle, which does the same thing, does work for a blob png: http://jsfiddle.net/ec9y6k9e/

The only difference I can see is that I have to get the data into a binary form to pass it to the Blob... I've tried a few different ways of doing that, but it seems to make no difference.

EDIT: As pointed out by Kaiido, the problem seems to be the TextEncoder. I had tried iterating through the string to fill a Uint8Array earlier, but at that time I had a second issue which was I was calling the Blob constructor without putting brackets around the first parameter. Here's working code:

var target1 = document.getElementById("target1");
target1.src = 'data:image/png;base64,'+p.getBase64();
var pngStr = atob(target1.src.split(',')[1]);
var bytes = new Uint8Array(pngStr.length);
for(var i=0; i<pngStr.length; i++){
    bytes[i]= pngStr.charCodeAt(i);
}
var blob = new Blob([bytes],  {type: 'image/png'});
var url = URL.createObjectURL(blob);
var target2 = document.getElementById("target2");
target2.src = url;

EDIT 2: A great answer would have included this: Chars in javascript are 2 bytes (https://mathiasbynens.be/notes/javascript-encoding) so thinking of them as equivalent to a byte can lead to unexpected results. TextEncoder is UTF-8 (https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder) so it represents characters with a code point higher than 127 is two bytes, where charCodeAt returns an integer representing the character (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charCodeAt) - if that integer is 255 or less, it can be used in a Uint8Array to represent a single byte.

new TextEncoder().encode("\211")
->Uint8Array(2) [194, 137]

"\211".charCodeAt(0)
->137
Aerik
  • 2,307
  • 1
  • 27
  • 39
  • I'm hesitating to vote to reopen because the issue here is that `TextEncoder` returns an utf-8 encoded representation of the data, while you need an utf-16 one. Unfortunately, implementations have dropped the `encoding` option of `TextEncoder`... – Kaiido May 16 '17 at 04:21
  • I have tried creating uint8array and filling it with charcodeat also, but still couldnt get it to work. @guest271314, I dont see how its an exact duplicate, Im asking for guidance as to why my code doesnot work, which those questions dont provide. – Aerik May 16 '17 at 06:47
  • 1
    the solutions provided in the dupes should work : https://jsfiddle.net/1c0ggvfy/5/ As I said in the previous comment, if the solution in your question doesn't work it's because TextEncoder encodes in utf-8. Also, if you want to use a blob, working directly with TypedArrays in this PNGLib function would probably be better, though it may need some work. – Kaiido May 16 '17 at 13:07
  • @Kaiido Should Question be reopened to address `TextEncoder` usage by OP? – guest271314 May 16 '17 at 14:17
  • @guest271314 I was hesitant this morning but this seems to be a rather hackish failed workaround which should not be helpful to too many people in the future for this particular case. My first comment should be enough, real solutions are in the dupe target. – Kaiido May 16 '17 at 14:20
  • @Kaiido Concur except for the term "hackish" as a description of OP's attempts to return expected result. That term being applied to another user could be construed in a manner which is not positive depending on perspective. That is, "hackish" is not OP's user name. – guest271314 May 16 '17 at 14:23
  • @Kaiido Thank you very much for the working code. I think these comments provide a helpful advice should someone else stumble on to this question, although I can't grasp why there is so much controversy over whether or not to just answer the question - as Kaiido basically did in the first comment. P.S. Why describe some "proof of concept" code as "a hackish failed workaround"? – Aerik May 16 '17 at 14:26
  • @guest271314 and OP, I'm not a native English speaker but for me "haskish" is an adjective derived from "hack / hacking" which in our audience area means "use of unexpected ways to obtain an expected result". There is nothing negative in it when it comes from my keyboard. And the hack here was to use TextEncoder for something that it wasn't made for. Clever, could have worked, but didn't. – Kaiido May 16 '17 at 23:00
  • @Kaiido Perhaps it is just this user. english is not this users' "native" tongue either. "hackish" was used recently as a way to accuse this user of attempting to appear to be, ironically, "clever". Which wound up with a so-called "moderator" pushing their little button to give this user an "account suspension" when stood on original code, and in kind, rebutted the "ish" moniker. This users' user name is not "hackish". Do no do anything "ish", here. Either full bore or nothing at all. In any event, no worries; did not get a negative vibration from you. Your contributions are clearly positive – guest271314 May 16 '17 at 23:15
  • Thanks for the clarifications guys. And thanks again for pointing out the error with TextEncoder. – Aerik May 17 '17 at 01:59

0 Answers0