diff --git a/README.md b/README.md index d989f3960..385bd5dd7 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ # Img2Num -_Img2Num_ is a fast and accurate raster vectorizer. +_Img2Num_ is a fast and accurate raster vectorizer. It converts raster images (like PNGs and JPGs) into clean SVGs with _high accuracy and performance_. @@ -23,23 +23,28 @@ It converts raster images (like PNGs and JPGs) into clean SVGs with _high accura [![Docs](https://img.shields.io/badge/docs-full-blue?logo=gitbook&logoColor=white)](https://img2num.dev/docs/) [![Changelog](https://img.shields.io/badge/changelog-full-orange?logo=git&logoColor=white)](https://img2num.dev/changelog/) +[![Sponsor](https://img.shields.io/badge/Sponsor-%E2%9D%A4-EA4AAA?logo=githubsponsors&logoColor=white)](https://github.com/sponsors/Ryan-Millard) +[![Security Policy](https://img.shields.io/badge/Security-Policy-red?logo=github)](SECURITY.md) + ## Contents - - @@ -54,17 +53,17 @@ It converts raster images (like PNGs and JPGs) into clean SVGs with _high accura ## Before vs After | Input (Original Raster) | Output (SVG) | |----------|------------------| -| Original input raster image (Aerial view of mountains) | Final output SVG image (Aerial view of mountains) | -| Original input raster image (A garden in Margate, South Africa) | Final output SVG image (A garden in Margate, South Africa) | -| Original input raster image (A ring on a woman's hand) | Final output SVG image  (A ring on a woman's hand) | +| Original input raster image (Aerial view of mountains) | Final output SVG image (Aerial view of mountains) | +| Original input raster image (A garden in Margate, South Africa) | Final output SVG image (A garden in Margate, South Africa) | +| Original input raster image (A ring on a woman's hand) | Final output SVG image  (A ring on a woman's hand) | ### What are you waiting for? -Try our [image to color-by-number demo](https://img2num.dev/example-apps/react-js/)! +Try one of our [example-apps](https://img2num.dev/example-apps/)! +
-> [!IMPORTANT] > ### Why Img2Num? > > Most raster-to-SVG vectorizers were designed for clean, synthetic input images such as logos, icons, diagrams, and flat illustrations. @@ -101,14 +100,18 @@ Try our [image to color-by-number demo](https://img2num.dev/example-apps/react-j | Language | Package Info | |-----------:|:------------| -| C | C [![Docs](https://img.shields.io/badge/docs-C-A8B9CC?logo=gitbook&logoColor=white)](https://img2num.dev/docs/c/) [![C Changelog](https://img.shields.io/badge/changelog-C-A8B9CC?logo=c)](https://img2num.dev/changelog/c/) | -| C++ | C++ [![Docs](https://img.shields.io/badge/docs-C++-00599C?logo=gitbook&logoColor=white)](https://img2num.dev/docs/cpp/) [![C++ Changelog](https://img.shields.io/badge/changelog-C%2B%2B-00599C?logo=c%2B%2B&logoColor=white)](https://img2num.dev/changelog/cpp/) | -| JavaScript | [![npm](https://img.shields.io/npm/v/img2num?logo=npm)](https://www.npmjs.com/package/img2num) ![Downloads](https://img.shields.io/npm/dm/img2num?logo=npm) JavaScript [![Docs](https://img.shields.io/badge/docs-JavaScript-F7DF1E?logo=gitbook&logoColor=white)](https://img2num.dev/docs/js/) [![JavaScript Changelog](https://img.shields.io/badge/changelog-JavaScript-F7DF1E?logo=javascript)](https://img2num.dev/changelog/js/) | -| Python | ![PyPI](https://img.shields.io/pypi/v/img2num?logo=pypi) [![PyPI Downloads](https://img.shields.io/pypi/dm/img2num?logo=pypi)](https://pypi.org/project/img2num/) [![Supported Versions](https://img.shields.io/pypi/pyversions/img2num?logo=python)](https://pypi.org/project/img2num/) Python [![Docs](https://img.shields.io/badge/docs-Python-3776AB?logo=gitbook&logoColor=white)](https://img2num.dev/docs/py/) [![Python Changelog](https://img.shields.io/badge/changelog-Python-3776AB?logo=python)](https://img2num.dev/changelog/py/) | +| C logo | C package releases [![Docs](https://img.shields.io/badge/docs-C-A8B9CC?logo=gitbook&logoColor=white)](https://img2num.dev/docs/c/) [![C Changelog](https://img.shields.io/badge/changelog-C-A8B9CC?logo=c)](https://img2num.dev/changelog/c/) | +| C++ logo | C++ package releases [![Docs](https://img.shields.io/badge/docs-C++-00599C?logo=gitbook&logoColor=white)](https://img2num.dev/docs/cpp/) [![C++ Changelog](https://img.shields.io/badge/changelog-C%2B%2B-00599C?logo=c%2B%2B&logoColor=white)](https://img2num.dev/changelog/cpp/) | +| JavaScript logo | [![npm](https://img.shields.io/npm/v/img2num?logo=npm)](https://www.npmjs.com/package/img2num) [![jsDelivr CDN](https://img.shields.io/badge/CDN-jsDelivr-%23f7df1e?logo=jsdelivr&logoColor=black)](https://www.jsdelivr.com/package/npm/img2num) [![unpkg CDN](https://img.shields.io/badge/CDN-unpkg-%23cb3837?logo=npm&logoColor=white)](https://app.unpkg.com/img2num) [![Downloads](https://img.shields.io/npm/dm/img2num?logo=npm)](https://www.npmjs.com/package/img2num) JavaScript package releases [![Docs](https://img.shields.io/badge/docs-JavaScript-F7DF1E?logo=gitbook&logoColor=white)](https://img2num.dev/docs/js/) [![JavaScript Changelog](https://img.shields.io/badge/changelog-JavaScript-F7DF1E?logo=javascript)](https://img2num.dev/changelog/js/) | +| Python logo | [![PyPI](https://img.shields.io/pypi/v/img2num?logo=pypi)](https://pypi.org/project/img2num/) [![PyPI Downloads](https://img.shields.io/pypi/dm/img2num?logo=pypi)](https://pypi.org/project/img2num/) [![Supported Versions](https://img.shields.io/pypi/pyversions/img2num?logo=python)](https://pypi.org/project/img2num/) Python package releases [![Docs](https://img.shields.io/badge/docs-Python-3776AB?logo=gitbook&logoColor=white)](https://img2num.dev/docs/py/) [![Python Changelog](https://img.shields.io/badge/changelog-Python-3776AB?logo=python)](https://img2num.dev/changelog/py/) | ## Community Links + [![Changelog](https://img.shields.io/badge/Changelog-Full-orange?logo=git&logoColor=white)](https://img2num.dev/changelog/) [![Contributing](https://img.shields.io/badge/Contributing-Guide-blue?logo=github)](https://github.com/Ryan-Millard/Img2Num/blob/main/CONTRIBUTING.md) +[![Security Policy](https://img.shields.io/badge/Security-Policy-red?logo=github)](https://github.com/Ryan-Millard/Img2Num/blob/main/SECURITY.md) +[![License](https://img.shields.io/badge/License-MIT-blue?logo=open-source-initiative&logoColor=white)](https://github.com/Ryan-Millard/Img2Num/blob/main/LICENSE) +[![Sponsor](https://img.shields.io/badge/Sponsor-%E2%9D%A4-EA4AAA?logo=githubsponsors&logoColor=white)](https://github.com/sponsors/Ryan-Millard) [![Issues](https://img.shields.io/badge/Issues-Available-brightgreen?logo=github)](https://github.com/Ryan-Millard/Img2Num/issues/views/1151) [![Good First Issues](https://img.shields.io/badge/Good%20First%20Issues-Welcome-6cc644?logo=github)](https://github.com/Ryan-Millard/Img2Num/issues/views/1155) [![Blog](https://img.shields.io/badge/Blog-Updates-ff6f00?logo=githubpages)](https://img2num.dev/blog/) @@ -116,97 +119,170 @@ Try our [image to color-by-number demo](https://img2num.dev/example-apps/react-j ## Supported Runtimes -![Browsers](https://img.shields.io/badge/Browsers-Modern_Browsers-4CAF50?logo=googlechrome&logoColor=white) -![Node.js](https://img.shields.io/badge/Node.js-%3E%3D14-339933?logo=nodedotjs&logoColor=white) +[![Browsers](https://img.shields.io/badge/Browsers-Modern_(ES2020)-4CAF50?logo=googlechrome&logoColor=white)](https://img2num.dev/docs/js/requirements/) +[![Node.js](https://img.shields.io/badge/Node.js-%3E%3D18-339933?logo=nodedotjs&logoColor=white)](https://img2num.dev/docs/js/requirements/) -> [!CAUTION] -> This package currently supports **ESM only.** [#483](https://github.com/Ryan-Millard/Img2Num/issues/483) tracks this fix. +For more information, please see our [Requirements Page](https://img2num.dev/docs/js/requirements/). -## Installation +## Node.js Usage -```bash -npm install img2num -``` +> We recommend using [sharp](https://www.npmjs.com/package/sharp) to decode images in Node.js, however you +> are free to use whichever library you like as long as you use a `Uint8ClampedArray` in RGBA format as the +> input image (`pixels`) to the functions. -```bash -pnpm add img2num +### Node.js ESM + +```sh +npm install img2num sharp ``` -```bash -yarn add img2num +> or `pnpm add img2num sharp` / `yarn add img2num sharp` / `bun add img2num sharp` + +```js +import { writeFileSync } from "fs"; +import { imageToSvg, terminateWasmModule } from "img2num"; +import sharp from "sharp"; + +const { data, info } = await sharp("input.png").ensureAlpha().raw().toBuffer({ resolveWithObject: true }); + +const pixels = new Uint8ClampedArray(data.buffer, data.byteOffset, data.byteLength); + +try { + const { svg } = await imageToSvg({ pixels, width: info.width, height: info.height }); + writeFileSync("output.svg", svg); +} finally { + await terminateWasmModule(); +} ``` +[Try it on CodeSandbox](https://codesandbox.io/p/devbox/node-esm-jmn444) + +### Node.js CommonJS -```bash -bun add img2num +```sh +npm install img2num sharp ``` -## Browser Usage (CDN) +> or `pnpm add img2num sharp` / `yarn add img2num sharp` / `bun add img2num sharp` -> [!IMPORTANT] -> This approach only works in Browsers. +```js +const { writeFileSync } = require("fs"); +const { imageToSvg, terminateWasmModule } = require("img2num"); +const sharp = require("sharp"); -### jsDelivr CDN -[![jsDelivr](https://img.shields.io/badge/CDN-jsDelivr-ff5627?logo=jsdelivr&logoColor=white)](https://www.jsdelivr.com/package/npm/img2num) +async function main() { + const { data, info } = await sharp("input.png").ensureAlpha().raw().toBuffer({ resolveWithObject: true }); -```html - - + const pixels = new Uint8ClampedArray(data.buffer, data.byteOffset, data.byteLength); + + try { + const { svg } = await imageToSvg({ pixels, width: info.width, height: info.height }); + writeFileSync("output.svg", svg); + } finally { + await terminateWasmModule(); + } +} + +main().catch(console.error); ``` -### unpkg CDN -[![unpkg](https://img.shields.io/badge/CDN-unpkg-red?logo=npm&logoColor=white)](https://app.unpkg.com/img2num@0.2.0) +[Try it on CodeSandbox](https://codesandbox.io/p/devbox/node-cjs-dp5ltr) -```html - - +## Browser Usage + +### Browser ESM + +```sh +npm install img2num ``` -## Quick Start +> or `pnpm add img2num` / `yarn add img2num` / `bun add img2num` -### All-in-one (recommended) ```js -import { imageToUint8ClampedArray, imageToSvg, terminateWasmModule } from "img2num"; -// Browsers: -const { pixels, width, height } = await imageToUint8ClampedArray(file); -// Node.js equivalent: -// const { data, info } = await sharp(imagePath).ensureAlpha().raw().toBuffer({ resolveWithObject: true }); -// const { width, height } = info; -const { svg } = await imageToSvg({ pixels, width, height }); -await terminateWasmModule(); // WebAssembly and GPU cleanup -``` +import { imageToUint8ClampedArray, imageToSvg } from "img2num"; -> [!NOTE] -> `imageToUint8ClampedArray` uses browser APIs (`Image`, `canvas`) and is only available in browser environments. In Node.js, use a library like [`sharp`](https://www.npmjs.com/package/sharp) to decode images to a `Uint8ClampedArray` in RGBA format before passing to the WASM functions. +const fileInput = document.querySelector("#fileInput"); -## API Reference +fileInput.addEventListener("change", async (e) => { + const { pixels, width, height } = await imageToUint8ClampedArray(e.target.files[0]); + const { svg } = await imageToSvg({ pixels, width, height }); -All WebAssembly-backed functions are `async` and return Promises. For full details see the [JavaScript API reference](https://img2num.dev/docs/js/api/). + document.querySelector("#preview").src = "data:image/svg+xml;base64," + btoa(svg); +}); +``` +[Try it on CodeSandbox](https://codesandbox.io/p/sandbox/delicate-bird-3kprj2) ---- +### jsDelivr CDN -## Navigating WebAssembly +[![jsDelivr](https://img.shields.io/badge/CDN-jsDelivr-ff5627?logo=jsdelivr&logoColor=white)](https://www.jsdelivr.com/package/npm/img2num) -This package ships a `.wasm` binary and a worker file. The library automatically selects the correct worker implementation for your runtime — browser Web Workers or Node.js `worker_threads`. Some bundlers need extra configuration to handle `.wasm` assets correctly: +**IIFE:** +```html + + +``` +[Try it on CodeSandbox](https://codesandbox.io/p/sandbox/iife-fh25gg) -- **Vite** — add to `vite.config.js`: -```js - assetsInclude: ["**/*.wasm"] +**UMD (RequireJS):** +```html + + ``` -- **Webpack 5** — enable `asyncWebAssembly: true` in `experiments`. -- **Other bundlers** — if you run into issues, please [open an issue](https://github.com/Ryan-Millard/Img2Num/issues) so we can document the solution and help others facing the same problem. +[Try it on CodeSandbox](https://codesandbox.io/p/sandbox/competent-shape-2drsrz) + +## API Reference + +All WebAssembly-backed functions are `async` and return Promises. For full details see the [JavaScript API reference](https://img2num.dev/docs/js/api/). -We actively welcome contributions to this section — if you've configured a bundler not listed here, please open a PR to add it to our [documentation](https://img2num.dev/docs/). +--- ## Examples + - **React** color-by-number website: [`example-apps/react-js`](https://github.com/Ryan-Millard/Img2Num/tree/main/example-apps/react-js) -- **Node.js** console app: [`example-apps/console-js`](https://github.com/Ryan-Millard/Img2Num/tree/main/example-apps/console-js) +- **Node.js (ESM)** console app: [`example-apps/console-js-esm`](https://github.com/Ryan-Millard/Img2Num/tree/main/example-apps/console-js-esm) +- **Node.js (CommonJS)** console app: [`example-apps/console-js-cjs`](https://github.com/Ryan-Millard/Img2Num/tree/main/example-apps/console-js-cjs) + Try the [live demo (`React example`)](https://img2num.dev/example-apps/react-js/). + > **Have a cool idea or want to showcase a new environment?💡** +> > We welcome new [example apps](https://github.com/Ryan-Millard/Img2Num/tree/main/example-apps). ## License [MIT](https://github.com/Ryan-Millard/Img2Num/blob/main/LICENSE) © Ryan Millard +> This package (the library you install from npm) is MIT-licensed. Documentation, example apps, and CI/config in the main repository are AGPLv3 — see the [repository license overview](https://github.com/Ryan-Millard/Img2Num#license) for details. + +## Supporting Us + +[![GitHub Sponsors](https://img.shields.io/badge/GitHub_Sponsors-%E2%9D%A4-EA4AAA?logo=githubsponsors&logoColor=white)](https://github.com/sponsors/Ryan-Millard) +[![Ko-fi](https://img.shields.io/badge/Ko--fi-Support-FF5E5B?logo=kofi&logoColor=white)](https://ko-fi.com/ryan_millard) + +Img2Num is free and open source. If it saves you time or you'd like to support its continued development: + +- ⭐ [Star the repository](https://github.com/Ryan-Millard/Img2Num) - it helps others discover the project +- ❤️ Sponsor us via [GitHub Sponsors](https://github.com/sponsors/Ryan-Millard) or [Ko-fi](https://ko-fi.com/ryan_millard) (it'll help us keep the [img2num.dev](https://img2num.dev/) domain) +- 🛠️ Contribute - see our [Contributing Guide](https://github.com/Ryan-Millard/Img2Num/blob/main/CONTRIBUTING.md) and [good first issues](https://github.com/Ryan-Millard/Img2Num/issues/views/1155) + ---
@@ -214,10 +290,16 @@ Try the [live demo (`React example`)](https://img2num.dev/example-apps/react-js/

GitHub · - Documentation + Documentation · Changelog · + Contributing + · + Security + · + Sponsor + · Issues · Discussions diff --git a/packages/js/package.json b/packages/js/package.json index 3a7303002..33c4962d0 100644 --- a/packages/js/package.json +++ b/packages/js/package.json @@ -22,6 +22,16 @@ "url": "git+https://github.com/Ryan-Millard/Img2Num.git", "directory": "packages/js" }, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/Ryan-Millard" + }, + { + "type": "ko-fi", + "url": "https://ko-fi.com/ryan_millard" + } + ], "license": "MIT", "author": "Ryan-Millard", "type": "module", diff --git a/packages/py/README.md b/packages/py/README.md index 63d592b46..6cb345a7e 100644 --- a/packages/py/README.md +++ b/packages/py/README.md @@ -10,18 +10,17 @@ It converts raster images (like PNGs and JPGs) into clean SVGs with _high accura _Img2Num_ is **optimized for natural images**. +[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/Ryan-Millard/Img2Num/blob/main/LICENSE) ![Status](https://img.shields.io/badge/status-active_development-brightgreen?logo=github) -[![Deploy to GitHub Pages](https://github.com/Ryan-Millard/Img2Num/actions/workflows/deploy.yml/badge.svg)](https://github.com/Ryan-Millard/Img2Num/actions/workflows/deploy.yml) -[![Multi-Language Release Generation](https://github.com/Ryan-Millard/Img2Num/actions/workflows/release.yml/badge.svg)](https://github.com/Ryan-Millard/Img2Num/actions/workflows/release.yml) +[![Docs](https://img.shields.io/badge/docs-full-blue?logo=gitbook&logoColor=white)](https://img2num.dev/docs/) +[![Changelog](https://img.shields.io/badge/changelog-full-orange?logo=git&logoColor=white)](https://img2num.dev/changelog/) -[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/Ryan-Millard/Img2Num/blob/main/LICENSE) [![Contributors](https://img.shields.io/github/contributors/Ryan-Millard/Img2Num)](https://github.com/Ryan-Millard/Img2Num/graphs/contributors) [![Stars](https://img.shields.io/github/stars/Ryan-Millard/Img2Num?style=social)](https://github.com/Ryan-Millard/Img2Num) -[![Docker Pulls](https://img.shields.io/docker/pulls/ryanmillard/img2num-dev)](https://hub.docker.com/repository/docker/ryanmillard/img2num-dev/general) -[![Open in Codespaces](https://img.shields.io/badge/-Open%20in%20Codespaces-black?logo=github)](https://codespaces.new/Ryan-Millard/Img2Num) -[![Docs](https://img.shields.io/badge/docs-full-blue?logo=gitbook&logoColor=white)](https://img2num.dev/docs/) -[![Changelog](https://img.shields.io/badge/changelog-full-orange?logo=git&logoColor=white)](https://img2num.dev/changelog/) + +[![Sponsor](https://img.shields.io/badge/Sponsor-%E2%9D%A4-EA4AAA?logo=githubsponsors&logoColor=white)](https://github.com/sponsors/Ryan-Millard) +[![Security Policy](https://img.shields.io/badge/Security-Policy-red?logo=github)](https://github.com/Ryan-Millard/Img2Num/blob/main/SECURITY.md) ## Contents @@ -35,14 +34,18 @@ It converts raster images (like PNGs and JPGs) into clean SVGs with _high accura - [Multi-Language Support](#multi-language-support) - [Community Links](#community-links) +

@@ -51,17 +54,17 @@ It converts raster images (like PNGs and JPGs) into clean SVGs with _high accura ## Before vs After | Input (Original Raster) | Output (SVG) | |----------|------------------| -| Original input raster image (Aerial view of mountains) | Final output SVG image (Aerial view of mountains) | -| Original input raster image (A garden in Margate, South Africa) | Final output SVG image (A garden in Margate, South Africa) | -| Original input raster image (A ring on a woman's hand) | Final output SVG image  (A ring on a woman's hand) | +| Original input raster image (Aerial view of mountains) | Final output SVG image (Aerial view of mountains) | +| Original input raster image (A garden in Margate, South Africa) | Final output SVG image (A garden in Margate, South Africa) | +| Original input raster image (A ring on a woman's hand) | Final output SVG image  (A ring on a woman's hand) | ### What are you waiting for? -Try our [image to color-by-number demo](https://img2num.dev/)! +Try one of our [example-apps](https://img2num.dev/example-apps/)! +
-> [!IMPORTANT] > ### Why Img2Num? > > Most raster-to-SVG vectorizers were designed for clean, synthetic input images such as logos, icons, diagrams, and flat illustrations. @@ -98,14 +101,17 @@ Try our [image to color-by-number demo](https://img2num.dev/)! | Language | Package Info | |-----------:|:------------| -| | [![Docs](https://img.shields.io/badge/docs-C-A8B9CC?logo=gitbook&logoColor=white)](https://img2num.dev/docs/c/) [![C Changelog](https://img.shields.io/badge/changelog-C-A8B9CC?logo=c)](https://img2num.dev/changelog/c/) | -| | [![Docs](https://img.shields.io/badge/docs-C++-00599C?logo=gitbook&logoColor=white)](https://img2num.dev/docs/cpp/) [![C++ Changelog](https://img.shields.io/badge/changelog-C%2B%2B-00599C?logo=c%2B%2B&logoColor=white)](https://img2num.dev/changelog/cpp/) | -| | [![npm](https://img.shields.io/npm/v/img2num?logo=npm)](https://www.npmjs.com/package/img2num) ![Downloads](https://img.shields.io/npm/dm/img2num?logo=npm) [![Docs](https://img.shields.io/badge/docs-JavaScript-F7DF1E?logo=gitbook&logoColor=white)](https://img2num.dev/docs/js/) [![JavaScript Changelog](https://img.shields.io/badge/changelog-JavaScript-F7DF1E?logo=javascript)](https://img2num.dev/changelog/js/) | -| | ![PyPI](https://img.shields.io/pypi/v/img2num?logo=pypi) [![PyPI Downloads](https://img.shields.io/pypi/dm/img2num?logo=pypi)](https://pypi.org/project/img2num/) [![Supported Versions](https://img.shields.io/pypi/pyversions/img2num?logo=python)](https://pypi.org/project/img2num/) [![Docs](https://img.shields.io/badge/docs-Python-3776AB?logo=gitbook&logoColor=white)](https://img2num.dev/docs/py/) [![Python Changelog](https://img.shields.io/badge/changelog-Python-3776AB?logo=python)](https://img2num.dev/changelog/py/) | +| C logo | C package releases [![Docs](https://img.shields.io/badge/docs-C-A8B9CC?logo=gitbook&logoColor=white)](https://img2num.dev/docs/c/) [![C Changelog](https://img.shields.io/badge/changelog-C-A8B9CC?logo=c)](https://img2num.dev/changelog/c/) | +| C++ logo | C++ package releases [![Docs](https://img.shields.io/badge/docs-C++-00599C?logo=gitbook&logoColor=white)](https://img2num.dev/docs/cpp/) [![C++ Changelog](https://img.shields.io/badge/changelog-C%2B%2B-00599C?logo=c%2B%2B&logoColor=white)](https://img2num.dev/changelog/cpp/) | +| JavaScript logo | [![npm](https://img.shields.io/npm/v/img2num?logo=npm)](https://www.npmjs.com/package/img2num) [![jsDelivr CDN](https://img.shields.io/badge/CDN-jsDelivr-%23f7df1e?logo=jsdelivr&logoColor=black)](https://www.jsdelivr.com/package/npm/img2num) [![unpkg CDN](https://img.shields.io/badge/CDN-unpkg-%23cb3837?logo=npm&logoColor=white)](https://app.unpkg.com/img2num) [![Downloads](https://img.shields.io/npm/dm/img2num?logo=npm)](https://www.npmjs.com/package/img2num) JavaScript package releases [![Docs](https://img.shields.io/badge/docs-JavaScript-F7DF1E?logo=gitbook&logoColor=white)](https://img2num.dev/docs/js/) [![JavaScript Changelog](https://img.shields.io/badge/changelog-JavaScript-F7DF1E?logo=javascript)](https://img2num.dev/changelog/js/) | +| Python logo | [![PyPI](https://img.shields.io/pypi/v/img2num?logo=pypi)](https://pypi.org/project/img2num/) [![PyPI Downloads](https://img.shields.io/pypi/dm/img2num?logo=pypi)](https://pypi.org/project/img2num/) [![Supported Versions](https://img.shields.io/pypi/pyversions/img2num?logo=python)](https://pypi.org/project/img2num/) Python package releases [![Docs](https://img.shields.io/badge/docs-Python-3776AB?logo=gitbook&logoColor=white)](https://img2num.dev/docs/py/) [![Python Changelog](https://img.shields.io/badge/changelog-Python-3776AB?logo=python)](https://img2num.dev/changelog/py/) | ## Community Links [![Changelog](https://img.shields.io/badge/Changelog-Full-orange?logo=git&logoColor=white)](https://img2num.dev/changelog/) [![Contributing](https://img.shields.io/badge/Contributing-Guide-blue?logo=github)](https://github.com/Ryan-Millard/Img2Num/blob/main/CONTRIBUTING.md) +[![Security Policy](https://img.shields.io/badge/Security-Policy-red?logo=github)](https://github.com/Ryan-Millard/Img2Num/blob/main/SECURITY.md) +[![License](https://img.shields.io/badge/License-MIT-blue?logo=open-source-initiative&logoColor=white)](https://github.com/Ryan-Millard/Img2Num/blob/main/LICENSE) +[![Sponsor](https://img.shields.io/badge/Sponsor-%E2%9D%A4-EA4AAA?logo=githubsponsors&logoColor=white)](https://github.com/sponsors/Ryan-Millard) [![Issues](https://img.shields.io/badge/Issues-Available-brightgreen?logo=github)](https://github.com/Ryan-Millard/Img2Num/issues/views/1151) [![Good First Issues](https://img.shields.io/badge/Good%20First%20Issues-Welcome-6cc644?logo=github)](https://github.com/Ryan-Millard/Img2Num/issues/views/1155) [![Blog](https://img.shields.io/badge/Blog-Updates-ff6f00?logo=githubpages)](https://img2num.dev/blog/) @@ -117,15 +123,17 @@ Try our [image to color-by-number demo](https://img2num.dev/)! pip install img2num ``` +```bash +uv add img2num +``` + **Runtime dependency:** `numpy>=1.23.5` **Supported Python versions:** 3.10, 3.11, 3.12 ## Quick Start - -> [!Important] -> Input images must be 4 channel `uint8` arrays with channel order RGBA +> **Important:** Input images must be 4 channel `uint8` arrays with channel order RGBA ### All-in-one (recommended) @@ -147,7 +155,13 @@ with open("output.svg", "w") as f: `width` and `height` are automatically injected from the image shape, do not pass them manually. -For full API details see the [Python API reference](https://img2num.dev/docs/python/). +For full API details see the [Python API reference](https://img2num.dev/docs/py/). + +--- + +## Type Hints + +This package is fully typed. Wheels include a PEP 561 `py.typed` marker and generated `.pyi` stubs for the native `_img2num` extension, so mypy, pyright, and IDE autocomplete work out of the box — no extra stub packages needed. ## Examples @@ -164,26 +178,51 @@ uv build python -m build ``` +Type stubs are generated with `pybind11-stubgen` during the CMake build and bundled into the wheel automatically. + Release wheels are built automatically via `cibuildwheel` and published to PyPI using OIDC trusted publishing through the GitHub Actions release workflow. ## License [MIT](https://github.com/Ryan-Millard/Img2Num/blob/main/LICENSE) © Ryan Millard +> This package (the library you install from PyPI) is MIT-licensed. Documentation, example apps, and CI/config in the main repository are AGPLv3 — see the [repository license overview](https://github.com/Ryan-Millard/Img2Num#license) for details. + +## Supporting Us + +[![GitHub Sponsors](https://img.shields.io/badge/GitHub_Sponsors-%E2%9D%A4-EA4AAA?logo=githubsponsors&logoColor=white)](https://github.com/sponsors/Ryan-Millard) +[![Ko-fi](https://img.shields.io/badge/Ko--fi-Support-FF5E5B?logo=kofi&logoColor=white)](https://ko-fi.com/ryan_millard) + +Img2Num is free and open source. If it saves you time or you'd like to support its continued development: + +- ⭐ [Star the repository](https://github.com/Ryan-Millard/Img2Num) - it helps others discover the project +- ❤️ Sponsor us via [GitHub Sponsors](https://github.com/sponsors/Ryan-Millard) or [Ko-fi](https://ko-fi.com/ryan_millard) (it'll help us keep the [img2num.dev](https://img2num.dev/) domain) +- 🛠️ Contribute - see our [Contributing Guide](https://github.com/Ryan-Millard/Img2Num/blob/main/CONTRIBUTING.md) and [good first issues](https://github.com/Ryan-Millard/Img2Num/issues/views/1155) + ---
+

