Node.js library to remove solid background colors from images without AI/ML based on bgone by Benface.
- Automatic background detection - Detects solid background colors by sampling image edges
- Color unmixing - Separates foreground from background using advanced alpha blending algorithms
- Foreground color deduction - Automatically deduce unknown foreground colors using
"auto" - Strict and non-strict modes - Choose between exact color matching or flexible unmixing
- Parallel processing - Utilizes all CPU cores for maximum performance
- Cross-platform - Works on Windows, macOS, Linux, and more
| Input | Output |
|---|---|
![]() |
![]() |
Example image from Unsplash
npm install @neplex/bgone
# or
yarn add @neplex/bgone
# or
pnpm add @neplex/bgone
# or
bun add @neplex/bgone
# or
deno add npm:@neplex/bgoneimport { readFileSync, writeFileSync } from 'fs';
import { processImage, processImageSync, detectBackgroundColor } from '@neplex/bgone';
const input = readFileSync('input.png');
// Async processing (recommended for large images)
const output = await processImage({
input,
strictMode: false,
trim: false,
});
writeFileSync('output.png', output);
// Sync processing
const outputSync = processImageSync({
input,
strictMode: false,
trim: false,
});You can use bgone directly from the command line:
# Using npx (no installation required)
npx @neplex/bgone input.pngUsage: npx @neplex/bgone [options] <input> [output]
Remove solid background colors from images
Arguments:
input Input image file
output Output image file (defaults to input-bgone.png)
Options:
-V, --version output the version number
-b, --bg <color> Background color to remove (hex, e.g. #ffffff or fff)
-f, --fg <colors...> Foreground colors (hex or "auto" for deduction)
-s, --strict Strict mode - only use specified foreground colors
-t, --threshold <value> Color closeness threshold (0.0-1.0)
--trim Trim output to content bounding box
--detect Only detect and print background color, do not process
-h, --help display help for command
# Fully automatic - detects background and removes it
npx @neplex/bgone input.png
# Specify output path
npx @neplex/bgone input.png output.png
# With explicit background color
npx @neplex/bgone input.png --bg=#ffffff
npx @neplex/bgone input.png -b fff
# With foreground color for optimized opacity
npx @neplex/bgone input.png --fg=#ff0000
# Multiple foreground colors
npx @neplex/bgone input.png --fg ff0000 00ff00 0000ff
# Foreground color deduction
npx @neplex/bgone input.png --fg auto
npx @neplex/bgone input.png --fg auto auto --bg ffffff
# Mix known and unknown colors
npx @neplex/bgone input.png --fg ff0000 auto
# Strict mode with foreground colors
npx @neplex/bgone input.png --strict --fg=#ff0000
npx @neplex/bgone input.png -s --fg auto
# With threshold and trim
npx @neplex/bgone input.png -f f00 0f0 00f -b fff -t 0.1 --trim
# Only detect background color
npx @neplex/bgone input.png --detectinterface RgbColor {
r: number; // 0-255
g: number; // 0-255
b: number; // 0-255
}
interface RgbaColor {
r: number; // 0-255
g: number; // 0-255
b: number; // 0-255
a: number; // 0-255
}
interface NormalizedRgbColor {
r: number; // 0.0-1.0
g: number; // 0.0-1.0
b: number; // 0.0-1.0
}
interface ProcessImageOptions {
/** The input image buffer (PNG, JPEG, etc.) */
input: Buffer;
/** Foreground colors as hex strings. Use "auto" to deduce unknown colors. */
foregroundColors?: string[];
/** Background color as hex string. Auto-detected if not specified. */
backgroundColor?: string;
/** Restricts unmixing to only the specified foreground colors. */
strictMode: boolean;
/** Threshold for color closeness (0.0-1.0, default: 0.05) */
threshold?: number;
/** Trim output to bounding box of non-transparent pixels. */
trim: boolean;
}
interface UnmixResult {
/** Weight for each foreground color */
weights: number[];
/** Overall alpha value (0.0-1.0) */
alpha: number;
}Process an image asynchronously to remove its background. Returns a Promise that resolves to the processed image buffer (PNG format).
// Fully automatic - detects background and removes it
const output = await processImage({
input: imageBuffer,
strictMode: false,
trim: false,
});
// With explicit background color
const output = await processImage({
input: imageBuffer,
backgroundColor: '#ffffff',
strictMode: false,
trim: true,
});
// With foreground colors for optimized opacity
const output = await processImage({
input: imageBuffer,
foregroundColors: ['#ff0000', '#00ff00'],
backgroundColor: '#ffffff',
strictMode: false,
trim: false,
});
// Foreground color deduction using "auto"
const output = await processImage({
input: imageBuffer,
foregroundColors: ['auto'],
backgroundColor: '#ffffff',
strictMode: false,
trim: false,
});
// Mix known and unknown colors
const output = await processImage({
input: imageBuffer,
foregroundColors: ['#ff0000', 'auto'],
strictMode: true,
trim: false,
});
// Strict mode - restricts to exact foreground colors
const output = await processImage({
input: imageBuffer,
foregroundColors: ['#ff0000'],
backgroundColor: '#ffffff',
strictMode: true,
trim: false,
});Synchronous version of processImage. Use for smaller images or when async is not needed.
const output = processImageSync({
input: imageBuffer,
strictMode: false,
trim: false,
});Detect the background color of an image by sampling its edges and corners.
const bgColor = detectBackgroundColor(imageBuffer);
console.log(`Background: rgb(${bgColor.r}, ${bgColor.g}, ${bgColor.b})`);Trim an image to the bounding box of non-transparent pixels.
const trimmed = trimImage(imageBuffer);Parse a hex color string into an RGB color. Supports formats: "#ff0000", "ff0000", "#f00", "f00".
const red = parseColor('#ff0000');
// { r: 255, g: 0, b: 0 }
const green = parseColor('0f0');
// { r: 0, g: 255, b: 0 }Convert an RGB color (0-255) to a normalized RGB color (0.0-1.0).
const normalized = colorToNormalized({ r: 255, g: 128, b: 0 });
// { r: 1.0, g: 0.502, b: 0.0 }Convert a normalized RGB color (0.0-1.0) to an RGB color (0-255).
const rgb = normalizedToColor({ r: 1.0, g: 0.5, b: 0.0 });
// { r: 255, g: 128, b: 0 }Unmix an observed color into foreground color components. Given an observed color and known foreground/background colors, determines how much of each foreground color contributed to the observed color.
const result = unmixColor(
{ r: 128, g: 0, b: 0 }, // observed color
[{ r: 255, g: 0, b: 0 }], // foreground colors
{ r: 0, g: 0, b: 0 }, // background
);
console.log(result.weights); // [0.502...]
console.log(result.alpha); // 0.502...Compute the final RGBA color from an unmix result.
const rgba = computeUnmixResultColor([0.5, 0.5], 1.0, [
{ r: 255, g: 0, b: 0 },
{ r: 0, g: 255, b: 0 },
]);
// { r: 128, g: 128, b: 0, a: 255 }Composite an RGBA pixel over an RGB background color. If the pixel is translucent (alpha < 255), pre-composes it over the background to produce an opaque equivalent.
const result = compositeOverBackground({ r: 255, g: 0, b: 0, a: 128 }, { r: 0, g: 0, b: 0 });
// { r: 128, g: 0, b: 0 }Get the default threshold for color closeness (0.05 = 5% of max RGB distance).
const threshold = getDefaultThreshold();
// 0.05In non-strict mode, the algorithm finds the optimal foreground color and alpha that produces the observed color when alpha-blended with the background. This mode:
- Works without specifying foreground colors
- Allows any color to be used as foreground
- Optimizes for minimum alpha (maximum transparency)
- Always produces perfect reconstruction of the original image
When foreground colors are specified in non-strict mode:
- Pixels close to specified foreground colors use the optimized unmixing algorithm
- Pixels NOT close to any foreground color can use ANY color (preserves glows, gradients, etc.)
- Uses the
thresholdoption to determine "closeness"
Strict mode restricts unmixing to only the specified foreground colors:
- Requires at least one foreground color (can be
"auto"for deduction) - Output pixels can only be a mix of the specified foreground colors
- Best for images with known, limited color palettes
Use "auto" in the foregroundColors array to automatically deduce unknown colors:
// Deduce one unknown color
const output = await processImage({
input,
foregroundColors: ['auto'],
strictMode: true,
trim: false,
});
// Mix known and unknown colors
const output = await processImage({
input,
foregroundColors: ['#ff0000', 'auto', 'auto'],
strictMode: true,
trim: false,
});The library uses Rayon for parallel processing, utilizing all available CPU cores. For best performance:
- Use
processImage(async) for large images to avoid blocking the event loop - Use
processImageSyncfor small images or batch processing - Consider using worker threads for processing multiple images
MIT
Based on bgone by Benface.

