Simple Usage
With the GetCroppedCanvasDataURLAsync
method
you can get canvas drawn the cropped image in URL format.
GetCroppedCanvasDataURLAsync
method have following arguments:
GetCroppedCanvasOptions (required)
- used to get a cropped canvas;
type (not required)
- string indicating the image format. The default type is image/png;
this image format will be also used if the specified type is not supported;
number (not required)
- number between 0 and 1 indicating the image quality to be used when creating images using file formats that support lossy compression (such as image/jpeg or image/webp).
Different browsers have different image encoder compression, usually it is 92 or 80 percent of the full image quality. The default value is 1 with maximum image quality.
CancellationToken (not required)
- used to propagate notifications that the operation should be canceled.

@using Cropper.Blazor.Extensions; @using Cropper.Blazor.Models; <div class="img-container"> <CropperComponent Class="big-img" Src="images/budir-church-bu-akirkja-iceland.jpg" @ref="cropperComponent" Options="new Blazor.Models.Options()" /> </div> <div class="button" @onclick="GetCroppedCanvasDataURLAsync"> Get cropped image </div> <img class="cropped-img-container" src="" /> @* Make sure the size of the image fits perfectly into the container *@ <style> .big-img { max-height: 400px; /* This rule is very important, please don't ignore this */ max-width: 100%; } .img-container { max-height: 400px; width: 100%; } /* Means that the cropped image will take up 100% of the width of its containing element */ .cropped-img-container { width: 100%; } /* These styles are just needed for a nice button and don't related with cropper component */ .button { display: inline-block; padding: 10px 20px; background-color: #007bff; color: #fff; border: none; border-radius: 5px; text-align: center; text-decoration: none; font-size: 16px; cursor: pointer; } </style>
@code { private CropperComponent? cropperComponent = null!; private string croppedCanvasDataURL; public async Task GetCroppedCanvasDataURLAsync() { GetCroppedCanvasOptions getCroppedCanvasOptions = new GetCroppedCanvasOptions { MaxHeight = 4096, MaxWidth = 4096, ImageSmoothingQuality = ImageSmoothingQuality.High.ToEnumString() }; croppedCanvasDataURL = await cropperComponent!.GetCroppedCanvasDataURLAsync(getCroppedCanvasOptions); } }
Advanced Usage
With the GetCroppedCanvasAsync
method
you can get a canvas drawn from the cropped image (lossy compression). If it is not cropped, then returns a canvas drawn the whole image.
GetCroppedCanvasAsync
method have following argument:
GetCroppedCanvasOptions (required)
- used to get a cropped canvas;
CancellationToken (not required)
- used to propagate notifications that the operation should be canceled.
This
GetCroppedCanvasAsync
method returns CroppedCanvas
.
Use JSRuntimeObjectRef
in the
CroppedCanvas
which represents a reference to a JavaScript cropped canvas object for get a Data URL
via
HTMLCanvasElement.toDataURL:
CroppedCanvas.JSRuntimeObjectRef.InvokeAsync<string>("toDataURL", type, encoderOptions);

@using Cropper.Blazor.Extensions; @using Cropper.Blazor.Models; <div class="img-container"> <CropperComponent Class="big-img" Src="images/budir-church-bu-akirkja-iceland.jpg" @ref="cropperComponent" Options="new Blazor.Models.Options()" /> </div> <div class="button" @onclick="GetCroppedCanvasAsync"> Get cropped image </div> <img class="cropped-img-container" src="" /> @* Make sure the size of the image fits perfectly into the container *@ <style> .big-img { max-height: 400px; /* This rule is very important, please don't ignore this */ max-width: 100%; } .img-container { max-height: 400px; width: 100%; } /* Means that the cropped image will take up 100% of the width of its containing element */ .cropped-img-container { width: 100%; } /* These styles are just needed for a nice button and don't related with cropper component */ .button { display: inline-block; padding: 10px 20px; background-color: #007bff; color: #fff; border: none; border-radius: 5px; text-align: center; text-decoration: none; font-size: 16px; cursor: pointer; } </style>
@code { private CropperComponent? cropperComponent = null!; private string croppedCanvasDataURL; public async Task GetCroppedCanvasAsync() { GetCroppedCanvasOptions getCroppedCanvasOptions = new GetCroppedCanvasOptions { MaxHeight = 4096, MaxWidth = 4096, ImageSmoothingQuality = ImageSmoothingQuality.High.ToEnumString() }; // Get a reference to a JavaScript cropped canvas object. CroppedCanvas croppedCanvas = await cropperComponent!.GetCroppedCanvasAsync(getCroppedCanvasOptions); // Invoke toDataURL JavaScript function from the canvas object. croppedCanvasDataURL = await croppedCanvas!.JSRuntimeObjectRef.InvokeAsync<string>("toDataURL", "image/png", 1); } }
Crop a round image

@using Cropper.Blazor.Extensions; @using Cropper.Blazor.Models; <div class="img-container cropper-face-circle"> <CropperComponent Class="big-img" Src="images/lone-tree.jpg" @ref="cropperComponent" Options="new Blazor.Models.Options()" /> </div> <div class="button" @onclick="GetCroppedCanvasAsync"> Get cropped image </div> <img class="cropped-img-container" src="" /> @* Make sure the size of the image fits perfectly into the container *@ <style> .cropper-face { opacity: 25%; } .img-container.cropper-face-circle .cropper-container .cropper-crop-box .cropper-face { border-radius: 50%; } .big-img { max-height: 400px; /* This rule is very important, please don't ignore this */ max-width: 100%; } .img-container { max-height: 400px; width: 100%; } /* Means that the cropped image will take up 100% of the width of its containing element */ .cropped-img-container { width: 100%; } /* These styles are just needed for a nice button and don't related with cropper component */ .button { display: inline-block; padding: 10px 20px; background-color: #007bff; color: #fff; border: none; border-radius: 5px; text-align: center; text-decoration: none; font-size: 16px; cursor: pointer; } </style>
@code { [Inject] private IJSRuntime? JSRuntime { get; set; } private CropperComponent? cropperComponent = null!; private string croppedCanvasDataURL; public async Task GetCroppedCanvasAsync() { GetCroppedCanvasOptions getCroppedCanvasOptions = new GetCroppedCanvasOptions { MaxHeight = 4096, MaxWidth = 4096, ImageSmoothingQuality = ImageSmoothingQuality.High.ToEnumString() }; // Get a reference to a JavaScript cropped canvas object. CroppedCanvas croppedCanvas = await cropperComponent!.GetCroppedCanvasAsync(getCroppedCanvasOptions); // Invoke toDataURL JavaScript function from the canvas object. croppedCanvasDataURL = await JSRuntime!.InvokeAsync<string>("window.getEllipseImage", croppedCanvas!.JSRuntimeObjectRef); } }
Crop a polygon image

@using Cropper.Blazor.Extensions; @using Cropper.Blazor.Models; <div class="img-container cropper-face-pentagon"> <CropperComponent Class="big-img" Src="images/Mushrooms.jpg" @ref="cropperComponent" Options="new Blazor.Models.Options()" /> </div> <div class="button" @onclick="GetCroppedCanvasAsync"> Get cropped image </div> <img class="cropped-img-container" src="" /> @* Make sure the size of the image fits perfectly into the container *@ <style> .cropper-face { opacity: 25%; } .img-container.cropper-face-pentagon .cropper-container .cropper-crop-box .cropper-face { clip-path: polygon(50% 0%, 100% 38%, 82% 100%, 18% 100%, 0% 38%); } .big-img { max-height: 400px; /* This rule is very important, please don't ignore this */ max-width: 100%; } .img-container { max-height: 400px; width: 100%; } /* Means that the cropped image will take up 100% of the width of its containing element */ .cropped-img-container { width: 100%; } /* These styles are just needed for a nice button and don't related with cropper component */ .button { display: inline-block; padding: 10px 20px; background-color: #007bff; color: #fff; border: none; border-radius: 5px; text-align: center; text-decoration: none; font-size: 16px; cursor: pointer; } </style>
@code { [Inject] private IJSRuntime? JSRuntime { get; set; } private CropperComponent? cropperComponent = null!; private string croppedCanvasDataURL; public async Task GetCroppedCanvasAsync() { GetCroppedCanvasOptions getCroppedCanvasOptions = new GetCroppedCanvasOptions { MaxHeight = 4096, MaxWidth = 4096, ImageSmoothingQuality = ImageSmoothingQuality.High.ToEnumString() }; // Get a reference to a JavaScript cropped canvas object. CroppedCanvas croppedCanvas = await cropperComponent!.GetCroppedCanvasAsync(getCroppedCanvasOptions); // Invoke toDataURL JavaScript function from the canvas object. croppedCanvasDataURL = await JSRuntime!.InvokeAsync<string>( "window.getPolygonImage", croppedCanvas!.JSRuntimeObjectRef, // Defines a polygon using an SVG fill rule and a set of vertices previously defined in the following format styles: // .img-container.cropper-face-pentagon.cropper-container.cropper-crop-box.cropper-face { // clip-path: polygon(50% 0%, 100% 38%, 82% 100%, 18% 100%, 0% 38%); // } // In our case, we need to pass the same data, but without the percent sign (%) new int[] { 50, 0, 100, 38, 82, 100, 18, 100, 0, 38 }); } }
Crop in Background
With the GetCroppedCanvasDataInBackgroundAsync
method
you can get a canvas drawn from the cropped image (lossy compression). If it is not cropped, then returns a canvas drawn the whole image.
GetCroppedCanvasDataInBackgroundAsync
method have following argument:
GetCroppedCanvasOptions (required)
- used to get a cropped canvas;
type (not required)
- string indicating the image format. The default type is image/png;
this image format will be also used if the specified type is not supported;
number (not required)
- number between 0 and 1 indicating the image quality to be used when creating images using file formats that support lossy compression (such as image/jpeg or image/webp).
Different browsers have different image encoder compression, usually it is 92 or 80 percent of the full image quality. The default value is 1 with maximum image quality.
maximumReceiveChunkSize (not required)
- the maximum size of each image chunk to receive, in bytes.
For example, 65536 equals 64 KB. If specified, incoming image data will be split into chunks of this size during transmission.
If null, the chunk size will be handled automatically based on the stream's native chunking behavior.
This helps control memory usage and ensures compatibility with interop limits.
CancellationToken (not required)
- used to propagate notifications that the operation should be canceled.
This
GetCroppedCanvasDataInBackgroundAsync
method returns ImageReceiver
.
Use GetImageChunkStreamAsync
method in the
ImageReceiver
for reads the image chunks into a memory stream
or to throw an ImageProcessingException
when error occurs during image processin.

@using Cropper.Blazor.Extensions; @using Cropper.Blazor.Models; @using Cropper.Blazor.Exceptions; <div class="img-container"> <CropperComponent Class="big-img" Src="images/budir-church-bu-akirkja-iceland.jpg" @ref="cropperComponent" Options="new Blazor.Models.Options()" /> </div> <div class="button" @onclick="GetCroppedCanvasDataInBackgroundAsync"> Get cropped image in background </div> <img class="cropped-img-container" src="" /> @* Make sure the size of the image fits perfectly into the container *@ <style> .big-img { max-height: 400px; /* This rule is very important, please don't ignore this */ max-width: 100%; } .img-container { max-height: 400px; width: 100%; } /* Means that the cropped image will take up 100% of the width of its containing element */ .cropped-img-container { width: 100%; } /* These styles are just needed for a nice button and don't related with cropper component */ .button { display: inline-block; padding: 10px 20px; background-color: #007bff; color: #fff; border: none; border-radius: 5px; text-align: center; text-decoration: none; font-size: 16px; cursor: pointer; } </style>
@code { private CropperComponent? cropperComponent = null!; private string croppedCanvasDataURL; public async Task GetCroppedCanvasDataInBackgroundAsync() { // Define options for the cropped canvas, including size and image quality GetCroppedCanvasOptions getCroppedCanvasOptions = new GetCroppedCanvasOptions { MaxHeight = 4096, MaxWidth = 4096, ImageSmoothingQuality = ImageSmoothingQuality.High.ToEnumString() }; // Call the cropper component to get the cropped canvas image ImageReceiver imageReceiver = await cropperComponent!.GetCroppedCanvasDataInBackgroundAsync(getCroppedCanvasOptions); try { // Retrieve the image stream from the receiver using MemoryStream croppedCanvasDataStream = await imageReceiver.GetImageChunkStreamAsync(); // Convert the stream to a byte array byte[] croppedCanvasData = croppedCanvasDataStream.ToArray(); // Encode the image data as a base64 data URL for use in HTML croppedCanvasDataURL = "data:image/png;base64," + Convert.ToBase64String(croppedCanvasData); } catch (ImageProcessingException ex) { // Handle any image processing errors (currently empty - consider logging or rethrowing) } } }
Crop a round image in Background

@using Cropper.Blazor.Extensions; @using Cropper.Blazor.Models; @using Cropper.Blazor.Exceptions; <div class="img-container cropper-face-circle"> <CropperComponent Class="big-img" Src="images/lone-tree.jpg" @ref="cropperComponent" Options="new Blazor.Models.Options()" /> </div> <div class="button" @onclick="GetCroppedCanvasDataInBackgroundAsync"> Get cropped image in background </div> <img class="cropped-img-container" src="" /> @* Make sure the size of the image fits perfectly into the container *@ <style> .cropper-face { opacity: 25%; } .img-container.cropper-face-circle .cropper-container .cropper-crop-box .cropper-face { border-radius: 50%; } .big-img { max-height: 400px; /* This rule is very important, please don't ignore this */ max-width: 100%; } .img-container { max-height: 400px; width: 100%; } /* Means that the cropped image will take up 100% of the width of its containing element */ .cropped-img-container { width: 100%; } /* These styles are just needed for a nice button and don't related with cropper component */ .button { display: inline-block; padding: 10px 20px; background-color: #007bff; color: #fff; border: none; border-radius: 5px; text-align: center; text-decoration: none; font-size: 16px; cursor: pointer; } </style>
@code { [Inject] private IJSRuntime? JSRuntime { get; set; } private CropperComponent? cropperComponent = null!; private string croppedCanvasDataURL; public async Task GetCroppedCanvasDataInBackgroundAsync() { GetCroppedCanvasOptions getCroppedCanvasOptions = new GetCroppedCanvasOptions { MaxHeight = 4096, MaxWidth = 4096, ImageSmoothingQuality = ImageSmoothingQuality.High.ToEnumString() }; CroppedCanvasReceiver croppedCanvasReceiver = await cropperComponent!.GetCroppedCanvasInBackgroundAsync( getCroppedCanvasOptions, async (croppedCanvas, ct) => { // Create an image receiver to receive the processed image data ImageReceiver imageReceiver = new ImageReceiver(); try { // Invoke a JavaScript function to apply elliptical background processing to the canvas, // passing in the cropped canvas object and a .NET object reference for callback await JSRuntime!.InvokeVoidAsync( "window.getEllipseImageInBackground", croppedCanvas!.JSRuntimeObjectRef, DotNetObjectReference.Create(imageReceiver)); // Retrieve the image stream from the receiver using MemoryStream croppedCanvasDataStream = await imageReceiver.GetImageChunkStreamAsync(); // Convert the stream to a byte array byte[] croppedCanvasData = croppedCanvasDataStream.ToArray(); // Encode the image data as a base64 data URL for use in HTML croppedCanvasDataURL = "data:image/png;base64," + Convert.ToBase64String(croppedCanvasData); // Force a UI refresh to reflect the new image // This is required because we're in an async JS interop callback context, // which runs outside of Blazor’s normal rendering/event loop. // Calling StateHasChanged directly here might not work as expected // because it may not execute on the Blazor synchronization context. // InvokeAsync ensures StateHasChanged is called on the correct thread. // Use InvokeAsync(StateHasChanged) in the following cases: // 1. **JS Interop callbacks** – when data is updated via JS and needs a re-render. // 2. **Background tasks** – when working with tasks outside the Blazor rendering context. // **Be careful with InvokeAsync(StateHasChanged) in components with many elements or heavy rendering logic**: // - Calling StateHasChanged frequently can cause **performance issues** if the component contains many UI elements. // - Each call to StateHasChanged forces a full re-render of the component, which can be costly in large or complex components. // - To mitigate this, consider breaking down your large components into **smaller, more manageable child components**. // - **Smaller components** will re-render independently, reducing the overall re-render scope and improving performance. await InvokeAsync(StateHasChanged); } catch (ImageProcessingException ex) { // Handle any image processing errors (currently empty - consider logging or rethrowing) } }); } }
Crop a polygon image in Background

@using Cropper.Blazor.Extensions; @using Cropper.Blazor.Models; @using Cropper.Blazor.Exceptions; <div class="img-container cropper-face-pentagon"> <CropperComponent Class="big-img" Src="images/Mushrooms.jpg" @ref="cropperComponent" Options="new Blazor.Models.Options()" /> </div> <div class="button" @onclick="GetCroppedCanvasDataInBackgroundAsync"> Get cropped image in background </div> <img class="cropped-img-container" src="" /> @* Make sure the size of the image fits perfectly into the container *@ <style> .cropper-face { opacity: 25%; } .img-container.cropper-face-pentagon .cropper-container .cropper-crop-box .cropper-face { clip-path: polygon(50% 0%, 100% 38%, 82% 100%, 18% 100%, 0% 38%); } .big-img { max-height: 400px; /* This rule is very important, please don't ignore this */ max-width: 100%; } .img-container { max-height: 400px; width: 100%; } /* Means that the cropped image will take up 100% of the width of its containing element */ .cropped-img-container { width: 100%; } /* These styles are just needed for a nice button and don't related with cropper component */ .button { display: inline-block; padding: 10px 20px; background-color: #007bff; color: #fff; border: none; border-radius: 5px; text-align: center; text-decoration: none; font-size: 16px; cursor: pointer; } </style>
@code { [Inject] private IJSRuntime? JSRuntime { get; set; } private CropperComponent? cropperComponent = null!; private string? croppedCanvasDataURL; public async Task GetCroppedCanvasDataInBackgroundAsync() { GetCroppedCanvasOptions getCroppedCanvasOptions = new GetCroppedCanvasOptions { MaxHeight = 4096, MaxWidth = 4096, ImageSmoothingQuality = ImageSmoothingQuality.High.ToEnumString() }; CroppedCanvasReceiver croppedCanvasReceiver = await cropperComponent!.GetCroppedCanvasInBackgroundAsync( getCroppedCanvasOptions, async (croppedCanvas, ct) => { // Create an image receiver to receive the processed image data ImageReceiver imageReceiver = new ImageReceiver(); try { // Invoke a JavaScript function to apply elliptical background processing to the canvas, // passing in the cropped canvas object and a .NET object reference for callback await JSRuntime!.InvokeVoidAsync( "window.getPolygonImageInBackground", croppedCanvas!.JSRuntimeObjectRef, // Defines a polygon using an SVG fill rule and a set of vertices previously defined in the following format styles: // .img-container.cropper-face-pentagon.cropper-container.cropper-crop-box.cropper-face { // clip-path: polygon(50% 0%, 100% 38%, 82% 100%, 18% 100%, 0% 38%); // } // In our case, we need to pass the same data, but without the percent sign (%) new int[] { 50, 0, 100, 38, 82, 100, 18, 100, 0, 38 }, DotNetObjectReference.Create(imageReceiver)); // Retrieve the image stream from the receiver using MemoryStream croppedCanvasDataStream = await imageReceiver.GetImageChunkStreamAsync(); // Convert the stream to a byte array byte[] croppedCanvasData = croppedCanvasDataStream.ToArray(); // Encode the image data as a base64 data URL for use in HTML croppedCanvasDataURL = "data:image/png;base64," + Convert.ToBase64String(croppedCanvasData); // Force a UI refresh to reflect the new image // This is required because we're in an async JS interop callback context, // which runs outside of Blazor’s normal rendering/event loop. // Calling StateHasChanged directly here might not work as expected // because it may not execute on the Blazor synchronization context. // InvokeAsync ensures StateHasChanged is called on the correct thread. // Use InvokeAsync(StateHasChanged) in the following cases: // 1. **JS Interop callbacks** – when data is updated via JS and needs a re-render. // 2. **Background tasks** – when working with tasks outside the Blazor rendering context. // **Be careful with InvokeAsync(StateHasChanged) in components with many elements or heavy rendering logic**: // - Calling StateHasChanged frequently can cause **performance issues** if the component contains many UI elements. // - Each call to StateHasChanged forces a full re-render of the component, which can be costly in large or complex components. // - To mitigate this, consider breaking down your large components into **smaller, more manageable child components**. // - **Smaller components** will re-render independently, reducing the overall re-render scope and improving performance. await InvokeAsync(StateHasChanged); } catch (ImageProcessingException ex) { // Handle any image processing errors (currently empty - consider logging or rethrowing) } }); } }
Preparing the image for uploading to the server
With the Decode
extension method
in DataUrlDecoder
static class
from the Cropper.Blazor.Extensions
namespace,
you can decode the data url into a Base64 image data and outs the media type.
Decode
method have following argument:
dataUrl (required)
- The data url to be decoded (e.g. data:image/png;base64,SGVsbG8gd29ybGQ=).
ArgumentException
exception with the following message:
Could not parse '{dataUrl}' as '"data:(?<type>.+?),(?<data>.+)"' data URL pattern.

@using Cropper.Blazor.Extensions; @using Cropper.Blazor.Models; <div class="img-container"> <CropperComponent Class="big-img" Src="icon-515x512.png" @ref="cropperComponent" Options="new Blazor.Models.Options()" /> </div> @if (decodedImageData is { base64ImageData: null, mediaType: null }) { <div class="button" @onclick="GetDecodedImageDataAsync"> Get decoded image data </div> } else { <MudText Typo="Typo.body2"> Media type: @decodedImageData!.mediaType </MudText> <MudText Typo="Typo.body2" Class="text-with-dots"> Base64: @decodedImageData!.base64ImageData </MudText> <MudText Typo="Typo.body2" Class="text-with-dots"> Data URL: @croppedCanvasDataURL </MudText> } @* Make sure the size of the image fits perfectly into the container *@ <style> .big-img { max-height: 400px; /* This rule is very important, please don't ignore this */ max-width: 100%; } .img-container { max-height: 400px; width: 100%; } /* Means that the cropped image will take up 100% of the width of its containing element */ .cropped-img-container { width: 100%; } /* These styles are just needed for a nice button and don't related with cropper component */ .button { display: inline-block; padding: 10px 20px; background-color: #007bff; color: #fff; border: none; border-radius: 5px; text-align: center; text-decoration: none; font-size: 16px; cursor: pointer; } </style>
@code { private CropperComponent? cropperComponent = null!; private string croppedCanvasDataURL; private (string base64ImageData, string mediaType) decodedImageData; public async Task GetDecodedImageDataAsync() { GetCroppedCanvasOptions getCroppedCanvasOptions = new GetCroppedCanvasOptions { MaxHeight = 4096, MaxWidth = 4096, ImageSmoothingQuality = ImageSmoothingQuality.High.ToEnumString() }; croppedCanvasDataURL = await cropperComponent!.GetCroppedCanvasDataURLAsync(getCroppedCanvasOptions); decodedImageData = croppedCanvasDataURL.Decode(); } }