GitHub · - Documentation + Documentation · Changelog · + Contributing + · + Security + · + Sponsor + · Issues · Discussions + · + Blog

+

Contributors diff --git a/pyproject.toml b/pyproject.toml index 66278f994..fad6007a8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,6 +27,7 @@ Documentation = "https://img2num.dev/docs/" Changelog = "https://img2num.dev/changelog/py/" "Changelog (GitHub)" = "https://github.com/Ryan-Millard/Img2Num/blob/main/packages/py/CHANGELOG.md" "Bug Tracker" = "https://github.com/Ryan-Millard/Img2Num/issues" +Funding = "https://github.com/sponsors/Ryan-Millard" [build-system] requires = [

+ - [Before vs After](#before-vs-after) - [Why Img2Num?](#why-img2num) - [Features](#features) - [Multi-Language Support](#multi-language-support) - [Community Links](#community-links) +- [Quick Start](#quick-start) + -- [Quick Start](#quick-start) - [License](#license) +- [Security](#security) +- [Supporting Us](#supporting-us) - [Can't find something?](#cant-find-something) - [Maintainers](#maintainers) - [Contributors & Credits](#contributors--credits) @@ -89,6 +94,7 @@ Try our [image to color-by-number demo](https://img2num.dev/example-apps/react-j - **C** - lightweight C API (add as a submodule) - **Python** (`pip install img2num`) - NumPy arrays in, SVG strings out - **JavaScript** (`npm i img2num`) - same C++ core compiled to WebAssembly, works in browser and Node +- **WebAssembly-powered** - The native C++ core is compiled to WebAssembly (WASM) for high-performance execution in browsers (JavaScript-only). - **Zero-copy bindings** - Direct memory access via NumPy in Python and TypedArrays in JS, avoiding unnecessary data copying. - **Minimal dependencies** - Core library built for speed with only one external runtime dependency (Google's [Dawn](https://dawn.googlesource.com/dawn)). - **Cross-platform CI** - Tested on Linux, macOS, Windows, and WASM. @@ -101,12 +107,15 @@ Try our [image to color-by-number demo](https://img2num.dev/example-apps/react-j |-----------:|:------------| | C logo | C package releases [![Docs](https://img.shields.io/badge/docs-C-A8B9CC?logo=gitbook&logoColor=white)](https://img2num.dev/docs/c/) [![C Changelog](https://img.shields.io/badge/changelog-C-A8B9CC?logo=c)](https://img2num.dev/changelog/c/) | | C++ logo | C++ package releases [![Docs](https://img.shields.io/badge/docs-C++-00599C?logo=gitbook&logoColor=white)](https://img2num.dev/docs/cpp/) [![C++ Changelog](https://img.shields.io/badge/changelog-C%2B%2B-00599C?logo=c%2B%2B&logoColor=white)](https://img2num.dev/changelog/cpp/) | -| JavaScript logo | [![npm](https://img.shields.io/npm/v/img2num?logo=npm)](https://www.npmjs.com/package/img2num) ![Downloads](https://img.shields.io/npm/dm/img2num?logo=npm) JavaScript package releases [![Docs](https://img.shields.io/badge/docs-JavaScript-F7DF1E?logo=gitbook&logoColor=white)](https://img2num.dev/docs/js/) [![JavaScript Changelog](https://img.shields.io/badge/changelog-JavaScript-F7DF1E?logo=javascript)](https://img2num.dev/changelog/js/) | -| Python logo | ![PyPI](https://img.shields.io/pypi/v/img2num?logo=pypi) [![PyPI Downloads](https://img.shields.io/pypi/dm/img2num?logo=pypi)](https://pypi.org/project/img2num/) [![Supported Versions](https://img.shields.io/pypi/pyversions/img2num?logo=python)](https://pypi.org/project/img2num/) Python package releases [![Docs](https://img.shields.io/badge/docs-Python-3776AB?logo=gitbook&logoColor=white)](https://img2num.dev/docs/py/) [![Python Changelog](https://img.shields.io/badge/changelog-Python-3776AB?logo=python)](https://img2num.dev/changelog/py/) | +| JavaScript logo | [![npm](https://img.shields.io/npm/v/img2num?logo=npm)](https://www.npmjs.com/package/img2num) [![jsDelivr CDN](https://img.shields.io/badge/CDN-jsDelivr-%23f7df1e?logo=jsdelivr&logoColor=black)](https://www.jsdelivr.com/package/npm/img2num) [![unpkg CDN](https://img.shields.io/badge/CDN-unpkg-%23cb3837?logo=npm&logoColor=white)](https://app.unpkg.com/img2num) [![Downloads](https://img.shields.io/npm/dm/img2num?logo=npm)](https://www.npmjs.com/package/img2num) JavaScript package releases [![Docs](https://img.shields.io/badge/docs-JavaScript-F7DF1E?logo=gitbook&logoColor=white)](https://img2num.dev/docs/js/) [![JavaScript Changelog](https://img.shields.io/badge/changelog-JavaScript-F7DF1E?logo=javascript)](https://img2num.dev/changelog/js/) | +| Python logo | [![PyPI](https://img.shields.io/pypi/v/img2num?logo=pypi)](https://pypi.org/project/img2num/) [![PyPI Downloads](https://img.shields.io/pypi/dm/img2num?logo=pypi)](https://pypi.org/project/img2num/) [![Supported Versions](https://img.shields.io/pypi/pyversions/img2num?logo=python)](https://pypi.org/project/img2num/) Python package releases [![Docs](https://img.shields.io/badge/docs-Python-3776AB?logo=gitbook&logoColor=white)](https://img2num.dev/docs/py/) [![Python Changelog](https://img.shields.io/badge/changelog-Python-3776AB?logo=python)](https://img2num.dev/changelog/py/) | ## Community Links [![Changelog](https://img.shields.io/badge/Changelog-Full-orange?logo=git&logoColor=white)](https://img2num.dev/changelog/) -[![Contributing](https://img.shields.io/badge/Contributing-Guide-blue?logo=github)](https://github.com/Ryan-Millard/Img2Num/blob/main/CONTRIBUTING.md) +[![Contributing](https://img.shields.io/badge/Contributing-Guide-blue?logo=github)](CONTRIBUTING.md) +[![Security Policy](https://img.shields.io/badge/Security-Policy-red?logo=github)](SECURITY.md) +[![License](https://img.shields.io/badge/License-MIT-blue?logo=open-source-initiative&logoColor=white)](LICENSE) +[![Sponsor](https://img.shields.io/badge/Sponsor-%E2%9D%A4-EA4AAA?logo=githubsponsors&logoColor=white)](https://github.com/sponsors/Ryan-Millard) [![Issues](https://img.shields.io/badge/Issues-Available-brightgreen?logo=github)](https://github.com/Ryan-Millard/Img2Num/issues/views/1151) [![Good First Issues](https://img.shields.io/badge/Good%20First%20Issues-Welcome-6cc644?logo=github)](https://github.com/Ryan-Millard/Img2Num/issues/views/1155) [![Blog](https://img.shields.io/badge/Blog-Updates-ff6f00?logo=githubpages)](https://img2num.dev/blog/) @@ -125,7 +134,7 @@ This process is too detailed to put in a `README.md` file, so please see our doc > [!TIP] > You can install the library from our GitHub releases: -> +> > - [C](https://github.com/Ryan-Millard/Img2Num/releases?q=bindings-c&expanded=true) > - [C++](https://github.com/Ryan-Millard/Img2Num/releases?q=cpp&expanded=true) @@ -143,7 +152,7 @@ For more detailed information on installing this package, please refer to [our d ```html - + ``` #### Package Manager @@ -197,6 +206,25 @@ Subdirectories retain their own licenses: - [`example-apps/react-js/` ![AGPLv3](https://img.shields.io/badge/license-AGPLv3-red.svg?logo=react)](example-apps/react-js/LICENSE) - [`.github/` ![AGPLv3](https://img.shields.io/badge/license-AGPLv3-red.svg?logo=github)](.github/LICENSE) +## Security + +[![Security Policy](https://img.shields.io/badge/Security-Policy-red?logo=github)](SECURITY.md) + +Found a vulnerability? Please **do not** open a public issue. + +Report it privately by following our [Security Policy](SECURITY.md). + +## Supporting Us + +[![GitHub Sponsors](https://img.shields.io/badge/GitHub_Sponsors-%E2%9D%A4-EA4AAA?logo=githubsponsors&logoColor=white)](https://github.com/sponsors/Ryan-Millard) +[![Ko-fi](https://img.shields.io/badge/Ko--fi-Support-FF5E5B?logo=kofi&logoColor=white)](https://ko-fi.com/ryan_millard) + +Img2Num is free and open source. If it saves you time or you'd like to support its continued development: + +- ⭐ [Star the repository](https://github.com/Ryan-Millard/Img2Num) - it helps others discover the project +- ❤️ Sponsor us via [GitHub Sponsors](https://github.com/sponsors/Ryan-Millard) or [Ko-fi](https://ko-fi.com/ryan_millard) (it'll help us keep the [img2num.dev](https://img2num.dev/) domain) +- 🛠️ Contribute - see our [Contributing Guide](CONTRIBUTING.md) and [good first issues](https://github.com/Ryan-Millard/Img2Num/issues/views/1155) + ## Can't find something? If you need something, see [our documentation](https://img2num.dev/docs/). diff --git a/SECURITY.md b/SECURITY.md index 21f4ff2a9..83e768a68 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -4,34 +4,24 @@ Thank you for helping keep Img2Num and its users secure. We take security issues ## Supported Versions -Security updates are provided for the latest **v0.2.x** release series of each component. The `main` branch is actively maintained for development, but it is not a supported release channel. - -| Component | Supported Versions | Supported | -| ----------------------------------- | ------------------ | :----------------: | -| C++ Library | `v0.2.x` | :white_check_mark: | -| C Bindings | `v0.2.x` | :white_check_mark: | -| JavaScript Package | `v0.2.x` | :white_check_mark: | -| Python Package | `v0.2.x` | :white_check_mark: | -| Development (`main`) | `Latest` | Development Only | -| Older releases (v0.1.x and earlier) | - | :x: | - -## Release History - -| Component | Releases | -| ------------------ | ---------------------- | -| C++ Library | v0.2.0, v0.1.0 | -| C Bindings | v0.2.0, v0.1.0 | -| JavaScript Package | v0.2.1, v0.2.0, v0.1.0 | -| Python Package | v0.2.1, v0.2.0, v0.1.0 | +Security updates are provided for the latest release of each component (C++ library, C bindings, JavaScript package, and Python package). +See the [Releases page](https://github.com/Ryan-Millard/Img2Num/releases) for the current version of each component. -## Reporting a Vulnerability +The `main` branch is actively maintained for development and treated as a _stable development branch_, but it is not a supported release channel. +Releases prior to the current minor version of each component do not receive backported fixes — please upgrade to the latest release. -**Please do not report security vulnerabilities through public GitHub issues or discussions.** +> [!NOTE] +> v0.2.x of the JavaScript package is no longer supported due to incompatibilities with several environments. Please upgrade to v0.3.0 or later. -Instead, report vulnerabilities privately using one of the following methods: +## Reporting a Vulnerability -- **GitHub Security Advisories** (preferred): Use the repository's **Report a vulnerability** feature under the **Security** tab. -- **Email:** [security@img2num.dev](mailto:security@img2num.dev) +> [!CAUTION] +> Please do not report security vulnerabilities through public GitHub issues or discussions. +> +> Instead, report vulnerabilities privately using one of the following methods: +> +> - **GitHub Security Advisories** (preferred): Use the repository's **Report a vulnerability** feature under the **Security** tab. +> - **Email:** [security@img2num.dev](mailto:security@img2num.dev) or [ryan@img2num.dev](mailto:ryan@img2num.dev) Please include as much information as possible: diff --git a/docs/blog/2026-08-19-img2num_js_0_4_2/img/social.png b/docs/blog/2026-08-19-img2num_js_0_4_2/img/social.png new file mode 100644 index 000000000..74cb65e7e Binary files /dev/null and b/docs/blog/2026-08-19-img2num_js_0_4_2/img/social.png differ diff --git a/docs/blog/2026-08-19-img2num_js_0_4_2/img/social.svg b/docs/blog/2026-08-19-img2num_js_0_4_2/img/social.svg new file mode 100644 index 000000000..cda2ac87f --- /dev/null +++ b/docs/blog/2026-08-19-img2num_js_0_4_2/img/social.svg @@ -0,0 +1,105 @@ + + + + + + IMG2NUM · JAVASCRIPT RELEASE + JS 0.4.2 + One package, + five purpose-built bundles + browser ESM +IIFE +UMD +node ESM +node CJS + img2num.dev + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + raster → svg + \ No newline at end of file diff --git a/docs/blog/2026-08-19-img2num_js_0_4_2/index.md b/docs/blog/2026-08-19-img2num_js_0_4_2/index.md new file mode 100644 index 000000000..ea1d64171 --- /dev/null +++ b/docs/blog/2026-08-19-img2num_js_0_4_2/index.md @@ -0,0 +1,348 @@ +--- +title: "Img2Num JS 0.4.2: One npm Package, Five Purpose-Built WebAssembly Bundles" +description: "Img2Num 0.4.2 ships five purpose-built WASM bundles on npm - browser ESM, IIFE, UMD, and Node ESM/CJS - fixing CommonJS require() crashes and bundler .wasm resolution for image-to-SVG conversion in JavaScript." +keywords: [img2num, image to svg, raster to svg, javascript svg converter, webassembly, wasm, npm, commonjs, esm, vectorization] +image: ./img/social.png +slug: img2num_js_0_4_2 +authors: [ryan-millard] +tags: [release, javascript, wasm] +--- + +import Link from "@docusaurus/Link"; +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +![Hero](./img/social.png) + +Img2Num's [JavaScript package v0.4.2](https://www.npmjs.com/package/img2num) is out on npm, and it's the biggest change to +the npm distribution since we first shipped WebAssembly builds. + +In short, instead of one compromise bundle, the package now ships five purpose-built bundles, +each backed by its own Emscripten glue variant, and getting started no longer requires +knowing anything about Emscripten - regardless of whether you're in a bundled web app, +a plain ` + +``` + +**[Try it on CodeSandbox](https://codesandbox.io/p/sandbox/iife-fh25gg)** + + + + +Loaded as an AMD module - nothing is added to the global scope: + +```html + + +``` + +**[Try it on CodeSandbox](https://codesandbox.io/p/sandbox/competent-shape-2drsrz)** + + + + +`import` resolves the Node ESM build. Decode with whatever you like - here, [sharp](https://www.npmjs.com/package/sharp): + +```js +import { writeFileSync } from "fs"; +import { imageToSvg, terminateWasmModule } from "img2num"; +import sharp from "sharp"; + +const { data, info } = await sharp("input.png").ensureAlpha().raw().toBuffer({ resolveWithObject: true }); + +const pixels = new Uint8ClampedArray(data.buffer, data.byteOffset, data.byteLength); + +try { + const { svg } = await imageToSvg({ pixels, width: info.width, height: info.height }); + writeFileSync("output.svg", svg); +} finally { + await terminateWasmModule(); +} +``` + +**[Try it on CodeSandbox](https://codesandbox.io/p/devbox/node-esm-jmn444)** + + + + +`require()` resolves the CJS build - the one this release exists to fix. No flags, no interop wrappers: + +```js +const { writeFileSync } = require("fs"); +const { imageToSvg, terminateWasmModule } = require("img2num"); +const sharp = require("sharp"); + +async function main() { + const { data, info } = await sharp("input.png").ensureAlpha().raw().toBuffer({ resolveWithObject: true }); + + const pixels = new Uint8ClampedArray(data.buffer, data.byteOffset, data.byteLength); + + try { + const { svg } = await imageToSvg({ pixels, width: info.width, height: info.height }); + writeFileSync("output.svg", svg); + } finally { + await terminateWasmModule(); + } +} + +main().catch(console.error); +``` + +**[Try it on CodeSandbox](https://codesandbox.io/p/devbox/node-cjs-dp5ltr)** + + + + +## Breaking changes + +This is a majorish release for a reason, though migration is small for most codebases: + +:::danger[`dist/` layout and filenames have changed.] + +- If you were deep-importing into `dist/`, update those paths to the table above. +- If you import the package root, you don't have to change anything. + +::: + +:::danger[Export conditions are reordered.] + +The `browser` condition now comes first, so bundlers targeting the browser actually get the browser build - +previously they matched `import` first and silently received the Node build. +If your bundle got smaller and your weird workaround stopped being necessary, that's why. + +::: + +:::danger[Minimum supported Node is now v18.] + +Previously we documented Node >= 14; the new node-glue builds require version 18. + +::: + +:::note[Other Improvements] + +Two quieter improvements ride along: + +1. The optional `webgpu` dependency in Node is now properly guarded: + if it's missing (`--ignore-optional`), fails to install on your platform, or can't + be loaded, Img2Num logs a warning and falls back to CPU instead of throwing. + (0.4.0 and 0.4.1 claimed this and didn't deliver it - the fallback path itself crashed. + 0.4.2 delivers it, verified against both the ESM and CJS console examples with + `webgpu` removed.) + +2. Initial WASM memory **dropped from 2 GB to 32 MB** - a 2 GB + reservation fails outright on mobile Safari and bought nothing with memory growth enabled. + +::: + +## What about the synchronous API? + +That was last release. +[0.3.0](https://www.npmjs.com/package/img2num/v/0.3.0) removed the internal Web Worker and made the API fully synchronous - +Img2Num does the math, you decide where it runs. +If you're moving from an earlier version straight to [v0.4.2](https://www.npmjs.com/package/img2num), +the [0.3.0](https://www.npmjs.com/package/img2num/v/0.3.0) +migration still applies: delete the `await`, and wrap calls in your own worker if you need to keep the main thread free: + +```js +// worker.js +import { process } from "img2num"; +self.onmessage = ({ data }) => { + self.postMessage(process(data.imageData, data.options)); +}; +``` + +[v0.4.2](https://www.npmjs.com/package/img2num) is what that change unlocked: +with no worker plumbing forced into every artifact, each target could finally get a build shaped for its actual environment. + +:::tip[Why did [0.3.0](https://www.npmjs.com/package/img2num/v/0.3.0) remove the workers?] + +Cross-environment compatibility. A hidden worker only made sense in some targets, and it +fought any worker architecture you already had. Running synchronously works everywhere - +Img2Num does the math, and you decide which thread it runs on. + +::: + +## Example apps for every binding + +Talking about build targets is abstract, so the examples got a matching overhaul: + +- `console-js` is now split into console-js-esm and console-js-cjs, + so the `import` and `require` export conditions are each exercised by a real consumer (and we fixed a byte-offset bug in the pixel-buffer construction while we were in there). +- The `html-js` example was rebuilt as a single shared template compiled into three self-contained variants - + + ESM + + ,  + + IIFE + + , and  + + UMD + +  - each deployable as plain static files with no build tooling at runtime. +- The docs site now has an [example apps index](https://img2num.dev/example-apps/) with a card and representative snippet for every binding: + React, browser ESM, IIFE, UMD, Node ESM/CJS - and Python, C++, and C, because Img2Num was never just a JavaScript library. +- Every JS target is also runnable in your browser right now - the CodeSandbox links in the + [tabs above](#how-to-use-img2num-in-the-browser-and-nodejs) are one click from "processed image" with nothing installed. + +Each example is intentionally minimal: the shortest path from "empty directory" to "processed image" in your environment of choice. +They're also our first line of defense - and this release proved it twice. +The React example caught the 0.4.0 browser bug before almost anyone could hit it, +and the new Node CJS example caught the CommonJS bug that survived into 0.4.1 the same way. +Every entry point now has a real consumer that runs it the way you would. + +## Getting started + +```bash title="Using npm" +npm install img2num +``` + +```html title="Using a CDN (the CDN default resolves to the single-file IIFE build)" + +``` + +(Pin the version - your future self will thank you.) + +## What's next + +Purpose-built targets give us a clean baseline for the work we've wanted to do for a while: +benchmarking across environments and exploring WebGPU acceleration beyond the current optional Node support. +If you hit anything odd with the new builds - an environment we didn't test, an interop edge case - +please [open an issue](https://github.com/Ryan-Millard/Img2Num/issues) so we can fix it for you. +Reports from real setups are exactly what a release like this needs. + +Thanks for using Img2Num! 🦔🦔 diff --git a/docs/blog/tags.yml b/docs/blog/tags.yml index b70701aca..564b09dbf 100644 --- a/docs/blog/tags.yml +++ b/docs/blog/tags.yml @@ -12,3 +12,18 @@ maintainers: label: Maintainers permalink: /maintainers description: Updates from maintainers and openings + +release: + label: Release + permalink: /release + description: New version releases and changelogs + +javascript: + label: JavaScript + permalink: /javascript + description: Posts about the JavaScript/npm package + +wasm: + label: WebAssembly + permalink: /wasm + description: WebAssembly builds and browser usage diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index 1e9065459..80cc03c87 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -38,8 +38,7 @@ const algoliaHeadTag = { content: "DB4B5FEC1545D32B", }; -const GitHubNavbarLink = ` - - - - -`; + + Sponsor + `; /** @type {import('@docusaurus/types').Config} */ const config = { @@ -267,15 +268,16 @@ const config = { }, { to: "/changelog", label: "Changelog", position: "left" }, { to: "/blog", label: "Blog", position: "left" }, + { type: "search", position: "right" }, { type: "html", position: "right", - value: GitHubNavbarLink, + value: SponsorLink, }, { type: "html", position: "right", - value: SponsorLink, + value: GitHubNavbarLink, }, ], hideOnScroll: false, diff --git a/docs/src/css/custom.css b/docs/src/css/custom.css index 182ea8659..b8a6120ad 100644 --- a/docs/src/css/custom.css +++ b/docs/src/css/custom.css @@ -1,4 +1,6 @@ :root { + --ifm-color-primary: var(--primary); + --font-sans: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; --spacing-xs: 4px; --spacing-sm: 8px; @@ -234,6 +236,26 @@ hr { .navbar__inner { justify-content: space-evenly; } + + .DocSearch-Button { + margin: 0; + width: min(28vw, 300px); + justify-content: space-between; + } +} + +/* + * Narrow desktops: collapse to icon-only so the centered search + * never crowds the nav links or the sponsor button + */ +@media screen and (min-width: 997px) and (max-width: 1200px) { + .DocSearch-Button { + width: auto; + } + .DocSearch-Button-Placeholder, + .DocSearch-Button-Keys { + display: none; + } } .navbar__title, @@ -511,8 +533,11 @@ div[class^="buttonGroup"] button { .DocSearch-Modal { border: 1px solid var(--glass-border); } +.DocSearch-Hit a { + background-color: var(--glass-bg); +} .DocSearch-Hit[aria-selected="true"] a { - background-color: var(--primary); + background-color: var(--white); } .DocSearch-Hit-source { color: var(--primary); @@ -521,3 +546,112 @@ div[class^="buttonGroup"] button { .DocSearch-Cancel { color: var(--text-light); } + +/* ---- Sponsor button ---- */ +:root { + --sponsor-shine: rgba(255, 255, 255, 0.8); +} + +[data-theme="dark"] { + --sponsor-shine: rgba(255, 255, 255, 0.45); +} + +.navbar__sponsor { + position: relative; + overflow: hidden; + display: inline-flex; + align-items: center; + gap: 7px; + margin: 0 6px; + padding: 5px 10px; + border-radius: var(--radius-md); + border: 1px solid var(--glass-border); + background-color: var(--glass-bg); + color: var(--text); + transition: + background-color 0.15s ease, + border-color 0.15s ease, + transform 0.2s ease, + box-shadow 0.2s ease; +} + +.navbar__sponsor-heart { + flex: none; + color: var(--accent); +} + +.navbar__sponsor:hover, +.navbar__sponsor:focus-visible { + background-color: var(--accent-light); + border-color: var(--accent); + color: var(--text); + text-decoration: none; + transform: translateY(-1px); + box-shadow: 0 2px 8px var(--glass-shadow); +} + +.navbar__sponsor:active { + transform: translateY(0) scale(0.98); +} + +.navbar__sponsor:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +.navbar__sponsor::before { + content: ""; + position: absolute; + top: -25%; + bottom: -25%; + left: 0; + width: 45%; + background: linear-gradient(105deg, transparent, var(--sponsor-shine), transparent); + transform: translateX(-130%) skewX(-18deg); + pointer-events: none; +} + +.navbar__sponsor:hover::before { + animation: sponsor-shine 0.7s ease; +} + +@keyframes sponsor-shine { + to { + transform: translateX(330%) skewX(-18deg); + } +} + +.navbar__sponsor:hover .navbar__sponsor-heart { + animation: sponsor-heartbeat 0.8s ease-in-out; + transform-origin: center; +} + +@keyframes sponsor-heartbeat { + 0%, + 100% { + transform: scale(1); + } + 20% { + transform: scale(1.25); + } + 45% { + transform: scale(1); + } + 65% { + transform: scale(1.12); + } +} + +@media (prefers-reduced-motion: reduce) { + .navbar__sponsor::before { + display: none; + } + .navbar__sponsor, + .navbar__sponsor:hover, + .navbar__sponsor:active { + transform: none; + } + .navbar__sponsor:hover .navbar__sponsor-heart { + animation: none; + } +} diff --git a/packages/js/README.md b/packages/js/README.md index d51050b08..1530b9dd8 100644 --- a/packages/js/README.md +++ b/packages/js/README.md @@ -4,24 +4,23 @@ # Img2Num -_Img2Num_ is a fast and accurate raster vectorizer. +_Img2Num_ is a fast and accurate raster vectorizer. It converts raster images (like PNGs and JPGs) into clean SVGs with _high accuracy and performance_. _Img2Num_ is **optimized for natural images**. +[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/Ryan-Millard/Img2Num/blob/main/LICENSE) ![Status](https://img.shields.io/badge/status-active_development-brightgreen?logo=github) -[![Deploy to GitHub Pages](https://github.com/Ryan-Millard/Img2Num/actions/workflows/deploy.yml/badge.svg)](https://github.com/Ryan-Millard/Img2Num/actions/workflows/deploy.yml) -[![Multi-Language Release Generation](https://github.com/Ryan-Millard/Img2Num/actions/workflows/release.yml/badge.svg)](https://github.com/Ryan-Millard/Img2Num/actions/workflows/release.yml) +[![Docs](https://img.shields.io/badge/docs-full-blue?logo=gitbook&logoColor=white)](https://img2num.dev/docs/) +[![Changelog](https://img.shields.io/badge/changelog-full-orange?logo=git&logoColor=white)](https://img2num.dev/changelog/) -[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/Ryan-Millard/Img2Num/blob/main/LICENSE) [![Contributors](https://img.shields.io/github/contributors/Ryan-Millard/Img2Num)](https://github.com/Ryan-Millard/Img2Num/graphs/contributors) [![Stars](https://img.shields.io/github/stars/Ryan-Millard/Img2Num?style=social)](https://github.com/Ryan-Millard/Img2Num) -[![Docker Pulls](https://img.shields.io/docker/pulls/ryanmillard/img2num-dev)](https://hub.docker.com/repository/docker/ryanmillard/img2num-dev/general) -[![Open in Codespaces](https://img.shields.io/badge/-Open%20in%20Codespaces-black?logo=github)](https://codespaces.new/Ryan-Millard/Img2Num) -[![Docs](https://img.shields.io/badge/docs-full-blue?logo=gitbook&logoColor=white)](https://img2num.dev/docs/) -[![Changelog](https://img.shields.io/badge/changelog-full-orange?logo=git&logoColor=white)](https://img2num.dev/changelog/) + +[![Sponsor](https://img.shields.io/badge/Sponsor-%E2%9D%A4-EA4AAA?logo=githubsponsors&logoColor=white)](https://github.com/sponsors/Ryan-Millard) +[![Security Policy](https://img.shields.io/badge/Security-Policy-red?logo=github)](https://github.com/Ryan-Millard/Img2Num/blob/main/SECURITY.md) ## Contents @@ -40,12 +39,12 @@ It converts raster images (like PNGs and JPGs) into clean SVGs with _high accura -- [Installation](#installation) -- [Browser Usage (CDN)](#browser-usage-cdn) -- [Quick Start](#quick-start) +- [Node.js Usage](#nodejs-usage) +- [Browser Usage](#browser-usage) - [API Reference](#api-reference) -- [Navigating WebAssembly](#navigating-webassembly) - [Examples](#examples) +- [License](#license) +- [Supporting Us](#supporting-us)
- [Installation](#installation) - [Quick Start](#quick-start) - [API Reference](#api-reference) +- [Type Hints](#type-hints) - [Examples](#examples) - [Building and Publishing](#building-and-publishing) +- [License](#license) +- [Supporting Us](#supporting-us)