{"id":15125,"library":"image-q","title":"Image-Q: Image Quantization Library","description":"Image-Q is a comprehensive TypeScript library for image color quantization, providing various algorithms to reduce the number of colors in an image while preserving visual quality. It supports alpha channels and offers multiple quantization methods, including NeuQuant, RGBQuant, and Xiaolin Wu's algorithms, alongside a broad selection of color distance formulas such as Euclidean, Manhattan, CIEDE2000, and CIE94. The library features both synchronous and promise-based asynchronous APIs, as well as generator-based advanced APIs, making it adaptable for various use cases. It supports both browser (Chrome 7+, Firefox 4+, IE 10+, Opera 11.6+, Safari 5.1+) and Node.js (6.0+) environments. Currently stable at version 4.0.0, the package has a moderate release cadence, with previous major versions introducing significant API changes, particularly around method naming and build outputs. Its key differentiators include a rich set of algorithms and distance metrics, full TypeScript support, and broad platform compatibility. The library is MIT licensed.","status":"active","version":"4.0.0","language":"javascript","source_language":"en","source_url":"https://github.com/ibezkrovnyi/image-quantization","tags":["javascript","image","palette","quantization","quantizer","color","neuquant","rgbquant","xiaolin wu","typescript"],"install":[{"cmd":"npm install image-q","lang":"bash","label":"npm"},{"cmd":"yarn add image-q","lang":"bash","label":"yarn"},{"cmd":"pnpm add image-q","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"The recommended ES Module import. This will load the ESM build via bundlers. CommonJS `require` is also supported but loads the UMD build since v3.0.2.","wrong":"const iq = require('image-q');","symbol":"iq","correct":"import * as iq from 'image-q';"},{"note":"For granular imports of specific sub-modules, which can aid tree-shaking in bundlers.","symbol":"{ utils, dist, palette, image }","correct":"import { utils, dist, palette, image } from 'image-q';"},{"note":"Standard CommonJS import. Since v3.0.2, this loads the UMD build, which bundles all dependencies into a single file.","symbol":"iq","correct":"var iq = require('image-q');"}],"quickstart":{"code":"import {\n  utils,\n  dist,\n  palette,\n  image,\n} from 'image-q';\n\n// Mock ImageData for demonstration. In a real app, you'd get this from a CanvasRenderingContext2D.\nconst width = 16;\nconst height = 16;\nconst data = new Uint8Array(width * height * 4);\nfor (let i = 0; i < data.length; i += 4) {\n  data[i] = Math.floor(Math.random() * 256);     // R\n  data[i + 1] = Math.floor(Math.random() * 256); // G\n  data[i + 2] = Math.floor(Math.random() * 256); // B\n  data[i + 3] = 255;                             // A\n}\nconst imageData = { data, width, height };\n\nasync function quantizeImage() {\n  // 1. Convert raw image data to PointContainer format\n  const inPointContainer = utils.PointContainer.fromImageData(imageData);\n\n  // 2. Define a color distance metric (e.g., Euclidean with BT.709 coefficients)\n  const distanceCalculator = new dist.EuclideanBT709();\n\n  // 3. Define a palette quantizer (e.g., NeuQuant to generate a 256-color palette)\n  const paletteQuantizer = new palette.NeuQuant(distanceCalculator, 256);\n  const colorPointContainer = await paletteQuantizer.quantize(inPointContainer);\n\n  // 4. Define an image quantizer (e.g., Floyd-Steinberg error diffusion dithering)\n  const imageQuantizer = new image.ErrorDiffusionArray(\n    distanceCalculator,\n    image.ErrorDiffusionArrayKernel.FloydSteinberg\n  );\n\n  // 5. Quantize the image pixels against the generated palette\n  const outPointContainer = await imageQuantizer.quantize(inPointContainer, colorPointContainer);\n\n  // 6. Get the result as a Uint8Array (RGBA data)\n  const quantizedData = outPointContainer.toUint8Array();\n  console.log('Quantized image data (first 16 bytes):', quantizedData.slice(0, 16));\n  console.log('Original image dimensions:', `${width}x${height}`);\n  console.log('Quantized image data length:', quantizedData.length);\n}\n\nquantizeImage().catch(console.error);\n","lang":"typescript","description":"This quickstart demonstrates how to perform image quantization using a mock `ImageData` object, applying a NeuQuant palette generation algorithm and Floyd-Steinberg dithering to reduce the image's color count. It showcases the full async API flow."},"warnings":[{"fix":"Update calls from `quantize()` to `quantizeSync()` for synchronous operations, or use the new `await quantize()` for asynchronous, promise-based workflows.","message":"The synchronous `quantize` method on `PaletteQuantizer` and `ImageQuantizer` classes was renamed to `quantizeSync` to distinguish it from the new promise-based `quantize` method.","severity":"breaking","affected_versions":">=2.1.1"},{"fix":"Review and update usages of affected color distance classes to their new names according to the API documentation.","message":"Several color distance class names were updated for clarity. For example, `EuclideanRgbQuantWOAlpha` became `EuclideanBT709NoAlpha`, and `EuclideanRgbQuantWithAlpha` became `EuclideanBT709`.","severity":"breaking","affected_versions":">=2.0.1"},{"fix":"Users relying on strict CommonJS module behavior or specific CJS build characteristics should verify compatibility. Consider using ES module imports (`import * as iq from 'image-q';`) with a bundler for optimal results, especially in Node.js ESM projects.","message":"From version 3.0.2, the dedicated CommonJS (CJS) build was removed and replaced by a UMD (Universal Module Definition) build. While `require('image-q')` still functions, its behavior might have changed slightly, as the UMD build bundles all dependencies, potentially leading to larger bundle sizes or different loading characteristics compared to a pure CJS build.","severity":"gotcha","affected_versions":">=3.0.2"}],"env_vars":null,"last_verified":"2026-04-21T00:00:00.000Z","next_check":"2026-07-20T00:00:00.000Z","problems":[{"fix":"If you intend a synchronous operation, change the call to `paletteQuantizer.quantizeSync(...)`. If you intend an asynchronous operation, ensure you `await` the call: `await paletteQuantizer.quantize(...)`.","cause":"Attempting to call the synchronous `quantize` method after it was renamed. The `quantize` method is now asynchronous (returns a Promise), and the synchronous version is `quantizeSync`.","error":"TypeError: iq.PaletteQuantizer.quantize is not a function"},{"fix":"Use the ES Module import syntax: `import * as iq from 'image-q';` or `import { utils } from 'image-q';`. Ensure your environment or bundler is configured to handle ES Modules.","cause":"Trying to use the CommonJS `require()` syntax in an ES Module context (e.g., in a Node.js project with `\"type\": \"module\"` or a browser environment without a CJS-aware bundler).","error":"ReferenceError: require is not defined"},{"fix":"Ensure you are using specific named imports for sub-modules if you're not importing the entire namespace: `import { utils, dist, palette, image } from 'image-q';` rather than relying solely on `import * as iq from 'image-q'` for direct access to sub-modules without namespace qualification (e.g., `iq.utils.PointContainer`).","cause":"This Webpack/bundler-specific error often indicates an issue with how sub-modules are imported, especially when a global `iq` object might be expected or tree-shaking is over-aggressive.","error":"TypeError: (0 , image_q__WEBPACK_IMPORTED_MODULE_0__.utils).PointContainer.fromImageData is not a function"}],"ecosystem":"npm"}