Haiku Vector Icons: HVIF, BIconUtils, and the Rendering Pipeline
A source-grounded guide to Haiku's HVIF format, BIconUtils rendering, file attributes, package icons, bitmap fallbacks, sizing, and validation.
Haiku’s vector icon format, HVIF, is designed for compact icons that can be stored and rendered as native system metadata. BIconUtils is the public API that reads vector-icon data from a node attribute or byte buffer and rasterizes it into a caller-provided BBitmap. Understanding that boundary helps developers avoid treating an icon as a generic PNG, confusing an application’s icon with a file type’s icon, or constructing an invalid bitmap target.
Haiku’s current documentation describes icons as 64-by-64 vector artwork stored in a compact “flat icon” form. The native coordinate space is scaled into the destination bitmap. HVIF was specifically designed to keep icon data small enough to fit in filesystem inodes, allowing the icon to be displayed as file metadata without an extra disk access. That is an implementation-oriented design goal, not a promise that every icon is free, that every rendering is zero-copy, or that an attribute can never be too large for a particular filesystem operation.
Distinguish vector icon data from the rendered bitmap
HVIF is an input representation; a BBitmap is the rasterized output. BIconUtils::GetVectorIcon() requires an already allocated destination bitmap. The documented destination colorspace should be B_RGBA32 or at least B_RGB32, and its dimensions should be square. The format’s native 64-by-64 geometry is scaled to the bitmap width; a non-square target can crop the icon or leave unused space vertically.
This means that “resolution independent” describes the source drawing instructions, not an absence of rasterization choices. A 16-pixel icon and a 128-pixel icon still render into different pixel buffers. For a crisp result, allocate the size the UI actually needs, choose a supported pixel layout, and avoid repeated scaling of an already rasterized small bitmap.
The public GetIcon() helper can select among vector, small bitmap, and large bitmap icon attributes depending on the supplied bitmap colorspace and requested icon_size. The old BeOS bitmap-icon attributes remain useful for compatibility and may be preferable at very small sizes. Do not assume a vector icon always wins: the API’s documented selection depends on the target colorspace, and a B_CMAP8 destination requires a matching requested icon size.
File icons and application icons are separate metadata
A filesystem node can carry icon attributes used by Tracker or other file browsers. File type metadata and application metadata are related but distinct. A MIME type can have a shared type icon; an application executable can also publish an application icon and supported types; an individual document may override its icon. A custom program should decide which object it is modifying before writing metadata.
BIconUtils::GetVectorIcon(BNode*, attrName, bitmap) reads a named vector-icon attribute from a node. The BNode must be initialized and refer to the intended filesystem object. The API does not choose the right object for the caller. Passing an executable node when intending to change a MIME database type, or passing an arbitrary document node when intending to define a global file type, changes the wrong scope.
Icons that are part of an application binary can also be bundled as resources and loaded through the resource pipeline. This is appropriate for UI artwork an application owns, while a system icon or file-type icon may be better loaded through GetSystemIcon() or MIME metadata. Use the established API for the source of truth rather than embedding the same bytes in several places and letting them drift.
Use BIconUtils as a renderer, not a file-format parser
The public utilities offer GetIcon(), GetVectorIcon(), GetCMAP8Icon(), conversion between color spaces, and lookup of system icons. They are static methods; BIconUtils is not an object to instantiate. GetSystemIcon() loads the standardized Haiku icon set using icon names that follow the FreeDesktop naming convention, with documented Haiku extensions. Prefer a system icon for common actions where it accurately conveys the function, because consistent iconography helps users discover controls.
An application that receives raw vector bytes should validate its source and length before calling the renderer, check the returned status, and discard or replace a failed bitmap safely. Do not reinterpret bytes from an arbitrary file as an icon merely because its suffix looks like an HVIF file. Let the documented MIME/metadata path identify the input and handle malformed content as an ordinary error.
The icon format is specialized. The public BIconUtils interface does not expose a general-purpose API for parsing arbitrary vector paths, editing individual layers, or round-tripping a design into source artwork. Use Icon-O-Matic and the supported file/resource workflow to author or modify icons; use BIconUtils for loading and rasterizing them in applications.
Package and installation behavior
An application should obtain icons from its own package resources, file metadata, or the system icon set according to ownership. Do not write generated icons into package-managed files: package contents are not the mutable settings layer. If an application supports custom user themes, store overrides in a user-owned configuration location and keep a system/default fallback.
When icon data lives in a BFS attribute, backup and copy tools must preserve attributes if the metadata is expected to survive. A file copy that preserves only file bytes may retain the document while losing its icon override or application-specific attributes. Verify the actual tool and destination filesystem; do not infer attribute preservation from the fact that the filename and content were copied.
Updates can also change a system icon or application package while the application still has a cached raster. Decide whether a long-lived application should cache bitmap outputs, listen for relevant changes, or reload on next launch. Cache invalidation policy should be proportional to the application’s needs; re-reading and rasterizing every icon on each paint is wasteful, while keeping stale bitmaps after theme changes can be visibly wrong.
Bitmap construction and lifetime checks
Before calling GetVectorIcon(), allocate a bitmap with valid bounds, supported colorspace, and a complete initialization path. Check InitCheck() and Lock() as required by the bitmap’s use; do not pass an invalid or uninitialized object. Avoid relying on a hard-coded byte stride: bitmap rows may contain padding, and BBitmap::BytesPerRow() is the relevant row stride if pixels are accessed directly.
Choose ownership clearly. The caller owns the result bitmap and is responsible for releasing it when no longer needed. If the icon is used by a view, ensure the bitmap remains alive while drawing; do not store a pointer into a temporary output or free it as soon as DrawBitmap() returns if another code path still references it. If drawing occurs from another thread or window, obey the bitmap and Interface Kit locking requirements.
Use bounded sizes. A malicious or corrupt vector input should not trigger an unbounded allocation from metadata. The caller chooses destination dimensions, so impose a reasonable cap and reject zero, nonsquare, or excessive dimensions before allocation. Keep conversion errors visible in logs without dumping private file contents.
Acceptance tests
Test one vector icon rendered at several square sizes and verify proportions and edges. Test an intentionally non-square bitmap and confirm the documented crop/empty-space behavior, then fix the destination rather than adjusting the icon bytes blindly. Test the same source into RGBA and the supported legacy bitmap path. Check behavior for a missing attribute, malformed bytes, an unsupported colorspace, and a node that disappears between lookup and rendering.
Also verify the metadata scope: a file-specific icon override should affect only that file; a MIME icon should affect the intended file type; the application icon should remain tied to the executable/application metadata. Copy the test data with the actual backup mechanism and check whether attributes survive. Inspect both the application UI and Tracker to ensure each layer uses the intended icon.
HVIF is most useful when treated as compact vector source plus a deliberate rasterization target. BIconUtils supplies the system’s supported loading and conversion boundary; MIME and node metadata determine which icon belongs to which object; the application remains responsible for allocation, lifetime, scope, and error handling. Following those boundaries keeps icons sharp, small, and consistent with Haiku’s filesystem and application model.
Related:
- Haiku’s MIME Database: Types, Attributes, App Signatures, and Preferred Handlers
- Haiku BResources: Packaging Typed Data Inside Executables
Sources: