HomeDev GuideAPI Reference
Dev GuideAPI ReferenceUser GuidesLegal TermsDev CommunityOptimizely AcademySubmit a ticketLog In
Dev Guide

Image resizing using CDN

The CDN’s image resizing feature lets you optimize and transform images on the fly by appending parameters to the image's URL. You can resize, crop, rotate, adjust quality, and apply filters to images without having to store multiple versions of the same image on your server. This can improve the performance and user experience of your website or application.

Use Cloudflare's image resizing feature and the URL format

To use Cloudflare's image resizing feature, you need to append parameters to the image URL using the following:

https://<DOMAIN>/cdn-cgi/image/<OPTIONS>/<SOURCE-IMAGE>

  • <DOMAIN> – The domain on Optimizely, such as www.domain.com.
  • /cdn-cgi/image/ – A fixed prefix that identifies that this is a special path handled by the image resizing feature.
  • <OPTIONS> – A comma-separated list of options such as width, height, and quality.
  • <SOURCE-IMAGE> – An absolute path on the origin server, pointing to an image to resize, such as globalassets/image.png.

📘

Note

You cannot resize images from a third-party domain.

The following example shows a URL with <OPTIONS> set to width=80,quality=75 and a <SOURCE-IMAGE> of uploads/avatar1.jpg:

<img src="/cdn-cgi/image/width=80,quality=75/uploads/avatar1.jpg" />

You must specify at least one of the following options:

  • anim – Preserve animation frames from input files. By default, set to true. Set to false to reduce animations to still images.

  • background – Background color to add underneath the image. This applies to images with transparency (such as PNG) and images resized with fit=pad. Accepts any CSS color, such as #RRGGBB and rgba(…).

  • blur – Blur factor between 1 (slight blur) and 250 (maximum).

    📘

    Note

    You cannot use this option to reliably obscure image content because users can modify an image's URL and remove the blur option.

  • brightness – Increase brightness by a factor.

    • 1.0 – No change
    • 0.5 – Half brightness
    • 2.0 – Twice as bright
    • 0 – Ignored
  • contrast – Increase contrast by a factor.

    • 1.0 – No change
    • 0.5 – Low contrast
    • 2.0 – High contrast
    • 0 – Ignored
  • Device Pixel Ratio – Multiplier for width or height that makes it easier to specify higher-DPI sizes in <img srcset>. The default is 1.

  • fit – Affects interpretation of width and height. All resizing modes preserve the aspect ratio. Available modes are the following:

    • contain – Resizes (shrinks or enlarges) to be as large as possible within the given width or height while preserving the aspect ratio. If you only provide a single dimension (for example, only width), the image is shrunk or enlarged to match that dimension.

    • cover – Resizes (shrinks or enlarges) to fill the entire area of width and height. If the image has an aspect ratio different from the ratio of width and height, it is cropped to fit.

    • crop – Crops to fit within the area specified by width and height. The image is not enlarged. For images smaller than the given dimensions, it is the same as scale-down. For images larger than the given dimensions, it is the same as cover.

    • Format – The automatic option serves the WebP or AVIF format to browsers that support it. If this option is not specified, a standard format like JPEG or PNG is used. Image resizing defaults to JPEG when possible due to the large size of PNG files. Available modes are the following:

      • avif – Generates images in AVIF format if possible (with WebP as a fallback).
      • webp – Generates images in WebP format. Set the quality to 100 to get the WebP lossless format.
      • jpeg – Generates images in interlaced progressive JPEG format, in which data is compressed in multiple passes of progressively higher detail.
      • baseline-jpeg – Generate images in baseline sequential JPEG format. It should be used in cases when target devices do not support progressive JPEG or other modern file formats.
      • json – Instead of generating an image, outputs information about the image in JSON format. The JSON object will contain data such as image size (before and after resizing), source image’s MIME type, and file size.
    • gamma – Increase exposure by a factor.

      • 1.0 – No change
      • 0.5 – Darkens the image
      • 2.0 – Lightens the image
      • 0 – Ignored
    • gravity – If you crop with fit: "cover" and fit: "crop", this parameter defines the side or point that should not be cropped. Available modes are the following:

      • auto – Selects focal point based on saliency detection (using maximum symmetric surround algorithm).
      • side – A side ("left", "right", "top", "bottom") or coordinates specified on a scale.
        • 0.0 – Top or left
        • 1.0 – Bottom or right
        • 0.5 – Center
          The X and Y coordinates are separated by lowercase x in the URL format. For example, 0x1 means left and bottom, 0.5x0.5 is the center, 0.5x0.33 is a point in the top third of the image.
    • height – Specifies the maximum height of the image in pixels. The exact behavior depends on the fit mode. For example, height=250 (or h=250).

    • onerror=redirect – If a fatal error prevents the image from being resized, this redirects to the un-resized source image URL. This may be useful if some images require user authentication and cannot be fetched anonymously. This option should not be used if there is a chance the source image is large.

    • pad – Resizes to the maximum size that fits within the given width and height and then fills the remaining area with a background color (white by default).

      📘

      Note

      You should not us this mode because you can achieve the same effect more efficiently with the contain mode and the CSS object-fit: contain property.

    • quality – Specifies the quality for images in JPEG, WebP, and AVIF formats. The quality is on a 1 to 100 scale, but useful values are between 50 (low quality, small file size) and 90 (high quality, large file size). 85 is the default.

    • rotate – Number of degrees (90, 180, or 270) to rotate the image by. Width and height options refer to axes after rotation. For example, rotate=90.

    • scale-down – Similar to contain, but the image is never enlarged. It is resized if the image is larger than the given width or height. Otherwise, its original size is kept.

    • sharpen – Specifies strength of sharpening filter to apply to the image. The value is a floating-point number between 0 (no sharpening, default) and 10 (maximum). 1 is a recommended value for downscaled images.

    • trim – Specifies a number of pixels to cut off on each side. This lets you remove borders or cut out a specific fragment of an image. Trimming is performed before resizing or rotation and takes dpr into account. For image transformations and Cloudflare Images, use as four numbers in pixels separated by a semicolon, in the form of top;right;bottom;left or through separate values trim.width,trim.height, trim.left,trim.top as shown in the following:

      • trim:20;30;20;0
      • trim.width=678
      • trim.height=678
      • trim.left=30
      • trim.top=40
    • width – Specifies the maximum width of the image in pixels. The exact behavior depends on the fit mode (described below). For example, width=250 (or w=250).

