locked
Easy in memory image processing(grayscale, sepia, negative, resize, brightness and contrast) RRS feed

  • Question

  • User90671449 posted

    Howdie y'all,

    Here's the image processor i created and use with pleasure. So maybe you'll enjoy it as much a I do!

    It converts to: Grayscale, sepia and negative,
    It resizes with high quality,
    and sets brightness and contrast,

    ALL ON THE FLY!

    You can also call all these sweet functions from your code so you can, for example, resize and grayscale an uploaded image bij just 2 lines of code!

    And it's ten times faster then looping thru al you pixels.

    So how does it work???


    First:
    Create this class and compile it into a dll:

    <code>
    using System;
    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Drawing.Imaging;
    using System.IO;
    using System.Web;

    namespace YourNamespace
    {
        public class ImageProcessor : IHttpHandler
        {
            public void ProcessRequest(HttpContext context)
            {
                string src = (context.Request.QueryString["src"] == null) ? string.Empty : context.Server.MapPath(context.Server.UrlDecode(context.Request.QueryString["src"]));

                context.Response.Clear();
               
                if (File.Exists(src))
                {
                    context.Response.ContentType = "image/jpeg";
                    int wi = (context.Request.QueryString["w"] == null) ? 0 : Convert.ToInt32(context.Request.QueryString["w"]);
                    int hi = (context.Request.QueryString["h"] == null) ? 0 : Convert.ToInt32(context.Request.QueryString["h"]);
                    bool gb = (context.Request.QueryString["g"] == null) ? false : Convert.ToBoolean(context.Request.QueryString["g"]);
                    bool nb = (context.Request.QueryString["n"] == null) ? false : Convert.ToBoolean(context.Request.QueryString["n"]);
                    bool sb = (context.Request.QueryString["s"] == null) ? false : Convert.ToBoolean(context.Request.QueryString["s"]);
                    float bf = (context.Request.QueryString["b"] == null) ? 0 : Convert.ToSingle(context.Request.QueryString["b"]);
                    float cf = (context.Request.QueryString["c"] == null) ? 0 : Convert.ToSingle(context.Request.QueryString["c"]);

                    using (Stream imgStream = File.OpenRead(src))
                    {
                        using (Bitmap b = Resize(imgStream, wi, hi))
                        {
                            if (gb)
                                ToGrayscale(b);

                            if (nb)
                                ToNegative(b);

                            if (sb)
                                ToSepia(b);

                            if (bf != 0)
                                SetBrightness(b, bf);

                            if (cf != 1)
                                SetContrast(b, cf);

                            b.Save(context.Response.OutputStream, ImageFormat.Jpeg);
                        }
                    }
                }

                context.Response.End();
            }

            public bool IsReusable
            {
                get { return true; }
            }

            public static Bitmap Resize(Stream SourceImage, int MaxWidth, int MaxHeight)
            {
                Bitmap b = null;

                using (System.Drawing.Image i = System.Drawing.Image.FromStream(SourceImage))
                {
                    int _maxWidth = (MaxWidth > 0) ? MaxWidth : i.Width;
                    int _maxHeight = (MaxHeight > 0) ? MaxHeight : i.Height;
                    double _scaleWidth = (double)_maxWidth / (double)i.Width;
                    double _scaleHeight = (double)_maxHeight / (double)i.Height;
                    double _scale = (_scaleHeight < _scaleWidth) ? _scaleHeight : _scaleWidth;
                    _scale = (_scale > 1) ? 1 : _scale;

                    int _newWidth = (int)(_scale * i.Width);
                    int _newHeight = (int)(_scale * i.Height);

                    b = new Bitmap(_newWidth, _newHeight);

                    using (Graphics g = Graphics.FromImage(b))
                    {
                        g.CompositingQuality = CompositingQuality.HighQuality;
                        g.SmoothingMode = SmoothingMode.HighQuality;
                        g.InterpolationMode = InterpolationMode.HighQualityBicubic;

                        g.DrawImage(i, new Rectangle(0, 0, _newWidth, _newHeight));
                        g.Save();
                    }
                }

                return b;
            }

            public static void ToGrayscale(Bitmap b)
            {
                ColorMatrix cm = new ColorMatrix(new float[][]{
                                new float[] {0.3086f, 0.3086f, 0.3086f, 0f, 0f},
                                new float[] {0.6094f, 0.6094f, 0.6094f, 0f, 0f},
                                new float[] {0.0820f, 0.0820f, 0.0820f, 0f, 0f},
                                new float[] {     0f,      0f,      0f, 1f, 0f},
                                new float[] {     0f,      0f,      0f, 0f, 1f}});

                ApplyColorMatrix(b, cm);
            }

            public static void ToNegative(Bitmap b)
            {
                ColorMatrix cm = new ColorMatrix(new float[][]{
                                new float[] {0.992f,     0f,     0f, 0f, 0f},
                                new float[] {    0f, 0.992f,     0f, 0f, 0f},
                                new float[] {    0f,     0f, 0.992f, 0f, 0f},
                                new float[] {    0f,     0f,     0f, 1f, 0f},
                                new float[] {0.004f, 0.004f, 0.004f, 0f, 1f}});

                ApplyColorMatrix(b, cm);

                cm = new ColorMatrix(new float[][]{
                    new float[] {-1f,  0f,  0f, 0f, 0f},
                    new float[] { 0f, -1f,  0f, 0f, 0f},
                    new float[] { 0f,  0f, -1f, 0f, 0f},
                    new float[] { 0f,  0f,  0f, 1f, 0f},
                    new float[] { 0f,  0f,  0f, 0f, 1f}});

                ApplyColorMatrix(b, cm);
            }

            public static void ToSepia(Bitmap b)
            {
                ColorMatrix cm = new ColorMatrix(new float[][]{
                                new float[] {0.393f, 0.349f, 0.272f, 0f, 0f},
                                new float[] {0.769f, 0.686f, 0.534f, 0f, 0f},
                                new float[] {0.189f, 0.168f, 0.131f, 0f, 0f},
                                new float[] {    0f,     0f,     0f, 1f, 0f},
                                new float[] {    0f,     0f,     0f, 0f, 1f}});

                ApplyColorMatrix(b, cm);
            }

            public static void SetBrightness(Bitmap b, float Brightness)
            {
                ApplyColorMatrix(b, CreateBrightnessMatrix(Brightness));
            }

            public static void SetContrast(Bitmap b, float Contrast)
            {
                ApplyColorMatrix(b, CreateContrastMatrix(Contrast));
            }

            public static ColorMatrix CreateBrightnessMatrix(float Brightness)
            {
                if (Brightness < -1 || Brightness > 1)
                    throw new ArgumentOutOfRangeException("Brightness value is out of range");

                ColorMatrix cm = new ColorMatrix(new float[][]{
                                new float[] {        1f,          0,          0,  0,  0},
                                new float[] {         0,         1f,          0,  0,  0},
                                new float[] {         0,          0,         1f,  0,  0},
                                new float[] {         0,          0,          0, 1f,  0},
                                new float[] {Brightness, Brightness, Brightness, 1f, 1f}});

                return cm;
            }

            public static ColorMatrix CreateContrastMatrix(float Contrast)
            {
                if (Contrast < 0 || Contrast > 3)
                    throw new ArgumentOutOfRangeException("Contrast value is out of range");

                float Trans = (1f - Contrast) / 2f;

                ColorMatrix cm = new ColorMatrix(new float[][]{
                                new float[] {Contrast,       0f,       0f, 0f, 0f},
                                new float[] {      0f, Contrast,       0f, 0f, 0f},
                                new float[] {      0f,       0f, Contrast, 0f, 0f},
                                new float[] {      0f,       0f,       0f, 1f, 0f},
                                new float[] {   Trans,    Trans,    Trans, 0f, 1f}});

                return cm;
            }

            public static void ApplyColorMatrix(Bitmap b, ColorMatrix cm)
            {
                using (Graphics g = Graphics.FromImage(b))
                {
                    ImageAttributes ia = new ImageAttributes();
                    ia.SetColorMatrix(cm);

                    g.DrawImage(b, new Rectangle(0, 0, b.Width, b.Height), 0, 0, b.Width, b.Height, GraphicsUnit.Pixel, ia);
                    g.Save();
                }
            }
        }
    }

    </code>


    Second:
    Add this line to you web.config in <system.web>:


    <httpHandlers>
          <add verb="GET" path="ImageProcessor.ashx" type="YourNamespace.ImageProcessor, NameOfDll" />
    </httpHandlers>

    Third:
    Set the src attribute of an image to:

    ImageProcessor.ashx?src=..%2fUploads%2fMyImage.jpg&amp;w=0&amp;h=0&amp;g=False&amp;n=True&amp;s=False&amp;b=0&amp;c=1

    Where:
    src stands for the UrlEncoded Path of your image
    w stands for the maximum with an image can be
    h stands for the maximum height an image can be
    g stands for grayscaling the image
    n stands for negative of the image
    s stands for sepia of the image
    b stands for brightness of the image (between -1 and 1)
    c stand for contrast of the image (between 0 and 3 where 1 is standard)

    Fourth:
    To make it easier create this control as well and compile and use it together:

    <code>
    using System;
    using System.ComponentModel;
    using System.Drawing;
    using System.Text;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;

    namespace YourNamespace
    {
        [
        DefaultProperty("src"),
        ToolboxData("<{0}:BetterImage runat=\"server\"></{0}:BetterImage>"),
        ToolboxBitmap(typeof(System.Web.UI.WebControls.Image))
        ]
        public class BetterImage : System.Web.UI.WebControls.Image
        {
            [
            Bindable(true),
            Category("Behavior"),
            DefaultValue(0),
            Description("Maximum width of the image."),
            ]
            public virtual int MaxWidth
            {
                get
                {
                    object b = ViewState["MaxWidth"];
                    return (b == null) ? 0 : (int)b;
                }
                set
                {
                    ViewState["MaxWidth"] = value;
                }
            }

            [
            Bindable(true),
            Category("Behavior"),
            DefaultValue(0),
            Description("Maximum height of the image."),
            ]
            public virtual int MaxHeight
            {
                get
                {
                    object b = ViewState["MaxHeight"];
                    return (b == null) ? 0 : (int)b;
                }
                set
                {
                    ViewState["MaxHeight"] = value;
                }
            }

            [
            Bindable(true),
            Category("Behavior"),
            DefaultValue(false),
            Description("Grayscale the image."),
            ]
            public virtual bool Grayscale
            {
                get
                {
                    object b = ViewState["Grayscale"];
                    return (b == null) ? false : (bool)b;
                }
                set
                {
                    ViewState["Grayscale"] = value;
                }
            }

            [
            Bindable(true),
            Category("Behavior"),
            DefaultValue(false),
            Description("Negative of the image."),
            ]
            public virtual bool Negative
            {
                get
                {
                    object b = ViewState["Negative"];
                    return (b == null) ? false : (bool)b;
                }
                set
                {
                    ViewState["Negative"] = value;
                }
            }

            [
            Bindable(true),
            Category("Behavior"),
            DefaultValue(false),
            Description("Sepia of the image."),
            ]
            public virtual bool Sepia
            {
                get
                {
                    object b = ViewState["Sepia"];
                    return (b == null) ? false : (bool)b;
                }
                set
                {
                    ViewState["Sepia"] = value;
                }
            }

            [
            Bindable(true),
            Category("Behavior"),
            DefaultValue(0),
            Description("Brightness of the image."),
            ]
            public virtual float Brightness
            {
                get
                {
                    object b = ViewState["Brightness"];
                    return (b == null) ? 0: (float)b;
                }
                set
                {
                    if (value < -1 || value > 1)
                        throw new ArgumentOutOfRangeException("Brightness value is out of range");

                    ViewState["Brightness"] = value;
                }
            }

            [
            Bindable(true),
            Category("Behavior"),
            DefaultValue(1),
            Description("Contrast of the image."),
            ]
            public virtual float Contrast
            {
                get
                {
                    object b = ViewState["Contrast"];
                    return (b == null) ? 1 : (float)b;
                }
                set
                {
                    if (value < 0 || value > 3)
                        throw new ArgumentOutOfRangeException("Contrast value is out of range");

                    ViewState["Contrast"] = value;
                }
            }

            protected override void AddAttributesToRender(HtmlTextWriter writer)
            {

                if (MaxWidth > 0 || MaxHeight > 0 || Grayscale || Negative || Sepia || Brightness != 0 || Contrast != 1)
                {
                    StringBuilder newSrc = new StringBuilder("ImageProcessor.ashx?src=");
                    newSrc.Append(HttpContext.Current.Server.UrlEncode(base.ImageUrl) + "&w=");
                    newSrc.Append(MaxWidth + "&h=");
                    newSrc.Append(MaxHeight + "&g=");
                    newSrc.Append(Grayscale + "&n=");
                    newSrc.Append(Negative + "&s=");
                    newSrc.Append(Sepia + "&b=");
                    newSrc.Append(Brightness + "&c=");
                    newSrc.Append(Contrast);

                    base.ImageUrl = newSrc.ToString();
                }

                base.AddAttributesToRender(writer);
            }
        }
    }
    </code>

    Fifth:
    After compiling add this control to your Toolbox and simply use it as you would any other control!


    That's all!!

    Ohh.... no it's not... this post is getting even more exciting..... I've packed these two controls and two other ones in a sample web which you can download here. If you don't agree with me that this is a BetterImageProcessor just let me know!

    Cheers,

    Wes

    Tuesday, September 27, 2005 3:40 AM

