因为浏览器原生不支持PGM格式的图片,所以需要先将pgm图片转换为浏览器可以理解的格式。
demo 使用 vue3 + ts <个人使用记录>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
const canvas = ref();
onMounted(()=>{
// 获取远程的 pgm 地址 获取方式随意
// 获取成功后转换 arrayBuffer
fetch('pgmUrl').then(res=>res.arrayBuffer()).then(arrBufffer=>{
// 处理buffer 并获取数据
const pgmData = parsePGM(arrBufffer);
// 渲染buffer到canvas
drawPGMToCanvas(canvas, pgmData);
})
});
const parsePGM => (arrBufffer: ArrayBufferLike) {
const view = new DataView(arrBufffer);
// 读取文件头
let offset = 0;
while (offset < view.byteLength) {
const line = readLine(view, offset);
offset += line.length + 1; // 加上换行符的长度
if (line.startsWith('P5')) {
// P5 是 PGM 的二进制格式标识
break;
}
// 读取宽度、高度和最大灰度值
const width = readNumber(view, offset);
offset += width.length + 1;
const height = readNumber(view, offset);
offset += height.length + 1;
const maxValue = readNumber(view, offset);
offset += maxValue.length + 1;
// 读取图像数据
const data = new Uint8Array(view.buffer, offset);
return { width: parseInt(width), height: parseInt(height), maxValue: parseInt(maxValue), data };
}
}
const drawPGMToCanvas = (canvas: HTMLCanvasElement, pgmData: { width: number; height: number; maxValue: number; data: Uint8Array }) => {
const ctx = canvas.getContext('2d');
if (!ctx) return;
const { width, height, data } = pgmData;
const imageData = ctx.createImageData(width, height);
for (let i = 0; i < data.length; i++) {
imageData.data[i * 4] = data[i];
imageData.data[i * 4 + 1] = data[i];
imageData.data[i * 4 + 2] = data[i];
imageData.data[i * 4 + 3] = 255;
}
canvas.width = width;
canvas.height = height;
ctx.putImageData(imageData, 0, 0);
};
const readLine = (view: DataView, offset: number) => {
const chars = [];
const flag = true;
while (flag) { // eslint 限制while 不能直接使用字面量
const char = view.getUint8(offset);
if (char === 10 || char === 13) {
// 换行符或回车符
// flag = false;
break;
}
chars.push(String.fromCharCode(char));
offset++;
}
return chars.join('');
};
const readNumber = (view: DataView, offset: number) => {
const chars = [];
let flag = true; // eslint 限制while 不能直接使用字面量
while (flag) {
const char = view.getUint8(offset);
if (char === 32 || char === 10 || char === 13) {
// 空格、换行符或回车符
break;
}
chars.push(String.fromCharCode(char));
offset++;
}
return chars.join('');
};
</script>
<template>
<canvas :ref="canvas"><canvas>
<template>