I'm trying to replace all RGB pixels with the value of 0 to 1 (out of the max value of 255).
Here is my code on stackblitz.
You can see that after I'm reassigning the buffer with the new pixels some of the pixles are back to 0. On Firefox it's actually works with this image:
But won't work with the full size image:
It's like the browser won't allow a certain contrast of something like that.
Sharing my code here as well:
const getBase64FromFile = async (file: File): Promise<string> => {
return new Promise((resolve: Function, reject: Function) => {
let reader = new FileReader();
reader.addEventListener(
'load',
(arg) => {
resolve(reader.result);
},
false
);
reader.readAsDataURL(file);
});
};
// Returns the amount of pixels with RGB 0 value
const howManyZeros = async (src: string): Promise<number> => {
return new Promise((resolve: Function, reject: Function) => {
const image = new Image();
image.onload = () => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = image.naturalWidth;
canvas.height = image.naturalHeight;
ctx.drawImage(image, 0, 0);
const data = ctx.getImageData(
0,
0,
image.naturalWidth,
image.naturalHeight
).data;
let zeros = 0;
for (var i = 0; i < data.length; i += 4) {
if (data[i] === 0) zeros++;
if (data[i + 1] === 0) zeros++;
if (data[i + 2] === 0) zeros++;
}
resolve(zeros);
};
image.src = src;
});
};
const onFinish = async (src: string) => {
document.querySelector(
'p#after'
).textContent = `nunber of zeros after: ${await howManyZeros(src)}`;
(document.querySelector('img#after-img') as HTMLImageElement).src = src;
const a = document.querySelector('a');
a.setAttribute('href', src);
a.setAttribute('download', 'image.png');
a.style.display = '';
};
const onFileChange = async (e: Event | any) => {
const image = new Image();
image.onload = async () => {
const canvas = document.createElement('canvas');
canvas.width = image.naturalWidth;
canvas.height = image.naturalHeight;
const ctx = canvas.getContext('2d');
ctx.drawImage(image, 0, 0);
let data = ctx.getImageData(
0,
0,
image.naturalWidth,
image.naturalHeight
).data;
let buffer = new Uint8ClampedArray(
image.naturalWidth * image.naturalHeight * 4
);
// Iterate over all the pixels and increase all RGB 0 values to 1
for (var i = 0; i < data.length; i += 4) {
if (data[i] === 0) buffer[i] = 1;
else buffer[i] = data[i];
if (data[i + 1] === 0) buffer[i + 1] = 1;
else buffer[i + 1] = data[i + 1];
if (data[i + 2] === 0) buffer[i + 2] = 1;
else buffer[i + 2] = data[i + 2];
buffer[i + 3] = data[i + 3];
}
const iData = ctx.createImageData(image.naturalWidth, image.naturalHeight);
iData.data.set(buffer);
ctx.putImageData(iData, 0, 0);
onFinish(canvas.toDataURL('image/png', 1));
};
let src = await getBase64FromFile(e.target.files[0]);
document.querySelector(
'p#before'
).textContent = `nunber of zeros before: ${await howManyZeros(src)}`;
(document.querySelector('img#before-img') as HTMLImageElement).src = src;
image.src = src;
};
const input: HTMLInputElement = document.querySelector('input');
input.addEventListener('change', onFileChange, false);
Appreciate any help with this and praying that's not a browser issue but something with my code.


Due to
canvasspec, which doesn't guarantee that the pixels stay the same as you set them, you can't use browser built in image manipulation functions.In your case pixel values with high transparency get turned to 0 again.
This doesn't happen in WebGL context with the
premultipliedAlphacontext attribute set tofalse, but the solution involves a lot of code.The following code is based on the example from WebGL2 Fundamentals:
Alternatively you could do it with a 3rd party image manupulation library.
Here's an example using the UPNG.js library: