protected override Task ProcessImageAsync(MediaHandlerContext context, CachedImage cachedImage, Stream inputStream) { var processQuery = new ProcessImageQuery(context.ImageQuery) { Source = inputStream, Format = context.ImageQuery.Format ?? cachedImage.Extension, FileName = cachedImage.FileName, DisposeSource = false }; using (var result = _imageProcessor.ProcessImage(processQuery, false)) { Logger.DebugFormat($"Processed image '{cachedImage.FileName}' in {result.ProcessTimeMs} ms.", null); if (!cachedImage.Extension.IsCaseInsensitiveEqual(result.FileExtension)) { // jpg <> jpeg cachedImage.Path = Path.ChangeExtension(cachedImage.Path, result.FileExtension); cachedImage.Extension = result.FileExtension; } context.ResultStream = result.OutputStream; } return(Task.FromResult(0)); }
public ImageQueryCreatedEvent(ProcessImageQuery query, HttpContextBase httpContext, string mimeType, string extension) { Query = query; HttpContext = httpContext; MimeType = mimeType; Extension = extension; }
private void ValidateQuery(ProcessImageQuery query) { if (query.Source == null) { throw new ArgumentException("During image processing 'ProcessImageQuery.Source' must not be null.", nameof(query)); } }
/// <summary> /// Processes the loaded image. Inheritors should NOT save the image, this is done by the main method. /// </summary> /// <param name="query">Query</param> /// <param name="image">Processor instance</param> /// <param name="fxApplied"> /// Should be true if any effect has been applied that potentially changes the image visually (like background color, contrast, sharpness etc.). /// Resize and compression quality does NOT count as FX. /// </param> protected virtual void ProcessImageCore(ProcessImageQuery query, Image image, out bool fxApplied) { bool fxAppliedPrivate = false; // Resize var size = query.MaxWidth != null || query.MaxHeight != null ? new Size(query.MaxWidth ?? 0, query.MaxHeight ?? 0) : Size.Empty; image.Mutate(x => { if (!size.IsEmpty && (image.Width > size.Width || image.Height > size.Height)) { //image.Resize(new ResizeLayer( // size, // resizeMode: ConvertScaleMode(query.ScaleMode), // anchorPosition: ConvertAnchorPosition(query.AnchorPosition), // upscale: false)); x.Resize(new ResizeOptions { Size = size, Mode = ConvertScaleMode(query.ScaleMode), Position = ConvertAnchorPosition(query.AnchorPosition) }); } if (query.BackgroundColor.HasValue()) { x.BackgroundColor(Color.ParseHex(query.BackgroundColor)); fxAppliedPrivate = true; } }); //// Format //if (query.Format != null) //{ // var format = query.Format as IImageFormat; // if (format == null && query.Format is string) // { // var requestedFormat = ((string)query.Format).ToLowerInvariant(); // format = ImageSharpConfig.Default.ImageFormatsManager.FindFormatByFileExtension(requestedFormat); // } // if (format != null) // { // image.Format(format); // } //} //// Set Quality //if (query.Quality.HasValue) //{ // image.Quality(query.Quality.Value); //} fxApplied = fxAppliedPrivate; }
/// <summary> /// Processes the loaded image. Inheritors should NOT save the image, this is done by the main method. /// </summary> /// <param name="query">Query</param> /// <param name="processor">Processor instance</param> protected virtual void ProcessImageCore(ProcessImageQuery query, ImageFactory processor) { // Resize var size = query.MaxWidth != null || query.MaxHeight != null ? new Size(query.MaxWidth ?? 0, query.MaxHeight ?? 0) : Size.Empty; if (!size.IsEmpty) { processor.Resize(new ResizeLayer( size, resizeMode: ConvertScaleMode(query.ScaleMode), anchorPosition: ConvertAnchorPosition(query.AnchorPosition), upscale: false)); } if (query.BackgroundColor.HasValue()) { processor.BackgroundColor(ColorTranslator.FromHtml(query.BackgroundColor)); } // Format if (query.Format != null) { var format = query.Format as ISupportedImageFormat; if (format == null && query.Format is string) { var requestedFormat = ((string)query.Format).ToLowerInvariant(); switch (requestedFormat) { case "jpg": case "jpeg": format = new JpegFormat(); break; case "png": format = new PngFormat(); break; case "gif": format = new GifFormat(); break; } } if (format != null) { processor.Format(format); } } // Set Quality if (query.Quality.HasValue) { processor.Quality(query.Quality.Value); } }
public ProcessImageQuery(ProcessImageQuery query) : base(SanitizeCollection(query)) { Guard.NotNull(query, nameof(query)); Source = query.Source; Format = query.Format; DisposeSource = query.DisposeSource; }
public virtual string GenerateUrl( MediaFileInfo file, ProcessImageQuery imageQuery, string host = null, bool doFallback = true) { string path; // Build virtual path with pattern "media/{id}/{album}/{dir}/{NameWithExt}" if (file?.Path != null) { path = _processedImagesRootPath + file.Id.ToString(CultureInfo.InvariantCulture) + "/" + file.Path; } else if (doFallback) { path = _processedImagesRootPath + "0/" + _fallbackImageFileName; } else { return(null); } if (host == null) { host = _host; } else if (host == string.Empty) { host = _appPath; } else { host = host.EnsureEndsWith("/"); } var url = host; // Strip leading "/", the host/apppath has this already if (path[0] == '/') { path = path.Substring(1); } // Append media path url += path; // Append query var query = imageQuery?.ToString(false); if (query != null && query.Length > 0) { url += query; } return(url); }
public static string GetUrl(this IMediaService service, int?fileId, int thumbnailSize, string host = null, bool doFallback = true) { ProcessImageQuery query = thumbnailSize > 0 ? new ProcessImageQuery { MaxSize = thumbnailSize } : null; return(service.GetUrl(service.GetFileById(fileId ?? 0, MediaLoadFlags.AsNoTracking), query, host, doFallback)); }
public static string GetUrl(this IMediaService service, MediaFileInfo file, int thumbnailSize, string host = null, bool doFallback = true) { ProcessImageQuery query = thumbnailSize > 0 ? new ProcessImageQuery { MaxSize = thumbnailSize } : null; return(service.GetUrl(file, query, host, doFallback)); }
public static string GetFallbackUrl(this IMediaService service, int thumbnailSize = 0) { ProcessImageQuery query = thumbnailSize > 0 ? new ProcessImageQuery { MaxSize = thumbnailSize } : null; return(service.GetUrl((MediaFileInfo)null, query, null, true)); }
public virtual byte[] ValidatePicture(byte[] pictureBinary, string mimeType, out Size size) { Guard.NotNull(pictureBinary, nameof(pictureBinary)); Guard.NotEmpty(mimeType, nameof(mimeType)); size = Size.Empty; var originalSize = ImageHeader.GetDimensions(pictureBinary, mimeType); if (mimeType == "image/svg+xml") { size = originalSize; return(pictureBinary); } var maxSize = _mediaSettings.MaximumImageSize; var query = new ProcessImageQuery(pictureBinary) { Quality = _mediaSettings.DefaultImageQuality, Format = MimeTypes.MapMimeTypeToExtension(mimeType), IsValidationMode = true }; if (originalSize.IsEmpty || (originalSize.Height <= maxSize && originalSize.Width <= maxSize)) { // Give subscribers the chance to (pre)-process var evt = new ImageUploadValidatedEvent(query, originalSize); _eventPublisher.Publish(evt); if (evt.ResultBuffer != null) { // Maybe subscriber forgot to set this, so check size = evt.ResultSize.IsEmpty ? originalSize : evt.ResultSize; return(evt.ResultBuffer); } else { size = originalSize; return(pictureBinary); } } query.MaxWidth = maxSize; query.MaxHeight = maxSize; using (var result = _imageProcessor.ProcessImage(query)) { size = new Size(result.Width, result.Height); var buffer = result.OutputStream.ToArray(); return(buffer); } }
private static string CreateMessage(ProcessImageQuery query) { var fileName = query?.FileName; if (fileName.HasValue()) { return("Error while processing image '{0}'.".FormatCurrent(fileName)); } else { return("Error while processing image."); } }
private static string CreateMessage(ProcessImageQuery query, Exception innerException) { var fileName = query?.FileName; var msg = fileName.HasValue() ? "Error while processing image '{0}'".FormatCurrent(fileName) : "Error while processing image"; if (innerException != null) { msg += " (" + innerException.Message + ")"; } return(msg); }
/// <summary> /// Returns the images thumb path as is plus query (required for uploaded images) /// </summary> /// <param name="file">Image file to get thumbnail for</param> /// <param name="query"></param> /// <returns></returns> private string GetCachedImagePath(IFile file, ProcessImageQuery query) { if (!_imageProcessor.IsSupportedImage(file.Name)) { throw new InvalidOperationException("Thumbnails for '{0}' files are not supported".FormatInvariant(file.Extension)); } // TODO: (mc) prevent creating thumbs for thumbs AND check equality of source and target var imageFileName = String.Concat(file.Title, query.CreateHash()); var extension = (query.GetResultExtension() ?? file.Extension).EnsureStartsWith(".").ToLower(); var path = _fileSystem.Combine(file.Directory, imageFileName + extension); return(path.TrimStart('/', '\\')); }
protected bool ProcessImage(MediaFile file, Stream inStream, out IImage outImage) { outImage = null; var originalSize = Size.Empty; var format = _imageProcessor.Factory.GetImageFormat(file.Extension) ?? new UnsupportedImageFormat(file.MimeType, file.Extension); try { originalSize = ImageHeader.GetDimensions(inStream, file.MimeType); } catch { } if (format is UnsupportedImageFormat) { outImage = new ImageWrapper(inStream, originalSize, format); return(true); } var maxSize = _mediaSettings.MaximumImageSize; var query = new ProcessImageQuery(inStream) { Quality = _mediaSettings.DefaultImageQuality, Format = file.Extension, DisposeSource = true, ExecutePostProcessor = ImagePostProcessingEnabled, IsValidationMode = true }; if (originalSize.IsEmpty || (originalSize.Height <= maxSize && originalSize.Width <= maxSize)) { // Give subscribers the chance to (pre)-process var evt = new ImageUploadedEvent(query, originalSize); _eventPublisher.Publish(evt); outImage = evt.ResultImage ?? new ImageWrapper(inStream, originalSize, format); return(true); } query.MaxSize = maxSize; using (var result = _imageProcessor.ProcessImage(query, false)) { outImage = result.Image; return(true); } }
private SourceImage LoadImage(ProcessImageQuery query) { var source = query.Source; Image image; IImageFormat format; Stream stream; long len; // Load source if (source is byte[] b) { stream = new MemoryStream(b); len = b.LongLength; } else if (source is Stream s) { stream = s; len = s.Length; } else if (source is string str) { var fi = new FileInfo(NormalizePath(str)); stream = fi.OpenRead(); len = fi.Length; } else if (source is IFile file) { len = file.Size; stream = file.OpenRead(); } else { throw new ProcessImageException("Invalid source type '{0}' in query.".FormatInvariant(query.Source.GetType().FullName), query); } image = Image.Load(stream, out format); return(new SourceImage { Image = image, Format = format, Stream = stream, Length = len, Width = image.Width, Height = image.Height }); }
public virtual CachedImageResult Get(IFile file, ProcessImageQuery query) { Guard.NotNull(file, nameof(file)); Guard.NotNull(query, nameof(query)); var imagePath = GetCachedImagePath(file, query); var thumbFile = _fileSystem.GetFile(BuildPath(imagePath)); var result = new CachedImageResult(thumbFile) { Path = imagePath, Extension = file.Extension.TrimStart('.'), IsRemote = _fileSystem.IsCloudStorage }; return(result); }
protected string GetCachedImagePath(int?mediaFileId, MediaPathData data, ProcessImageQuery query = null) { string result = ""; // xxxxxxx if (mediaFileId.GetValueOrDefault() > 0) { result = mediaFileId.Value.ToString(IdFormatString); } //// INFO: (mm) don't include folder id in pathes for now. It results in more complex image cache invalidation code. //// xxxxxxx-f //if (data.Folder != null) //{ // result = result.Grow(data.Folder.Id.ToString(CultureInfo.InvariantCulture), "-"); //} // xxxxxxx-f-abc result = result.Grow(data.FileTitle, "-"); if (result.IsEmpty()) { // files without name? No way! return(null); } if (query != null && query.NeedsProcessing()) { // xxxxxxx-f-abc-w100-h100 result += query.CreateHash(); } if (_mediaSettings.MultipleThumbDirectories && result.Length > MaxDirLength) { // Get the first four letters of the file name // 0001/xxxxxxx-f-abc-w100-h100 var subDirectoryName = result.Substring(0, MaxDirLength); result = subDirectoryName + "/" + result; } // 0001/xxxxxxx-f-abc-w100-h100.png return(result.Grow(data.Extension, ".")); }
public virtual CachedImage Get(int?mediaFileId, MediaPathData data, ProcessImageQuery query = null) { Guard.NotNull(data, nameof(data)); var resultExtension = query?.GetResultExtension(); if (resultExtension != null) { data.Extension = resultExtension; } var imagePath = GetCachedImagePath(mediaFileId, data, query); var file = _fileSystem.GetFile(BuildPath(imagePath)); var result = new CachedImage(file) { Path = imagePath, Extension = data.Extension, IsRemote = _fileSystem.IsCloudStorage }; return(result); }
/// <summary> /// Returns the file name with the subfolder (when multidirs are enabled) /// </summary> /// <param name="pictureId"></param> /// <param name="seoFileName">File name without extension</param> /// <param name="extension">Dot-less file extension</param> /// <param name="query"></param> /// <returns></returns> private string GetCachedImagePath(int?pictureId, string seoFileName, string extension, ProcessImageQuery query = null) { string firstPart = ""; if (pictureId.GetValueOrDefault() > 0) { firstPart = pictureId.Value.ToString(IdFormatString) + (seoFileName.IsEmpty() ? "" : "-"); } if (firstPart.IsEmpty() && seoFileName.IsEmpty()) { // files without name? No way! return(null); } seoFileName = seoFileName.EmptyNull(); string imageFileName; if (query == null || !query.NeedsProcessing()) { imageFileName = String.Concat(firstPart, seoFileName); } else { imageFileName = String.Concat(firstPart, seoFileName, query.CreateHash()); } if (_mediaSettings.MultipleThumbDirectories && imageFileName != null && imageFileName.Length > MaxDirLength) { // Get the first four letters of the file name var subDirectoryName = imageFileName.Substring(0, MaxDirLength); imageFileName = String.Concat(subDirectoryName, "/", imageFileName); } return(String.Concat(imageFileName, ".", extension)); }
public virtual CachedImageResult Get(int?pictureId, string seoFileName, string extension, ProcessImageQuery query = null) { Guard.NotEmpty(extension, nameof(extension)); extension = query?.GetResultExtension() ?? extension.TrimStart('.').ToLower(); var imagePath = GetCachedImagePath(pictureId, seoFileName, extension, query); var file = _fileSystem.GetFile(BuildPath(imagePath)); var result = new CachedImageResult(file) { Path = imagePath, Extension = extension, IsRemote = _fileSystem.IsCloudStorage }; if (file.Exists && file.Size <= 0) { result.Exists = false; } return(result); }
public ProcessImageException(ProcessImageQuery query, Exception innerException) : base(CreateMessage(query, innerException), innerException) { Query = query; }
public static string GetUrl(this IMediaService service, int?fileId, ProcessImageQuery imageQuery, string host = null, bool doFallback = true) { return(service.GetUrl(service.GetFileById(fileId ?? 0, MediaLoadFlags.AsNoTracking), imageQuery, host, doFallback)); }
public ImageProcessingEvent(ProcessImageQuery query, ImageFactory processor) { Query = query; Processor = processor; }
/// <summary> /// Adds an image to the cache. /// </summary> /// <param name="pictureId">The picture id, which will be part of the resulting file name.</param> /// <param name="seoFileName">The seo friendly picture name, which will be part of the resulting file name.</param> /// <param name="extension">The extension of the resulting file</param> /// <param name="buffer">The image binary data.</param> /// <param name="query">The image processing query. This object, if not <c>null</c>, is hashed and appended to the resulting file name.</param> public static void Put(this IImageCache imageCache, int?pictureId, string seoFileName, string extension, byte[] buffer, ProcessImageQuery query = null) { var cachedImage = imageCache.Get(pictureId, seoFileName, extension, query); imageCache.Put(cachedImage, buffer); }
public ProcessImageResult ProcessImage(ProcessImageQuery query) { Guard.NotNull(query, nameof(query)); ValidateQuery(query); var watch = new Stopwatch(); byte[] inBuffer = null; try { watch.Start(); using (var processor = new ImageFactory(preserveExifData: false, fixGamma: false)) { var source = query.Source; // Load source if (source is byte[] b) { inBuffer = b; } else if (source is Stream s) { inBuffer = s.ToByteArray(); } else if (source is Image img) { processor.Load(img); } else if (source is string str) { var path = NormalizePath(str); using (var fs = File.OpenRead(path)) { inBuffer = fs.ToByteArray(); } } else { throw new ProcessImageException("Invalid source type '{0}' in query.".FormatInvariant(query.Source.GetType().FullName), query); } if (inBuffer != null) { processor.Load(inBuffer); } // Pre-process event _eventPublisher.Publish(new ImageProcessingEvent(query, processor)); var result = new ProcessImageResult { Query = query, SourceWidth = processor.Image.Width, SourceHeight = processor.Image.Height, SourceMimeType = processor.CurrentImageFormat.MimeType }; // Core processing ProcessImageCore(query, processor, out var fxApplied); // Create & prepare result var outStream = new MemoryStream(); processor.Save(outStream); var fmt = processor.CurrentImageFormat; result.FileExtension = fmt.DefaultExtension == "jpeg" ? "jpg" : fmt.DefaultExtension; result.MimeType = fmt.MimeType; result.HasAppliedVisualEffects = fxApplied; result.Width = processor.Image.Width; result.Height = processor.Image.Height; if (inBuffer != null) { // Check whether it is more beneficial to return the source instead of the result. // Prefer result only if its size is smaller than the source size. // Result size may be larger if a high-compressed image has been uploaded. // During image processing the source compression algorithm gets lost and the image may be larger in size // after encoding with default encoders. var compare = // only when image was not altered visually... !fxApplied // ...size has not changed && result.Width == result.SourceWidth && result.Height == result.SourceHeight // ...and format has not changed && result.MimeType == result.SourceMimeType; if (compare && inBuffer.LongLength <= outStream.GetBuffer().LongLength) { // Source is smaller. Throw away result and get back to source. outStream.Dispose(); result.OutputStream = new MemoryStream(inBuffer, 0, inBuffer.Length, true, true); } } // Set output stream if (result.OutputStream == null) { result.OutputStream = outStream; } // Post-process event _eventPublisher.Publish(new ImageProcessedEvent(query, processor, result)); result.OutputStream.Position = 0; result.ProcessTimeMs = watch.ElapsedMilliseconds; return(result); } } catch (Exception ex) { var pex = new ProcessImageException(query, ex); Logger.Error(pex); throw pex; } finally { if (query.DisposeSource && query.Source is IDisposable source) { source.Dispose(); } watch.Stop(); _totalProcessingTime += watch.ElapsedMilliseconds; } }
/// <summary> /// Gets an instance of the <see cref="CachedImageResult"/> object, which contains information about a cached image. /// </summary> /// <param name="picture">The picture object for which to resolve a cached image.</param> /// <param name="query">The image processing query.</param> /// <returns>An instance of the <see cref="CachedImageResult"/> object</returns> /// <remarks>If the requested image does not exist in the cache, the value of the <c>Exists</c> property will be <c>false</c>.</remarks> public static CachedImageResult Get(this IImageCache imageCache, MediaFile picture, ProcessImageQuery query = null) { Guard.NotNull(picture, nameof(picture)); return(imageCache.Get(picture.Id, picture.Name, MimeTypes.MapMimeTypeToExtension(picture.MimeType), query)); }
public ImageProcessedEvent(ProcessImageQuery query, ImageFactory processor, ProcessImageResult result) { Query = query; Processor = processor; Result = result; }
/// <summary> /// Adds an image to the cache. /// </summary> /// <param name="picture">The picture object needed for building the resulting file name.</param> /// <param name="buffer">The image binary data.</param> /// <param name="query">The image processing query. This object, if not <c>null</c>, is hashed and appended to the resulting file name.</param> public static void Put(this IImageCache imageCache, MediaFile picture, byte[] buffer, ProcessImageQuery query = null) { Guard.NotNull(picture, nameof(picture)); imageCache.Put(picture.Id, picture.Name, MimeTypes.MapMimeTypeToExtension(picture.MimeType), buffer, query); }
public ImageUploadValidatedEvent(ProcessImageQuery query, Size size) { Query = query; Size = size; }