poppygl 0.0.23 → 0.0.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +10 -1
- package/dist/index.js +142 -20
- package/package.json +2 -1
package/dist/index.d.ts
CHANGED
|
@@ -195,8 +195,17 @@ declare function drawInfiniteGrid(software_renderer: SoftwareRenderer, params: {
|
|
|
195
195
|
|
|
196
196
|
declare const pureImageFactory: ImageFactory;
|
|
197
197
|
|
|
198
|
+
declare function encodePNG(image: BitmapLike): Promise<Uint8Array>;
|
|
199
|
+
|
|
198
200
|
declare function encodePNGToBuffer(image: BitmapLike): Promise<Buffer>;
|
|
199
201
|
|
|
202
|
+
interface RenderGLTFToPNGFromURLOptions extends RenderOptionsInput, LoadGLTFWithResourcesFromURLOptions {
|
|
203
|
+
}
|
|
204
|
+
declare function renderGLTFToPNGFromURL(url: string, options?: RenderGLTFToPNGFromURLOptions): Promise<Uint8Array>;
|
|
205
|
+
|
|
206
|
+
type RenderGLTFToPNGFromGLBOptions = RenderOptionsInput;
|
|
207
|
+
declare function renderGLTFToPNGFromGLB(glb: ArrayBuffer | Uint8Array, options?: RenderGLTFToPNGFromGLBOptions): Promise<Uint8Array>;
|
|
208
|
+
|
|
200
209
|
interface RenderGLTFToPNGBufferFromURLOptions extends RenderOptionsInput, LoadGLTFWithResourcesFromURLOptions {
|
|
201
210
|
}
|
|
202
211
|
declare function renderGLTFToPNGBufferFromURL(url: string, options?: RenderGLTFToPNGBufferFromURLOptions): Promise<Buffer>;
|
|
@@ -210,4 +219,4 @@ declare function renderGLTFToPNGBuffer(gltfOrJson: string | any, options?: Rende
|
|
|
210
219
|
|
|
211
220
|
declare function renderSceneFromGLTF(scene: GLTFScene, options?: RenderOptionsInput, imageFactory?: ImageFactory): RenderResult;
|
|
212
221
|
|
|
213
|
-
export { type BitmapLike, type Camera, type CameraRotation, type CameraUp, DEFAULT_LIGHT_DIR, DEFAULT_RENDER_OPTIONS, type DebugPoint, type DrawCall, type FetchLike, type GLTFResources, type GLTFScene, type GridOptions, type ImageFactory, type LightSettings, type LoadGLTFWithResourcesFromURLOptions, type Material, type MutableRGBA, type RGBA, type RenderGLTFToPNGBufferFromGLBBufferOptions, type RenderGLTFToPNGBufferFromURLOptions, type RenderGLTFToPNGBufferOptions, type RenderOptions, type RenderOptionsInput, type RenderResult, SoftwareRenderer, bufferFromDataURI, buildCamera, computeSmoothNormals, computeWorldAABB, createGrid, createInfiniteGrid, createSceneFromGLTF, createUint8Bitmap, decodeImageFromBuffer, drawInfiniteGrid, encodePNGToBuffer, getDefaultRenderOptions, hexToRgb, isJPG, isPNG, loadGLTFWithResourcesFromURL, pureImageFactory, renderDrawCalls, renderGLTFToPNGBuffer, renderGLTFToPNGBufferFromGLBBuffer, renderGLTFToPNGBufferFromURL, renderSceneFromGLTF, resolveRenderOptions };
|
|
222
|
+
export { type BitmapLike, type Camera, type CameraRotation, type CameraUp, DEFAULT_LIGHT_DIR, DEFAULT_RENDER_OPTIONS, type DebugPoint, type DrawCall, type FetchLike, type GLTFResources, type GLTFScene, type GridOptions, type ImageFactory, type LightSettings, type LoadGLTFWithResourcesFromURLOptions, type Material, type MutableRGBA, type RGBA, type RenderGLTFToPNGBufferFromGLBBufferOptions, type RenderGLTFToPNGBufferFromURLOptions, type RenderGLTFToPNGBufferOptions, type RenderGLTFToPNGFromGLBOptions, type RenderGLTFToPNGFromURLOptions, type RenderOptions, type RenderOptionsInput, type RenderResult, SoftwareRenderer, bufferFromDataURI, buildCamera, computeSmoothNormals, computeWorldAABB, createGrid, createInfiniteGrid, createSceneFromGLTF, createUint8Bitmap, decodeImageFromBuffer, drawInfiniteGrid, encodePNG, encodePNGToBuffer, getDefaultRenderOptions, hexToRgb, isJPG, isPNG, loadGLTFWithResourcesFromURL, pureImageFactory, renderDrawCalls, renderGLTFToPNGBuffer, renderGLTFToPNGBufferFromGLBBuffer, renderGLTFToPNGBufferFromURL, renderGLTFToPNGFromGLB, renderGLTFToPNGFromURL, renderSceneFromGLTF, resolveRenderOptions };
|
package/dist/index.js
CHANGED
|
@@ -1610,8 +1610,7 @@ function createSceneFromGLTF(gltf, resources) {
|
|
|
1610
1610
|
}
|
|
1611
1611
|
|
|
1612
1612
|
// lib/gltf/resourceUtils.ts
|
|
1613
|
-
import {
|
|
1614
|
-
import * as PImage from "pureimage";
|
|
1613
|
+
import { decode } from "fast-png";
|
|
1615
1614
|
|
|
1616
1615
|
// lib/utils/bytes.ts
|
|
1617
1616
|
function getNodeBuffer() {
|
|
@@ -1670,20 +1669,35 @@ function detectMimeTypeFromBuffer(buf, hint) {
|
|
|
1670
1669
|
if (buf.length >= 2 && buf[0] === 255 && buf[1] === 216) return "image/jpeg";
|
|
1671
1670
|
return null;
|
|
1672
1671
|
}
|
|
1673
|
-
function
|
|
1674
|
-
const
|
|
1672
|
+
async function decodeImageViaFastPng(buf) {
|
|
1673
|
+
const decoded = decode(buf);
|
|
1674
|
+
return {
|
|
1675
|
+
width: decoded.width,
|
|
1676
|
+
height: decoded.height,
|
|
1677
|
+
data: new Uint8ClampedArray(decoded.data)
|
|
1678
|
+
};
|
|
1679
|
+
}
|
|
1680
|
+
async function decodeImageViaPureImage(buf, mimeType) {
|
|
1681
|
+
const { PassThrough: PassThrough2 } = await import("readable-stream");
|
|
1682
|
+
const PImage3 = await import("pureimage");
|
|
1683
|
+
const stream = new PassThrough2();
|
|
1675
1684
|
stream.end(buf);
|
|
1676
|
-
return stream;
|
|
1685
|
+
if (mimeType === "image/png") return PImage3.decodePNGFromStream(stream);
|
|
1686
|
+
if (mimeType === "image/jpeg" || mimeType === "image/jpg")
|
|
1687
|
+
return PImage3.decodeJPEGFromStream(stream);
|
|
1688
|
+
throw new Error(`Unsupported embedded image mimeType: ${mimeType}`);
|
|
1677
1689
|
}
|
|
1678
1690
|
async function decodeImageFromBuffer(buf, mimeType) {
|
|
1679
1691
|
const type = detectMimeTypeFromBuffer(buf, mimeType);
|
|
1680
|
-
if (type
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1692
|
+
if (!type) {
|
|
1693
|
+
throw new Error(
|
|
1694
|
+
`Unsupported embedded image mimeType: ${mimeType ?? "unknown"}`
|
|
1695
|
+
);
|
|
1696
|
+
}
|
|
1697
|
+
if (type === "image/png") {
|
|
1698
|
+
return decodeImageViaFastPng(buf);
|
|
1699
|
+
}
|
|
1700
|
+
return decodeImageViaPureImage(buf, type);
|
|
1687
1701
|
}
|
|
1688
1702
|
|
|
1689
1703
|
// lib/gltf/parseGLB.ts
|
|
@@ -1839,14 +1853,26 @@ async function loadGLTFWithResourcesFromURL(url, options = {}) {
|
|
|
1839
1853
|
}
|
|
1840
1854
|
|
|
1841
1855
|
// lib/image/pureImageFactory.ts
|
|
1842
|
-
import * as
|
|
1843
|
-
var pureImageFactory = (width, height) =>
|
|
1856
|
+
import * as PImage from "pureimage";
|
|
1857
|
+
var pureImageFactory = (width, height) => PImage.make(width, height);
|
|
1858
|
+
|
|
1859
|
+
// lib/image/encodePNG.ts
|
|
1860
|
+
import { encode } from "fast-png";
|
|
1861
|
+
async function encodePNG(image) {
|
|
1862
|
+
return encode({
|
|
1863
|
+
width: image.width,
|
|
1864
|
+
height: image.height,
|
|
1865
|
+
data: image.data,
|
|
1866
|
+
channels: 4,
|
|
1867
|
+
depth: 8
|
|
1868
|
+
});
|
|
1869
|
+
}
|
|
1844
1870
|
|
|
1845
1871
|
// lib/image/encodePNGToBuffer.ts
|
|
1846
|
-
import { PassThrough
|
|
1847
|
-
import * as
|
|
1872
|
+
import { PassThrough } from "readable-stream";
|
|
1873
|
+
import * as PImage2 from "pureimage";
|
|
1848
1874
|
async function encodePNGToBuffer(image) {
|
|
1849
|
-
const passThrough = new
|
|
1875
|
+
const passThrough = new PassThrough();
|
|
1850
1876
|
const chunks = [];
|
|
1851
1877
|
passThrough.on(
|
|
1852
1878
|
"data",
|
|
@@ -1860,10 +1886,103 @@ async function encodePNGToBuffer(image) {
|
|
|
1860
1886
|
});
|
|
1861
1887
|
passThrough.on("error", reject);
|
|
1862
1888
|
});
|
|
1863
|
-
await
|
|
1889
|
+
await PImage2.encodePNGToStream(image, passThrough);
|
|
1864
1890
|
return await resultPromise;
|
|
1865
1891
|
}
|
|
1866
1892
|
|
|
1893
|
+
// lib/render/renderGLTFToPNGFromURL.ts
|
|
1894
|
+
async function renderGLTFToPNGFromURL(url, options = {}) {
|
|
1895
|
+
const { fetchImpl, ...renderOptions } = options;
|
|
1896
|
+
const { gltf, resources } = await loadGLTFWithResourcesFromURL(url, {
|
|
1897
|
+
fetchImpl
|
|
1898
|
+
});
|
|
1899
|
+
const scene = createSceneFromGLTF(gltf, resources);
|
|
1900
|
+
const { bitmap } = renderDrawCalls(
|
|
1901
|
+
scene.drawCalls,
|
|
1902
|
+
renderOptions,
|
|
1903
|
+
createUint8Bitmap
|
|
1904
|
+
);
|
|
1905
|
+
return encodePNG(bitmap);
|
|
1906
|
+
}
|
|
1907
|
+
|
|
1908
|
+
// lib/render/renderGLTFToPNGFromGLB.ts
|
|
1909
|
+
function normalizeToArrayBuffer(source) {
|
|
1910
|
+
if (source instanceof ArrayBuffer) return source;
|
|
1911
|
+
const { buffer, byteOffset, byteLength } = source;
|
|
1912
|
+
const viewBuffer = buffer;
|
|
1913
|
+
return viewBuffer.slice(byteOffset, byteOffset + byteLength);
|
|
1914
|
+
}
|
|
1915
|
+
async function renderGLTFToPNGFromGLB(glb, options = {}) {
|
|
1916
|
+
const arrayBuffer = normalizeToArrayBuffer(glb);
|
|
1917
|
+
const { gltf, binaryChunk } = parseGLB(arrayBuffer);
|
|
1918
|
+
const totalBuffers = Array.isArray(gltf.buffers) ? gltf.buffers.length : 0;
|
|
1919
|
+
const buffers = new Array(totalBuffers);
|
|
1920
|
+
for (let index = 0; index < totalBuffers; index++) {
|
|
1921
|
+
const entry = gltf.buffers[index];
|
|
1922
|
+
if (entry?.uri) {
|
|
1923
|
+
if (!entry.uri.startsWith("data:")) {
|
|
1924
|
+
throw new Error(
|
|
1925
|
+
`Buffer ${index} references external resource ${entry.uri}. Use renderGLTFToPNGFromURL for GLBs with external buffer URIs.`
|
|
1926
|
+
);
|
|
1927
|
+
}
|
|
1928
|
+
buffers[index] = bufferFromDataURI(entry.uri);
|
|
1929
|
+
continue;
|
|
1930
|
+
}
|
|
1931
|
+
if (!binaryChunk) {
|
|
1932
|
+
throw new Error(
|
|
1933
|
+
`GLB is missing the binary chunk required for buffer ${index}.`
|
|
1934
|
+
);
|
|
1935
|
+
}
|
|
1936
|
+
buffers[index] = binaryChunk;
|
|
1937
|
+
}
|
|
1938
|
+
const resolveBufferViewSlice = (bufferViewIndex) => {
|
|
1939
|
+
const bufferView = gltf.bufferViews?.[bufferViewIndex];
|
|
1940
|
+
if (!bufferView) {
|
|
1941
|
+
throw new Error(`Invalid bufferView index ${bufferViewIndex}.`);
|
|
1942
|
+
}
|
|
1943
|
+
const bufferIndex = bufferView.buffer;
|
|
1944
|
+
const buffer = buffers[bufferIndex];
|
|
1945
|
+
if (!buffer) {
|
|
1946
|
+
throw new Error(
|
|
1947
|
+
`Missing buffer data for bufferView ${bufferViewIndex} (buffer ${bufferIndex}).`
|
|
1948
|
+
);
|
|
1949
|
+
}
|
|
1950
|
+
const byteOffset = bufferView.byteOffset ?? 0;
|
|
1951
|
+
const byteLength = bufferView.byteLength;
|
|
1952
|
+
if (typeof byteLength !== "number") {
|
|
1953
|
+
throw new Error(`bufferView ${bufferViewIndex} is missing byteLength.`);
|
|
1954
|
+
}
|
|
1955
|
+
return buffer.subarray(byteOffset, byteOffset + byteLength);
|
|
1956
|
+
};
|
|
1957
|
+
const images = await Promise.all(
|
|
1958
|
+
(gltf.images ?? []).map(async (image, imageIndex) => {
|
|
1959
|
+
if (image.uri) {
|
|
1960
|
+
if (!image.uri.startsWith("data:")) {
|
|
1961
|
+
throw new Error(
|
|
1962
|
+
`Image ${imageIndex} references external resource ${image.uri}. Embed textures or load via renderGLTFToPNGFromURL.`
|
|
1963
|
+
);
|
|
1964
|
+
}
|
|
1965
|
+
const imageBytes = bufferFromDataURI(image.uri);
|
|
1966
|
+
return decodeImageFromBuffer(imageBytes, image.mimeType);
|
|
1967
|
+
}
|
|
1968
|
+
if (typeof image.bufferView === "number") {
|
|
1969
|
+
const slice = resolveBufferViewSlice(image.bufferView);
|
|
1970
|
+
return decodeImageFromBuffer(slice, image.mimeType);
|
|
1971
|
+
}
|
|
1972
|
+
throw new Error(
|
|
1973
|
+
`Image ${imageIndex} must supply a data URI or bufferView for GLB rendering.`
|
|
1974
|
+
);
|
|
1975
|
+
})
|
|
1976
|
+
);
|
|
1977
|
+
const scene = createSceneFromGLTF(gltf, { buffers, images });
|
|
1978
|
+
const { bitmap } = renderDrawCalls(
|
|
1979
|
+
scene.drawCalls,
|
|
1980
|
+
options,
|
|
1981
|
+
createUint8Bitmap
|
|
1982
|
+
);
|
|
1983
|
+
return encodePNG(bitmap);
|
|
1984
|
+
}
|
|
1985
|
+
|
|
1867
1986
|
// lib/render/renderGLTFToPNGBufferFromURL.ts
|
|
1868
1987
|
async function renderGLTFToPNGBufferFromURL(url, options = {}) {
|
|
1869
1988
|
const { fetchImpl, ...renderOptions } = options;
|
|
@@ -1880,14 +1999,14 @@ async function renderGLTFToPNGBufferFromURL(url, options = {}) {
|
|
|
1880
1999
|
}
|
|
1881
2000
|
|
|
1882
2001
|
// lib/render/renderGLTFToPNGBufferFromGLBBuffer.ts
|
|
1883
|
-
function
|
|
2002
|
+
function normalizeToArrayBuffer2(source) {
|
|
1884
2003
|
if (source instanceof ArrayBuffer) return source;
|
|
1885
2004
|
const { buffer, byteOffset, byteLength } = source;
|
|
1886
2005
|
const viewBuffer = buffer;
|
|
1887
2006
|
return viewBuffer.slice(byteOffset, byteOffset + byteLength);
|
|
1888
2007
|
}
|
|
1889
2008
|
async function renderGLTFToPNGBufferFromGLBBuffer(glb, options = {}) {
|
|
1890
|
-
const arrayBuffer =
|
|
2009
|
+
const arrayBuffer = normalizeToArrayBuffer2(glb);
|
|
1891
2010
|
const { gltf, binaryChunk } = parseGLB(arrayBuffer);
|
|
1892
2011
|
const totalBuffers = Array.isArray(gltf.buffers) ? gltf.buffers.length : 0;
|
|
1893
2012
|
const buffers = new Array(totalBuffers);
|
|
@@ -2089,6 +2208,7 @@ export {
|
|
|
2089
2208
|
createUint8Bitmap,
|
|
2090
2209
|
decodeImageFromBuffer,
|
|
2091
2210
|
drawInfiniteGrid,
|
|
2211
|
+
encodePNG,
|
|
2092
2212
|
encodePNGToBuffer,
|
|
2093
2213
|
getDefaultRenderOptions,
|
|
2094
2214
|
hexToRgb,
|
|
@@ -2100,6 +2220,8 @@ export {
|
|
|
2100
2220
|
renderGLTFToPNGBuffer,
|
|
2101
2221
|
renderGLTFToPNGBufferFromGLBBuffer,
|
|
2102
2222
|
renderGLTFToPNGBufferFromURL,
|
|
2223
|
+
renderGLTFToPNGFromGLB,
|
|
2224
|
+
renderGLTFToPNGFromURL,
|
|
2103
2225
|
renderSceneFromGLTF,
|
|
2104
2226
|
resolveRenderOptions
|
|
2105
2227
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "poppygl",
|
|
3
3
|
"main": "dist/index.js",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.24",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/tscircuit/poppygl.git"
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"typescript": "^5"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
+
"fast-png": "^8.0.0",
|
|
40
41
|
"gl-matrix": "^3.4.4",
|
|
41
42
|
"pureimage": "^0.4.18",
|
|
42
43
|
"readable-stream": "^4.7.0"
|