我的目标是将TIFF图像加载到HTML画布上。前端接收到TIFF图像的ArrayBuffer,我能够利用UTIF解码ArrayBuffer并将其呈现在HTML画布上。但是,另一个功能要求我导出画布内容。为此,我再次使用UTIF将其编码回ArrayBuffer,然后将其传递到后端服务器上使用。
我的实际情况是:
添加ArrayBuffer的代码:
private _addArrayBufferAsImageOnCanvas(buffer: ArrayBuffer, meta?: {}) {
console.log(buffer); // 8 MB input
// Using UTIF.js to decode the array buffer and convert it to ImageData
const ifds = UTIF.decode(buffer);
const timage = ifds[0];
UTIF.decodeImage(buffer, timage);
const array = new Uint8ClampedArray(UTIF.toRGBA8(timage));
// Forming image Data
const imageData = new ImageData(array, timage.width, timage.height);
// a temporary canvas element
const canvas = document.createElement('canvas');
canvas.width = timage.width;
canvas.height = timage.height;
// on which we draw the ImageData
const ctx = canvas.getContext('2d');
ctx.putImageData(imageData, 0, 0);
// Get the image data
const outImageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
// and use UTIF to encode the image
const binaryTiffImage = UTIF.encodeImage(outImageData.data, outImageData.width, outImageData.height);
//
console.log(binaryTiffImage); // 16 MB output
}
作为输入参数的buffer
的大小/字节长度是从画布中提取的binaryTiffImage
的大小/字节长度的一半。 (8MB输入,16MB输出)
是因为UTIF编码不会压缩数组吗? (https://github.com/photopea/UTIF.js/blob/master/README.md#utifencodeimagergba-w-h-metadata)
有没有一种方法可以从加载画布时获得与画布完全相同的ArrayBuffer?
对于比输入大两倍的输出,是的,压缩可能是最大的问题。
但是,即使压缩图像数据,也无法从正在执行的操作中获得完全相同的文件。
首先,压缩器将需要使用与最初使用的设置完全相同的设置,这可能会或可能不会,但是无论如何都不简单。
然后,您将丢失原始TIFF文件中的所有元数据。您的过程仅提取原始位图数据,但是所有可能嵌入此TIFF中的信息(EXIF,jpeg预览等)都将丢失。
不仅丢失了元数据,而且丢失了颜色配置文件和颜色深度,您的代码将原来在TIFF中的内容转换为sRGB @ 32Bits(24bits + alpha)。
[如果您的图像数据使用的是像JPEG这样的松散压缩(虽然很少见,那是可能的,那么您可以通过将凝聚的数据转换为现在的单个像素来创建新数据。
但是,即使您正在使用未经压缩的32bits原始像素数据(已经具有sRGB颜色配置文件并能够放回所有原始元数据,您仍然会遇到一个大问题:
2D canvas API松散:
const ctx = document.createElement('canvas').getContext('2d');
ctx.canvas.width = ctx.canvas.height = 50;
const input = new Uint8ClampedArray(50 * 50 * 4);
crypto.getRandomValues(input); // fill with noise
const input_img = new ImageData( input, 50, 50 );
ctx.putImageData(input_img, 0, 0);
const output = ctx.getImageData(0, 0, 50, 50).data;
const are_different = input.some( (input_value, index) => output[ index ] !== input_value );
console.log( 'input and output are', are_different ? 'different' : 'same' );
// check from your browser's dev-tools
console.table( [input, output] );
公平地说,由于这是由于Alpha预乘而引起的,如果仅只有完全不透明的像素,则不会发生这种情况,但是所有这些点只会加起来。