Beispiel #1
0
        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));
        }
Beispiel #2
0
 public ImageQueryCreatedEvent(ProcessImageQuery query, HttpContextBase httpContext, string mimeType, string extension)
 {
     Query       = query;
     HttpContext = httpContext;
     MimeType    = mimeType;
     Extension   = extension;
 }
Beispiel #3
0
 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;
        }
Beispiel #5
0
        /// <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;
        }
Beispiel #7
0
        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);
            }
        }
Beispiel #12
0
        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('/', '\\'));
        }
Beispiel #15
0
        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
            });
        }
Beispiel #17
0
        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);
        }
Beispiel #18
0
        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, "."));
        }
Beispiel #19
0
        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));
 }
Beispiel #24
0
 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);
        }
Beispiel #26
0
        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));
        }
Beispiel #28
0
 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);
 }
Beispiel #30
0
 public ImageUploadValidatedEvent(ProcessImageQuery query, Size size)
 {
     Query = query;
     Size  = size;
 }