A critical vulnerability was discovered in React Server Components (Next.js). Our systems remain protected but we advise to update packages to newest version. Learn More

Anders Hattestad
Feb 25, 2011
  4533
(0 votes)

Scale image using a virtual path provider and DDS

Itera.Media is a module that uses a virtual path provider to save and serve scaled images. But it uses a file share to store the scaled images.

But after I have been a DDS geek, I ported this function to use the DDS as the store.

The concept is simple I hook up on all requests that starts with ~/ImageScaler/

for instance

/ImageScaler/Global/StartPage/cms6_headerEN.jpg/width_202.jpg

the rest of the path is the file I want to resize (Global/StartPage/cms6_headerEN.jpg),

and the filename is the parameters I want to resize with (width_202.jpg)

I wanted a provider that was just to add a dll into the bin folder, so I used a Virtual File Provider auto registration method

Code Snippet
  1. public class StartUp : PlugInAttribute
  2. {
  3.     public static void Start()
  4.     {
  5.         System.Diagnostics.Debug.Write("VppInitializerX Loading Itera.ImageScaleProvider VPP from: " + typeof(StartUp).Assembly.CodeBase);
  6.         Assembly lateBoundAssembly = System.Reflection.Assembly.LoadFrom(typeof(StartUp).Assembly.CodeBase);
  7.         HostingEnvironment.RegisterVirtualPathProvider(
  8.             (VirtualPathProvider)lateBoundAssembly.CreateInstance(
  9.                 "Itera.ImageScaleProvider.ImageScaler_Provider"
  10.             )
  11.         );
  12.     }
  13. }

The actually method that returns the stream looks like this

Code Snippet
  1. public override System.IO.Stream Open()
  2. {
  3.     string orgFilePath = "";
  4.     string parameters = "";
  5.     SplitIntoOrgAndParameters(ref orgFilePath, ref parameters);
  6.  
  7.     var orgFil = System.Web.Hosting.HostingEnvironment.VirtualPathProvider.GetFile(orgFilePath) as UnifiedFile;
  8.     if (orgFil == null)
  9.         return null;
  10.     RedirectToLoginIfNotAllowed(orgFil);
  11.  
  12.     var dbFile = ScaledImages.GetCreate(virtualPath.ToLower());
  13.     Stream stream = new MemoryStream();
  14.     if (dbFile.Created == DateTime.MinValue || orgFil.Changed> dbFile.Created)
  15.     {
  16.         CreateImage(orgFilePath, parameters, orgFil, dbFile, stream);
  17.     }
  18.     else
  19.     {
  20.         stream.Write(dbFile.ImageData, 0, dbFile.ImageData.Length);
  21.         stream.Seek(0, SeekOrigin.Begin);
  22.     }
  23.     return stream;
  24. }

First I find the original file, and try to load it.If it exists I check the ACL to ensure that none can access a restricted file.

Then I check the Dynamic Data Store table to check if the images exists there, and is newer than the original image.

The images is stored in a DDS table that looks like this. The image is stored as a byte[] array

Code Snippet
  1. class ScaledImages : IDynamicData
  2. {
  3.     public EPiServer.Data.Identity Id { get; set; }
  4.     public string RequestUrl { get; set; }
  5.     public DateTime Created { get; set; }
  6.     public byte[] ImageData { get; set; }
  7.     public double TimeUsedCreating { get; set; }
  8.     public static  ScaledImages GetCreate(string requestUrl)
  9.     {
  10.         var query = from item in Items where item.RequestUrl == requestUrl select item;
  11.         var result = new ScaledImages() { RequestUrl = requestUrl };
  12.         foreach (var item in query)
  13.         {
  14.             result = item;
  15.         }
  16.         return result;
  17.     }
  18.     public static IOrderedQueryable<ScaledImages> Items
  19.     {
  20.         get
  21.         {
  22.             return Store.Items<ScaledImages>();
  23.         }
  24.     }
  25.     public static DynamicDataStore Store
  26.     {
  27.         get
  28.         {
  29.                 
  30.             return DynamicDataStoreFactory.Instance.GetStore(typeof(ScaledImages)) ?? DynamicDataStoreFactory.Instance.CreateStore(typeof(ScaledImages));
  31.         }
  32.     }
  33. }

So I can access the resized files using some of these filename

/ImageScaler/Global/StartPage/cms6_headerEN.jpg/

width_200.jpg

width_200.height_200.color_black.mode_FillArea.jpg

width_200.height_200.color_black.mode_FillAreaWithCrop.jpg

width_200.height_200.color_black.mode_MaxWidthOrHeight.jpg

width_200.height_200.color_black.mode_FillAreaWithCrop.pos_Left.jpg

The resize code, is some old code my brother made, but it works :)

The DDS looks like this

image

And are logging time used created, so its easy to find problems at a later stage.

There is only one drawback. The Virtual Path is added to the web site, and it works, but for some strange reason I get this error

image

If I add this to web.config

Code Snippet
  1. <location path="ImageScaler">
  2.   <system.webServer>
  3.     <handlers>
  4.       <clear />
  5.       <add name="wildcard" path="*" verb="*" type="EPiServer.Web.StaticFileHandler, EPiServer" />
  6.     </handlers>
  7.   </system.webServer>
  8. </location>

it works.

So I have to add stuff in web.config, until I can sort out why I get the error.

Full code is here

Feb 25, 2011

Comments

Please login to comment.
Latest blogs
A day in the life of an Optimizely OMVP: Learning Optimizely Just Got Easier: Introducing the Optimizely Learning Centre

On the back of my last post about the Opti Graph Learning Centre, I am now happy to announce a revamped interactive learning platform that makes...

Graham Carr | Jan 31, 2026

Scheduled job for deleting content types and all related content

In my previous blog post which was about getting an overview of your sites content https://world.optimizely.com/blogs/Per-Nergard/Dates/2026/1/sche...

Per Nergård (MVP) | Jan 30, 2026

Working With Applications in Optimizely CMS 13

💡 Note:  The following content has been written based on Optimizely CMS 13 Preview 2 and may not accurately reflect the final release version. As...

Mark Stott | Jan 30, 2026

Experimentation at Speed Using Optimizely Opal and Web Experimentation

If you are working in experimentation, you will know that speed matters. The quicker you can go from idea to implementation, the faster you can...

Minesh Shah (Netcel) | Jan 30, 2026

How to run Optimizely CMS on VS Code Dev Containers

VS Code Dev Containers is an extension that allows you to use a Docker container as a full-featured development environment. Instead of installing...

Daniel Halse | Jan 30, 2026

A day in the life of an Optimizely OMVP: Introducing Optimizely Graph Learning Centre Beta: Master GraphQL for Content Delivery

GraphQL is transforming how developers query and deliver content from Optimizely CMS. But let's be honest—there's a learning curve. Between...

Graham Carr | Jan 30, 2026