@turbox3d/shared
Version:
turbox shared internal utility
247 lines (234 loc) • 7.27 kB
text/typescript
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;
}