Search code examples
c#system.drawing

Overlay watermark PNG on JPG file centered


I have a method that takes an image and resizes it and saves it preserving the exif information. What I want to do now is overlay a transparent PNG image on top of the image as a watermark. The size of the png will always be larger than any of the images I want to place it on. I would like to center it on top of the image preserving the watermark's aspect ratio. Here is the code as I have it so far:

private static void ResizeImage(Image theImage, int newSize, string savePath, IEnumerable<PropertyItem> propertyItems)
{
    int width;
    int height;
    CalculateNewRatio(theImage.Width, theImage.Height, newSize, out width, out height);
    using (var b = new Bitmap(width, height))
    {
        using (var g = Graphics.FromImage(b))
        {
            g.SmoothingMode = SmoothingMode.AntiAlias;
            g.InterpolationMode = InterpolationMode.HighQualityBicubic;
            g.PixelOffsetMode = PixelOffsetMode.HighQuality;
            using(var a = Image.FromFile("Watermark.png"))
            {
                g.DrawImage();  //What to do here?
            }
            g.DrawImage(theImage, new Rectangle(0, 0, width, height));

            var qualityParam = new EncoderParameter(Encoder.Quality, 80L);
            var codecs = ImageCodecInfo.GetImageEncoders();
            var jpegCodec = codecs.FirstOrDefault(t => t.MimeType == "image/jpeg");
            var encoderParams = new EncoderParameters(1);
            encoderParams.Param[0] = qualityParam;
            foreach(var item in propertyItems)
            {
                b.SetPropertyItem(item);
            }
            b.Save(savePath, jpegCodec, encoderParams);
        }
    }
}

Solution

  • I figured out the solution, the code is below. May not be the optimal code but it is fast and does what I need it to do which is take all JPG images in a directory and re-size them to full and thumb images for a photo gallery while overlaying a watermark on the image.

    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Drawing.Imaging;
    using System.IO;
    using System.Linq;
    using System.Reflection;
    using System.Threading.Tasks;
    
    namespace ImageResize
    {
        internal class Program
        {
            private static readonly string directory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
    
            private static void Main()
            {
                var strFiles = Directory.GetFiles(directory, "*.jpg");
    
                //Using parallel processing for performance
                Parallel.ForEach(strFiles, strFile =>
                                               {
                                                   using (var image = Image.FromFile(strFile, true))
                                                   {
                                                       var exif = image.PropertyItems;
                                                       var b = directory + "\\" + Path.GetFileNameWithoutExtension(strFile);
                                                       ResizeImage(image, 800, b + "_FULL.jpg", exif);
                                                       ResizeImage(image, 200, b + "_THUMB.jpg", exif);
                                                   }
                                                   File.Delete(strFile);
                                               });
            }
    
            private static void ResizeImage(Image theImage, int newSize, string savePath, IEnumerable<PropertyItem> propertyItems)
            {
                try
                {
                    int width;
                    int height;
                    CalculateNewRatio(theImage.Width, theImage.Height, newSize, out width, out height);
                    using (var b = new Bitmap(width, height))
                    {
                        using (var g = Graphics.FromImage(b))
                        {
                            g.SmoothingMode = SmoothingMode.AntiAlias;
                            g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                            g.PixelOffsetMode = PixelOffsetMode.HighQuality;
                            g.DrawImage(theImage, new Rectangle(0, 0, width, height));
    
                            //Using FileStream to avoid lock issues because of the parallel processing
                            using (var stream = new FileStream(directory + "\\Watermark.png", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                            {
                                using (var overLay = Image.FromStream(stream))
                                {
                                    stream.Close();
                                    int newWidth;
                                    int newHeight;
                                    CalculateNewRatio(overLay.Width, overLay.Height, height > width ? width : newSize, out newWidth, out newHeight);
                                    var x = (b.Width - newWidth) / 2;
                                    var y = (b.Height - newHeight) / 2;
                                    g.DrawImage(overLay, new Rectangle(x, y, newWidth, newHeight));
                                }
                            }
    
                            var qualityParam = new EncoderParameter(Encoder.Quality, 80L);
                            var codecs = ImageCodecInfo.GetImageEncoders();
                            var jpegCodec = codecs.FirstOrDefault(t => t.MimeType == "image/jpeg");
                            var encoderParams = new EncoderParameters(1);
                            encoderParams.Param[0] = qualityParam;
                            foreach (var item in propertyItems)
                            {
                                b.SetPropertyItem(item);
                            }
                            b.Save(savePath, jpegCodec, encoderParams);
                        }
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                }
            }
    
            private static void CalculateNewRatio(int width, int height, int desiredSize, out int newWidth, out int newHeight)
            {
                if ((width >= height && width > desiredSize) || (width <= height && height > desiredSize))
                {
                    if (width > height)
                    {
                        newWidth = desiredSize;
                        newHeight = height*newWidth/width;
                    }
                    else if (width < height)
                    {
                        newHeight = desiredSize;
                        newWidth = width*newHeight/height;
                    }
                    else
                    {
                        newWidth = desiredSize;
                        newHeight = desiredSize;
                    }
                }
                else
                {
                    newWidth = width;
                    newHeight = height;
                }
            }
        }
    }