-
Notifications
You must be signed in to change notification settings - Fork 64
Image Processing and Storage extension points
This article is written in response to a good question by Diego Martin. Rather than answer directly on that issue I thought it would be better to write documentation that will be easier to find.
When using the web page to create or edit content, images are converted to base64 strings within the content and are posted to the server as part of the content. Base64 strings are very large especially for large images so while this is a convenient method for getting the images to the server, we don't want to just keep them as embedded strings within the content. On the server the strings are extracted from the content, converted to actual image files and then the content is updated to have urls linking to the files instead of having embedded base64 strings. At the time of this writing there is no built in support for resizing or optimizing images uploaded this way, but we do have plans to implement that in the future, probably using the ImageProcessor library. For now it is best to optimize images yourself before adding them to the content.
When creating or editing content using Open Live Writer, images are posted to the metawebloag api which is an xml/rpc style service. OLW lets you resize images within its content editor and it posts them to the server individually and it gets back a response with the url of the file. OLW actually uploads 2 images, the resized one and the original and then in the content it makes the resized one link to the original full size image. As a side note the only thing I don't like is that OLW also puts some hard coded styles on the img elements which prevents the images from being automatically scaled to the screen size by javascript that would otherwise do so. With OLW, the images are uploaded separately then the post is updated with the urls returned by the service before the post itself is then posted to the server for storage.
The handling of images can be customized by implementing your own version of IMediaProcessor. You would add your own implementation to DI services to replace the built in FileSystemMediaProcessor. There are just 4 methods to implement IMediaProcessor:
public interface IMediaProcessor
{
Task<string> ResolveMediaUrl(string mediaVirtualPath, string fileName);
Task ConvertBase64EmbeddedImagesToFilesWithUrls(string mediaVirtualPath, IPost post);
Task ConvertBase64EmbeddedImagesToFilesWithUrls(string mediaVirtualPath, IPage page);
Task SaveMedia(string mediaVirtualPath, string fileName, byte[] bytes);
}
The mediaVirtualPath that is passed into these methods would be like a relative file system url, so in the FileSystemMediaProcessor the ResolveMediaUrl method simply combines that with the file name. If implementing some other kind of storage you could discard that or store it as part of a key or meta data for retrieving the file that might be useful if your storage is hierarchical.
The important thing is that you are able to return a valid url to the file from the ResolveMediaUrl method which is called by OLW after it uploads an image so that it can create the url to the image within the content. So, OLW would call SaveMedia to upload the file you would store it somewhere and then it will immediately call ResolveMediaUrl to get the url of the file it just uploaded.
The other methods are for handling images within the content posted from the web page for blog Posts and Pages respectively. Your job is to extract the images from base64, converting to bytes, storing the resulting file in your storage and updating the content to remove the base64 strings and replace them with valid urls to the image storage.
This is not a perfect architecture for handling images, especially if you want to use some kind of blob storage like Azure or AWS. In a perfect world images would be uploaded directly to blob storage, but in this case the images are first uploaded to the web server and then from there you would have to upload again to the remote storage. Given the nature of the mechanisms used, there is no easy way around that that I can think of, but there are some possible ways.
OLW only knows how to talk to Xml/Rpc so we don't have any option from within SimpleContent to change it's behavior. It is possible to write plugins for OLW though so maybe you or someone else could write a plugin to make OLW directly upload files to some blob storage service getting back an url to the file that it can then use within the content.
To directly upload images to some remote storage from the web editor would require implementing a custom editor and related views instead of using the default editor that just embeds the images directly as base64. Maybe a custom toolbar item could be built into the editor toolbar to upload to a remote storage and insert a link to the image instead.
If you implement something along these lines please let us know and share the love!