Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


This forum is in read only mode, you can no longer reply
  • Søren Kottal 702 posts 4497 karma points MVP 5x c-trib
    Jul 01, 2015 @ 13:43
    Søren Kottal
    0

    Resize (crop) image, then mask, then overlay

    I have noticed the cool Mask and Overlay features on your own site, and are now trying to put them to use.

    I want to let an editor pick any photo from the media library, and then turn it into a usable image in the frontend. The image should end up like below, with the photo embedded in the green drop in center.

    End result

    For that, I have created a mask image in png with the center drop isolated. And an overlay image with the blue wings to overlay onto the masked image.

    But since I want to let the editor choose the photo themselves, I need to crop the photo before masking, and overlaying.

    I have tried doing a querystring like ?width=400&height=600&mode=crop&format=png&mask=drop.png&overlay=wings.png, but the drop gets resized with the image.

    Is there anyway I can resize/crop the image, before adding the mask and overlay?

  • James Jackson-South 489 posts 1747 karma points c-trib
    Jul 01, 2015 @ 14:30
    James Jackson-South
    1

    Hi Søren,

    ImageProcessors commands are imperative so you will actually be cropping the image before adding a mask or overlay.

    Masks resize to match the image by design, this is to ensure everything scales together correctly.

    https://github.com/JimBobSquarePants/ImageProcessor/blob/b207c6c463d368a19fda8afa4d865793761b8394/src/ImageProcessor/Processors/Mask.cs#L79

    My advice would be to create a custom IGraphicsProcessor and IWebGraphicsProcessor based on the current mask one and implement what you need using that. If you are not using the config files then everthing should get automatically loaded; otherwise you will need to add the new IWebGraphicsProcessor to processing.config

    Hope that helps

    James

  • Søren Kottal 702 posts 4497 karma points MVP 5x c-trib
    Jul 01, 2015 @ 16:27
    Søren Kottal
    0

    Thanks James, I will look into that!

  • James Jackson-South 489 posts 1747 karma points c-trib
    Jul 01, 2015 @ 16:44
    James Jackson-South
    0

    No worries! If you get stuck, just give me a shout.

  • Søren Kottal 702 posts 4497 karma points MVP 5x c-trib
    Jul 01, 2015 @ 17:52
    Søren Kottal
    0

    Heres a shout then :)

    I tried making a copy of the IWebGraphicsProcessor and IGraphicsProcessor of Overlay, to make my own (called OverlayReverse).

    And put this in processing.config

    <plugin name="OverlayReverse" type="ImageProcessor.Web.Processors.OverlayReverse, ImageProcessor.Web">
      <settings>
        <setting key="VirtualPath" value="~/images/imageprocessor/overlay/" />
      </settings>
    </plugin>
    

    But I only get a YSOD saying Couldn't load IWebGraphicsProcessor: ImageProcessor.Web.Processors.OverlayReverse, ImageProcessor.Web when trying to access an image.

    First I added the to .cs files in App_Code, but since that didn't work, I made a new project and built into my Umbraco project, then referencing the new dll.

    I think it's because of the new setting in processing.config, because when I uninstall ImageProcessor.Web.Config, I get another error where it loads the overlay image (probably because of the missing VirtualPath setting).

  • James Jackson-South 489 posts 1747 karma points c-trib
    Jul 01, 2015 @ 19:24
    James Jackson-South
    0

    Is the namespace correct? Could you share the code you wrote?

  • Søren Kottal 702 posts 4497 karma points MVP 5x c-trib
    Jul 01, 2015 @ 19:35
    Søren Kottal
    0
    // --------------------------------------------------------------------------------------------------------------------
    // <copyright file="Overlay.cs" company="James South">
    //   Copyright (c) James South.
    //   Licensed under the Apache License, Version 2.0.
    // </copyright>
    // <summary>
    //   Adds an image overlay to the current image.
    // </summary>
    // --------------------------------------------------------------------------------------------------------------------
    
    namespace ImageProcessor.Processors
    {
        using System;
        using System.Collections.Generic;
        using System.Drawing;
        using System.Drawing.Drawing2D;
    
        using ImageProcessor.Common.Exceptions;
        using ImageProcessor.Imaging;
        using ImageProcessor.Imaging.Helpers;
    
        /// <summary>
        /// Adds an image overlay to the current image. 
        /// If the overlay is larger than the image it will be scaled to match the image.
        /// </summary>
        public class OverlayReverse : IGraphicsProcessor
        {
            /// <summary>
            /// Initializes a new instance of the <see cref="Overlay"/> class.
            /// </summary>
            public OverlayReverse()
            {
                this.Settings = new Dictionary<string, string>();
            }
    
            /// <summary>
            /// Gets or sets the dynamic parameter.
            /// </summary>
            public dynamic DynamicParameter
            {
                get;
                set;
            }
    
            /// <summary>
            /// Gets or sets any additional settings required by the processor.
            /// </summary>
            public Dictionary<string, string> Settings
            {
                get;
                set;
            }
    
            /// <summary>
            /// Processes the image.
            /// </summary>
            /// <param name="factory">
            /// The current instance of the <see cref="T:ImageProcessor.ImageFactory"/> class containing
            /// the image to process.
            /// </param>
            /// <returns>
            /// The processed image from the current instance of the <see cref="T:ImageProcessor.ImageFactory"/> class.
            /// </returns>
            public Image ProcessImage(ImageFactory factory)
            {
                Bitmap newImage = null;
                Image image = factory.Image;
    
                try
                {
                    newImage = new Bitmap(image);
                    ImageLayer imageLayer = this.DynamicParameter;
                    Bitmap overlay = new Bitmap(imageLayer.Image);
    
                    // Set the resolution of the overlay and the image to match.
                    overlay.SetResolution(newImage.HorizontalResolution, newImage.VerticalResolution);
    
                    Size size = imageLayer.Size;
                    int width = image.Width;
                    int height = image.Height;
                    int overlayWidth = size != Size.Empty ? Math.Min(image.Size.Width, size.Width) : Math.Min(image.Size.Width, overlay.Size.Width);
                    int overlayHeight = size != Size.Empty ? Math.Min(image.Size.Height, size.Height) : Math.Min(image.Size.Height, overlay.Size.Height);
    
                    Point? position = imageLayer.Position;
                    int opacity = imageLayer.Opacity;
    
                    if (image.Size != overlay.Size || image.Size != new Size(overlayWidth, overlayHeight))
                    {
                        // Find the maximum possible dimensions and resize the image.
                        ResizeLayer layer = new ResizeLayer(new Size(overlayWidth, overlayHeight), ResizeMode.Max);
                        overlay = new Resizer(layer).ResizeImage(overlay);
                        overlayWidth = overlay.Width;
                        overlayHeight = overlay.Height;
                    }
    
                    // Figure out bounds.
                    Rectangle parent = new Rectangle(0, 0, width, height);
                    Rectangle child = new Rectangle(0, 0, overlayWidth, overlayHeight);
    
                    // Apply opacity.
                    if (opacity < 100)
                    {
                        overlay = Adjustments.Alpha(overlay, opacity);
                    }
    
                    using (Graphics graphics = Graphics.FromImage(newImage))
                    {
                        graphics.SmoothingMode = SmoothingMode.AntiAlias;
                        graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
                        graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
                        graphics.CompositingQuality = CompositingQuality.HighQuality;
    
                        if (position != null)
                        {
                            // Draw the image in position catering for overflow.
                            graphics.DrawImage(overlay, new Point(Math.Min(position.Value.X, width - overlayWidth), Math.Min(position.Value.Y, height - overlayHeight)));
                        }
                        else
                        {
                            RectangleF centered = ImageMaths.CenteredRectangle(parent, child);
                            graphics.DrawImage(overlay, new PointF(centered.X, centered.Y));
                        }
                    }
    
                    image.Dispose();
                    image = newImage;
                }
                catch (Exception ex)
                {
                    if (newImage != null)
                    {
                        newImage.Dispose();
                    }
    
                    throw new ImageProcessingException("Error processing image with " + this.GetType().Name, ex);
                }
    
                return image;
            }
        }
    }
    

    and

    // --------------------------------------------------------------------------------------------------------------------
    // <copyright file="Overlay.cs" company="James South">
    //   Copyright (c) James South.
    //   Licensed under the Apache License, Version 2.0.
    // </copyright>
    // <summary>
    //   Adds an image overlay to the current image.
    //   If the overlay is larger than the image it will be scaled to match the image.
    // </summary>
    // --------------------------------------------------------------------------------------------------------------------
    
    namespace ImageProcessor.Web.Processors
    {
        using System.Collections.Specialized;
        using System.Drawing;
        using System.IO;
        using System.Text.RegularExpressions;
        using System.Web;
        using System.Web.Hosting;
    
        using ImageProcessor.Imaging;
        using ImageProcessor.Processors;
        using ImageProcessor.Web.Helpers;
    
        /// <summary>
        /// Adds an image overlay to the current image. 
        /// If the overlay is larger than the image it will be scaled to match the image.
        /// </summary>
        public class OverlayReverse : IWebGraphicsProcessor
        {
            /// <summary>
            /// The regular expression to search strings for.
            /// </summary>
            private static readonly Regex QueryRegex = new Regex(@"overlayreverse=[\w+-]+." + ImageHelpers.ExtensionRegexPattern);
    
            /// <summary>
            /// Initializes a new instance of the <see cref="Overlay"/> class.
            /// </summary>
            public OverlayReverse()
            {
                this.Processor = new ImageProcessor.Processors.OverlayReverse();
            }
    
            /// <summary>
            /// Gets the regular expression to search strings for.
            /// </summary>
            public Regex RegexPattern
            {
                get
                {
                    return QueryRegex;
                }
            }
    
            /// <summary>
            /// Gets the order in which this processor is to be used in a chain.
            /// </summary>
            public int SortOrder { get; private set; }
    
            /// <summary>
            /// Gets the associated graphics processor.
            /// </summary>
            public IGraphicsProcessor Processor { get; private set; }
    
            /// <summary>
            /// The position in the original string where the first character of the captured substring was found.
            /// </summary>
            /// <param name="queryString">The query string to search.</param>
            /// <returns>
            /// The zero-based starting position in the original string where the captured substring was found.
            /// </returns>
            public int MatchRegexIndex(string queryString)
            {
                this.SortOrder = int.MaxValue;
                Match match = this.RegexPattern.Match(queryString);
    
                if (match.Success)
                {
                    this.SortOrder = match.Index;
                    NameValueCollection queryCollection = HttpUtility.ParseQueryString(queryString);
                    Image image = this.ParseImage(queryCollection["overlay"]);
    
                    Point? position = queryCollection["overlay.position"] != null
                          ? QueryParamParser.Instance.ParseValue<Point>(queryCollection["overlay.position"])
                          : (Point?)null;
    
                    int opacity = queryCollection["overlay.opacity"] != null
                                      ? QueryParamParser.Instance.ParseValue<int>(queryCollection["overlay.opacity"])
                                      : 100;
                    Size size = QueryParamParser.Instance.ParseValue<Size>(queryCollection["overlay.size"]);
    
                    this.Processor.DynamicParameter = new ImageLayer
                    {
                        Image = image,
                        Position = position,
                        Opacity = opacity,
                        Size = size
                    };
                }
    
                return this.SortOrder;
            }
    
            /// <summary>
            /// Returns an image from the given input path.
            /// </summary>
            /// <param name="input">
            /// The input containing the value to parse.
            /// </param>
            /// <returns>
            /// The <see cref="Image"/> representing the given image path.
            /// </returns>
            public Image ParseImage(string input)
            {
                Image image = null;
    
                // Correctly parse the path.
                string path;
                this.Processor.Settings.TryGetValue("VirtualPath", out path);
    
                if (!string.IsNullOrWhiteSpace(path) && path.StartsWith("~/"))
                {
                    string imagePath = HostingEnvironment.MapPath(path);
                    if (imagePath != null)
                    {
                        imagePath = Path.Combine(imagePath, input);
                        using (ImageFactory factory = new ImageFactory())
                        {
                            factory.Load(imagePath);
                            image = new Bitmap(factory.Image);
                        }
                    }
                }
    
                return image;
            }
        }
    }
    
  • James Jackson-South 489 posts 1747 karma points c-trib
    Jul 01, 2015 @ 23:20
    James Jackson-South
    1

    Cheers...

    It looks like you're using the wrong root namespace in the configuration. Your root should be ImageProcessor.Web.Processors.

    <plugin name="OverlayReverse" type="ImageProcessor.Web.Processors.OverlayReverse, ImageProcessor.Web.Processors">
      <settings>
        <setting key="VirtualPath" value="~/images/imageprocessor/overlay/" />
      </settings>
    </plugin>
    
Please Sign in or register to post replies

Write your reply to:

Draft