photopea / UPNG.js

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

APNG images at second index until <numimages> gets offset and gets wrong size #72

Closed EtherTechDev closed 2 years ago

EtherTechDev commented 2 years ago

When encoding buffers to APNG, I noticed that the second (and next-following) images are offset by 1 pixel left/top and has 1 pixel deducted from width and height. This seems like a bug, and it is caused by this code in UPNG.encode.framize function:

if(max==-1) mix=miy=max=may=0;
if(evenCrd) {  if((mix&1)==1)mix--;  if((miy&1)==1)miy--;  }
var sarea = (max-mix+1)*(may-miy+1);
if(sarea<tarea) {
    tarea = sarea;  tstp = it;
    nx = mi
}

I commented the code, and presto, the offset and w/h was correctly encoded for all images. Perhaps removing the code will break something else (I didn't notice any problem though). I used this excellent tool to inspect the APNG images: https://github.com/davidmz/apng-js.

photopea commented 2 years ago

I am not able to make it happen :(

How exactly are you using UPNG.js? If you use it according to the manual, "evenCrd" is never "true".

EtherTechDev commented 2 years ago

It is this code which causes the offset: var sarea = (max-mix+1)*(may-miy+1); if(sarea<tarea) { tarea = sarea; tstp = it; nx = mix; ny = miy; nw = max-mix+1; nh = may-miy+1; } In my code, using 12 64x64 images, nx and ny becomes 1 and nw/nh becomes 63 for image 2 and forward, every image from image 2 has this offset including the last image. When running the code and debugging it, from image 2 and forward, variables get following values sarea is 3969, tarea is 1000000000. mix/miy is 1 max/may is 63

photopea commented 2 years ago

I do not understand what you are saying. Could you send me maybe two static images, which I will give to UPNG.js to see the content "move"?

photopea commented 2 years ago

I tried to put these two PNG into an animation with UPNG.js, but they did not move, the size is correct, too. a b a_b

EtherTechDev commented 2 years ago

Because it is only 1 pixel it is not really noticeable. I will prepare an example, give me a few minutes. Can I send a link or upload a zip or something?

EtherTechDev commented 2 years ago

Sorry, this is not a bug, it seems to be a data (size) saving feature in APNG file format. After some more analysis, it turns out that it contains partial image inter-frame, and it seems like the code mentioned actually is used to determine which part to include (the part of the image that has changed since last frame). I didn't know APNG had this optimization feature, but now I learnt something new. I'm sorry for taking up your time.

EtherTechDev commented 2 years ago

Closing due to not being a bug, but as it seems, a feature of APNG.

photopea commented 2 years ago

Both APNG and GIF can store frames as a "difference from a previous frame", even with transparent pixels (which do not replace pixels in a previous frame), to save space.

EtherTechDev commented 2 years ago

Thanks, got it. Found this link which explains it well. http://littlesvr.ca/apng/inter-frame.html