Skip to content

BUG: SVG icons are clipped when the artwork does not start at the viewBox origin #4574

Description

@eliasaraf

Checks

  • I have checked that this issue has not already been reported.
  • I am using the latest version of Flow Launcher.
  • I am using the prerelease version of Flow Launcher.

Problem Description

ImageLoader.LoadSvgImage scales an SVG by its drawing bounds and sizes the output bitmap to those scaled bounds, but it never translates the drawing by the bounds' origin. When Drawing.Bounds.X/Y are non-zero — i.e. any SVG with padding between the viewBox and the artwork — the content is drawn at that offset inside a bitmap that is only as large as the content itself, so the right and bottom edges fall outside the bitmap and are cut off.

In Flow.Launcher.Infrastructure/Image/ImageLoader.cs:

var scale = desiredHeight / drawingBounds.Height;
...
drawingContext.PushTransform(new ScaleTransform(scale, scale));
drawingContext.DrawDrawing(drawing);   // drawn at drawingBounds.X/Y, but the bitmap starts at 0,0

This affects any icon set with an inset viewBox. GitHub's Octicons, for example, use a 24x24 viewBox whose artwork spans (1,1)-(23,23), so every icon loses ~1px off two edges. SVGs whose artwork touches (0,0) — such as one with a full-bleed background rect — render correctly, which is why the bug is easy to miss.

Suggested fix — translate the drawing back to the origin before rendering:

drawingContext.PushTransform(new ScaleTransform(scale, scale));
drawingContext.PushTransform(new TranslateTransform(-drawingBounds.X, -drawingBounds.Y));
drawingContext.DrawDrawing(drawing);

A plugin-side workaround is to add a full-bleed transparent rect to anchor the bounds at the origin: <rect width="24" height="24" fill="#000000" fill-opacity="0"/>. Note that fill="none" does not work, as it contributes no bounds.

To Reproduce

  1. Point a plugin's IcoPath (or a result's IcoPath) at an SVG whose artwork is inset from the viewBox, e.g.:

    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
      <circle cx="12" cy="12" r="11" fill="#1A7F37"/>
    </svg>

    Its drawing bounds are (1,1) 22x22.

  2. Query the plugin so the icon is shown.

  3. The icon's right and bottom edges are clipped. Adding <rect width="24" height="24" fill="#000000" fill-opacity="0"/> as the first child makes the bounds (0,0) 24x24 and the icon renders in full.

Screenshots

The same SVGs rendered through LoadSvgImage, before and after adding the translate. The thin box is the bitmap the loader produces; ink touching the box is ink falling outside it. Bounds reported by the loader: circle (1,1) 22x22, issue (1,1) 22x22, pull-request (1,0) 23x22, alert (1,1) 23x20.

Image

Flow Launcher Version

2.1.3

Windows Build Number

10.0.26200.7462

Error Log

Not applicable — nothing is logged; the icon is silently clipped.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingkind/uirelated to UI, icons, themes, etc

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions