UNPKG

threepipe

Version:

A 3D viewer framework built on top of three.js in TypeScript with a focus on quality rendering, modularity and extensibility.

115 lines 4.46 kB
import { DataUtils, FloatType, HalfFloatType, LinearSRGBColorSpace, UnsignedByteType, } from 'three'; import { canvasFlipY, LinearToSRGB } from 'ts-browser-helpers'; export function getTextureDataType(renderer) { if (!renderer) return UnsignedByteType; const halfFloatSupport = renderer.extensions.has('EXT_color_buffer_half_float') || renderer.capabilities.isWebGL2 && renderer.extensions.has('EXT_color_buffer_float'); const floatSupport = renderer.capabilities.isWebGL2 || renderer.extensions.has('OES_texture_float') || renderer.extensions.has('WEBGL_color_buffer_float'); return halfFloatSupport ? HalfFloatType : floatSupport ? FloatType : UnsignedByteType; } export function textureDataToImageData(imgData, colorSpace, outData) { const data = outData?.data ?? new Uint8ClampedArray(imgData.height * imgData.width * 4); const isFloat32 = imgData.data instanceof Float32Array; const isUint16 = imgData.data instanceof Uint16Array; for (let i = 0; i < data.length; i++) { if (isFloat32) { // Float32 data[i] = imgData.data[i] * 255; } else if (isUint16) { // Uint16 (half float) data[i] = DataUtils.fromHalfFloat(imgData.data[i]) * 255; } else { // Uint8 data[i] = imgData.data[i]; } if (colorSpace === LinearSRGBColorSpace) { data[i] = LinearToSRGB(data[i] / 255.0) * 255; } // todo: rgbm? } return outData ?? new ImageData(data, imgData.width, imgData.height); } /** * * @param texture * @param maxWidth * @param flipY * @param canvas */ export function textureToCanvas(texture, maxWidth, flipY = false) { let img; if (texture.isDataTexture) img = textureDataToImageData(texture.image, texture.colorSpace); else img = texture.image; return texImageToCanvas(img, maxWidth, flipY); } export function texImageToCanvas(image, maxWidth, flipY = false) { let width, height; if (!window.VideoFrame) window.VideoFrame = HTMLVideoElement; if (image instanceof window.VideoFrame) { width = image.displayWidth; height = image.displayHeight; } else { width = image.width; height = image.height; } if (window.VideoFrame === HTMLVideoElement) delete window.VideoFrame; const canvas = document.createElement('canvas'); // resize it to the size of our image canvas.width = Math.min(maxWidth, width); canvas.height = Math.floor(1.0 + canvas.width * height / width); const ctx = canvas.getContext('2d'); if (!ctx) { console.error('textureToDataUrl: could not get canvas context'); return canvas; } if (flipY === true) { ctx.translate(0, canvas.height); ctx.scale(1, -1); } let needsFlipY = false; if (image.data !== undefined) { // THREE.DataTexture const imageData = image; if (width !== canvas.width || height !== canvas.height) { const tempCanvas = document.createElement('canvas'); tempCanvas.width = width; tempCanvas.height = height; const tempCtx = tempCanvas.getContext('2d'); if (!tempCtx) { console.error('textureToDataUrl: could not get temp canvas context'); ctx.putImageData(imageData, 0, 0); } else { tempCtx.putImageData(imageData, 0, 0); // for resize ctx.drawImage(tempCanvas, 0, 0, canvas.width, canvas.height); } } else { ctx.putImageData(imageData, 0, 0); if (flipY) needsFlipY = true; // because of putImageData } } else { ctx.drawImage(image, 0, 0, canvas.width, canvas.height); } return !needsFlipY ? canvas : canvasFlipY(canvas); } export function textureToDataUrl(texture, maxWidth, flipY, mimeType, quality) { return textureToCanvas(texture, maxWidth, flipY).toDataURL(mimeType, quality); } export async function textureToBlob(texture, maxWidth, flipY, mimeType, quality) { const canvas = textureToCanvas(texture, maxWidth, flipY); return new Promise((resolve, reject) => { canvas.toBlob(blob => { if (blob) resolve(blob); else reject(new Error('Failed to create blob')); }, mimeType, quality); }); } //# sourceMappingURL=texture.js.map