Resizing causes the original image to be fetched from the origin server and cached, following the usual rules of HTTP caching, Cache-Control header, and so on. Requests for multiple different image sizes are likely to reuse the cached original image without causing extra transfers from the origin server.

Resized images follow the same caching rules as the original image they were resized from, except the minimum cache time is one hour. If you need images to be updated more frequently, add must-revalidate to the Cache-Control header. Resizing supports cache revalidation, so you should serve images with the Etag header.

Use tag helpers in .NET to resize images responsively

You can leverage .NET and image resizing to responsively render images depending on the user’s viewport size, commonly referred to as responsive images. This approach assumes you upload the highest-quality image available. Image resizing then handles dynamically resizing and serving the appropriate version and quality to the end user.

The following example shows what the image tag might look like in an HTML source:

<img
  sizes="(min-width: 1440) 620px, (min-width: 1280px) calc(50vm - 100px),
         (min-width: 1024px) calc(50vw - 60px), 
         (min-width: 768px) calc(50vm - 30px), calc(100vm - 40px)"
  alt="Netcel Employees"
  src="/globassets/about/about-intro-people-collage-4.jpg?width=1024"
  srcset="
    /globassets/about/about-intro-people-collage-4.jpg?width=280   280w,
	  /globassets/about/about-intro-people-collage-4.jpg?width=550   550w,
	  /globassets/about/about-intro-people-collage-4.jpg?width=768   768w,
	  /globassets/about/about-intro-people-collage-4.jpg?width=830   830w,
	  /globassets/about/about-intro-people-collage-4.jpg?width=1024 1024w,
	  /globassets/about/about-intro-people-collage-4.jpg?width=1100 1100w,
	  /globassets/about/about-intro-people-collage-4.jpg?width=1536 1536w,
	  /globassets/about/about-intro-people-collage-4.jpg?width=1650 1650w,
	  /globassets/about/about-intro-people-collage-4.jpg?width=2304 2304w,
	  /globassets/about/about-intro-people-collage-4.jpg?width=2490 2940w,
	  /globassets/about/about-intro-people-collage-4.jpg?width=3840 3840w,
	  /globassets/about/about-intro-people-collage-4.jpg?width=5760 5760w
  "
  loading="lazy"
  width="2232"
  height="2240"
/>  

In this example, the image file about-intro-people-collage-4.jpg represents the original high-quality image. The srcset attribute complements the sizes attribute by specifying various image options with their corresponding widths. Together, these attributes determine the appropriate sizes of the image for different viewport widths, display pixel density, and layout.

  • Small viewport – 320 pixels width
  • Medium viewport – 768 pixels width
  • Large viewport – 1200 pixels width

To manage this through code and attribute Image Content References with the Width and Sizes. attributes are simple, and the follwoing is an example of an image on a promo block:

[Display(
  Name = "Image",
  Description = "Image",
  GroupName = TabsGroups.Content,
  Order = 100)]
[CultureSpecific]
[UIHint(UIHint.Image)]
[ImageSize(Width = 210)]
[ImageSize(Width = 280)]
[ImageSize(Width = 335)]
[ImageSize(Width = 420)]
[ImageSize(Width = 452)]
[ImageSize(Width = 526)]
[ImageSize(Width = 550, IsDefault = true)]
[ImageSize(Width = 560)]
[ImageSize(Width = 630)]
[ImageSize(Width = 670)]
[ImageSize(Width = 840)]
[ImageSize(Width = 904)]
[ImageSize(Width = 1005)]
[ImageSize(Width = 1052)]
[ImageSize(Width = 1100)]
[ImageSize(Width = 1356)]
[ImageSize(Width = 1578)]
[ImageSize(Width = 1650)]
[ImageSizes(Sizes = "(min-width: 1280px) 550px, (min-width: 1024px) calc(100vw - 120px) / 2, (min-width: 768px) calc(100vw - 80px) / 2, calc(100vw - 40px)")]
[Required]

