PixelBox is a fast and customizable BitBlt-based pixel magnification control for WPF. The library contains the standalone magnifier control itself, and a ready-to-use mouse-tracked pixel magnifier and color picker window, similar to what you would find in browser developer tools.
In a nutshell, what the control can provide is:
- Adjustable grid size, pixel size, and refresh rate.
- Toggleable grid lines.
- Color sampling ranging from single pixel up to a 5×5 region.
- Individual screen axes locking, like in macOS' Digital Color Meter.
- High-DPI support.
Here's a quick demo of the built-in magnifier window:
- Operating System: Windows 7 SP1 or later.
- .NET: 8.0 or later (uses C# 12 features).
Caution
Loupe holds unmanaged resources for its lifetime and implements IDisposable. Call Dispose() when the control is no longer needed to properly release these resources.
<Window x:Class="WpfApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:pb="clr-namespace:PixelBox;assembly=PixelBox">
<Grid>
<!-- The size of the Loupe control is automatically determined by its
GridSize and PixelSize properties. Do not set the control size
manually -->
<pb:Loupe HorizontalAlignment="Left" VerticalAlignment="Top"
GridSize="15"
PixelSize="10"
ShowGrid="True"
RefreshInterval="30"
PixelChanged="OnPixelChanged"/>
</Grid>
</Window>The PixelChanged event is raised whenever the sampled pixel changes. You can use this event to receive the new sampled color and screen position.
private Color _color;
private Point _position;
private void OnPixelChanged(object? sender, PixelChangedEventArgs e)
{
_color = e.Color;
_position = e.ScreenPosition;
}The Loupe control does not automatically capture the screen. You must call StartCapture() to begin capturing, and StopCapture() to stop.
The Loupe control exposes the public APIs listed in the tables below.
| API | Type |
|---|---|
Loupe.GridSize |
Dependency Property |
Loupe.PixelSize |
Dependency Property |
Loupe.RefreshInterval |
Dependency Property |
Loupe.SamplingMode |
Dependency Property |
Loupe.ShowGrid |
Dependency Property |
| API | Type |
|---|---|
Loupe.IsCapturing |
CLR Property |
Loupe.PositionLocked |
CLR Property |
Loupe.PositionXLocked |
CLR Property |
Loupe.PositionYLocked |
CLR Property |
| API | Type |
|---|---|
Loupe.StartCapture() |
Method |
Loupe.StopCapture() |
Method |
Loupe.ToggleCapture() |
Method |
Loupe.LockPosition(Point) |
Method |
Loupe.LockPosition(Point, bool, bool) |
Method |
Loupe.LockPositionX() |
Method |
Loupe.LockPositionY() |
Method |
Loupe.UnlockPositionX() |
Method |
Loupe.UnlockPositionY() |
Method |
Loupe.UnlockPosition() |
Method |
Tip
A project demonstrating the use of the built-in window is provided under PixelBox.Demo.
var picker = new PixelBox.LoupeWindow();
// ShowDialog() will return true if the window was closed via either Enter key or
// mouse left click. You can use the return result to update your UI conditionally
picker.ShowDialog();
var color = picker.PixelColor;
var position = picker.PixelPosition;The magnifier window uses the following keybinds by default:
| Command | Keybind | Alternative Input |
|---|---|---|
LoupeWindowCommands.ToggleGrid |
G | |
LoupeWindowCommands.IncreaseGridSize |
Shift OemPlus | Shift Mouse Wheel Up |
LoupeWindowCommands.DecreaseGridSize |
Shift OemMinus | Shift Mouse Wheel Down |
LoupeWindowCommands.IncreasePixelSize |
Ctrl OemPlus | Ctrl Mouse Wheel Up |
LoupeWindowCommands.DecreasePixelSize |
Ctrl OemMinus | Ctrl Mouse Wheel Down |
LoupeWindowCommands.IncreaseColorSamplerSize |
OemPlus | |
LoupeWindowCommands.DecreaseColorSamplerSize |
OemMinus | |
LoupeWindowCommands.Close |
Enter |
Note
OemPlus and OemMinus are the + and - keys to the left of Backspace. However, they may vary on non-US keyboard layouts.
You can remap the keybinds for any of the listed commands before instantiating the window:
LoupeWindow.ConfigureKeyBindings(bindings =>
{
bindings.Close = new KeyBinding
{
Command = LoupeWindowCommands.Close,
Key = Key.Space,
Modifiers = ModifierKeys.None
};
});
var picker = new LoupeWindow();You can customize how the color and screen position values are formatted in the info panel (visible when ShowInfoPanel = true) by providing your own IValueConverter implementations to the PixelColorConverter and PixelPositionConverter properties.
The example below formats the color value using CSS RGB syntax instead of the default HTML hex format:
using System.Globalization;
using System.Windows.Data;
using System.Windows.Media;
internal class ColorToCssStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is not Color c)
return string.Empty;
return $"rgb({c.R}, {c.G}, {c.B})";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
=> throw new NotImplementedException();
}// Set the converter after instantiating the window
var picker = new LoupeWindow
{
PixelColorConverter = new ColorToCssStringConverter(),
InfoPanelMinWidth = 175
};Tip
The InfoPanelMinWidth property can be used to set the minimum width of the info panel. This is useful when the panel's content might exceed the default minimum width, which would otherwise cause the magnifier position to shift horizontally due to its centering.
All code in this repository is available under the terms of the MIT license.