mirror of
https://github.com/livebook-dev/livebook.git
synced 2025-02-22 13:53:23 +08:00
83 lines
2.1 KiB
JavaScript
83 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;
|