Add a watermark to the image.

    Hi, Habrahabr!
    Yesterday, after reading an article by SergeyVoyteshonok on rendering the logo of a site or company (in other words, a “watermark”) on images uploaded by users, I was surprised at the gravity of the solution proposed by the author.
    Then I promised to experiment a bit and offer a more rational option.


    In my version, the rendering method looks like this:

    public void DrawWatermark(Image original, Bitmap watermark,
        WatermarkPosition position, Color transparentColor, float opacity)
    {
        if (original == null)
            throw new ArgumentNullException("original");
        if (watermark == null)
            throw new ArgumentNullException("watermark");
        if (opacity < 0 || opacity > 1)
            throw new ArgumentOutOfRangeException("Watermark opacity value is out of range");

        Rectangle dest = new Rectangle(
            GetDestination(original.Size, watermark.Size, position), watermark.Size);

        using (Graphics g = Graphics.FromImage(original))
        {
            ImageAttributes attr = new ImageAttributes();
            ColorMatrix matrix = new ColorMatrix(new float[][] {
                new float[] { opacity, 0f, 0f, 0f, 0f },
                new float[] { 0f, opacity, 0f, 0f, 0f },
                new float[] { 0f, 0f, opacity, 0f, 0f },
                new float[] { 0f, 0f, 0f, opacity, 0f },
                new float[] { 0f, 0f, 0f, 0f, opacity } });
            attr.SetColorMatrix(matrix);
            watermark.MakeTransparent(transparentColor);

            g.DrawImage(watermark, dest, 0, 0, watermark.Width, watermark.Height,
                GraphicsUnit.Pixel, attr, null, IntPtr.Zero);
            g.Save();
        }
    }

    * This source code was highlighted with Source Code Highlighter.

    Additionally, we also use two things:
    public enum WatermarkPosition
    {
        TopLeft = 0,
        TopRight,
        BottomLeft,
        BottomRight,
        Middle
    }

    * This source code was highlighted with Source Code Highlighter.

    to indicate the anchor point, and a method that returns us a specific location of the watermark depending on the size of the images and the anchor point:
    private static Point GetDestination(Size originalSize, Size watermarkSize, WatermarkPosition position)
    {
        Point destination = new Point(0, 0);
        switch (position)
        {
            case WatermarkPosition.TopRight:
                destination.X = originalSize.Width - watermarkSize.Width;
                break;
            case WatermarkPosition.BottomLeft:
                destination.Y = originalSize.Height - watermarkSize.Height;
                break;
            case WatermarkPosition.BottomRight:
                destination.X = originalSize.Width - watermarkSize.Width;
                destination.Y = originalSize.Height - watermarkSize.Height;
                break;
            case WatermarkPosition.Middle:
                destination.X = (originalSize.Width - watermarkSize.Width) / 2;
                destination.Y = (originalSize.Height - watermarkSize.Height) / 2;
                break;
        }
        return destination;
    }
    * This source code was highlighted with Source Code Highlighter.

    In my opinion, everything is quite transparent. The actual logo rendering took only 15 lines, given all the formatting bells and whistles, and even less without them! This result was achieved by using the capabilities of the .NET class ColorMatrix to solve the problem.
    In general, the ColorMatrix class has very wide possibilities for manipulating image settings. With it, you can not only set transparency, but also change the contrast, saturation of the picture, make it negative and much more.

    In conclusion, two things must be noted. The first is the logo used as a watermark, it is better to save it in PNG. GIF format for simple logos is also acceptable. In this case, we can not set transparentColor (more precisely, remove the line altogetherwatermark.MakeTransparent(transparentColor);) and expand the watermark type to Image.

    The second, somewhat more important - my method performs rendering directly on the picture passed to it, without creating a new instance. Therefore, if you need to preserve the original, you will need to slightly redo the method for rendering so that it returns the modified image without affecting the original.

    UPD: If you downloaded the original image from a file and want to save it under the same name, you will also need to create a copy and save it outside the using block.

    UPD2: At the request of Sergeyev, he added a demonstration of the result (on the left is the original picture, on the right is it with the logo well-known to everyone. Not photoshop! :)
     

    Well, that's all!

    PS: So, absolutely imperceptibly, my first topic appeared on Habré :)


    Also popular now: