gpt4 book ai didi

JavaScript 将 Canvas 转换为 PGM

转载 作者:行者123 更新时间:2023-11-30 15:17:41 25 4
gpt4 key购买 nike

我正在尝试将 JavaScript 中的 Canvas 转换为 pgm。在我转换文件并将其下载到我的 table ​​面后,它具有 pgm 扩展名,但是当我用编辑器打开它时,它被编码为 png。我认为如果 JavaScript 无法识别您要转换为的扩展名,它会默认将其转换为 png。所以 JavaScript 可以转换为 png、jpeg 等,但不能转换为 pgm?

我的问题是是否可以使用 JavaScript 将 canvas 转换为 pgm,如果没有,是否有任何可用的插件或 Js 库可以这样做。

function image_download() {
canvas = $('#canvas').get(0);
var image = new Image();
image.src = canvas.toDataURL("image/pgm");


var download = document.createElement('a');
download.href = image.src;
download.download = 'map.pgm';
download.click();
}

最佳答案

PGM 编写器

为了将 Canvas 保存为 PGM,我刚去了 http://netpbm.sourceforge.net/doc/pgm.html其中详细说明了文件格式,并使用该信息创建了一个将 Canvas 转换为 PGM bin 的函数。

转化

文件有一个描述文件和内容的头,然后是一个二进制值数组,8 位或 16 位

所以从标题开始并将其创建为字符串

const CR = "\n";
var header = "P5" // required
header += CR; // add whitespace char
header += canvas.width;
header += CR; // add whitespace char
header += canvas.height;
header += CR; // add whitespace char

header 不完整,但我们需要获取像素值的最大值,以便转换图像并找到最大值。

因此通过 2D 上下文获取像素数据。

var imgData = ctx.getImageData(0,0,ctx.canvas.width,ctx.height);

关于您想要的数据,您有多种选择。该格式为某些值指定对数标度,为其他值指定线性标度。如果保持 Gamma 很重要,我会留给你找到转换。 (请注意,仅当您计划广播或保存光值(例如天文图像)时才需要)

有一个实用程序可以将线性 Gamma 函数转换为 BT.709 Gamma 函数。查看链接文档

我添加了一些简单的格式。两个为16位,最大值为3*255。

如果您从 jpeg 编码图像转换,最好通过首先将像素 RGB 转换为 HSL 并仅将 L 保存为 8 位值来从图像中提取亮度,这将阻止 jpeg 质量差的色调和饱和度数据影响结果(jpeg 具有近乎无损的灰度数据)

const formats = {
mean : {
convert (r, g, b) { bin[j++] = ((r + g + b) / 3 ) | 0 },
dataStore (w, h) { return new Uint8Array(w * h) },
},
summed : {
convert (r, g, b) { bin[j++] = r + g + b },
dataStore (w, h) { return new Uint16Array(w * h) },
},
meanLog : {
convert (r, g, b) { bin[j++] = Math.sqrt((r * r + g * g + b * b)/ 3) | 0 },
dataStore (w, h) { return new Uint8Array(w * h) },
},
summedLog : {
convert (r, g, b) { bin[j++] = Math.sqrt(r * r + g * g + b * b) | 0 },
dataStore (w, h) { return new Uint16Array(w * h) },
}
}
var imgData = ctx.getImageData(0,0,ctx.canvas.width,ctx.canvas.height);
var format = formats.mean;
var bin = format.dataStore(canvas.width, canvas.height);
var r,g,b,summed,mean,summedLog,meanLog;
var i = 0;
var j = 0;
var max = 0;
var d = imgData.data; // shorthand var to pixel data
while(i < d.length){
format.convert(d[i++],d[i++],d[i++]);
max = Math.max(bin[j-1],max);
i++; // skip alpha
}
header += max; // max value.
header += CR; // add whitespace char
// We have all that is needed to create the file so first convert
// header string to ascII
var fileBin = new Uint8Array(header.length + bin.length);
for(i = 0; i < header.length; i++){
fileBin[i] = header.charCodeAt(i) & 0b01111111; // strip of top bit just in case superstitious coder reads this
}
fileBin.set(new Uint8Array(bin.buffer),header.length); // add the pixel data

// fileBin is the 8bit bin of the PGM file
// Note transparent pixels are black.
// Note I do not check for all black. Format doc indicates that a max val in the head of zero is illegal. What that means you will have to find out.

就是这样。您可以将其转换为 Base64 编码,或者按原样保存

请注意,在此答案之前我从未使用过或听说过这种图像格式,上面的代码是对答案顶部链接的文档的快速解释。如果它有效,我不知道,因为我没有任何东西可以测试它。该代码没有语法和运行时错误。

它更像是展示如何为特定格式创建二进制文件的指南

更新

JPEG 亮度保留

我想我还会添加一种格式来处理 JPEG 图像,它只需要一个良好的 RGB 到 HSL 函数。

   // NOTE to prevent data loss the out put of lum has been
// scaled from the normal 0-100 to 0-255 for the example PGM image format
// If you use this function to get HSL values compatible with HSL CSS
// colours change the multipliers from 255 to 100. Commented with [*1]
function rgb2hsl(r,g,b){ // integers in the range 0-255
var minC, maxC, dif, h, l, s;
h = l = s = 0;
r /= 255; // normalize channels
g /= 255;
b /= 255;
min = Math.min(r, g, b);
max = Math.max(r, g, b);
if(min === max){ // [*1] no colour so early exit
return {
h, s,
l : Math.floor(min * 255), // this normally is 0-100
}
}
dif = max - min;
l = (max + min) / 2;
if (l > 0.5) { s = dif / (2 - max - min) }
else { s = dif / (max + min) }
if (max === r) {
if (g < b) { h = (g - b) / dif + 6.0 }
else { h = (g - b) / dif }
} else if(max === g) { h = (b - r) / dif + 2.0 }
else {h = (r - g) / dif + 4.0 }
h = Math.floor(h * 60);
s = Math.floor(s * 100);
l = Math.floor(l * 255); // [*1] this normally is 0-100
return {h, s, l};
},

然后将以下内容添加到格式对象

    formats.jpegLumPreserve = {
convert (r, g, b) { bin[j++] = rgb2hsl(r + g + b).l},
dataStore (w, h) { return new Uint8Array(w * h) },
}

如果您从最初存储为 jpeg (jpg) 的图像中保存,您应该使用此格式

    format = formats.jpegLumPreserve;

感知

因为总是有一些聪明人啊...需要兜售感知亮度转换的人,我也会补充一点,因为他们通常会弄错。正如我认为转换是一个老笑话,转换基于 2/7/1 规则并在对数空间中完成。

    formats.perceptual = {
convert (r, g, b) { bin[j++] = Math.sqrt(r * r * 0.2 + g * g * 0.7 + b * b * 0.1) | 0},
dataStore (w, h) { return new Uint8Array(w * h) },
}

这是基于成年人感知红色、绿色和蓝色 3 种原色并将灰色(亮度)结果与感知颜色亮度相匹配的平均能力。

关于JavaScript 将 Canvas 转换为 PGM,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44260008/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com