PhotoEditor.Maui
0.9.7
dotnet add package PhotoEditor.Maui --version 0.9.7
NuGet\Install-Package PhotoEditor.Maui -Version 0.9.7
<PackageReference Include="PhotoEditor.Maui" Version="0.9.7" />
<PackageVersion Include="PhotoEditor.Maui" Version="0.9.7" />
<PackageReference Include="PhotoEditor.Maui" />
paket add PhotoEditor.Maui --version 0.9.7
#r "nuget: PhotoEditor.Maui, 0.9.7"
#:package PhotoEditor.Maui@0.9.7
#addin nuget:?package=PhotoEditor.Maui&version=0.9.7
#tool nuget:?package=PhotoEditor.Maui&version=0.9.7
PhotoEditor.Maui
A cross-platform .NET MAUI photo editor control with crop, freehand draw, arrows, and text overlays. Built on SkiaSharp with an optional full UI shell (PhotoEditorView) or a bare canvas (SkiaPhotoEditorView).
Features
- Crop with rotate
- Freehand draw with color palette
- Arrow annotations
- Text overlays (RTL-aware when configured)
- Undo / Redo
- PNG or JPEG export with max dimensions and quality
- Themeable built-in toolbar (text, Unicode symbols, or icon font)
Preview
Built-in UI (default)
https://github.com/user-attachments/assets/5caaea8b-5f01-46ed-a071-31c893c015ec
Themed default UI
Custom UI
Installation
dotnet add package PhotoEditor.Maui
Setup
In MauiProgram.cs:
builder
.UseMauiApp<App>()
.UsePhotoEditor();
UsePhotoEditor() registers SkiaSharp handlers (required for SKCanvasView on Windows and other platforms). The library does not register or bundle any fonts.
Text fonts — overlay text uses the platform default Skia typeface unless you point PhotoEditorTextFontOptions.Current at app-package font files:
builder.UsePhotoEditor();
PhotoEditorTextFontOptions.Current.LatinFontAssetFileName = "MyFont-Regular.ttf";
PhotoEditorTextFontOptions.Current.RtlFontAssetFileName = "MyFont-Arabic.ttf";
Pack fonts as MauiAsset (with LogicalName) so FileSystem.OpenAppPackageFileAsync can load them at runtime. Configure RTL picking via PreferRtlTypeface.
The built-in toolbar uses text labels and Unicode symbols by default (no icon font).
Customization
Configure defaults app-wide in MauiProgram.cs. Leave theme properties unset (null) to inherit your app resource dictionary and light/dark theme:
builder.UsePhotoEditor(options =>
{
// Optional — only set what you want to override
options.Theme.AccentColor = Color.FromArgb("#E91E63");
options.Canvas.DrawColors = [Colors.White, Colors.Black, Colors.Red];
options.Canvas.DefaultStrokeWidth = 8f;
options.Canvas.Arrow.DefaultStrokeWidth = 10f;
options.Features.Arrow = false; // hide arrow tool in built-in toolbar
options.Messages.DiscardTitle = "Leave editor?";
});
Unset theme colors resolve from app resources (Primary, Secondary, Gray*, etc.) with MAUI template fallbacks, and update automatically when Application.Current.RequestedTheme changes.
For a single editor instance, clone defaults so you do not mutate the shared PhotoEditorOptions.Default:
editor.Options = PhotoEditorOptions.Default.Clone();
Toolbar icons — set Theme.Toolbar.IconFontFamily to a registered icon font and override individual glyphs (defaults are text labels, not icon code points):
builder.UsePhotoEditor(options =>
{
options.Theme.Toolbar.IconFontFamily = "MaterialIcons";
options.Theme.Toolbar.Undo = "\ue166";
options.Theme.Toolbar.Crop = "\ue3be";
options.Theme.Toolbar.Done = "\ue876";
});
Register the font in your app's MauiProgram.cs (fonts.AddFont("MaterialIcons-Regular.ttf", "MaterialIcons")). See samples/PhotoEditor.Maui.Sample/Themes/MaterialIconsToolbar.cs for a full glyph set.
Or per control in XAML/code via the Options property on PhotoEditorView or SkiaPhotoEditorView.
PhotoEditorOptions groups:
- Canvas — draw palette, text sizes, draw/arrow stroke width defaults and ranges, undo depth, max edit dimensions (
MaxEditWidth/MaxEditHeightdownscale on load), crop/arrow/text-input tuning - Theme — optional accent/surface/text colors (null = app theme), toolbar and palette surfaces, button borders and corner radius, active tool styling, loading overlay, tool-mode canvas margin, Toolbar labels/icons
- Features — enable/disable crop, draw, arrow, text, undo/redo
- Messages — discard confirmation dialog strings (defaults: "Discard changes?", "Your edits will be lost.", …)
Set ShowBuiltInToolbar="False" on PhotoEditorView and bind to PhotoEditor for a fully custom UI while reusing the same options. Built-in Cancel/Done and tool action bars are hidden when the toolbar is off.
Color palette swatches in the built-in UI use a neutral gray ring and shadow so every swatch stays visible on light and dark fills. For custom palettes, use PhotoEditorColorSwatch.Create() and PhotoEditorColorSwatch.SetSelected().
Sample app
The included sample (samples/PhotoEditor.Maui.Sample) launches from a home page with three options under Pages/:
- Built-in UI —
Pages/BuiltInEditorPage(default text/Unicode toolbar, app theme colors) - Themed default UI —
Pages/ThemedDefaultEditorPage(built-in UI customized viaPhotoEditorThemeOptions: colors, rounded buttons, Material Icons toolbar) - Custom UI —
Pages/CustomEditorPage(fully custom UI,ShowBuiltInToolbar="False")
On Done / Save, the sample uses Community Toolkit FileSaver so the user picks file name and location (Services/SampleSaveHelper + PhotoEditorView.SaveImageAsync). The library itself does not depend on Community Toolkit.
Usage
Full editor (toolbar + Cancel/Done)
<ContentPage xmlns:mhr="http://mhrastegari.com/photoeditor">
<mhr:PhotoEditorView
ImageSourcePath="{Binding PhotoPath}"
MaxOutputHeight="720"
MaxOutputWidth="1280"
OutputFormat="Jpeg"
OutputQuality="90" />
</ContentPage>
var editor = new PhotoEditorView("/path/to/photo.jpg");
editor.Completed += (_, path) => { /* saved path, or null if cancelled */ };
Without SaveImageAsync, Done saves to FileSystem.CacheDirectory and returns that path via Completed.
Skia surface only (custom UI)
<mhr:SkiaPhotoEditorView x:Name="Editor" />
await Editor.LoadImageAsync(path);
Editor.OutputFormat = PhotoEditorOutputFormat.Jpeg;
Editor.OutputQuality = 90;
await Editor.SaveEditedImageAsync(FileSystem.CacheDirectory, "edited", 1280, 720);
Tool orchestration (custom toolbar):
Editor.ToggleTool(SkiaPhotoEditorInteractionMode.Draw); // tap again to cancel
Editor.ActivateTool(SkiaPhotoEditorInteractionMode.Crop); // exclusive — cancels other tools
await Editor.ApplyActiveToolAsync(); // Apply / Done prep
Editor.CancelActiveTool();
The same helpers are exposed on PhotoEditorView when using ShowBuiltInToolbar="False".
License
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-android36.0 is compatible. net10.0-browser was computed. net10.0-ios was computed. net10.0-ios26.0 is compatible. net10.0-maccatalyst was computed. net10.0-maccatalyst26.0 is compatible. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. net10.0-windows10.0.19041 is compatible. |
-
net10.0
- Microsoft.Maui.Controls (>= 10.0.20)
- SkiaSharp (>= 3.116.1)
- SkiaSharp.HarfBuzz (>= 3.116.1)
- SkiaSharp.Views.Maui.Controls (>= 3.116.1)
-
net10.0-android36.0
- Microsoft.Maui.Controls (>= 10.0.20)
- SkiaSharp (>= 3.116.1)
- SkiaSharp.HarfBuzz (>= 3.116.1)
- SkiaSharp.Views.Maui.Controls (>= 3.116.1)
-
net10.0-ios26.0
- Microsoft.Maui.Controls (>= 10.0.20)
- SkiaSharp (>= 3.116.1)
- SkiaSharp.HarfBuzz (>= 3.116.1)
- SkiaSharp.Views.Maui.Controls (>= 3.116.1)
-
net10.0-maccatalyst26.0
- Microsoft.Maui.Controls (>= 10.0.20)
- SkiaSharp (>= 3.116.1)
- SkiaSharp.HarfBuzz (>= 3.116.1)
- SkiaSharp.Views.Maui.Controls (>= 3.116.1)
-
net10.0-windows10.0.19041
- Microsoft.Maui.Controls (>= 10.0.20)
- SkiaSharp (>= 3.116.1)
- SkiaSharp.HarfBuzz (>= 3.116.1)
- SkiaSharp.Views.Maui.Controls (>= 3.116.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.