UNPKG

safeer-pdf-generator

Version:

Framework-agnostic PDF generation library with chunking, merging, S3 upload, and email delivery

135 lines 4.82 kB
import { noOpLogger } from '../config/defaults.js'; /** * Convert image URL to base64 data URI */ export async function convertImageToBase64(url, logger = noOpLogger, fetcher) { if (!url) { logger.debug('Empty URL provided for image conversion'); return ''; } try { // Handle data URIs directly if (url.startsWith('data:image')) { logger.debug('Image is already a data URI'); return url; } // Use custom fetcher if provided if (fetcher) { logger.debug('Using custom fetcher for image conversion'); return await fetcher(url); } // Handle external URLs with fetch logger.debug(`Fetching image from URL: ${url}`); const response = await fetch(url); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } const buffer = await response.arrayBuffer(); const contentType = response.headers.get('content-type') || 'application/octet-stream'; // Validate content type if (!contentType.startsWith('image/')) { logger.warn(`Invalid content type for image: ${contentType}`); return ''; } const base64 = Buffer.from(buffer).toString('base64'); const dataUri = `data:${contentType};base64,${base64}`; logger.debug(`Successfully converted image to base64 (${(base64.length / 1024).toFixed(1)}KB)`); return dataUri; } catch (error) { logger.error(`Image conversion failed for URL ${url}:`, error); return ''; // Return empty string to avoid breaking template } } /** * Validate if a URL looks like an image */ export function isImageUrl(url) { if (!url || typeof url !== 'string') return false; // Data URI check if (url.startsWith('data:image/')) return true; // File extension check const imageExtensions = /\.(jpg|jpeg|png|gif|bmp|svg|webp)(\?.*)?$/i; return imageExtensions.test(url); } /** * Get image dimensions from buffer (basic PNG/JPEG support) */ export function getImageDimensions(buffer) { try { // PNG signature if (buffer.length >= 24 && buffer.toString('hex', 0, 8) === '89504e470d0a1a0a') { const width = buffer.readUInt32BE(16); const height = buffer.readUInt32BE(20); return { width, height }; } // JPEG signature if (buffer.length >= 4 && buffer[0] === 0xff && buffer[1] === 0xd8) { // This is a simplified JPEG parser - for production, consider using a proper image library let offset = 2; while (offset < buffer.length - 8) { if (buffer[offset] === 0xff && (buffer[offset + 1] === 0xc0 || buffer[offset + 1] === 0xc2)) { const height = buffer.readUInt16BE(offset + 5); const width = buffer.readUInt16BE(offset + 7); return { width, height }; } offset++; } } return null; } catch (error) { return null; } } /** * Resize image dimensions while maintaining aspect ratio */ export function calculateResizedDimensions(originalWidth, originalHeight, maxWidth, maxHeight) { const aspectRatio = originalWidth / originalHeight; let width = originalWidth; let height = originalHeight; // Scale down if too wide if (width > maxWidth) { width = maxWidth; height = width / aspectRatio; } // Scale down if too tall if (height > maxHeight) { height = maxHeight; width = height * aspectRatio; } return { width: Math.round(width), height: Math.round(height), }; } /** * Extract file extension from URL or filename */ export function getImageExtension(url) { if (url.startsWith('data:image/')) { const match = url.match(/data:image\/([^;]+)/); return match ? match[1] : ''; } const match = url.match(/\.([a-zA-Z0-9]+)(\?.*)?$/); return match ? match[1].toLowerCase() : ''; } /** * Generate a fallback image placeholder as data URI */ export function generatePlaceholderImage(width = 100, height = 100, text = '?') { // Simple SVG placeholder const svg = ` <svg width="${width}" height="${height}" xmlns="http://www.w3.org/2000/svg"> <rect width="100%" height="100%" fill="#f0f0f0" stroke="#ddd" stroke-width="1"/> <text x="50%" y="50%" dominant-baseline="middle" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" fill="#999">${text}</text> </svg> `.trim(); return `data:image/svg+xml;base64,${Buffer.from(svg).toString('base64')}`; } //# sourceMappingURL=image.js.map