Skip to content

Library Architecture ​

This document provides a detailed overview of the SVGIconImageList library architecture, design patterns, and internal structure.

Overview ​

SVGIconImageList is designed with a flexible, modular architecture that separates concerns:

  • Storage Layer: Manages SVG icon collections
  • Rendering Layer: Converts SVG to bitmaps using pluggable engines
  • Presentation Layer: VCL/FMX components for displaying icons
  • Factory Pattern: Abstracts rendering engine implementations

Component Architecture ​

VCL Components Hierarchy ​

TComponent
├── TDragImageList
│   └── TSVGIconImageListBase (abstract base)
│       ├── TSVGIconImageList (classic all-in-one)
│       └── TSVGIconVirtualImageList (virtual, Delphi 10.3+)
│
├── TCustomImageCollection (Delphi 10.3+)
│   └── TSVGIconImageCollection (storage only)
│
└── TGraphicControl
    └── TSVGIconImage (display component)

TGraphic
└── TSVGGraphic (TPicture integration)

TOwnedCollection
└── TSVGIconItems
    └── TCollectionItem
        └── TSVGIconItem

FMX Components Hierarchy ​

TComponent
└── TCustomImageList
    └── TSVGIconImageList (cross-platform)

TImage
└── TSVGIconImage (cross-platform display)

TCustomSourceItem
└── TSVGIconSourceItem

TMultiResBitmap
└── TSVGIconMultiResBitmap
    └── TCustomBitmapItem
        └── TSVGIconBitmapItem

Factory Pattern ​

The library uses the Factory Pattern to abstract SVG rendering engines:

Interface Hierarchy ​

ISVGFactory
├── GetImage32SVGFactory → TImage32SVGFactory
├── GetSkiaSVGFactory → TSkiaSVGFactory
├── GetD2DSVGFactory → TD2DSVGFactory
└── GetSVGMagicFactory → TSVGMagicFactory

ISVG (common interface)
├── TImage32SVG (Image32 implementation)
├── TSkiaSVG (Skia4Delphi implementation)
├── TD2DSVG (Direct2D implementation)
└── TSVGMagic (SVGMagic implementation)

Factory Selection ​

pascal
// Global factory selection
SetGlobalSvgFactory(GetImage32SVGFactory);  // Default
SetGlobalSvgFactory(GetSkiaSVGFactory);
SetGlobalSvgFactory(GetD2DSVGFactory);
SetGlobalSvgFactory(GetSVGMagicFactory);

// All new ISVG instances use selected factory
var SVG := GlobalSVGFactory.NewSvg;

Rendering Pipeline ​

VCL Rendering Flow ​

1. SVG Source (XML text)
   ↓
2. ISVG Interface (via Factory)
   ↓
3. Apply Rendering Attributes
   - FixedColor
   - Opacity
   - GrayScale
   - ApplyFixedColorToRootOnly
   ↓
4. Engine-Specific Rendering
   - Image32: Rasterize using Image32 library
   - Skia: Render using Skia4Delphi
   - D2D: Render using Direct2D
   - SVGMagic: Render using SVGMagic library
   ↓
5. TBitmap Output
   ↓
6. VCL ImageList Integration
   ↓
7. Display in Controls

FMX Rendering Flow ​

1. SVG Source (XML text)
   ↓
2. TFmxImageSVG (engine-specific)
   - TFmxImage32SVG
   - TFmxImageSKIASVG
   ↓
3. Apply Rendering Attributes
   - FixedColor (TAlphaColor)
   - Opacity
   - GrayScale
   - BitmapZoom
   ↓
4. Multi-Resolution Bitmap Generation
   - 1x scale
   - 1.5x scale
   - 2x scale
   - 3x scale
   ↓
5. FMX ImageList Integration
   ↓
6. Display in Controls (cross-platform)

Storage Patterns ​

Classic Pattern (TSVGIconImageList) ​

Used in: All Delphi versions (XE6+)

TSVGIconImageList
├── SVGIconItems: TSVGIconItems
│   ├── Item[0]: TSVGIconItem
│   │   ├── IconName: string
│   │   ├── SVG: ISVG
│   │   └── Rendering properties
│   ├── Item[1]: TSVGIconItem
│   └── ...
└── Bitmap Cache (internal)
    ├── Size 16x16
    ├── Size 24x24
    └── Size 32x32

Advantages:

  • Self-contained
  • Simple to use
  • Works with all Delphi versions

Disadvantages:

  • Duplicate storage for multiple sizes
  • Higher memory usage

Virtual Pattern (TSVGIconImageCollection + VirtualImageList) ​

Used in: Delphi 10.3+

TSVGIconImageCollection (Storage)
├── SVGIconItems: TSVGIconItems
│   ├── Item[0]: TSVGIconItem (SVG source)
│   ├── Item[1]: TSVGIconItem (SVG source)
│   └── ...
    ↓ Referenced by ↓
TSVGIconVirtualImageList (Size 16)
├── Rendered bitmaps at 16x16
└── Reference to Collection

