11import { AnyCircuitElement } from "circuit-json"
2- import { convertCircuitJsonToSimple3dSvg } from "circuit-json-to-simple-3d "
2+ import { renderCircuitJsonTo3dPng } from "circuit-json-to-3d-png "
33import {
44 convertCircuitJsonToAssemblySvg ,
55 convertCircuitJsonToPcbSvg ,
@@ -16,6 +16,18 @@ interface DownloadCircuitPngOptions {
1616 height ?: number
1717}
1818
19+ // SVG-based formats are rendered to an SVG string and then rasterized to PNG.
20+ // Anything not listed here (i.e. "3d") is rendered directly to PNG bytes.
21+ const SVG_RENDERERS : Record <
22+ string ,
23+ ( circuitJson : AnyCircuitElement [ ] , options : any ) => string
24+ > = {
25+ schematic : convertCircuitJsonToSchematicSvg ,
26+ pcb : convertCircuitJsonToPcbSvg ,
27+ assembly : convertCircuitJsonToAssemblySvg ,
28+ pinout : convertCircuitJsonToPinoutSvg ,
29+ }
30+
1931const convertSvgToPng = async ( svgString : string ) : Promise < Blob > => {
2032 return new Promise ( ( resolve , reject ) => {
2133 const canvas = document . createElement ( "canvas" )
@@ -54,45 +66,36 @@ const convertSvgToPng = async (svgString: string): Promise<Blob> => {
5466 } )
5567}
5668
69+ const renderCircuitToPng = async (
70+ circuitJson : AnyCircuitElement [ ] ,
71+ options : DownloadCircuitPngOptions ,
72+ ) : Promise < Blob > => {
73+ const renderSvg = SVG_RENDERERS [ options . format . toLowerCase ( ) ]
74+ if ( renderSvg ) {
75+ const svgOptions : { width ?: number ; height ?: number } = { }
76+ if ( options . width ) svgOptions . width = options . width
77+ if ( options . height ) svgOptions . height = options . height
78+ return convertSvgToPng ( renderSvg ( circuitJson , svgOptions ) )
79+ }
80+
81+ const pngBytes = await renderCircuitJsonTo3dPng ( circuitJson , {
82+ cameraPreset : "top-left-corner" ,
83+ boardTextureResolution : 2048 ,
84+ } )
85+ // Copy into a fresh ArrayBuffer: a Uint8Array view isn't assignable to BlobPart.
86+ const pngBuffer = new ArrayBuffer ( pngBytes . byteLength )
87+ new Uint8Array ( pngBuffer ) . set ( pngBytes )
88+ return new Blob ( [ pngBuffer ] , { type : "image/png" } )
89+ }
90+
5791export const downloadCircuitPng = async (
5892 circuitJson : AnyCircuitElement [ ] ,
5993 fileName : string ,
6094 options : DownloadCircuitPngOptions = { format : "pcb" } ,
6195) => {
6296 try {
63- let blob : Blob
64- let svg : string
65-
66- const svgOptions : any = { }
67- if ( options . width ) svgOptions . width = options . width
68- if ( options . height ) svgOptions . height = options . height
69-
70- switch ( options . format . toLowerCase ( ) ) {
71- case "schematic" :
72- svg = convertCircuitJsonToSchematicSvg ( circuitJson , svgOptions )
73- break
74- case "pcb" :
75- svg = convertCircuitJsonToPcbSvg ( circuitJson , svgOptions )
76- break
77- case "assembly" :
78- svg = convertCircuitJsonToAssemblySvg ( circuitJson , svgOptions )
79- break
80- case "pinout" :
81- svg = convertCircuitJsonToPinoutSvg ( circuitJson , svgOptions )
82- break
83- default :
84- svg = await convertCircuitJsonToSimple3dSvg ( circuitJson , {
85- background : {
86- color : "#fff" ,
87- opacity : 0.0 ,
88- } ,
89- defaultZoomMultiplier : 1.1 ,
90- } )
91- }
92-
93- blob = await convertSvgToPng ( svg )
94- const downloadFileName = `${ fileName } _${ options . format } .png`
95- saveAs ( blob , downloadFileName )
97+ const blob = await renderCircuitToPng ( circuitJson , options )
98+ saveAs ( blob , `${ fileName } _${ options . format } .png` )
9699 } catch ( error ) {
97100 console . error ( error )
98101 throw new Error ( `Failed to download ${ options . format } PNG: ${ error } ` )
0 commit comments