The official development kit for extending ImageGlass 10. ImageGlass.SDK is a single .NET 10 class library that defines the public contracts for the two ways you can extend ImageGlass.
The two extension surfaces are independent β pick the one that matches what you want to build. Each has a step-by-step guide that builds a real sample from scratch.
| You want to⦠| Build⦠| How it runs | Step-by-step guide |
|---|---|---|---|
| Add support for an image format ImageGlass can't open yet (a new or proprietary codec) | Plugin | Native, in-process codec loaded through a versioned C ABI | Building a Native Codec Plugin β covers the C ABI, decode pipeline, memory ownership, animation, and AOT publishing (builds Base64Codec) |
| Add a feature that reacts to the user β read pixels under the cursor, inspect the current photo, drive the viewer, run host commands | Tool | Out-of-process program ImageGlass launches and drives over a named pipe | Building an External Tool β covers lifecycle hooks, the HostApi, real-time events, reading pixels, and registration (builds ConsoleColorPicker) |
A few concrete examples of what the SDK makes possible:
- A codec that decodes a custom or rare image format and renders it like any built-in format β still or animated.
- A color picker that reports the RGBA value under the user's click.
- A batch/automation tool that watches photo navigation and runs actions against the current image, selection, or theme.
See Samples for working, end-to-end examples, and the guides above for the full walkthroughs. The sections further down are a quick orientation.
Install the package from NuGet:
dotnet add package ImageGlass.SDKThe library targets net10.0 and depends only on SkiaSharp. It is AOT- and trim-compatible, so your plugin or tool can publish with Native AOT.
Requires the .NET 10 SDK.
dotnet build source/ImageGlass.SDK.slnxSupported platforms: x64, ARM64, AnyCPU.
The samples/ folder contains complete, runnable projects β the fastest way to see each extension surface end to end. Each sample has its own README with build, install, and registration steps.
| Sample | Surface | What it shows |
|---|---|---|
| Base64Codec | Plugin (codec) | A tiny cross-platform native codec that adds .b64 support β reads a base64-encoded image, decodes it with SkiaSharp into a 32bpp BGRA buffer, and manages pixel-buffer memory through the ABI. Publishes as a Native AOT shared library. |
| ConsoleColorPicker | Tool | A console tool that connects over the named pipe, reads metadata of the current photo, follows photo navigation, and logs the RGBA value of the pixel the user clicks in the viewer via opt-in pointer events. |
π Full walkthrough: docs/codec-plugin-development.md builds the Base64Codec sample step by step. The summary below is just an orientation.
Plugins run in-process and communicate with the host through function-pointer tables (a C ABI), so they can be written in any language that can export a C entry point and produce a native shared library.
A plugin ships as a folder containing the native library plus an igplugin.json manifest:
The host loads the library and calls the single required export:
const IGPluginApi* ig_plugin_get_api(int hostAbiVersion, const IGHostApi* hostApi);It returns an IGPluginApi table (plugin identity + GetCodec/Initialize/Shutdown/SelfTest). Each codec then exposes an IGCodecApi table: capability reporting, extension/signature matching, LoadMetadata, DecodeStaticRaster, and optional animation entry points.
Key contracts to honor:
- ABI version β encoded as
MAJOR * 1_000_000 + MINOR * 1_000 + PATCH(IGNativeAbi.IG_PLUGIN_ABI_VERSION). The host rejects plugins whose major version does not match. - Memory ownership β the plugin allocates pixel/animation buffers; the host calls back into the plugin's
FreePixelBuffer/FreeAnimationInfoto release them.FreePixelBuffermust be thread-safe β it may be invoked from any thread when the host disposes the image. - Animation β decoded animation frames must be fully composed RGBA at full canvas size. The host does not perform sub-rect composition or disposal/blend replay, so codecs like GIF/APNG must composite internally.
- Cancellation β long operations receive an opaque cancellation token; poll
IGHostCoreApi.IsCancellationRequestedand returnIGStatus.Canceledwhen set.
After you compile and publish the plugin with Native AOT, copy its entire output folder
into the _plugins folder of ImageGlass's config directory:
| Platform | Config directory |
|---|---|
| Windows | %LocalAppData%\ImageGlass_10 |
| Linux | ~/.local/share/ImageGlass_10 |
| macOS | /Users/<username>/Library/Application Support/ImageGlass_10 |
Make sure the igplugin.json manifest is located inside that folder, for example:
configdir/_plugins/my_codec/igplugin.json. ImageGlass scans _plugins on launch,
discovers the manifest, and loads the codec.
π Full walkthrough: docs/tool-development.md builds the ConsoleColorPicker sample step by step. The summary below is just an orientation.
Tools run out-of-process. Subclass ToolBase, then start it from your program's entry point:
using ImageGlass.SDK.Tools;
public sealed class MyTool : ToolBase
{
public override string ToolId => "MyTool"; // must match igconfig.json
protected override Task OnExecuteAsync(CancellationToken ct)
{
// Triggered by the host. Talk back through HostApi.
return Task.CompletedTask;
}
protected override void OnPhotoChanged(PhotoChangedEventArgs e)
{
// React to the user navigating to another photo.
}
}
public static class Program
{
public static Task Main(string[] args) => new MyTool().RunAsync(args);
}ImageGlass launches the tool with a --pipe <name> argument; RunAsync connects to the host and runs the message loop until shutdown.
- Host β tool events arrive as
OnXxxoverrides (OnInitializedAsync,OnExecuteAsync,OnPhotoChanged,OnThemeChanged,OnSelectionChanged, β¦). - Tool β host calls go through
HostApi(IToolHostProxy): read pixels, get the full pixel buffer (via a memory-mapped file), query photo metadata and the photo list, get/set the selection, run named ImageGlass API methods, and read theme info. - Real-time pointer/selection/frame events are opt-in via
HostApi.SubscribeEventsAsync. - Register the tool with ImageGlass through an
igconfig.jsonentry whoseToolIdmatches yourToolBase.ToolId.
In the Arguments field of the igconfig.json entry you can use the <file> macro. ImageGlass replaces it with the full path of the currently viewed image when it launches the tool:
"Tools": [
{
"ToolId": "Tool_MyTool",
"ToolName": "My Tool",
"Executable": "C:\\path\\to\\MyTool.exe",
"Arguments": "--input \"<file>\"", // expands to: --input "C:\Photos\my image.png"
"IsIntegrated": true,
"Hotkeys": ["Alt+1"]
}
]IsIntegratedβtruemakes this an SDK tool: ImageGlass launches the process with the--pipe <name>argument and wires up the two-wayHostApiproxy, so the tool can useToolBase/HostApito talk to the host. Set itfalse(or omit it) for a plain external program that is just launched with its arguments and gets no pipe connection.Hotkeysβ an array of key-combination strings that run the tool when pressed in ImageGlass (e.g.["Alt+1"],["K"]). Use an empty array[]if you don't want a shortcut.
<file> expands to the path without quotes β wrap it yourself as "<file>" when the path may contain spaces. The expanded value arrives in your tool's args (the string[] passed to Main / RunAsync).
Set EnableDebug = true and provide a DebugLog sink before calling RunAsync to trace pipe connection and message dispatch when a tool appears to "do nothing".
MIT Β© 2026 Duong Dieu Phap
{ "id": "Plugin_MyCodec", "name": "My Codec", "version": "1.0.0", "author": "You", "kind": "Codec", "executable": "MyCodec.dll", // MyCodec.so / MyCodec.dylib on other platforms "supportedExtensions": ".foo;.bar" // optional; overrides the plugin-reported list }