TSVGIconVirtualImageList (Size 32)
├── Rendered bitmaps at 32x32
└── Reference to Collection (same icons!)

Advantages:

  • Shared storage (memory efficient)
  • Centralized management
  • Multiple sizes from one source

Disadvantages:

  • Requires Delphi 10.3+
  • Slightly more complex setup

SVG Engine Implementations ​

Image32 Engine ​

Location: Image32SVGFactory.pas

Implementation:

  • Uses Image32 library by Angus Johnson
  • Pure Pascal implementation
  • No external dependencies
  • Good SVG 1.1 compliance
  • Rasterizes to 32-bit bitmaps

Key Classes:

  • TImage32SVGFactory: Factory implementation
  • TImage32SVG: ISVG implementation
  • Uses Image32 and Img32.SVG.Reader units

Rendering Process:

pascal
1. Parse SVG XML → Image32 SVG object tree
2. Apply transformations and styles
3. Rasterize to Image32 TImage
4. Apply FixedColor/GrayScale/Opacity
5. Convert to VCL TBitmap

Skia4Delphi Engine ​

Location: SkiaSVGFactory.pas

Implementation:

  • Uses Skia4Delphi wrapper by Vinícius Barbosa
  • Wraps Google's Skia graphics library
  • Excellent rendering quality
  • Hardware acceleration support
  • Strong SVG 1.1 compliance

Key Classes:

  • TSkiaSVGFactory: Factory implementation
  • TSkiaSVG: ISVG implementation
  • Uses Skia, Skia.API units

Rendering Process:

pascal
1. Parse SVG → Skia SkDOM
2. Create SkSVGDOM
3. Render to SkSurface
4. Apply effects (color, opacity)
5. Convert to VCL TBitmap

Direct2D Engine ​

Location: D2DSVGFactory.pas

Implementation:

  • Uses Windows Direct2D API
  • Native Windows rendering
  • GPU acceleration
  • Requires Windows 7+
  • Good performance on modern Windows

Key Classes:

  • TD2DSVGFactory: Factory implementation
  • TD2DSVG: ISVG implementation
  • Uses Winapi.D2D1, D2DSVGHandler units

Rendering Process:

pascal
1. Parse SVG XML → D2D geometry
2. Create D2D render target
3. Draw geometries with D2D
4. Apply transforms and effects
5. Convert to VCL TBitmap

SVGMagic Engine ​

Location: SVGMagicFactory.pas

Implementation:

  • Uses SVGMagic library
  • GDI+ based rendering
  • Windows only
  • Good compatibility

Key Classes:

  • TSVGMagicFactory: Factory implementation
  • TSVGMagic: ISVG implementation
  • Uses TWSVG, TWSVGGraphic, TWSVGGDIPlusRasterizer

Rendering Process:

pascal
1. Parse SVG → TWSVG object
2. Create TWSVGGDIPlusRasterizer
3. Render to TWSVGGraphic (bitmap)
4. Apply FixedColor/GrayScale (post-processing)
5. Apply Opacity (AlphaBlend)
6. Return as TBitmap

Bitmap Caching Strategy ​

Cache Structure ​

pascal
type
  TBitmapCache = record
    Size: TSize;           // Width x Height
    FixedColor: TColor;
    GrayScale: Boolean;
    Opacity: Byte;
    Bitmap: TBitmap;
    LastAccess: TDateTime;
  end;

// Cached internally per icon per size
// Invalidated when properties change

Cache Lifecycle ​

1. Icon Requested
   ↓
2. Check Cache
   ├─→ Hit: Return cached bitmap
   └─→ Miss: ↓
3. Render SVG
   ↓
4. Store in Cache
   ↓
5. Return bitmap

Cache Invalidation ​

Triggers that clear cache:

  • Size change
  • Opacity change
  • FixedColor change
  • GrayScale change
  • SVGText change
  • RecreateBitmaps() call

DPI Awareness ​

VCL DPI Handling ​

pascal
procedure TSVGIconImageListBase.DPIChanged(Sender: TObject; const OldDPI, NewDPI: Integer);
begin
  if Scaled then
  begin
    // Calculate new size
    FWidth := MulDiv(FWidth, NewDPI, OldDPI);
    FHeight := MulDiv(FHeight, NewDPI, OldDPI);

    // Recreate bitmaps at new size
    RecreateBitmaps;
  end;
end;

FMX Multi-Scale Handling ​

pascal
// Automatically generates bitmaps for standard scales
procedure TSVGIconMultiResBitmap.UpdateImageSize(const AWidth, AHeight, AZoom: Integer);
const
  SCALES: array[0..3] of Single = (1.0, 1.5, 2.0, 3.0);
var
  Scale: Single;
begin
  for Scale in SCALES do
  begin
    // Generate bitmap for each scale
    CreateBitmapItem(Round(AWidth * Scale), Round(AHeight * Scale), Scale);
  end;
end;

Message Broadcasting ​

Update Notification System ​

pascal
// VCL: Uses messaging system for updates
procedure TSVGIconItems.Update(Item: TCollectionItem);
begin
  inherited;
  TMessageManager.DefaultManager.SendMessage(Self,
    TSVGItemsUpdateMessage.Create);

  // Notify VirtualImageLists (Delphi 10.3+)
  if Owner is TSVGIconImageCollection then
    TMessageManager.DefaultManager.SendMessage(nil,
      TImageCollectionChangedMessage.Create(...));
end;

Automatic Updates ​

When SVGIconItems change:

  1. Collection sends update message
  2. TSVGIconImageList receives message
  3. Invalidates affected bitmaps
  4. VirtualImageLists receive ImageCollection message
  5. All linked controls refresh automatically

Memory Management ​

Object Lifecycle ​

pascal
// Component creation
TSVGIconImageList.Create
  ├─→ Create SVGIconItems collection
  │   └─→ Each item creates ISVG interface
  ├─→ Initialize bitmap cache
  └─→ Subscribe to DPI change messages

// Icon loading
LoadFromFile
  ├─→ Create ISVG via GlobalSVGFactory
  ├─→ Load SVG source
  └─→ Add to collection

// Rendering
GetBitmap(Index, Width, Height)
  ├─→ Check cache
  ├─→ If miss: Render via ISVG.PaintTo
  ├─→ Store in cache
  └─→ Return bitmap

// Component destruction
TSVGIconImageList.Destroy
  ├─→ Free all cached bitmaps
  ├─→ Free SVGIconItems collection
  │   └─→ Each item releases ISVG interface
  └─→ Call inherited

Reference Counting ​

pascal
// ISVG uses interface reference counting
type
  ISVG = interface
    ['{...}']
    // Methods...
  end;

// Implementations
type
  TImage32SVG = class(TInterfacedObject, ISVG)
  // Automatically freed when reference count reaches 0

Thread Safety ​

Current Implementation ​

Not thread-safe by default:

  • Bitmap cache is not synchronized
  • SVG rendering is not thread-safe
  • Collections are not protected by locks

Safe usage:

  • Load all icons on main thread
  • Access from main thread only
  • Use TThread.Synchronize for updates

Thread-Safe Patterns ​

pascal
// Safe: Load in background, add on main thread
TTask.Run(
  procedure
  var
    SVG: ISVG;
  begin
    SVG := GlobalSVGFactory.NewSvg;
    SVG.LoadFromFile('icon.svg');  // OK: Creates separate ISVG instance

    TThread.Synchronize(nil,
      procedure
      begin
        SVGIconImageList1.Add(SVG, 'icon');  // Must be on main thread
      end
    );
  end
);

Extensibility Points ​

Custom Rendering Engine ​

To add a new SVG rendering engine:

pascal
// 1. Implement ISVG interface
type
  TMyCustomSVG = class(TInterfacedObject, ISVG)
  private
    // Your rendering engine integration
  public
    // Implement all ISVG methods
    function IsEmpty: Boolean;
    procedure LoadFromFile(const FileName: string);
    procedure PaintTo(DC: HDC; R: TRectF; KeepAspectRatio: Boolean = True);
    // ... etc
  end;

// 2. Implement ISVGFactory
type
  TMyCustomSVGFactory = class(TInterfacedObject, ISVGFactory)
  public
    function NewSvg: ISVG;
  end;

// 3. Provide factory getter
function GetMyCustomSVGFactory: ISVGFactory;
begin
  if FMyCustomSVGFactory = nil then
    FMyCustomSVGFactory := TMyCustomSVGFactory.Create;
  Result := FMyCustomSVGFactory;
end;

// 4. Use your factory
SetGlobalSvgFactory(GetMyCustomSVGFactory);

Custom Icon Item ​

pascal
// Extend TSVGIconItem for custom behavior
type
  TMyCustomIconItem = class(TSVGIconItem)
  published
    property CustomProperty: string;
  end;

// Use with custom collection
type
  TMyCustomIconItems = class(TSVGIconItems)
  public
    constructor Create(AOwner: TComponent); override;
  end;

constructor TMyCustomIconItems.Create(AOwner: TComponent);
begin
  inherited Create(AOwner, TMyCustomIconItem);  // Use custom item class
end;

File Format Support ​

SVG Compliance ​

Supported SVG 1.1 features:

  • Basic shapes (rect, circle, ellipse, line, polyline, polygon)
  • Paths with all commands
  • Text elements (basic support)
  • Groups and transformations
  • Fill and stroke attributes
  • Gradients (linear, radial)
  • Opacity and colors
  • ViewBox and preserveAspectRatio

Limited support:

  • Filters (depends on engine)
  • Animations (static rendering only)
  • Embedded images (depends on engine)
  • External references

Not supported:

  • JavaScript/ECMA scripts
  • Interactive features
  • SMIL animations (runtime)

For best results:

  1. Remove unnecessary metadata
  2. Simplify complex paths
  3. Use viewBox for scalability
  4. Minimize decimal precision
  5. Use consistent units
  6. Avoid external references

See Also ​

Released under Apache License, Version 2.0.