photopea / UPNG.js

Fast and advanced PNG (APNG) decoder and encoder (lossy / lossless)
MIT License
2.1k stars 259 forks source link

Generate png and retrieve the exact pixel value in canvas #46

Closed traffisco closed 4 years ago

traffisco commented 4 years ago

Hi, I'm trying to encode a raw pixel buffer and later retrieve those exact pixel values on canvas.

let data = new Uint8Array(16* 16* 4);

for (var x = 0; x < data.length; x += 4) {
    data[x] = 1;
    data[x + 1] = 2;
    data[x + 2] = 3;
    data[x + 3] = 4;
}
let imageBuffer = UPNG.encode([data.buffer], 16, 16, 0);

However, I get the pixels compressed when I load the file in canvas(except the alpha which is always correct).

image = document.querySelector('img')    
canvas = document.createElement('canvas');
canvas.height = image.height;
canvas.width = image.width;
context = canvas.getContext("2d");
context.drawImage(image, 0, 0);
data = context.getImageData(0, 0, canvas.width, canvas.height).data;
console.log(data);
photopea commented 4 years ago

Hi, what exactly are you getting? What do you mean by "pixels compressed"?

traffisco commented 4 years ago

I expect to see the raw pixel data. [1,2,3,4] becomes [0,0,0,4]. My goal is to retrieve the exact pixel values [1,2,3,4] without any compression. With pngjs its almost possible with but have little changes to the values 120 randomly becomes 121 for example

photopea commented 4 years ago

I think it is a "bug" in a HTML5 Canvas. The same thing happens here, without any PNG images: https://jsfiddle.net/0g7ykdnr/1/

photopea commented 4 years ago

Most of HTML5 implementations of Canvas represent the data in a "alpha-premultiplied" format.

1 (4/255) / (4/255) == 1, but Math.round(1 (4/255) ) / (4/255) == 0

so if you putImageData into a canvas, and then getImageData, you might receive different data.

traffisco commented 4 years ago

Hmmm... I know canvas used to do browser fingerprinting but thought it's only for specific complex rendering, not with pure buffer.

Is it possible to create a raw data like I can with pngjs? Not sure about writing and reading directly on canvas but it works with a python script. I'm looking for a js implementation to run it on cloudflair worker

בתאריך יום ה׳, 27 בפבר׳ 2020, 18:31, מאת Photopea ‏<notifications@github.com

:

I think it is a "bug" in a HTML5 Canvas. The same thing happens here, without any PNG images: https://jsfiddle.net/0g7ykdnr/1/

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/photopea/UPNG.js/issues/46?email_source=notifications&email_token=AHHOQYHTJMHC2MSETWMUOWDRE7THXA5CNFSM4K45R4Y2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOENFABLQ#issuecomment-592052398, or unsubscribe https://github.com/notifications/unsubscribe-auth/AHHOQYB3SUUMWMOMYFN5TATRE7THXANCNFSM4K45R4YQ .

photopea commented 4 years ago

i dont know what you mean by fingerprinting and how it is related to this.

If you encode specific bytes with UPNG.js, it stores the pixels correctly. But in your example, you draw the image into a canvas, and read it back. You see, that values you get from canvas are different, that those you put inside it (it is not related to UPNG.js at all).

If you need to get the exact pixel values of a PNG image, avoid drawing it into a canvas, and use UPNG.decode() instead.

traffisco commented 4 years ago

My first issue is that the library doesn't draw the pixels correctly like in the code sample above(but with real data). Your library creates a huge difference compared to the raw data. With Pngjs, I get only minor difference. I assumed compression applied.

בתאריך יום ה׳, 27 בפבר׳ 2020, 18:50, מאת Photopea ‏<notifications@github.com

:

i dont know what you mean by fingerprinting and how it is related to this.

If you encode specific bytes with UPNG.js, it stores the pixels correctly. But in your example, you draw the image into a canvas, and read it back. You see, that what you can get different values from canvas, that you put inside it.

If you need to get the exact pixel values of a PNG image, avoid drawing it into a canvas, and use UPNG.decode() instead.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/photopea/UPNG.js/issues/46?email_source=notifications&email_token=AHHOQYCABAY4I5VG5INAD3TRE7VO7A5CNFSM4K45R4Y2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOENFCO2A#issuecomment-592062312, or unsubscribe https://github.com/notifications/unsubscribe-auth/AHHOQYBEQVECE2UJSTWGJV3RE7VO7ANCNFSM4K45R4YQ .

photopea commented 4 years ago

Do you understand the code at my jsfiddle link? I did not use upng.js there

čtvrtek 27. února 2020 Traffisco notifications@github.com napsal(a):

My first issue is that the library doesn't draw the pixels correctly like in the code sample above(but with real data). Your library creates a huge difference compared to the raw data. With Pngjs, I get only minor difference. I assumed compression applied.

בתאריך יום ה׳, 27 בפבר׳ 2020, 18:50, מאת Photopea ‏< notifications@github.com

:

i dont know what you mean by fingerprinting and how it is related to this.

If you encode specific bytes with UPNG.js, it stores the pixels correctly. But in your example, you draw the image into a canvas, and read it back. You see, that what you can get different values from canvas, that you put inside it.

If you need to get the exact pixel values of a PNG image, avoid drawing it into a canvas, and use UPNG.decode() instead.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/photopea/UPNG.js/issues/46?email_ source=notifications&email_token=AHHOQYCABAY4I5VG5INAD3TRE7VO7A 5CNFSM4K45R4Y2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5 WW2ZLOORPWSZGOENFCO2A#issuecomment-592062312, or unsubscribe https://github.com/notifications/unsubscribe-auth/ AHHOQYBEQVECE2UJSTWGJV3RE7VO7ANCNFSM4K45R4YQ .

— You are receiving this because you modified the open/close state. Reply to this email directly, view it on GitHub https://github.com/photopea/UPNG.js/issues/46?email_source=notifications&email_token=ADZXMZSM5VIOJB4IKX3ZWSDRE7XIPA5CNFSM4K45R4Y2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOENFEL4Y#issuecomment-592070131, or unsubscribe https://github.com/notifications/unsubscribe-auth/ADZXMZXLOSGTPZWOVABNRSTRE7XIPANCNFSM4K45R4YQ .

traffisco commented 4 years ago

Yes, i do. That refers to a specific case when both reading and writing done in the canvas :

Due to the lossy nature of converting to and from premultiplied alpha color values, pixels that have just been set using putImageData() might be returned to an equivalent getImageData() as different values.

I hope, that the case is different with already existing data. But, my problem is creating the png, not with the data not being exact(for now). The png the produced with your library is not even close to the original like with Pngjs. I assumed that I missing the correct setting/procedure.

Thanks בתאריך יום ה׳, 27 בפבר׳ 2020, 19:08, מאת Photopea ‏<notifications@github.com

:

Do you understand the code at my jsfiddle link? I did not use upng.js there

čtvrtek 27. února 2020 Traffisco notifications@github.com napsal(a):

My first issue is that the library doesn't draw the pixels correctly like in the code sample above(but with real data). Your library creates a huge difference compared to the raw data. With Pngjs, I get only minor difference. I assumed compression applied.

בתאריך יום ה׳, 27 בפבר׳ 2020, 18:50, מאת Photopea ‏< notifications@github.com

:

i dont know what you mean by fingerprinting and how it is related to this.

If you encode specific bytes with UPNG.js, it stores the pixels correctly. But in your example, you draw the image into a canvas, and read it back. You see, that what you can get different values from canvas, that you put inside it.

If you need to get the exact pixel values of a PNG image, avoid drawing it into a canvas, and use UPNG.decode() instead.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/photopea/UPNG.js/issues/46?email_ source=notifications&email_token=AHHOQYCABAY4I5VG5INAD3TRE7VO7A 5CNFSM4K45R4Y2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5 WW2ZLOORPWSZGOENFCO2A#issuecomment-592062312, or unsubscribe https://github.com/notifications/unsubscribe-auth/ AHHOQYBEQVECE2UJSTWGJV3RE7VO7ANCNFSM4K45R4YQ .

— You are receiving this because you modified the open/close state. Reply to this email directly, view it on GitHub < https://github.com/photopea/UPNG.js/issues/46?email_source=notifications&email_token=ADZXMZSM5VIOJB4IKX3ZWSDRE7XIPA5CNFSM4K45R4Y2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOENFEL4Y#issuecomment-592070131 , or unsubscribe < https://github.com/notifications/unsubscribe-auth/ADZXMZXLOSGTPZWOVABNRSTRE7XIPANCNFSM4K45R4YQ

.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/photopea/UPNG.js/issues/46?email_source=notifications&email_token=AHHOQYEOYHNVX3NDVQLMVHTRE7XSJA5CNFSM4K45R4Y2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOENFEVSI#issuecomment-592071369, or unsubscribe https://github.com/notifications/unsubscribe-auth/AHHOQYCPY65D722SCAJYAA3RE7XSJANCNFSM4K45R4YQ .

photopea commented 4 years ago

The way you achieved the value [0,0,0,4] is not a correct way of reading exact pixel color values from an image. So it is not a proof, that UPNG.js modified your data.

traffisco commented 4 years ago

You are correct. Just did the tests all over again. UPNG.js produces the data I expected. I didn't accounted for alpha channel, setting it to 255 produces the exact pixel data even when displayed on canvas.

Thank you for the help and quick reponses