vnbaaij / ImageProcessor.Web.Episerver

Integrate ImageProcessor into Episerver and use it in your views with a fluent API. For Editor integration do not use ImageProcessor.Web.Episerver.UI but instead use ImageProcessor.Web.Episerver.UI.Blocks. For more information see
http://world.episerver.com/blogs/vincent-baaij/dates/2017/10/episerver-and-imageprocessor-more-choice-for-developers-and-designers/
MIT License
20 stars 9 forks source link

Is this working on static assets? #4

Closed jonascarlbaum closed 6 years ago

jonascarlbaum commented 6 years ago

Hi, I'm just trying this one on a new EPi 11 site, just installed this package . I have an Azure asset storage previously setup. It's a new project where I haven't done much backend yet, so I have no pages (Except a startpage without properties) and no stored assets to work with — yet.

I'm setting things up for colleagues so that they can take my mockups and do most of the backend, but I want to make sure that things works as I intend. So I decided to test this nuget-package out with static assets from my mockup using plain querystring such as //static/logo.png?width=250&height=160&mode=crop.

This results in the original image (lets say 1920x1200) being served. Actually, at first it returned an broken link (an inner exception I guess), but when installing ImageProcessor.Web.Episerver.Azure I got the original image served at least.

Reading the two implementations of IImageService and the method GetImage I suspect (but I'm not sure) that static images get the result null, meaning no image processing will occur!?


Am I right in my assumptions or does it look like I have done something wrong?


Is there a way to include static assets into the processing pipeline? If so, is that something that you would consider adding?

jonascarlbaum commented 6 years ago

Added images as ContentReference now and using the HTML-helper-methods, things work just fine (even tested simple stuff as changing mode from max to crop in the URL works fine), when I went back to disk caching. So I'll stick to disk caching for now... ;)

However, I can now confirm that static images is not processed, only MediaData that the URL-lookup methods in IImageService.GetImage-implementations considers valid images to process.

vnbaaij commented 6 years ago

Hi, sorry to not answer sooner, but your conclusion is correct On Azure it only works for images coming from Episerver and not for static ones. I'll see if I can add that in a future version.

jonascarlbaum commented 6 years ago

Hi, thank you for your response!

So, if we have the Default Blob Provider (local storage), instead of the Azure Blob Provider, the static assets will work?

If so, that is good knowledge, since we don't know the production environment at the moment — it is to be decided — and we can assume we can fallback to static assets with resize parameters if we don't use Azure Blob Provider there.

vnbaaij commented 6 years ago

Sorry, no it will not work for static images. In the current setup the GetImage() method (both in local and Azure blob storage) the code relies on the EPiServer.Web.Routing.UrlResolver to route the url (in this case path/filename) to the corresponding IContent instance. Based on that IContent I get the bytes of the image to return either direct (local blob) or through a WebReponse.

jonascarlbaum commented 6 years ago

Guess something like this (pseudo/blind coded) won't work, since object id won't be the url?

        public async Task<byte[]> GetImage(object id)
        {
            var content = UrlResolver.Current.Route(new UrlBuilder((string)id));

            if (content != null && content.QueryDistinctAccess(AccessLevel.Read))
            {
                if (content is IBinaryStorable binary)
                    return await Task.FromResult(binary.BinaryData.ReadAllBytes());
            } else {
                    return await DownloadImageFromWebsiteAsync((string)id);
            }

            return null;
        }

        private async Task<byte[]> DownloadImageFromWebsiteAsync(string url)
        {
          try
          {
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
            using (WebResponse response = await request.GetResponseAsync())
            using (var result = new MemoryStream())
            {
              await imageStream.CopyToAsync(result);
              return result.ToArray();
            }
          }
          catch (WebException ex)
          {
            return null;
          }
        }
vnbaaij commented 6 years ago

I've been playing around a bit with this problem and I think I've solved a small part of it.

Because Episerver stores the media in blobs, it should not matter if it is local blob storage or Azure. As long as we use Episerver to get to the data of the image, the binary.BinaryData.ReadAllBytes() works for both. It turns out this is indeed the case, so we don't need the AzureImageService anymore! I tested this in my AlloyAzureSample site and this indeed seems to work as expected. Does it help for static files? Unfortunately not really, but it is a nice change nonetheless.

For static files, the ImageService needs to differentiate between Episerver blobs and local files. I got that part solved. The real problem comes with caching those processed static files. In the current situation the cache location is set to the folder where the blob is coming from. Obviously we don't have that folder with a static file, so where are we going to cache it? Suggestions welcome!

jonascarlbaum commented 6 years ago

Great to hear about the progress! 👍

I actually don't know about cache locations, why not keeping it simple but still unique? ~/App_Data/cache/static/example/com/path/to/my/image.png.mode-and-sizes-etc ? ;)

jonascarlbaum commented 6 years ago

Now I guess I misunderstood. Can't you create custom folders for the static files with unique identifiers based on URL and process-parameters?

vnbaaij commented 6 years ago

Yes, that might be an option. Will require a lot of code though. I also need to take into consideration the automatic cache trimmer that is part of the package. We need to remove items from the cache when they expire...