cmy / image-processing-logic.js
Rajhuggingface4253's picture
Update image-processing-logic.js
945e629 verified
const sharp = require('sharp');
const stream = require('stream');
class ImageProcessor {
/**
* Processes an image to CMYK TIFF format from a readable stream.
* @param {stream.Readable} input - The incoming stream of image data.
* @param {Object} options - Processing options including quality.
* @returns {stream.Readable} - A readable stream of the processed CMYK TIFF image.
*/
processImage(input, options = {}) {
return new Promise((resolve, reject) => {
try {
const { quality = 95 } = options;
// Validate input stream
if (!input || typeof input.pipe !== 'function') {
throw new Error('Invalid input stream provided');
}
let sharpInstance = sharp();
// Handle Sharp initialization errors
sharpInstance.on('error', (error) => {
reject(new Error(`Image processing failed: ${error.message}`));
});
const compressionLevel = Math.max(1, Math.min(9, Math.round(parseInt(quality) / 100 * 9)));
// Apply CMYK conversion with TIFF compression
sharpInstance = sharpInstance
.toColorspace('cmyk')
.tiff({
compression: 'deflate', // CHANGED: Use PNG-style lossless compression
quality: 100, // This is now ignored, but we set to 100
level: compressionLevel, // NEW: Use our mapped level
predictor: 'horizontal'
});
// Create transform stream for error handling
const transformStream = new stream.PassThrough();
// Handle stream errors
input.on('error', (error) => {
reject(new Error(`Input stream error: ${error.message}`));
});
transformStream.on('error', (error) => {
reject(new Error(`Processing stream error: ${error.message}`));
});
// Pipe through Sharp with error handling
const processingStream = input.pipe(sharpInstance).pipe(transformStream);
processingStream.on('error', (error) => {
reject(new Error(`Pipeline error: ${error.message}`));
});
resolve(processingStream);
} catch (error) {
reject(new Error(`Setup error: ${error.message}`));
}
});
}
/**
* Validates processing options
* @param {Object} options - Processing options
* @returns {Object} - Validated options
*/
validateOptions(options) {
const { quality } = options;
// Validate quality exists and is valid
if (quality && isNaN(quality)) {
throw new Error('Quality must be a number');
}
const qualityValue = quality ? parseInt(quality) : 95;
if (qualityValue < 1 || qualityValue > 100) {
throw new Error('Quality must be between 1 and 100');
}
return { quality: qualityValue };
}
/**
* Validates the input content type
* @param {string} contentType - Request content type
*/
validateContentType(contentType) {
if (!contentType) {
throw new Error('Content-Type header is required');
}
const supportedTypes = [
'image/jpeg',
'image/jpg',
'image/png',
'image/tiff',
'image/webp',
'image/avif'
];
if (!supportedTypes.some(type => contentType.startsWith(type))) {
throw new Error(`Unsupported image format. Supported: ${supportedTypes.join(', ')}`);
}
}
}
module.exports = new ImageProcessor();