Image handling · v5.3

AJAX image upload for ASP.NET Web Forms.

Pick a photo and it uploads immediately — no postback, no page reload, a thumbnail and a progress bar while it goes. The image is previewed, resized, rotated upright and optionally cropped in the browser, so a 6 MB phone photo arrives as a few hundred kilobytes.

v5.3 ships a content-aware image editor: focal-point smart-crop (edge-energy heuristic, no AI), draggable text and sticker overlays, brightness/contrast/saturation filter presets, an EXIF info panel, crop-ratio quick-pick chips, and AVIF/WebP output with a quality slider - plus EXIF auto-rotate on upload, PDF poster thumbnails, HEIC decode, and presets, all before a byte leaves the browser.

The smallest version that works

Two files. The control renders its own AJAX transport, so there is no UpdatePanel, no <form enctype> change and no handler to register — dropping the tag on the page is the whole client side:

<%@ Register Assembly="AjaxUploader" Namespace="AjaxUploader.Controls" TagPrefix="au" %>

<au:AjaxFileUpload ID="Uploader1" runat="server"
                   AllowMultiple="true"
                   AllowedFileExtensions=".jpg,.jpeg,.png,.gif,.webp"
                   ShowThumbnails="true"
                   ImageResize="true" ResizeMaxWidth="1600" ResizeMaxHeight="1600"
                   AutoOrient="true"
                   OnFileUploaded="Uploader1_FileUploaded" />

The upload has already finished by the time your code runs. The file is held under a GUID, and you decide where it lands:

protected void Uploader1_FileUploaded(object sender, FileUploadedEventArgs e)
{
    var destination = Server.MapPath("~/uploads/" + e.FileName);
    new UploadService().CopyFile(e.FileGuid, destination);

    // e.FileName, e.FileSize, e.ContentType and e.RelativePath
    // describe what just arrived - use MoveFile instead of CopyFile
    // if you do not want the temporary copy kept.
}

That is a working AJAX image upload: multi-select, per-file thumbnails, a progress bar, browser-side downscaling and upright photos. Everything below is refinement on top of it.

Why AJAX matters more for images than for other files

A classic <asp:FileUpload> posts the whole form back. For images that is the worst case on both ends: the user stares at a frozen page with no progress while several megabytes of camera-roll JPEG travel, and the page they were filling in is thrown away and rebuilt on return.

Uploading over AJAX changes three things that only matter once files are large:

  • The page survives. No postback, so form state, scroll position and anything else the user typed stay exactly where they were.
  • Progress is real. The transfer is a request you can observe, so a per-file progress bar reflects bytes actually sent rather than a spinner.
  • The bytes shrink first. Because the file is read in the browser before it is sent, it can be downscaled and re-encoded on the way out — which a form post cannot do at all.

That last one is the big one. A 6 MB photo bounded to 1600 px is usually 200-400 KB, so it never reaches IIS at full size, never counts against maxRequestLength, and costs a fraction of the bandwidth — on a phone connection the difference is often the difference between an upload that completes and one that times out. See the full comparison with <asp:FileUpload>.

Shrink images before they are uploaded

A phone photo is often 4-8 MB. Resizing in the browser means that is never transferred, never buffered by IIS, and never counted against maxRequestLength. Set ImageResize="true" and give it a bound:

<au:AjaxFileUpload ID="Uploader1" runat="server" AllowMultiple="true"
                   ImageResize="true"
                   ResizeMaxWidth="1600" ResizeMaxHeight="1600"
                   ResizeQuality="0.82" ResizeFormat="image/webp"
                   OnFileUploaded="Uploader1_FileUploaded" />

Aspect ratio is preserved - the two maximums are a bounding box, not a target size. ResizeFormat is optional; leave it off to keep the original format. EnableImageResize is a compatibility alias for the same switch.

Reject the wrong images before the upload starts

Dimension rules are evaluated in the browser, so a too-small logo or an enormous scan is refused without a round trip. Turn the check on with EnableImageDimensions and set whichever bounds matter:

PropertyDefaultPurpose
ShowThumbnailstruePreview each image in the queue before upload.
EnableImageDimensionsfalseEnables the Min/Max width and height checks below.
MinWidth / MinHeight0Floor, in pixels. 0 means no floor.
MaxWidth / MaxHeight0Ceiling, in pixels. 0 means no ceiling.
AutoOrientfalseRotate photos upright from their EXIF orientation tag. EnableExifOrient is an alias.

Client-side rules are a convenience, not a security boundary - the server re-checks every upload on arrival. See Securing uploads.

Getting the image in

Browse and drag-and-drop are not the only routes. A screenshot is already on the clipboard, so Ctrl+V paste skips saving it to disk first — the uploader names the pasted image from its timestamp and treats it like any other file. Everything on this page applies to a pasted image too.

Cropping

Crop="true" opens the interactive editor before upload; CropAspectRatio locks the box to a ratio - "1" for a square avatar, "16/9" for a banner. Leave it empty for a free crop. EnableImageCrop is an alias for Crop.

Working demos