Image Cropper

TsgcHTMLComponent_ImageCropper: an image cropper that runs in the browser, for profile photos and scanned documents. Users crop, zoom, rotate and flip a photo, or mark the 4 corners of a page to get a straight rectangle back, and the server checks the result before your code or the disk sees it, in Delphi, C++ Builder and .NET.

TsgcHTMLComponent_ImageCropper

Set the shape and the size of the result and render it. The user selects, drops or pastes an image, or takes a photo, and edits it with no request to the server. Save renders the result from the original pixels, encodes it in the browser as JPEG, PNG or WebP and posts it to OnCrop, and UploadFolder keeps the file under a unique name.

Component class

TsgcHTMLComponent_ImageCropper, with a photo mode and a document mode

Renders

A toolbar, the editor and a live preview, from a script and CSS embedded in the component, with no external library and no CDN

Languages

Delphi, C++ Builder, .NET

An avatar cropper that saves to the server

A circle cropper with a 512 x 512 JPEG result. The server checks the image, writes it into a folder under a unique name, and TargetSelector shows the new avatar in the page once it is saved.

uses
  sgcHTML_Component_ImageCropper;

oCropper := TsgcHTMLComponent_ImageCropper.Create(Self);
oCropper.Name := 'AvatarCropper';
oCropper.HTMXEngine := sgcHTMXEngine1;
oCropper.CropperID := 'avatarCropper';
oCropper.CropShape := icsCircle;
oCropper.OutputWidth := 512;
oCropper.OutputHeight := 512;
oCropper.UploadFolder := 'C:\Portal\avatars';
oCropper.UploadURL := '/avatars/';   // map it to the folder in your server
oCropper.TargetSelector := '#avatar';
oCropper.OnCrop := CropperCrop;
oTemplate.BodyContent := '<img id="avatar" src="/avatars/default.jpg" alt="Avatar">' +
  oCropper.HTML;

procedure TForm1.CropperCrop(Sender: TObject; const aInfo: TsgcHTMLImageCropInfo;
  aStream: TStream; var aAccept: Boolean; var aErrorMessage: string);
begin
  // aInfo.URL is UploadURL plus the unique name the file gets
  StoreAvatarURL(CurrentUserID, aInfo.URL);   // your database
end;
@* Views/Profile/Photo.cshtml *@
@model ProfileModel

<img id="avatar" src="/avatars/current.jpg" alt="Avatar">
<sgc-image-cropper name="avatar" cropper-id="avatarCropper"
                   crop-shape="circle" output-width="512" output-height="512"
                   upload-folder="wwwroot/avatars" upload-url="/avatars/"
                   target-selector="#avatar" aria-label="Change your photo"
                   on-crop="Model.CheckCrop" />
using esegece.sgcWebSockets;

// OnCrop of the Tag Helper: the image is already checked by the server
public void CheckCrop(object sender, TsgcHTMLImageCropInfo aInfo, Stream aStream,
    ref bool aAccept, ref string aErrorMessage)
{
    if (!User.Identity!.IsAuthenticated)
    {
        aAccept = false;
        aErrorMessage = "Sign in to change your photo";
        return;
    }
    Profiles.SetAvatar(User, aInfo.URL);
}

// the same cropper in code, for a document scanner
var cropper = new TsgcHTMLComponent_ImageCropper();
cropper.Name = "ScanCropper";
cropper.HTMXEngine = engine;
cropper.Mode = TsgcHTMLImageCropperMode.icmDocument;
cropper.DocumentFilter = TsgcHTMLImageCropFilter.icflBlackWhite;
cropper.OutputFormat = TsgcHTMLImageCropFormat.icfPNG;
cropper.UploadFolder = @"C:\Portal\scans";
template.BodyContent = cropper.HTML;

What your users get

A photo editor for avatars and covers, and a scanner for pages and receipts, in one component.

Crop box and aspect ratios

A rectangle with 8 handles over the image: drag the box to move it and a handle to resize it, never below MinCropSize pixels of the source. AspectRatio locks the box to a ratio such as 16:9, and AspectRatios lists the presets of the toolbar, Free, 1:1, 4:3, 3:4 and 16:9 by default.

Circle avatars

CropShape icsCircle shows a round mask for avatars and locks the box to 1:1. PNG and WebP results get transparent corners, and JPEG results get BackgroundColor. A live thumbnail of the result, round for a circle, sits next to the editor.

Zoom, rotate, straighten and flip

Zoom with the buttons, the mouse wheel or a pinch, from 0.5 to 16 times, and drag the image outside the box to pan. Rotate left and right by 90 degrees, level a horizon with the Straighten slider from -45 to 45 degrees, flip horizontally or vertically, and Reset goes back to the whole image.

