{"id":29264445,"url":"https://github.com/utzel-butzel/epdoptimize","last_synced_at":"2025-07-04T12:34:43.956Z","repository":{"id":301877326,"uuid":"1010544101","full_name":"Utzel-Butzel/epdoptimize","owner":"Utzel-Butzel","description":null,"archived":false,"fork":false,"pushed_at":"2025-06-29T10:41:00.000Z","size":13458,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-06-29T11:29:24.549Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Utzel-Butzel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-06-29T09:53:31.000Z","updated_at":"2025-06-29T10:41:03.000Z","dependencies_parsed_at":"2025-06-29T11:39:40.503Z","dependency_job_id":null,"html_url":"https://github.com/Utzel-Butzel/epdoptimize","commit_stats":null,"previous_names":["utzel-butzel/epdoptimize"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/Utzel-Butzel/epdoptimize","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Utzel-Butzel%2Fepdoptimize","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Utzel-Butzel%2Fepdoptimize/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Utzel-Butzel%2Fepdoptimize/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Utzel-Butzel%2Fepdoptimize/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Utzel-Butzel","download_url":"https://codeload.github.com/Utzel-Butzel/epdoptimize/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Utzel-Butzel%2Fepdoptimize/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263542605,"owners_count":23477456,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-07-04T12:34:43.473Z","updated_at":"2025-07-04T12:34:43.948Z","avatar_url":"https://github.com/Utzel-Butzel.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# EDP Optimize\n\n[Interactive demo](https://utzel-butzel.github.io/epdoptimize/) 📦📦 📦\n\nA JavaScript library for reducing image colors and dithering them to fit (color) eInk displays with optimal visual quality.\n\nWe are using it for our eInk picture frames at [paperlesspaper](https://paperlesspaper.de/en).\n\nThe library works with both front end js (using the Browser Canvas API) and node.js (using [node-canvas](https://www.npmjs.com/package/canvas))\n\nBtw. you can order our new Spectra 6 eInk picture frame [here](https://www.smarthome-agentur.de/produkt/next-gen-e-paper-bilderrahmen-7-3-mit-app-anbindung-paperlesspaper-spectra6-esche-echtholz). 🎉\n\n[![Node.js Package](https://github.com/Utzel-Butzel/epdoptimize/actions/workflows/npm-publish.yml/badge.svg)](https://github.com/Utzel-Butzel/epdoptimize/actions/workflows/npm-publish.yml)\n\n## Supported Displays\n\n- [AcEP](https://www.eink.com/brand/detail/Gallery)\n- [Spectra 6](https://www.eink.com/brand?bookmark=Spectra)\n\nYou can easily add your own displays and use custom color tables.\n\n![Intro image](https://raw.githubusercontent.com/Utzel-Butzel/epdoptimize/refs/heads/main/intro-image.jpg)\n\n## Features\n\n- **Dithering Algorithms:** Multiple high-quality dithering options to improve color blending and gradients.\n- **Color Calibration:** Match device-specific color characteristics for more accurate results.\n\n## Installation\n\n```bash\nnpm install epdoptimize\n```\n\n## Usage Example\n\n```html\n\u003ccanvas id=\"inputCanvas\" /\u003e\n\u003ccanvas id=\"ditheredCanvas\" /\u003e\n\u003ccanvas id=\"ditheredCanvasWithDeviceColors\" /\u003e\n```\n\n```js\nimport { ditherImage, getDefaultPalettes, getDeviceColors } from 'epdoptimize';\n\n// Access the canvas elements\nconst inputCanvas = document.getElementById(\"inputCanvas\");\nconst ditheredCanvas =  document.getElementById(\"ditheredCanvas\");\nconst ditheredCanvasWithDeviceColors =  document.getElementById(\"ditheredCanvasWithDeviceColors\");\n\nconst palette = getDefaultPalettes('spectra6');\nconst spectra6colors = getDeviceColors('spectra6'); // Spectra 6 color set (can be default, spectra6 or acep)\n\nconst options = {\n  algorithm: 'floydSteinberg',\n  palette,\n};\n\n// Dither the image\nconst dithered = ditherImage(inputCanvas, ditheredCanvas, options);\n\n// Convert the colors to the displays native colors\nconst prepared = replaceColors(ditheredCanvas,ditheredCanvasWithDeviceColors {\n    originalColors: palette,\n    replaceColors: spectra6colors\n});\n\n```\n\n## Dithering Options\n\n| Option                   | Type             | Default          | Description                                                                                                                                 |\n| ------------------------ | ---------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |\n| `ditheringType`          | string           | \"errorDiffusion\" | The main dithering algorithm. Options: `errorDiffusion`, `ordered`, `random`, `quantizationOnly`.                                           |\n| `errorDiffusionMatrix`   | string           | \"floydSteinberg\" | Error diffusion kernel. Options: `floydSteinberg`, `falseFloydSteinberg`, `jarvis`, `stucki`, `burkes`, `sierra3`, `sierra2`, `sierra2-4a`. |\n| `serpentine`             | boolean          | false            | If true, alternates scan direction for each row (serpentine scanning) in error diffusion.                                                   |\n| `orderedDitheringType`   | string           | \"bayer\"          | Type of ordered dithering. Currently only `bayer` is supported.                                                                             |\n| `orderedDitheringMatrix` | [number, number] | [4, 4]           | Size of the Bayer matrix for ordered dithering.                                                                                             |\n| `randomDitheringType`    | string           | \"blackAndWhite\"  | Type of random dithering. Options: `blackAndWhite`, `rgb`.                                                                                  |\n| `palette`                | string/array     | \"default\"        | Palette to use for quantization. Can be a string (predefined) or a custom array of colors.                                                  |\n| `sampleColorsFromImage`  | boolean          | false            | If true, generates palette by sampling colors from the image.                                                                               |\n| `numberOfSampleColors`   | number           | 10               | Number of colors to sample from the image if `sampleColorsFromImage` is true.                                                               |\n\nAdd these options to your `ditherImage` call to customize dithering behavior for your use case.\n\n## How It Works\n\n### Color Calibration\n\neInk displays often render colors less vibrantly than their digital values suggest (e.g., a device red like `#ff0000` may appear duller in reality). By calibrating with real-world color measurements, the library ensures that dithering and color reduction use the actual appearance of colors on your target display. After processing, you can map the calibrated colors back to the device's required values.\n\n### Dithering Algorithms\n\nDithering helps create the illusion of intermediate colors by distributing quantization errors across neighboring pixels. This is especially important for eInk displays with limited color palettes.\n\n#### Available Diffusion Algorithms\n\n| Algorithm               | Description                                                                                        |\n| ----------------------- | -------------------------------------------------------------------------------------------------- |\n| **floydSteinberg**      | Classic Floyd-Steinberg error diffusion. Distributes error to four neighbors. Visually pleasing.   |\n| **falseFloydSteinberg** | Simplified Floyd-Steinberg. Distributes error to three neighbors. Faster, slightly different look. |\n| **jarvis**              | Jarvis, Judice, and Ninke. Spreads error over three rows for smooth gradients, more blurring.      |\n| **stucki**              | Similar to Jarvis, different weights. Balances smoothness and sharpness.                           |\n| **burkes**              | Simplified Stucki. Fewer neighbors, less computation, good results.                                |\n| **sierra3**             | Sierra-3 (original). High-quality, less blurring than Jarvis.                                      |\n| **sierra2**             | Reduced Sierra-3. Fewer neighbors, faster, less diffusion.                                         |\n| **sierra2-4a**          | Lightweight, fast. Distributes error to three neighbors. Good for speed-critical use.              |\n\n## Using Your Own Colors\n\nYou can use your own custom color palette by passing an array of colors to the `palette` option. Colors should be provided as hex strings (e.g., `#FF0000`).\n\n**Example:**\n\n```js\nconst myPalette = [\n  \"#000000\", // black\n  \"#FFFFFF\", // white\n  \"#FF0000\", // red\n  \"#00FF00\", // green\n  \"#0000FF\", // blue\n];\n\nconst options = {\n  ditheringType: \"errorDiffusion\",\n  palette: myPalette,\n};\n\nconst dithered = ditherImage(image, options);\n```\n\n## Resources\n\n- [paperlesspaper](https://paperlesspaper.de)\n\n## Credits\n\n- [Dither me this](https://github.com/DitheringIdiot/dither-me-this)\n\n---\n\n_Contributions and feedback are welcome!_\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Futzel-butzel%2Fepdoptimize","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Futzel-butzel%2Fepdoptimize","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Futzel-butzel%2Fepdoptimize/lists"}