@remove-background-ai/rembg.js
Version:
A simple wrapper for the https://www.rembg.com API
161 lines (160 loc) • 8.11 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.rembg = void 0;
const fs = __importStar(require("fs"));
const axios_1 = __importDefault(require("axios"));
const form_data_1 = __importDefault(require("form-data"));
const tmp_promise_1 = require("tmp-promise");
const buffer_1 = require("buffer");
const D_FORMAT = 'WEBP';
/**
* Removes the background from an image using the rembg.com API.
*
* @param apiKey - The API key for rembg.com.
* @param inputImage - file path, Buffer, or an object with a { base64: string } property.
* @param onUploadProgress - A callback function to handle upload progress events. Defaults to console.log.
* @param onDownloadProgress - A callback function to handle download progress events. Defaults to console.log.
* @param options - set of options for image Post processing.
* @param options.returnMask - If true, returns the alpha-Matte (mask) image instead of the image.
* @param options.returnBase64 - If true, returns the output image as a Base64 string instead of saving it to a file.
* @param options.w - The width of the output image.
* @param options.h - The height of the output image.
* @param options.exact_resize - If true, the output image will be resized to the specified width and height.
* @param options.format - format the image to target format, by default it is WEBP.
* @param options.angle - Rotation angle in degrees (optional).
* @param options.expand - Add padding so rotated images aren't cropped (optional, defaults to true).
* @param options.bg_color - Optional solid background color in hex (e.g. #FFFFFFFF) or named color (e.g. "red", "blue").
* @returns If returnBase64 is true, returns an object with the base64Image property containing the Base64 string of the output image.
* If returnBase64 is false, returns an object with the outputImagePath property containing the path to the output image file,
* and the cleanup function to delete the temporary file.
* @throws Throws an error if the API key is not provided or if the request fails.
*/
const rembg = ({ apiKey, inputImage, options, onUploadProgress = console.log, // it will log every uploadProgress event by default
onDownloadProgress = console.log, // it will log every uploadProgress event by default
}) => __awaiter(void 0, void 0, void 0, function* () {
if (!apiKey)
throw new Error(' ⚠️⚠️⚠️ WARNING ⚠️⚠️⚠️: API key not provided, trials will be very limited.');
const { returnMask = false, returnBase64 = false, w = 0, h = 0, exact_resize = false, angle, expand, bg_color } = options || {};
const url = "https://api.rembg.com/rmbg";
const API_KEY_HEADER = "x-api-key";
const data = new form_data_1.default();
// Handle different input types
if (typeof inputImage === 'string') {
// Input is a file path
data.append('image', fs.createReadStream(inputImage));
}
else if (buffer_1.Buffer.isBuffer(inputImage)) {
// Input is a Buffer
data.append('image', inputImage, { filename: 'image.png' });
}
else if (typeof inputImage === 'object' && 'base64' in inputImage) {
// Input is a base64 string
let base64Data = inputImage.base64;
// Remove data URL prefix if present
if (base64Data.startsWith('data:')) {
base64Data = base64Data.split(',')[1];
}
const buffer = buffer_1.Buffer.from(base64Data, 'base64');
data.append('image', buffer, { filename: 'image.png', contentType: 'image/png' });
}
else {
throw new Error('Invalid input type. Must be a file path, Buffer, or an object with a base64 property.');
}
data.append('exact_resize', exact_resize.toString());
data.append('w', w);
data.append('h', h);
data.append('mask', returnMask.toString());
data.append('return_base64', returnBase64.toString());
// Add new parameters if provided
if (angle !== undefined) {
data.append('angle', angle.toString());
}
if (expand !== undefined) {
data.append('expand', expand.toString());
}
else {
data.append('expand', 'true'); // Default value when not provided
}
if (bg_color !== undefined) {
data.append('bg_color', bg_color);
}
const format = options === null || options === void 0 ? void 0 : options.format;
if (format && format.toLowerCase() === "png" || (format === null || format === void 0 ? void 0 : format.toLowerCase()) === "webp") {
data.append('format', options === null || options === void 0 ? void 0 : options.format);
}
const config = {
method: 'post',
maxBodyLength: Infinity,
url,
headers: Object.assign({ [API_KEY_HEADER]: apiKey }, data.getHeaders()),
data,
responseType: 'arraybuffer',
onUploadProgress,
onDownloadProgress
};
try {
const response = yield axios_1.default.request(config);
if (returnBase64) {
// Return a base64 string if returnBase64 is true
const base64Image = `data:image/png;base64,${buffer_1.Buffer.from(response.data).toString('base64')}`;
return { base64Image };
}
else {
const { path: outputImagePath, cleanup } = yield (0, tmp_promise_1.file)({ prefix: 'rembg-', postfix: `.${(options === null || options === void 0 ? void 0 : options.format) || D_FORMAT}` });
fs.writeFileSync(outputImagePath, response.data);
return { outputImagePath, cleanup };
}
}
catch (error) {
if (error.response) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
throw new Error(`❌ ${error.response.status} ${error.response.data.toString()}`);
}
else if (error.request) {
// The request was made but no response was received
throw new Error(`❌ ${error.message}`);
}
else {
// Something happened in setting up the request that triggered an Error
throw new Error(`❌ Request failed ${error.message}`);
}
}
});
exports.rembg = rembg;
exports.default = exports.rembg;