Document mode

With Mode icmDocument the user drags 4 corners onto the corners of a page, a receipt or a whiteboard, with a loupe at 4 times the zoom. The result is the quadrilateral mapped onto a straight rectangle, with bilinear sampling of the original pixels. There is no automatic edge detection: the user places the corners.

Document filters

Original, Grayscale, Black and white, an adaptive threshold that copes with shadows, and Enhance, a contrast stretch of every color channel. DocumentFilter sets the initial filter, and the user can change it in the toolbar.

Every image source

Select a file, drop it, paste it from the clipboard, or take a photo with the front or the rear camera (FacingMode) on a secure page. ImageURL loads an initial image such as the current avatar. The EXIF orientation of a photo is applied, so a portrait taken with a phone is upright.

Clean results

The result is always rendered from the original pixels, even when a large image is edited from a downscaled copy. OutputFormat selects JPEG, PNG or WebP, OutputQuality the quality and OutputWidth, OutputHeight and MaxOutputSize the size. The browser encodes the result again, so the EXIF and GPS data of the source are not in it.

Keyboard and accessibility

Every action can be done with the keyboard: the arrows move the crop box or the focused corner by 1 pixel (Shift for 10), Alt+arrows resize the box, + and - zoom and R rotates. The crop box and every corner are sliders with a value text, and a polite live region announces the crop size and the result of a save. The cropper follows data-bs-theme="dark" and reduced motion.

Key properties, methods & events

The members you reach for most often.

Server checks

The server never trusts the browser. The type must be JPEG, PNG or WebP and match OutputFormat, the data is checked against MaxResultSize before and after decoding, its magic bytes must be those of the type, and the width and height read from the header must equal the posted size within MaxOutputSize. Every number of the crop data is range checked, and the source name loses its path parts.

OnCrop

OnCrop(Sender, aInfo, aStream, aAccept, aErrorMessage) receives the validated info and the image bytes. Store the image yourself, change the URL, or set aAccept to False with your own text. It fires on the thread of the request, where sgcHTMLRequestSession gives the session.

UploadFolder and UploadURL

With UploadFolder the server picks a unique name of 32 hexadecimal characters with the extension of the type, never the posted name, and writes the file only after the image is accepted. SavedFileName and URL, which is UploadURL plus that name, are filled in. The component does not serve the folder: map UploadURL to it in your server.

Form integration

FieldName names a hidden input that receives the result as a data: URL, so a surrounding form posts it with its other fields. TargetSelector updates every matching img element, and the DOM event sgc-image-cropped bubbles after every save with the URL, width, height and type. Without an engine or ActionURL, Save only applies the result in the browser.

sgcHTMLImageInfo

The header reader of the server is public, so your own code can check an image with the same rule: sgcHTMLImageInfo(aStream, aType, aWidth, aHeight) reads the type and the size of a PNG, JPEG or WebP image without decoding it. In .NET it is a static method of sgcHTMLImageCropperHelpers.

JavaScript API

window.sgcImageCropper offers scan, instances, get, load, loadFile, setCrop, reset, result and save. The script initialises every cropper of the page, also after an htmx swap, and several croppers on one page share it.

ASP.NET Core

In a Razor view the <sgc-image-cropper> Tag Helper renders the cropper, and Save posts to the component events endpoint of UseSgcHtml. A value that is not in the list of its attribute throws an InvalidOperationException when the page renders, and the MaxRequestBodySize of Kestrel still caps the request.

The demo

Demos\60.HTML\01.RunTime\33.ImageCropper is sgc Profile Studio, a server on port 8135 with three croppers: a circle avatar saved through OnCrop, a document scanner with the Black and white filter that keeps every scan in UploadFolder, and a 16:9 product cover posted with its form through FieldName. The design time, Lazarus and .NET versions mirror it.

Keep exploring

Try It OnlineSee it in the Image Cropper demo, running live on the eSeGeCe demo server.
Online HelpFull API reference and usage guide for this component.
File Upload ComponentA drag and drop upload zone that posts files as multipart form data.
Camera Scanner ComponentScan barcodes and QR codes with the camera of the device.
All sgcHTML ComponentsBrowse the full feature matrix of 80+ components.
Download Free TrialThe 30-day trial ships the 60.HTML demo projects.
PricingSingle, Team and Site licenses with full source code.
Best value: All-AccessEvery eSeGeCe product, Premium Support included, from €1,059/year.
See All-Access pricing

Ready to Get Started?

Download the free trial and start building web UIs in Delphi, C++ Builder and .NET.