/**
* Image utilities using jimp for cross-platform compatibility
*/
const Jimp = require('jimp');
/**
* Capture a screenshot from WebDriver and ensure it's in PNG format
*/
export async function captureScreenshot(driver: any): Promise<Buffer> {
const screenshot = await driver.takeScreenshot();
const buffer = Buffer.from(screenshot, 'base64');
try {
// Use Jimp to ensure PNG format
const image = await Jimp.read(buffer);
return await image.getBufferAsync(Jimp.MIME_PNG);
} catch (error) {
// If Jimp fails, return the buffer as-is (WebDriver screenshots are usually PNG)
console.warn('Jimp processing failed, returning raw screenshot:', error);
return buffer;
}
}
/**
* Generate an image with text using Jimp
*/
export async function generateImage(
width: number = 1280,
height: number = 720,
text?: string
): Promise<Buffer> {
try {
// Create a new image with light gray background
const image = new Jimp(width, height, '#f0f0f0');
// Load font and add text if provided
if (text) {
const font = await Jimp.loadFont(Jimp.FONT_SANS_32_BLACK);
// Calculate text position (centered)
const textWidth = Jimp.measureText(font, text);
const textHeight = Jimp.measureTextHeight(font, text, width);
const x = (width - textWidth) / 2;
const y = (height - textHeight) / 2;
image.print(font, x, y, {
text,
alignmentX: Jimp.HORIZONTAL_ALIGN_CENTER,
alignmentY: Jimp.VERTICAL_ALIGN_MIDDLE
}, width, height);
}
return await image.getBufferAsync(Jimp.MIME_PNG);
} catch (error) {
console.warn('Failed to generate image with Jimp:', error);
// Fallback: return a minimal 1x1 transparent PNG
return Buffer.from(
'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==',
'base64'
);
}
}
/**
* Crop an image to specified area
*/
export async function cropImage(
imageBuffer: Buffer,
area: { x: number; y: number; w: number; h: number }
): Promise<Buffer> {
try {
const image = await Jimp.read(imageBuffer);
image.crop(area.x, area.y, area.w, area.h);
return await image.getBufferAsync(Jimp.MIME_PNG);
} catch (error) {
console.warn('Failed to crop image:', error);
return imageBuffer; // Return original if crop fails
}
}
/**
* Get image dimensions
*/
export async function getImageDimensions(imageBuffer: Buffer): Promise<{ width: number; height: number }> {
try {
const image = await Jimp.read(imageBuffer);
return {
width: image.getWidth(),
height: image.getHeight()
};
} catch (error) {
console.warn('Failed to get image dimensions:', error);
// Return default dimensions
return { width: 1920, height: 1080 };
}
}
/**
* Apply redaction to an image (black boxes)
*/
export async function applyRedaction(
imageBuffer: Buffer,
areas: Array<{ x: number; y: number; w: number; h: number }>
): Promise<Buffer> {
try {
const image = await Jimp.read(imageBuffer);
// Draw black rectangles over redacted areas
for (const area of areas) {
// Create a black rectangle
const blackBox = new Jimp(area.w, area.h, '#000000');
image.composite(blackBox, area.x, area.y);
}
return await image.getBufferAsync(Jimp.MIME_PNG);
} catch (error) {
console.warn('Failed to apply redaction:', error);
return imageBuffer;
}
}
/**
* Convert image buffer to base64 string
*/
export function imageToBase64(buffer: Buffer): string {
return buffer.toString('base64');
}
/**
* Check if image processing is available
*/
export function isImageProcessingAvailable(): boolean {
return true; // Jimp is always available as it's pure JavaScript
}