public virtual ContentReference PromoImage{ 
  get; 
  set; 
}

You can then leverage a simple tag helper to read these attributes and generate the image tag.

📘

Note

Image resizing with the CDN only works when routing through the CDN and not locally, and not while in the CMS admin UI. Images do not resize in these scenarios.

[HtmlTargetElement("img", Attributes = "image-for")]
public class EdgeImageTagHelper: TagHelper {
  private readonly IUrlResolver _urlResolver;
  private readonly IContentLoaderService _contentLoader;
  private readonly IWebHostEnvironment _webHostEnvironment;
  public ModelExpression ImageFor {
    get;
    set;
  }
  public string CssClass {
    get;
    set;
  }
  public string Fit {
    get;
    set;
  }

  public EdgeImageTagHelper(IUrlResolver urlResolver, IContentLoaderService contentLoader, IWebHostEnvironment webHostEnvironment) {
    _urlResolver = urlResolver;
    _contentLoader = contentLoader;
    _webHostEnvironment = webHostEnvironment;
  }

  public override void Process(TagHelperContext context, TagHelperOutput output) {
    if (ImageFor.Model is not ContentReference edgeImage) return;
    if (ContentReference.IsNullOrEmpty(edgeImage)) return;
    if (!_contentLoader.TryGet(edgeImage, out ImageFile imageFile)) return;

    var actualUrl = _urlResolver.GetUrl(edgeImage);
    var property = ImageFor
      .Metadata
      .ContainerType
      .GetProperties()
      .FirstOrDefault(x => x.Name == ImageFor.Metadata.PropertyName);

    if (property == null) {
      RenderNonResponsiveImage(output, actualUrl);
      return;
    }

    var shouldSkipEdgeResizing = _webHostEnvironment.IsDevelopment() || _contentLoader.IsContentInEditMode;
    var imageSize = property.GetCustomAttributes < ImageSizeAttribute > ().ToList();
    var imageSizes = property.GetCustomAttribute < ImageSizesAttribute > ();

    var defaultImageSize = imageSize.FirstOrDefault(x => x.IsDefault);
    if (defaultImageSize == null) {
      RenderNonResponsiveImage(output, actualUrl);
      return;
    }

    var srcSetUrls = imageSize
      .OrderBy(x => x.Width)
      .Select(s => GetEdgeUrl(actualUrl, s.Width, shouldSkipEdgeResizing)).ToList();

    SetAttribute(output, "src", GetEdgeUrl(actualUrl, defaultImageSize.Width, shouldSkipEdgeResizing, true));
    SetAttribute(output, "srcset", string.Join(",", srcSetUrls));
    if (imageSizes != null) SetAttribute(output, "sizes", imageSizes.Sizes);
    SetAttribute(output, "alt", imageFile.AlternativeText);
    SetAttribute(output, "loading", "lazy");
    SetAttribute(output, "decoding", "auto");
    SetAttribute(output, "fetchpriority", "auto");
    SetAttribute(output, "class", CssClass);

    if (imageFile is not IHasPixelSize pixelSize) return;

    if (pixelSize.Width > 0) {
      SetAttribute(output, "width", pixelSize.Width.ToString());
    }

    if (pixelSize.Height > 0) {
      SetAttribute(output, "height", pixelSize.Height.ToString());
    }
  }

  private void RenderNonResponsiveImage(TagHelperOutput output, string url) {
    SetAttribute(output, "src", url);
    SetAttribute(output, "class", CssClass);
  }

  private string GetEdgeUrl(string actualUrl, int width, bool isLocal, bool isDefault = false) {
    if (!isLocal) {
      return isDefault ?
        $ "/cdn-cgi/image/{GetEdgeImageOptions(width)}{actualUrl}" :
        $ "/cdn-cgi/image/{GetEdgeImageOptions(width)}{actualUrl} {width}w";
    } else {
      return isDefault ?
        $ "{actualUrl}?{GetLocalImageOptions(width)}" :
        $ "{actualUrl}?{GetLocalImageOptions(width)} {width}w";
    }
  }

  private string GetLocalImageOptions(int width) {
    var options = $ "width={width}";
    if (!string.IsNullOrWhiteSpace(Fit)) {
      options += $ "&fit={Fit}";
    }

    return options;
  }

  private string GetEdgeImageOptions(int width) {
    var options = string.Empty;
    if (!string.IsNullOrWhiteSpace(Fit)) {
      options = $ "fit={Fit},";
    }

    options += $ "width={width}";
    return options;
  }

  private void SetAttribute(TagHelperOutput output, string key, string value) {
    if (!string.IsNullOrWhiteSpace(value)) {
      output.Attributes.SetAttribute(key, value);
    }
  }
}
}

To use the tag helper in the Razor view, do the following:

<div class="image" @Html.EditAttributes(x=>x.PromoImage)>
  <img image-for="@Model.PromoImage" css-class="promoBlockImage" fit="cover" FlexibleAttribute="Goes Here"/>
</div>

Related articles