UNPKG

@turbox3d/shared

Version:

turbox shared internal utility

247 lines (234 loc) 7.27 kB
import * as THREE from 'three'; import { updateQueryStringParameter } from './common'; import { Vec2 } from './graphic'; function convertUrl(url: string, key = 'turbox') { if (url.includes(';base64,') || !url) { return url; } return updateQueryStringParameter(url, key, 'true'); } export const mirrorImage = (image: string | Blob, materialDirection: Vec2, isBase64 = false, fileType = 'image/png', quality = 1) => { const img = new Image(); img.setAttribute('crossOrigin', 'anonymous'); img.src = image instanceof Blob ? URL.createObjectURL(image) : convertUrl(image); return new Promise<string | Blob>((resolve) => { img.onload = () => { image instanceof Blob && URL.revokeObjectURL(img.src); const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d')!; canvas.width = img.width; canvas.height = img.height; ctx.translate(materialDirection.x === -1 ? canvas.width : 0, materialDirection.y === -1 ? canvas.height : 0); ctx.scale(materialDirection.x, materialDirection.y); ctx.drawImage(img, 0, 0, canvas.width, canvas.height, 0, 0, canvas.width, canvas.height); if (isBase64) { resolve(`${canvas.toDataURL(fileType, quality)}`); } else { canvas.toBlob( blob => { if (blob) { resolve(blob); } }, fileType, quality ); } }; }); }; export const getRenderTargetImageData = ( app: any, width: number, height: number, scene: any, camera: any, fileType = 'image/png', quality = 1 ) => { const renderTarget = new THREE.WebGLRenderTarget(width, height, { minFilter: THREE.LinearFilter, }); // renderTarget.viewport = new THREE.Vector4(0, 0, width, height); app.setRenderTarget(renderTarget); app.render(scene, camera); const buffer = new Uint8Array(width * height * 4); const clamped = new Uint8ClampedArray(buffer.buffer); app.readRenderTargetPixels(renderTarget, 0, 0, width, height, buffer); return new Promise<Blob>(resolve => { const canvas = document.createElement('canvas'); canvas.width = width; canvas.height = height; const ctx = canvas.getContext('2d'); const imageData = new ImageData(clamped, width, height); ctx!.putImageData(imageData, 0, 0); app.setRenderTarget(null); app.render(scene, camera); canvas.toBlob( async blob => { if (blob) { const image = (await mirrorImage(blob, { x: 1, y: -1 }, false, fileType)) as Blob; resolve(image); } }, fileType, quality ); }); }; export async function loadImageBase64(url: string | Blob, fileType = 'image/png', quality = 1) { const img = new Image(); img.setAttribute('crossOrigin', 'anonymous'); img.src = url instanceof Blob ? URL.createObjectURL(url) : convertUrl(url); return new Promise<{ base64: string; width: number; height: number; }>(resolve => { img.onload = () => { url instanceof Blob && URL.revokeObjectURL(img.src); const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d')!; canvas.width = img.width; canvas.height = img.height; ctx.drawImage(img, 0, 0, canvas.width, canvas.height, 0, 0, canvas.width, canvas.height); const base64 = `${canvas.toDataURL(fileType, quality)}`; resolve({ base64, width: img.width, height: img.height, }); }; }); } export async function loadImage(url: string | Blob, fileType = 'image/png', quality = 1) { const img = new Image(); img.setAttribute('crossOrigin', 'anonymous'); img.src = url instanceof Blob ? URL.createObjectURL(url) : convertUrl(url); return new Promise<{ blob: Blob | null; width: number; height: number; }>(resolve => { img.onload = () => { url instanceof Blob && URL.revokeObjectURL(img.src); const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d')!; canvas.width = img.width; canvas.height = img.height; ctx.drawImage(img, 0, 0, canvas.width, canvas.height, 0, 0, canvas.width, canvas.height); canvas.toBlob( blob => { resolve({ blob, width: img.width, height: img.height, }); }, fileType, quality ); }; }); } export async function loadImageElement(url: string | Blob) { const img = new Image(); img.setAttribute('crossOrigin', 'anonymous'); img.src = url instanceof Blob ? URL.createObjectURL(url) : convertUrl(url); return new Promise<{ element: HTMLImageElement; width: number; height: number; }>(resolve => { img.onload = () => { url instanceof Blob && URL.revokeObjectURL(img.src); resolve({ element: img, width: img.width, height: img.height, }); }; }); } export async function cropImage( url: string | Blob | HTMLImageElement, rect: { start: Vec2; end: Vec2 }, fileType = 'image/png', quality = 1, ) { const img = new Image(); img.setAttribute('crossOrigin', 'anonymous'); if (url instanceof HTMLImageElement) { img.src = url.src; } else { img.src = url instanceof Blob ? URL.createObjectURL(url) : convertUrl(url); } return new Promise<{ blob: Blob | null; element?: HTMLImageElement; width: number; height: number; }>(resolve => { img.onload = () => { url instanceof Blob && URL.revokeObjectURL(img.src); const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d')!; canvas.width = rect.end.x - rect.start.x; canvas.height = rect.end.y - rect.start.y; ctx.drawImage( img, rect.start.x, rect.start.y, canvas.width, canvas.height, 0, 0, canvas.width, canvas.height ); canvas.toBlob( blob => { if (!blob) { resolve({ blob: null, width: 0, height: 0, }); return; } const url = URL.createObjectURL(blob); const img = new Image(); img.onload = () => { URL.revokeObjectURL(url); resolve({ blob, element: img, width: canvas.width, height: canvas.height, }); }; img.src = url; }, fileType, quality ); }; }); } export function base64toBlob(data: string, sliceSize = 512) { const parts = data.split(';base64,'); const imageType = parts[0].split(':')[1]; const byteCharacters = window.atob(parts[1]); const byteArrays: BlobPart[] = []; for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) { const slice = byteCharacters.slice(offset, offset + sliceSize); const byteNumbers = new Array(slice.length); for (let i = 0; i < slice.length; i++) { byteNumbers[i] = slice.charCodeAt(i); } const byteArray = new Uint8Array(byteNumbers); byteArrays.push(byteArray); } const blob = new Blob(byteArrays, { type: imageType }); return blob; }