mirror of
https://github.com/livebook-dev/livebook.git
synced 2024-11-10 17:15:09 +08:00
82 lines
2.1 KiB
JavaScript
82 lines
2.1 KiB
JavaScript
import { base64ToBuffer } from "../lib/utils";
|
|
|
|
/**
|
|
* A hook for the image output.
|
|
*
|
|
* Automatically converts image URLs from image/x-pixel to image/png.
|
|
*/
|
|
const ImageOutput = {
|
|
mounted() {
|
|
this.updateSrc();
|
|
},
|
|
|
|
updated() {
|
|
this.updateSrc();
|
|
},
|
|
|
|
updateSrc() {
|
|
const dataUrl = this.el.src;
|
|
const prefix = "data:image/x-pixel;base64,";
|
|
|
|
const base64Data = dataUrl.slice(prefix.length);
|
|
|
|
if (dataUrl.startsWith(prefix)) {
|
|
const buffer = base64ToBuffer(base64Data);
|
|
|
|
const view = new DataView(buffer);
|
|
const height = view.getUint32(0, false);
|
|
const width = view.getUint32(4, false);
|
|
const channels = view.getUint8(8);
|
|
const pixelBuffer = buffer.slice(9);
|
|
|
|
const imageData = imageDataFromPixelBuffer(
|
|
pixelBuffer,
|
|
width,
|
|
height,
|
|
channels
|
|
);
|
|
|
|
const canvas = document.createElement("canvas");
|
|
canvas.height = height;
|
|
canvas.width = width;
|
|
canvas.getContext("2d").putImageData(imageData, 0, 0);
|
|
const pngDataUrl = canvas.toDataURL("image/png");
|
|
|
|
this.el.src = pngDataUrl;
|
|
}
|
|
},
|
|
};
|
|
|
|
function imageDataFromPixelBuffer(buffer, width, height, channels) {
|
|
const pixelCount = width * height;
|
|
const bytes = new Uint8Array(buffer);
|
|
const data = new Uint8ClampedArray(pixelCount * 4);
|
|
|
|
for (let i = 0; i < pixelCount; i++) {
|
|
if (channels === 1) {
|
|
data[i * 4] = bytes[i];
|
|
data[i * 4 + 1] = bytes[i];
|
|
data[i * 4 + 2] = bytes[i];
|
|
data[i * 4 + 3] = 255;
|
|
} else if (channels === 2) {
|
|
data[i * 4] = bytes[i * 2];
|
|
data[i * 4 + 1] = bytes[i * 2];
|
|
data[i * 4 + 2] = bytes[i * 2];
|
|
data[i * 4 + 3] = bytes[i * 2 + 1];
|
|
} else if (channels === 3) {
|
|
data[i * 4] = bytes[i * 3];
|
|
data[i * 4 + 1] = bytes[i * 3 + 1];
|
|
data[i * 4 + 2] = bytes[i * 3 + 2];
|
|
data[i * 4 + 3] = 255;
|
|
} else if (channels === 4) {
|
|
data[i * 4] = bytes[i * 4];
|
|
data[i * 4 + 1] = bytes[i * 4 + 1];
|
|
data[i * 4 + 2] = bytes[i * 4 + 2];
|
|
data[i * 4 + 3] = bytes[i * 4 + 3];
|
|
}
|
|
}
|
|
|
|
return new ImageData(data, width, height);
|
|
}
|
|
|
|
export default ImageOutput;
|