@@ -13,7 +13,7 @@ A .NET library for rendering images from YAML templates with flexbox-like layout
1313- ** Flexbox Layout** - Row/column direction, wrap, justify, align, gap
1414- ** Template Engine** - Variables, loops (` type: each ` ), conditionals (` type: if ` )
1515- ** Multiple Content Types** - Text, images, QR codes, barcodes
16- - ** Output Formats** - PNG, JPEG, BMP
16+ - ** Output Formats** - PNG, JPEG, BMP, Raw
1717- ** CLI Tool** - Render templates from command line
1818- ** AOT Compatible** - No reflection, works with Native AOT
1919- ** Modular Architecture** - Install only what you need
@@ -58,6 +58,7 @@ dotnet add package FlexRender
5858| ` FlexRender.Skia ` | SkiaSharp renderer |
5959| ` FlexRender.QrCode ` | QR code support |
6060| ` FlexRender.Barcode ` | Barcode support |
61+ | ` FlexRender.Http ` | HTTP/HTTPS resource loading |
6162| ` FlexRender.DependencyInjection ` | Microsoft DI integration |
6263
6364``` bash
@@ -87,13 +88,6 @@ dotnet add package SkiaSharp.NativeAssets.Linux.NoDependencies
8788dotnet tool install -g FlexRender.Cli
8889```
8990
90- ### Dependency Injection
91-
92- ``` csharp
93- // Register all FlexRender services
94- services .AddFlexRender ();
95- ```
96-
9791## Quick Start
9892
9993### 1. Create a template (receipt.yaml)
@@ -149,43 +143,67 @@ layout:
149143### 2. Render with code
150144
151145` ` ` csharp
152- using FlexRender.Parsing;
153- using FlexRender.Rendering;
154- using FlexRender.Values;
155-
156- var parser = new TemplateParser();
157- var renderer = new SkiaRenderer();
158-
159- var template = parser.ParseFile("receipt.yaml");
146+ // Build renderer with fluent API
147+ var render = new FlexRenderBuilder()
148+ .WithBasePath("./templates")
149+ .WithSkia(skia => skia
150+ .WithQr()
151+ .WithBarcode())
152+ .Build();
160153
161154var data = new ObjectValue
162155{
163156 ["shopName"] = "My Shop",
164157 ["total"] = 1500,
165158 ["paymentUrl"] = "https://pay.example.com/123",
166- ["items"] = new ArrayValue(new TemplateValue[]
167- {
159+ ["items"] = new ArrayValue(
168160 new ObjectValue { ["name"] = "Product 1", ["price"] = 500 },
169- new ObjectValue { ["name"] = "Product 2", ["price"] = 1000 }
170- })
161+ new ObjectValue { ["name"] = "Product 2", ["price"] = 1000 })
171162};
172163
173- // Render to bitmap (async API)
174- using var bitmap = await renderer.Render(template, data);
164+ // Render to PNG bytes
165+ byte[] pngBytes = await render.RenderFile("receipt.yaml", data);
166+ await File.WriteAllBytesAsync("receipt.png", pngBytes);
167+ ```
168+
169+ ### 3. With Dependency Injection
175170
176- // Save to file
177- using var image = SKImage.FromBitmap(bitmap);
178- using var pngData = image.Encode(SKEncodedImageFormat.Png, 100);
179- using var stream = File.OpenWrite("receipt.png");
180- pngData.SaveTo(stream);
171+ ``` csharp
172+ // Program.cs
173+ services .AddFlexRender (builder => builder
174+ .WithBasePath (" /app/templates" )
175+ .WithSkia (skia => skia
176+ .WithQr ()
177+ .WithBarcode ()));
178+
179+ // In your service
180+ public class ReceiptService (IFlexRender render )
181+ {
182+ public async Task <byte []> Generate (ReceiptData data )
183+ {
184+ var values = MapToObjectValue (data );
185+ return await render .RenderFile (" receipt.yaml" , values );
186+ }
187+ }
181188```
182189
183- ### 3 . Or use CLI
190+ ### 4 . Or use CLI
184191
185192``` bash
186193flexrender render receipt.yaml -d data.json -o receipt.png
187194```
188195
196+ ## Output Formats
197+
198+ | Format | Extension | Description |
199+ | --------| -----------| -------------|
200+ | PNG | ` .png ` | Lossless compression, best quality |
201+ | JPEG | ` .jpg ` | Lossy compression, smaller file size |
202+ | BMP | ` .bmp ` | Uncompressed bitmap |
203+ | Raw | ` .raw ` | Raw BGRA pixel data (4 bytes per pixel) |
204+
205+ The Raw format outputs uncompressed pixel data in BGRA order (Blue, Green, Red, Alpha), 4 bytes per pixel, row by row from top to bottom. Useful for direct hardware integration or custom processing pipelines.
206+
189207## Template Syntax
190208
191209### Canvas Settings
@@ -382,57 +400,67 @@ flexrender watch template.yaml -d data.json -o preview.png
382400
383401## API Reference
384402
385- ### TemplateParser
403+ ### FlexRenderBuilder (recommended)
386404
387405``` csharp
406+ // Minimal setup
407+ var render = new FlexRenderBuilder ()
408+ .WithSkia ()
409+ .Build ();
410+
411+ // Full configuration
412+ var render = new FlexRenderBuilder ()
413+ .WithHttpLoader () // Enable HTTP resource loading
414+ .WithEmbeddedLoader (typeof (Program ).Assembly ) // Load from embedded resources
415+ .WithBasePath (" ./templates" ) // Base path for file resolution
416+ .WithLimits (limits => limits .MaxRenderDepth = 200 )
417+ .WithSkia (skia => skia
418+ .WithQr () // Enable QR code support
419+ .WithBarcode ()) // Enable barcode support
420+ .Build ();
421+
422+ // Render from YAML file (requires FlexRender.Yaml package)
423+ byte [] png = await render .RenderFile (" receipt.yaml" , data );
424+ byte [] jpg = await render .RenderFile (" receipt.yaml" , data , ImageFormat .Jpeg );
425+
426+ // Render from YAML string
427+ byte [] png = await render .RenderYaml (yamlString , data );
428+
429+ // Render from parsed template (for caching)
388430var parser = new TemplateParser ();
389-
390- // Parse from string
391- Template template = parser .Parse (yamlString );
392-
393- // Parse from file (with 1MB size limit)
394- Template template = parser .ParseFile (" template.yaml" );
395-
396- // Check supported element types
397- IReadOnlyCollection < string > types = parser .SupportedElementTypes ;
398- // Returns: ["text", "qr", "barcode", "image", "flex", "separator", "each", "if"]
431+ var template = parser .Parse (yamlString );
432+ byte [] png = await render .Render (template , data );
433+
434+ // Sandboxed mode (no file system access)
435+ var sandboxed = new FlexRenderBuilder ()
436+ .WithoutDefaultLoaders ()
437+ .WithEmbeddedLoader (typeof (Program ).Assembly )
438+ .WithSkia ()
439+ .Build ();
399440```
400441
401- ### TemplateExpander
402-
403- Templates with ` type: each ` and ` type: if ` are automatically expanded during rendering.
404- For manual expansion (useful for template caching):
405-
406- ``` csharp
407- var expander = new TemplateExpander ();
408-
409- // Expand control flow elements with data
410- Template expanded = expander .Expand (template , data );
411-
412- // The expanded template has no Each/If elements - they're replaced with concrete elements
413- // This allows parsing once and rendering with different data
414- ```
415-
416- ### SkiaRenderer
442+ ### Dependency Injection
417443
418444``` csharp
419- using var renderer = new SkiaRenderer ();
420-
421- // Set base font size (default: 12)
422- renderer .BaseFontSize = 14 f ;
423-
424- // Measure required size
425- SKSize size = renderer .Measure (template , data );
445+ // Basic registration
446+ services .AddFlexRender (builder => builder
447+ .WithSkia (skia => skia .WithQr ().WithBarcode ()));
426448
427- // Render to canvas
428- renderer .Render (canvas , template , data );
429- renderer .Render (canvas , template , data , offset : new SKPoint (10 , 10 ));
430-
431- // Render to bitmap
432- renderer .Render (bitmap , template , data );
433-
434- // Async render via ILayoutRenderer<SKBitmap>
435- using var bitmap = await renderer .Render (template , data );
449+ // With service provider access
450+ services .AddFlexRender ((sp , builder ) =>
451+ {
452+ var config = sp .GetRequiredService <IConfiguration >();
453+ builder
454+ .WithBasePath (config [" FlexRender:BasePath" ] ?? " ./templates" )
455+ .WithSkia (skia => skia .WithQr ().WithBarcode ());
456+ });
457+
458+ // Inject IFlexRender
459+ public class MyService (IFlexRender render )
460+ {
461+ public Task <byte []> GenerateImage (ObjectValue data )
462+ => render .RenderFile (" template.yaml" , data );
463+ }
436464```
437465
438466### TemplateValue Types
@@ -445,17 +473,15 @@ TemplateValue str = new StringValue("hello");
445473// Number
446474TemplateValue num = 42 ; // implicit from int
447475TemplateValue num = 3 . 14 ; // implicit from double
448- TemplateValue num = new NumberValue (42 );
449476
450477// Boolean
451478TemplateValue flag = true ; // implicit conversion
452- TemplateValue flag = new BoolValue (true );
453479
454480// Null
455481TemplateValue nil = NullValue .Instance ;
456482
457483// Array
458- var array = new ArrayValue (new TemplateValue [] { " a" , " b" , " c" } );
484+ var array = new ArrayValue (" a" , " b" , " c" );
459485int count = array .Count ;
460486TemplateValue first = array [0 ];
461487
0 commit comments