All replies

  • User90671449 posted
    Just wanted you guys to know that there's a new version to download from here. It has some new extras:

    1) setting opacity of an image - comes in handy if you want to watermark a picture
    2) caching the javascript

    Cheers,
    Wes
    Tuesday, October 18, 2005 6:40 PM
  • User-172133348 posted
    Very nice - Thanks for sharing. I was about to write something similar myself, but you've save me the effort.
    Friday, November 4, 2005 5:57 AM
  • User90671449 posted
    You're welcome and thanks for the reply! It has been downloaded more than a hundred times but your the first to react.

    Cheers,
    Wes
    Sunday, November 6, 2005 8:08 AM
  • User-1482891610 posted

    Just downloaded it an thinks its ace.... well done.... keep up teh good work!!!

    Tuesday, November 15, 2005 6:15 AM
  • User90671449 posted

    Howdie y'all... version 3.0.0.1 is available for download over here!

    Implemented the BetterImageSlideshow control as well as Quantizer classes from Morgan Skinner.

    You can choose to quantize gif images now so the quality of those is much much better if you like. And the BetterImageSlideshow... well this is definately the easiest way to get a slideshow on your website.

    Have fun and please let me know if you like this additions ;-)

    Cheers,

    Wes

    Friday, December 23, 2005 8:04 AM
  • User-1673888866 posted
    Hi Webbes,
    Nice article. Can you also tell me how to apply Red,Green and Blue colormatrix???


    Regards,
    Swami

    Wednesday, December 28, 2005 2:50 AM
  • User90671449 posted

    There's a good explanation on how the colormatrix works over here: http://www.codeproject.com/vb/net/colormatrix.asp

    Cheers,

    Wes

    Wednesday, December 28, 2005 4:53 AM
  • User-172133348 posted
    Unfortunately I can't get you library to work in a medium trust environment :( As soon as I drop your dll into my bin directory, my site errors with "Required permission can not be acquired".
    Thursday, December 29, 2005 12:12 PM
  • User90671449 posted

    That's probably because the octreequantizer is an unmanaged class.... unfortunately I can't do anything about it. I do know i forgot to set my permissionrequest to the correct permissionset and i will change it.

    Thanks for pointing me out on this one.

    Cheers,

    Wes

    Thursday, December 29, 2005 5:20 PM
  • User90671449 posted

    Howdie y'all... version 4.0.0.0 is available for download over here!

    I've added two controls for creating javascript slideshows with transitions(in IE).

    And there's a MediumTrust version (lacking the unsafe Quantization classes) included!!!

    Have fun and please let me know if you like these changes ;-)

    Cheers,

    Wes

    Tuesday, January 17, 2006 5:12 PM
  • User1169324036 posted
    Wes, I would like to say thanks for taking in consideration shared hosting by making a medium trust version. Keep up the good work!
    Tuesday, January 17, 2006 11:31 PM
  • User90671449 posted

    Blake05,

    Thanks for your reply and you're more than welcome. I wanted to use this library myself on shared hosting(I really love my own library ;-) ) so I had to create a Medium trust version anyway.

    Oh btw any suggestions for improvements are more than welcome. If I don't get feedback it's kind of hard to make enhancements....

    Cheers,

    Wes

    Wednesday, January 18, 2006 5:07 AM
  • User90671449 posted

    Howdie y'all,

    From now on there's a sample web showing some of the options over here. The download and any new versions will be mentioned in that place as well.

    Cheers,

    Wes

    Wednesday, January 18, 2006 10:10 AM
  • User-635331998 posted

     float Trans = (1f - Contrast) / 2f;

    I am wondering how come this formula?

    Thursday, April 5, 2007 1:23 AM
  • User-635331998 posted
    I just  noticed that this is not working with PNG files!
    Thursday, April 5, 2007 1:25 AM
  • User-1535631749 posted

    Hi all,

    Is anybody help me to give the effect on image like highlight,temprature,Exposure in c#?

    Thanks in Advance....

     

    Friday, June 20, 2008 11:46 AM
  • User1968999875 posted

    Hi Webbes thanks for such a great work 

    Wednesday, July 9, 2008 7:16 PM
  • User357708474 posted

    Hey Webbes Your Mentioned Code is Not working .I want To design same control For Image Processing  Like Brightness Contrast etc.

    So Please Mention The Clear Step.

    Saturday, March 30, 2013 1:48 AM