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 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 { PassThrough } from "readable-stream";
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 bufferToStream(buf) {
1674
- const stream = new PassThrough();
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 === "image/png")
1681
- return PImage.decodePNGFromStream(bufferToStream(buf));
1682
- if (type === "image/jpeg" || type === "image/jpg")
1683
- return PImage.decodeJPEGFromStream(bufferToStream(buf));
1684
- throw new Error(
1685
- `Unsupported embedded image mimeType: ${mimeType ?? "unknown"}`
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 PImage2 from "pureimage";
1843
- var pureImageFactory = (width, height) => PImage2.make(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 as PassThrough2 } from "readable-stream";
1847
- import * as PImage3 from "pureimage";
1872
+ import { PassThrough } from "readable-stream";
1873
+ import * as PImage2 from "pureimage";
1848
1874
  async function encodePNGToBuffer(image) {
1849
- const passThrough = new PassThrough2();
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 PImage3.encodePNGToStream(image, passThrough);
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 normalizeToArrayBuffer(source) {
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 = normalizeToArrayBuffer(glb);
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.23",
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"