説明
Issue or Feature
I'm trying to recreate the pixel data of an JPEG image from base64 or URL and compare it to the pixel values generated in Python's Pillow library, which is common regarded as a solid benchmark for Image Processing in Python. I noticed that an image read by node-canvas differs significantly from the same image in Python. Here are the scripts I've used to visualize this. I thought to compare node-canvas and python to jpeg-js as well, and found that all three of them differ.
An interesting point to note, while JPEG differs, the pixel data for PNG images in Python and node-canvas match.
Steps to Reproduce
Script used to generate a random image and then read and convert to pixel data (generates a comma-separated pixel file).
import numpy as np
from PIL import Image
arr = np.zeros((32,32,3), dtype=np.uint8)
for i in range(32):
for j in range(32):
arr[i,j] = np.random.randint(255, size=(1,3))
im = Image.fromarray(arr)
im.save('test.jpg')
img_8u = np.array(Image.open('test.jpg').getdata(), dtype=np.uint8)
with open('img_py.txt', 'w') as f:
f.write(','.join(map(str, img_8u.flatten().tolist())))
Script used to generate pixel data in Nodejs (generates a comma-separated pixel file):
const Canvas = require("canvas")
const fs = require("fs")
const jpeg = require("jpeg-js")
function drawCanvas(url, shape) {
var cvs = Canvas.createCanvas(shape[0], shape[1]);
var context = cvs.getContext('2d');
var img = new Canvas.Image;
img.onload = function() {
context.drawImage(img, 0, 0);
};
img.src = url;
return context;
}
function preprocessAndStore(imageData, fileName) {
var rgbFP32 = new Float32Array(cleanAndStripAlpha(imageData))
fs.writeFile(fileName, rgbFP32.join(','), (err) => {
if (err) throw err;
})
}
function cleanAndStripAlpha(imageData) {
const width = imageData.width;
const height = imageData.height;
const npixels = width * height;
const rgbaU8 = imageData.data;
// Drop alpha channel and retain rgb
const rgbU8 = new Uint8Array(npixels * 3);
for (let i = 0; i < npixels; ++i) {
rgbU8[i * 3] = rgbaU8[i * 4];
rgbU8[i * 3 + 1] = rgbaU8[i * 4 + 1];
rgbU8[i * 3 + 2] = rgbaU8[i * 4 + 2];
}
return rgbU8;
}
// Node-Canvas
var width = 32
var height = 32
var imgData = drawCanvas("test.jpg", [width, height])
preprocessAndStore(imgData.getImageData(0, 0, width, height), 'image_canv.txt')
// JPEG JS
// var jpegdata = fs.readFileSync('test.jpg')
// var rawImgData = jpeg.decode(jpegdata)
// preprocessAndStore(rawImgData, 'image_jpegjs.txt')
The two text files should be comparable with any diff checker. If you wish to recreate all my experiments, you will find that monochrome images or images with a uniform color will be regenerated correctly but the moment variation is introduced (an image of a dog for example), the colors returned are different, even though the image may look similar.
What might be causing this and how can this be resolved?
Your Environment
- Version of node-canvas (output of
npm list canvasoryarn list canvas): 2.6.1 - Environment (e.g. node 4.2.0 on Mac OS X 10.8): node v12.16.1