-
Notifications
You must be signed in to change notification settings - Fork 21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
16bit png/avif decode option #82
Comments
@Ceeeeeeeeb yes, this is definitely possible. I'll need to think about this and how it fits into the project. The packages contained in this repository are more-or-less the same codecs available in https://github.com/GoogleChromeLabs/squoosh. The project is focused on image optimisation and allowing easy interoperability between the image formats, as such only 8bit RGBA image arrays are used. While it would not be that hard to add this functionality, it's more a question of whether we should. |
Thanks for your reply, now I've found a workaround: simply swap the bigendian bytes then cast the Uint8Array to Uint16Array. But I'm still hoping for 16bit image decode support for png/avif decode (I've not found other avif web decode package can do this). Because we are developing a medical web viewer, which means higher bit depth is needed for medical diagnose. Regardless of whether this feature is ultimately supported or not, thank you for your consideration. |
@Ceeeeeeeeb it ended up being slightly more involved than I initially thought. I've released a beta version that you can install with If this works ok for your use cases I can look at tidying this up and creating a stable release. The beta package contains an explicit method for decoding to 16-bit RGBA data. It works on both 8-bit and 16-bit images. import { decodeRgba16 } from '@jsquash/png';
const imageBuffer = await fetchYour16BitImage();
// The data array will always be an instance of Uint16Array
const { data, width, height } = await decodeRgba16(imageBuffer);
// You might want to check that the 16-bit color values are correctly mapped in the data array You can also encode to a 16-bit PNG. import { encode } from '@jsquash/png';
async function create16bitImage(src) {
const pixels = new Uint16Array(4 * 50 * 50);
for (let i = 0; i < pixels.length; i += 4) {
pixels[i] = 0; // R
pixels[i + 1] = 65535; // G
pixels[i + 2] = 0; // B
pixels[i + 3] = 65535; // A
}
return {
data: pixels,
width: 50,
height: 50,
};
}
const rawImageData = await create16bitImage();
const png16bitBuffer = await encode(rawImageData, { bitDepth: 16 }); Edit: I'll need to think about how Endianess plays a role. From my knowledge PNG always requires Big Endianess, according to the standard. Curious why you need the opposite? |
@jamsinclair Thanks,I've tried the beta package and it works well for my use case. About the endianess, I need to pass the Uint16Array to webgl and render it to a canvas. And about the decoding perfomance, I tried to compare the decode time cost between your beta package and upng.js, sadly I found that decodeRgba16 is slower than my current using work flow:
var png = UPNG.decode(data);
var arr = png.data;
for (let i = 0; i < arr.length - 1; i += 2) {
[arr[i], arr[i + 1]] = [arr[i + 1], arr[i]];
}
var uintArray = new Uint16Array(arr.buffer); my test image will be attached to this comment. Futher more, is it possible to support 16bit decode for other format like avif? |
Thanks for the great feedback @Ceeeeeeeeb
On my MacOS with M1 CPU I got these results in the browser:
You're right, I think that's to be expected. There's a bit of a performance overhead with WASM as we have to both load the module and transfer data between the two contexts. Upng seems to be well written and performance tuned as it was made for the well known photo editing software Photopea.
With the current encoders, it seems like 12 bits is the maximum color depth available for encoding. The |
It looks like the newer JPEG XL format can support 32 bit values per channel. So theoretically I think RGBA16 lossless images could efficiently be shared in that format. I'm not sure if those images can be viewed as intended or whether you would need to do your own post-processing to get the correct RGBA values. |
ok, I have to use upng for png decoding for better performance 😔, but I will try libavif for avif files, actually we just need 10bit precision (as most medical monitor only support 10bit). Thanks a lot for your kind reply! By the way, currently @jsquash/avif don't support choose bitdepth either, perhaps I need a decodeRgba10 interface? |
@Ceeeeeeeeb That is correct. I'll need to implement that for the avif package. I have created a proof of concept so it's definitely doable. I'll need to think of if there's a cleaner interface for sharing the decoded data. To avoid breaking changes, for now, I'll likely proceed with new methods like:
Please note that the AVIF decoding speed is probably much slower than PNG. However, due to the smaller AVIF file sizes you may still slightly save on speed overall (e.g. faster image transfer on the network than PNG) |
Is your feature request related to a problem? Please describe.
I'm trying to decode a 16bit png, now I'm using upng.js which could correctly treat it as a 16bit per channel image, but stores the pixels as a bigendian Uint8Array, so I have to manually combine two 8bit value to the orignal 16bit value(this takes a lot time).
so I wonder could it be possible to decode the image as a Uint16Array directly?
Describe the solution you'd like
the decode function take an optional param (just like the avif.encode function does now) consider the bitDepth and return an Uint8Array which stores littlendian 16bit values,so I can directly convert it to Uint16Array without any manual conversion.
Describe alternatives you've considered
Consider the trade off between file size & encode/decode time cost, maybe avif.decode the better choice?
The text was updated successfully, but these errors were encountered: