Resource limits

edit

A small file can describe a huge image: a few kilobytes of PNG can declare a canvas of billions of pixels, and a GIF can hold thousands of frames. Resource limits bound what decoding, processing and encoding may cost, and fail with an ImageResourceLimitException before the library allocates the memory or reads the input. The defaults suit trusted files; lower them for files that come from users.

Set stricter limits

Put the limits in an ImageConfiguration and pass it to the load:

public static Image LoadAvatar(Stream upload)
{
    // Create the configuration once and share it: it is immutable and thread-safe
    var configuration = new ImageConfiguration
    {
        Limits = new ImageResourceLimits
        {
            MaxEncodedBytes = 10 * 1024 * 1024, // 10 MiB of input
            MaxWidth = 4096,
            MaxHeight = 4096,
            MaxFramePixels = 16_000_000,
            MaxFrames = 100,
        },
    };

    // An input over a limit throws ImageResourceLimitException before the memory is allocated.
    // The image keeps the configuration: its later operations are bound by the same limits
    return Image.Load(upload, new ImageDecodeOptions { Configuration = configuration });
}

An image keeps the configuration it was created or loaded with, and its later operations use it: a resize of this image to more than 4,096 pixels wide throws too. The configuration and the limits are immutable, so one instance can be shared by every thread.

The configuration is accepted wherever an image or an input is created: ImageDecodeOptions, ImageIdentifyOptions, ImageReaderOptions, ImageWriterOptions, the constructors of Image<TPixel>, ImportPixelData, ImportPixelBytes, and ImageCollection.Create and Load. Without one, ImageConfiguration.Default applies.

The limits

LimitDefaultBounds
MaxWidth, MaxHeight32,768The width and the height of the canvas, in pixels
MaxFramePixels100,000,000The pixels of one frame
MaxFrames1,000The frames of one input, a poster frame included, and of an image
MaxTotalPixels1,000,000,000The pixels of all the frames decoded from one input
MaxEncodedBytes256 MiBThe bytes read from one input
MaxMetadataBytes16 MiBThe metadata of one input (profiles, EXIF, XMP, text), once decompressed
MaxLiveAllocationBytes512 MiBThe memory of an image, or of a reader and the images it returns

The constants ImageResourceLimits.DefaultMaxDimension, DefaultMaxFramePixels, … hold the defaults. The other limits of ImageResourceLimits (MaxFontBytes, MaxFontCollectionFaces, MaxGlyphComplexity, MaxTextLength, MaxTextGlyphs, MaxTextLines) bound fonts and text layouts: see Fonts.

  • A limit is inclusive: a value equal to the limit is accepted.
  • Every limit must be positive; zero does not mean "unlimited". To lift a limit, set it to the largest value of its type (int.MaxValue or long.MaxValue).
  • MaxLiveAllocationBytes bounds each owner separately. It is a safety bound, not a cap on the memory of the process: bound the number of images you process at once too.
  • For forward-only parsing, MaxEncodedBytes equal to the input length is enough; a header-only identification or FrameLimit may stop before that many bytes are examined.
  • TIFF, ICO, CUR and ANI loads from a synchronous path or seekable stream charge the cumulative bytes read, including repeated reads of the same range. They can succeed with a limit below the input length or require more than that length. Span, non-seekable and asynchronous loads instead parse the whole input in memory and charge its length once, so the input length is exactly enough for this limit.

When a limit is exceeded

The exception tells which limit failed:

PropertyValue
KindThe limit, such as ImageResourceLimitKind.Width or ImageResourceLimitKind.EncodedBytes
LimitThe configured value
RequestedThe value the input or the operation asked for, when it is known

A limit failure is never turned into a partial result: the load returns no image, and a geometry change leaves the image unchanged. See Handling errors.

Limits are not a way to select frames

To decode only the first frames of an animation, use ImageDecodeOptions.FrameLimit (or ImageReaderOptions.FrameLimit), not MaxFrames. FrameLimit is a choice: decoding stops cleanly after that many frames, and the rest of the input is neither examined nor validated. MaxFrames is a safety bound: an input that needs more frames fails. See Loading images.

Untrusted input

For files that come from users:

Process untrusted uploads puts these together.