Skip to content

Commit

Permalink
feat: export as png
Browse files Browse the repository at this point in the history
  • Loading branch information
bertyhell committed Aug 28, 2024
1 parent 4fffadd commit 5ea61f8
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 27 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ This is a React-based canvas drawing application that allows users to draw vario
- drag left, to select by intersecting
- drag right, to select by containing
- Export drawing as an SVG file
- Export drawing as an PNG file

### Possible future feature ideas (TODO) in order of likelihood
- Eraser tool to delete segments
Expand Down
42 changes: 21 additions & 21 deletions docs/assets/index-rky34ouY.js → docs/assets/index-BDQF4V-l.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<link rel="icon" type="image/png" href="/openwebcad/favicon.png">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Open WebCAD</title>
<script type="module" crossorigin src="/openwebcad/assets/index-rky34ouY.js"></script>
<script type="module" crossorigin src="/openwebcad/assets/index-BDQF4V-l.js"></script>
<link rel="stylesheet" crossorigin href="/openwebcad/assets/index-Dp0fdRyL.css">
</head>
<body style="background-color: #111">
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"dev": "vite",
"build": "tsc -b && vite build --base=/openwebcad/",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
"preview": "vite preview",
"stats": "npx cloc ./src"
},
"dependencies": {
"@flatten-js/core": "^1.6.1",
Expand Down
6 changes: 6 additions & 0 deletions src/components/Toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
} from '../state.ts';
import { StateVariable } from '../helpers/undo-stack.ts';
import { exportEntitiesToSvgFile } from '../helpers/export-entities-to-svg.ts';
import { exportEntitiesToPngFile } from '../helpers/export-entities-to-png.ts';

interface ToolbarProps {}

Expand Down Expand Up @@ -152,6 +153,11 @@ export const Toolbar: FC<ToolbarProps> = () => {
label="SVG"
onClick={() => exportEntitiesToSvgFile()}
/>
<Button
title="Export PNG"
label="PNG"
onClick={() => exportEntitiesToPngFile()}
/>
<Button
className="mt-2"
title="Github"
Expand Down
69 changes: 69 additions & 0 deletions src/helpers/export-entities-to-png.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { getCanvasSize, getEntities } from '../state.ts';
import { saveAs } from 'file-saver';
import { convertEntitiesToSvgString } from './export-entities-to-svg.ts';

/**
* Takes an svg string and converts it to a png data uri
* by creating an svg element in the dom and drawing that element on the canvas
* Then taking the canvas data and outputting it as a png data blob
* @param svgString
* @param width
* @param height
* @param margin
*/
export function convertSvgToPngBlob(
svgString: string,
width: number,
height: number,
margin: number,
): Promise<Blob> {
return new Promise<Blob>((resolve, reject) => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');

if (!ctx) {
throw new Error('Could not get canvas context');
}

const img = new Image();
const svg = new Blob([svgString], { type: 'image/svg+xml' });
const url = URL.createObjectURL(svg);

img.onload = () => {
canvas.width = width + margin * 2;
canvas.height = height + margin * 2;

ctx.fillStyle = 'white';
ctx.fillRect(0, 0, canvas.width, canvas.height);

ctx.drawImage(img, margin, margin);

URL.revokeObjectURL(url);

canvas.toBlob(blob => {
if (blob) {
resolve(blob);
} else {
reject(new Error('Could not convert canvas to blob'));
}
}, 'image/png');
};

img.src = url;
});
}

export async function exportEntitiesToPngFile() {
const entities = getEntities();
const canvasSize = getCanvasSize();

const svg = convertEntitiesToSvgString(entities, canvasSize);
const pngDataBlob: Blob = await convertSvgToPngBlob(
svg.svgString,
svg.width,
svg.height,
20,
);

saveAs(pngDataBlob, 'open-web-cad--drawing.png');
}
14 changes: 10 additions & 4 deletions src/helpers/export-entities-to-svg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { saveAs } from 'file-saver';
export function convertEntitiesToSvgString(
entities: Entity[],
canvasSize: Point,
): string {
): { svgString: string; width: number; height: number } {
let boundingBoxMinX = canvasSize.x;
let boundingBoxMinY = canvasSize.y;
let boundingBoxMaxX = 0;
Expand Down Expand Up @@ -46,20 +46,26 @@ export function convertEntitiesToSvgString(
});

// Patch for bug: https://github.com/alexbol99/flatten-js/pull/186/files
return `
const svgString = `
<svg width="${boundingBoxWidth}" height="${boundingBoxHeight}" xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="0" width="${boundingBoxWidth}" height="${boundingBoxHeight}" fill="white" />
${svgStrings.join('')}
</svg>
`;

return {
svgString,
width: boundingBoxWidth,
height: boundingBoxHeight,
};
}

export function exportEntitiesToSvgFile() {
const entities = getEntities();
const canvasSize = getCanvasSize();

const svgFileContent = convertEntitiesToSvgString(entities, canvasSize);
const svg = convertEntitiesToSvgString(entities, canvasSize);

const blob = new Blob([svgFileContent], { type: 'text/svg;charset=utf-8' });
const blob = new Blob([svg.svgString], { type: 'text/svg;charset=utf-8' });
saveAs(blob, 'open-web-cad--drawing.svg');
}

0 comments on commit 5ea61f8

Please sign in to comment.