UNPKG

typography-canvas-renderer

Version:

A lightweight npm package for rendering typographic content (text and images) on HTML5 Canvas with full CSS styling support including borders, border-radius, multiple border styles, inline text rendering, auto height calculation, and image support

588 lines (505 loc) 17.6 kB
# Typography Canvas Renderer A lightweight npm package for rendering typographic content (text and images) on HTML5 Canvas in a browser environment. The package is designed to generate images in high resolution (up to 3000x4244 pixels) with minimal dependencies and full support for modern CSS styling including borders, border-radius, and various border styles. ## Features - 🎨 **High Resolution Support**: Generate images up to 3000x4244 pixels - 📝 **Text Rendering**: Support for custom fonts, colors, positioning, and styling with multi-line text support, automatic text wrapping, custom padding, vertical alignment, and inline text rendering - 🖼️ **Image Rendering**: Load and render images from URLs or base64 data - 🎯 **Absolute Positioning**: All elements use absolute positioning for precise control - 📐 **Z-Index Layering**: Proper element layering with z-index support - 🔄 **Automatic Scaling**: Smart scaling for high-resolution canvases - 🎨 **Advanced Border Support**: Complete border system with rounded corners and multiple styles - 🔲 **Border Radius**: Full support for rounded corners on both text and images - 📏 **Border Styles**: Support for solid, dashed, dotted, and double borders - 📐 **Text Fitting**: Proper text positioning and padding within borders - 🔄 **Auto Height Calculation**: Automatic height calculation based on content and padding - 📏 **Inline Text Rendering**: Text renders inline when width is not specified - 🖼️ **Image Support**: Full image rendering with borders, padding, and styling - ⚡ **Minimal Dependencies**: Only one external dependency (`csstree-validator`) - 🌐 **Browser-First**: Optimized for Chrome 100+, Firefox 100+, Safari 15+ ## Installation ```bash npm install typography-canvas-renderer ``` ### Minified Versions For production use, you can import minified versions for smaller bundle sizes: ```javascript // Regular versions import { renderCanvas } from 'typography-canvas-renderer'; // Minified versions (65% smaller) import { renderCanvas } from 'typography-canvas-renderer/min'; ``` **File Sizes:** - `index.js`: 34KB (regular) - `index.min.js`: 12KB (minified) - **65% smaller** - `index.esm.js`: 34KB (regular ESM) - `index.esm.min.js`: 12KB (minified ESM) - **65% smaller** - `index.umd.js`: 38KB (regular UMD) - `index.umd.min.js`: 12KB (minified UMD) - **68% smaller** ## Quick Start ```javascript import { renderCanvas, renderCanvasAsDataURL } from 'typography-canvas-renderer'; const input = { canvas: { width: 1000, height: 1000, background: 'white', format: 'png' }, texts: [ { text: 'Hello World', css: { 'font-size': '48px', 'color': 'black', 'left': '10px', 'top': '10px', 'background-color': '#f0f0f0', 'border': '2px solid #333', 'border-radius': '10px', 'z-index': '1' } } ], images: [ { src: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==', css: { 'width': '200px', 'height': '200px', 'left': '50px', 'top': '50px', 'border': '3px dashed blue', 'border-radius': '15px', 'z-index': '2' } } ] }; // Render as Blob const blob = await renderCanvas(input); // Render as Data URL const dataURL = await renderCanvasAsDataURL(input); ``` ## API Reference ### `renderCanvas(input, canvasContext?)` Renders typography content on canvas and returns a Blob. **Parameters:** - `input` (Input): Input object containing canvas configuration and elements - `canvasContext?` (CanvasRenderingContext2D): Optional existing canvas context **Returns:** `Promise<Blob>` ### `renderCanvasAsDataURL(input, canvasContext?)` Renders typography content on canvas and returns a data URL string. **Parameters:** - `input` (Input): Input object containing canvas configuration and elements - `canvasContext?` (CanvasRenderingContext2D): Optional existing canvas context **Returns:** `Promise<string>` ### `clearCache()` Clears the internal image cache. ## Input Object Structure ```typescript interface Input { canvas: { width: number; // Width in pixels (1-3000) height: number; // Height in pixels (1-4244) background?: string; // CSS background color (default 'white') format?: 'png' | 'jpeg'; // Export format (default 'png') quality?: number; // For JPEG (0-1, default 0.9) scaleFactor?: number; // Scaling factor (default 1) }; texts: Array<{ text: string; // Text string css: Record<string, string>; // CSS properties }>; images: Array<{ src: string; // URL or base64 image string css: Record<string, string>; // CSS properties }>; } ``` ## Supported CSS Properties Here you can see full css properties list. [Open link](./STYLES.md) ### Text Elements | Property | Type | Description | Example | |----------|------|-------------|---------| | `position` | string | Only `absolute` supported | `'absolute'` | | `left` | string | X position in pixels | `'50px'` | | `top` | string | Y position in pixels | `'100px'` | | `width` | string | Element width in pixels | `'200px'` | | `height` | string | Element height in pixels | `'80px'` | | `font-size` | string | Font size in pixels | `'24px'` | | `font-family` | string | Font family | `'Arial, sans-serif'` | | `color` | string | Text color | `'#333333'` or `'red'` | | `background-color` | string | Background color | `'#f0f0f0'` or `'transparent'` | | `opacity` | string | Opacity (0-1) | `'0.8'` | | `text-align` | string | Text alignment | `'left'`, `'center'`, `'right'` | | `vertical-align` | string | Vertical text alignment | `'top'`, `'middle'`, `'center'`, `'bottom'` | | `line-height` | string | Line height in pixels | `'32px'` | | `padding` | string | Custom padding in pixels | `'10px'` | | `border` | string | Border style | `'2px solid red'` | | `border-radius` | string | Border radius in pixels | `'10px'` | | `z-index` | string | Layer order (number) | `'1'` | ## Text Rendering Modes The package supports two text rendering modes based on whether the `width` property is specified: ### Inline Text Rendering (No Width) When `width` is not specified, text renders inline with automatic sizing: ```javascript { text: 'Inline Text with Auto Sizing', css: { 'font-size': '20px', 'color': '#2c3e50', 'left': '50px', 'top': '50px', 'background-color': '#e8f4f8', 'border': '2px solid #3498db', 'border-radius': '8px', 'padding': '15px' // No width specified - renders inline } } ``` **Features:** - ✅ Automatic width calculation based on text content - ✅ Automatic height calculation with padding - ✅ Proper text alignment (left, center, right) - ✅ Multiline support with automatic height adjustment - ✅ Background and border sizing based on content ### Block Text Rendering (With Width) When `width` is specified, text renders as a block with text wrapping: ```javascript { text: 'Block Text with Width Constraint and Automatic Wrapping', css: { 'font-size': '18px', 'color': '#ffffff', 'left': '50px', 'top': '50px', 'width': '300px', // Width specified - renders as block 'background-color': '#e74c3c', 'border': '2px solid #c0392b', 'border-radius': '10px', 'padding': '20px', 'text-align': 'center' // Height can be auto-calculated or specified } } ``` **Features:** - ✅ Text wrapping within specified width - ✅ Automatic height calculation based on wrapped lines - ✅ Padding reduces available width for text - ✅ Vertical alignment support - ✅ Proper background and border sizing ### Image Elements | Property | Type | Description | Example | |----------|------|-------------|---------| | `position` | string | Only `absolute` supported | `'absolute'` | | `left` | string | X position in pixels | `'50px'` | | `top` | string | Y position in pixels | `'100px'` | | `width` | string | Image width in pixels | `'300px'` | | `height` | string | Image height in pixels | `'200px'` | | `opacity` | string | Opacity (0-1) | `'0.9'` | | `background-color` | string | Background color | `'#f0f0f0'` | | `border` | string | Border style | `'3px dashed blue'` | | `border-radius` | string | Border radius in pixels | `'15px'` | | `z-index` | string | Layer order (number) | `'2'` | ## Border Styles The package supports comprehensive border styling with proper rendering: ### Border Style Syntax ```css border: [width] [style] [color] ``` ### Supported Border Styles | Style | Description | Example | Visual Effect | |-------|-------------|---------|---------------| | `solid` | Solid line border | `'2px solid red'` | Continuous line | | `dashed` | Dashed line border | `'3px dashed blue'` | Dashed line pattern | | `dotted` | Dotted line border | `'2px dotted green'` | Dotted line pattern | | `double` | Double line border | `'4px double purple'` | Two parallel lines | ### Border Radius Support - **Text Elements**: Rounded backgrounds and borders with proper text fitting - **Image Elements**: Rounded corners with proper image clipping - **Border Compatibility**: All border styles work with border-radius - **Padding**: Automatic padding ensures text fits properly within borders ## Examples ### Text with Padding and Vertical Alignment ```javascript const input = { canvas: { width: 800, height: 600 }, texts: [ { text: 'Top Aligned\nwith Custom Padding\n20px padding', css: { 'font-size': '20px', 'font-family': 'Arial, sans-serif', 'color': '#2c3e50', 'left': '50px', 'top': '50px', 'width': '200px', 'height': '120px', 'background-color': '#e8f4f8', 'text-align': 'center', 'vertical-align': 'top', 'padding': '20px', 'border': '3px solid #3498db', 'border-radius': '10px', 'line-height': '28px', 'z-index': '1' } }, { text: 'Middle Aligned\nwith Custom Padding\n15px padding', css: { 'font-size': '18px', 'color': '#ffffff', 'left': '300px', 'top': '50px', 'width': '200px', 'height': '120px', 'background-color': '#e74c3c', 'text-align': 'center', 'vertical-align': 'middle', 'padding': '15px', 'border': '2px solid #c0392b', 'border-radius': '12px', 'line-height': '26px', 'z-index': '2' } }, { text: 'Bottom Aligned\nwith Custom Padding\n10px padding', css: { 'font-size': '16px', 'color': '#34495e', 'left': '550px', 'top': '50px', 'width': '200px', 'height': '120px', 'background-color': '#ffffff', 'text-align': 'center', 'vertical-align': 'bottom', 'padding': '10px', 'border': '2px dashed #7f8c8d', 'border-radius': '8px', 'line-height': '24px', 'z-index': '3' } } ], images: [] }; ``` ### Image Rendering with Styling The package supports full image rendering with borders, padding, and styling: ```javascript const input = { canvas: { width: 600, height: 400 }, texts: [], images: [ { src: 'https://example.com/image.jpg', css: { 'width': '200px', 'height': '150px', 'left': '100px', 'top': '75px', 'border': '3px dashed blue', 'border-radius': '15px', 'z-index': '1' } }, { src: 'data:image/png;base64,...', css: { 'width': '150px', 'height': '100px', 'left': '350px', 'top': '100px', 'border': '2px dotted red', 'border-radius': '20px', 'background-color': '#f0f0f0', // Background behind image 'opacity': '0.9', // Image opacity 'z-index': '2' } } ] }; ``` **Image Features:** - ✅ Support for URLs and base64 data - ✅ All border styles (solid, dashed, dotted, double) - ✅ Border radius with proper clipping - ✅ Background colors behind images - ✅ Opacity control - ✅ Z-index layering - ✅ Automatic error handling with fallback ### Auto Height Calculation with Padding The package automatically calculates height when not specified, properly accounting for padding: ```javascript const input = { canvas: { width: 800, height: 600 }, texts: [ { text: 'This text will automatically calculate height based on content and padding. The height will adjust to fit all wrapped lines plus the specified padding.', css: { 'font-size': '20px', 'color': '#2c3e50', 'left': '50px', 'top': '50px', 'width': '300px', // No height specified - auto-calculated 'background-color': '#e8f4f8', 'border': '2px solid #3498db', 'border-radius': '5px', 'padding': '20px', // Padding reduces available width, creating more lines 'text-align': 'center' } }, { text: 'Inline Text\nWith Multiline\nAuto Height', css: { 'font-size': '18px', 'color': '#ffffff', 'left': '400px', 'top': '50px', // No width or height specified - inline rendering with auto sizing 'background-color': '#e74c3c', 'border': '2px solid #c0392b', 'border-radius': '8px', 'padding': '15px', 'text-align': 'center' } } ], images: [] }; ``` ### Mixed Content with Various Border Styles ```javascript const input = { canvas: { width: 1000, height: 800 }, texts: [ { text: 'Solid Border', css: { 'font-size': '24px', 'color': '#ffffff', 'left': '50px', 'top': '50px', 'width': '200px', 'height': '60px', 'background-color': '#e74c3c', 'text-align': 'center', 'border': '3px solid #c0392b', 'border-radius': '10px', 'z-index': '1' } }, { text: 'Double Border', css: { 'font-size': '22px', 'color': '#2c3e50', 'left': '300px', 'top': '50px', 'width': '200px', 'height': '60px', 'background-color': '#f39c12', 'text-align': 'center', 'border': '4px double #e67e22', 'border-radius': '5px', 'z-index': '2' } } ], images: [ { src: 'data:image/png;base64,...', css: { 'width': '150px', 'height': '100px', 'left': '550px', 'top': '50px', 'border': '2px dotted #8e44ad', 'border-radius': '25px', 'z-index': '3' } } ] }; ``` ### High Resolution with Scaling ```javascript const input = { canvas: { width: 2500, height: 2500, scaleFactor: 1.5 // Automatically applied for canvases > 2000px }, texts: [ { text: 'High Resolution', css: { 'font-size': '72px', 'left': '100px', 'top': '100px', 'border': '4px solid #333', 'border-radius': '20px', 'background-color': '#f8f9fa' } } ], images: [] }; ``` ## Complete Example A comprehensive example file (`complete-example.html`) is included that demonstrates all features: - **Interactive Presets**: 10+ different preset configurations - **Live Rendering**: Real-time canvas updates - **JSON Editor**: Edit configurations directly - **All Features**: Inline text, block text, images, borders, padding, alignment - **Auto Height**: Demonstrates automatic height calculation with padding - **Mixed Content**: Shows text and images working together To use the complete example: 1. Open `complete-example.html` in a web browser 2. Select different presets from the dropdown 3. Edit the JSON configuration 4. Click "Render" to see results 5. Download the canvas as PNG ## Browser Compatibility - Chrome 100+ - Firefox 100+ - Safari 15+ ## Error Handling The package throws custom errors for better debugging: - `InvalidInputError`: Invalid input data - `CssValidationError`: CSS validation errors - `ImageLoadError`: Image loading failures ```javascript import { InvalidInputError, CssValidationError, ImageLoadError } from 'typography-canvas-renderer'; try { const blob = await renderCanvas(input); } catch (error) { if (error instanceof InvalidInputError) { console.error('Invalid input:', error.message); } else if (error instanceof CssValidationError) { console.error('CSS error:', error.message); } else if (error instanceof ImageLoadError) { console.error('Image error:', error.message); } } ``` ## Performance Tips 1. **Image Caching**: Images are automatically cached during rendering 2. **Clear Cache**: Use `clearCache()` to free memory when done 3. **High Resolution**: Use `scaleFactor` for better performance on large canvases 4. **Minimize Elements**: Fewer elements = faster rendering 5. **Border Optimization**: Simple borders render faster than complex double borders ## Demo You can test the package functionality using the included `example-standalone.html` file. Simply open it in your browser to see various examples of text and image rendering with different border styles and border-radius effects. ## Future Plans The package is browser-oriented. Support for Node.js may be added in the future via a separate module (`typography-canvas-renderer-node`). ## License MIT ## Contributing Contributions are welcome! Please feel free to submit a Pull Request.