Please help me correct the small bugs in this image editor
- by Alex
Hi, I'm working on a website that will sell hand made jewelry and I'm finishing the image editor, but it's not behaving quite right.
Basically, the user uploads an image which will be saved as a source and then it will be resized to fit the user's screen and saved as a temp. The user will then go to a screen that will allow them to crop the image and then save it to it's final versions.
All of that works fine, except, the final versions have 3 bugs. First is some black horizontal line on the very bottom of the image. Second is an outline of sorts that follows the edges. I thought it was because I was reducing the quality, but even at 100% it still shows up... And lastly, I've noticed that the cropped image is always a couple of pixels lower than what I'm specifying...
Anyway, I'm hoping someone whose got experience in editing images with C# can maybe take a look at the code and see where I might be going off the right path.
Oh, by the way, this in an ASP.NET MVC application.
Here's the code:
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Web;
namespace Website.Models.Providers {
    public class ImageProvider {
        private readonly ProductProvider ProductProvider = null;
        private readonly EncoderParameters HighQualityEncoder = new EncoderParameters();
        private readonly ImageCodecInfo JpegCodecInfo = ImageCodecInfo.GetImageEncoders().Single(
            c =>
                (c.MimeType == "image/jpeg"));
        private readonly string Path = HttpContext.Current.Server.MapPath("~/Resources/Images/Products");
        private readonly short[][] Dimensions = new short[3][] {
            new short[2] {
                640,
                480
            },
            new short[2] {
                240,
                0
            },
            new short[2] {
                80,
                60
            }
        };
        //////////////////////////////////////////////////////////
        //  Constructor //////////////////////////////////////////
        //////////////////////////////////////////////////////////
        public ImageProvider(
            ProductProvider ProductProvider) {
            this.ProductProvider = ProductProvider;
            HighQualityEncoder.Param[0] = new EncoderParameter(Encoder.Quality, 100L);
        }
        //////////////////////////////////////////////////////////
        //  Crop    //////////////////////////////////////////////
        //////////////////////////////////////////////////////////
        public void Crop(
            string FileName,
            Image Image,
            Crop Crop) {
            using (Bitmap Source = new Bitmap(Image)) {
                using (Bitmap Target = new Bitmap(Crop.Width, Crop.Height)) {
                    using (Graphics Graphics = Graphics.FromImage(Target)) {
                        Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
                        Graphics.SmoothingMode = SmoothingMode.HighQuality;
                        Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
                        Graphics.CompositingQuality = CompositingQuality.HighQuality;
                        Graphics.DrawImage(Source, new Rectangle(0, 0, Target.Width, Target.Height), new Rectangle(Crop.Left, Crop.Top, Crop.Width, Crop.Height), GraphicsUnit.Pixel);
                    };
                    Target.Save(FileName, JpegCodecInfo, HighQualityEncoder);
                };
            };
        }
        //////////////////////////////////////////////////////////
        //  Crop & Resize   //////////////////////////////////////
        //////////////////////////////////////////////////////////
        public void CropAndResize(
            Product Product,
            Crop Crop) {
            using (Image Source = Image.FromFile(String.Format("{0}/{1}.source", Path, Product.ProductId))) {
                using (Image Temp = Image.FromFile(String.Format("{0}/{1}.temp", Path, Product.ProductId))) {
                    float Percent = ((float)Source.Width / (float)Temp.Width);
                    short Width = (short)(Temp.Width * Percent);
                    short Height = (short)(Temp.Height * Percent);
                    Crop.Height = (short)(Crop.Height * Percent);
                    Crop.Left = (short)(Crop.Left * Percent);
                    Crop.Top = (short)(Crop.Top * Percent);
                    Crop.Width = (short)(Crop.Width * Percent);
                    Img Img = new Img();
                    this.ProductProvider.AddImageAndSave(Product, Img);
                    this.Crop(String.Format("{0}/{1}.cropped", Path, Img.ImageId), Source, Crop);
                    using (Image Cropped = Image.FromFile(String.Format("{0}/{1}.cropped", Path, Img.ImageId))) {
                        this.Resize(this.Dimensions[0], String.Format("{0}/{1}-L.jpg", Path, Img.ImageId), Cropped, HighQualityEncoder);
                        this.Resize(this.Dimensions[1], String.Format("{0}/{1}-T.jpg", Path, Img.ImageId), Cropped, HighQualityEncoder);
                        this.Resize(this.Dimensions[2], String.Format("{0}/{1}-S.jpg", Path, Img.ImageId), Cropped, HighQualityEncoder);
                    };
                };
            };
            this.Purge(Product);
        }
        //////////////////////////////////////////////////////////
        //  Queue   //////////////////////////////////////////////
        //////////////////////////////////////////////////////////
        public void QueueFor(
            Product Product,
            HttpPostedFileBase PostedFile) {
            using (Image Image = Image.FromStream(PostedFile.InputStream)) {
                this.Resize(new short[2] {
                    1152,
                    0
                }, String.Format("{0}/{1}.temp", Path, Product.ProductId), Image, HighQualityEncoder);
            };
            PostedFile.SaveAs(String.Format("{0}/{1}.source", Path, Product.ProductId));
        }
        //////////////////////////////////////////////////////////
        //  Purge   //////////////////////////////////////////////
        //////////////////////////////////////////////////////////
        private void Purge(
            Product Product) {
            string Source = String.Format("{0}/{1}.source", Path, Product.ProductId);
            string Temp = String.Format("{0}/{1}.temp", Path, Product.ProductId);
            if (File.Exists(Source)) {
                File.Delete(Source);
            };
            if (File.Exists(Temp)) {
                File.Delete(Temp);
            };
            foreach (Img Img in Product.Imgs) {
                string Cropped = String.Format("{0}/{1}.cropped", Path, Img.ImageId);
                if (File.Exists(Cropped)) {
                    File.Delete(Cropped);
                };
            };
        }
        //////////////////////////////////////////////////////////
        //  Resize  //////////////////////////////////////////////
        //////////////////////////////////////////////////////////
        public void Resize(
            short[] Dimensions,
            string FileName,
            Image Image,
            EncoderParameters EncoderParameters) {
            if (Dimensions[1] == 0) {
                Dimensions[1] = (short)(Image.Height / ((float)Image.Width / (float)Dimensions[0]));
            };
            using (Bitmap Bitmap = new Bitmap(Dimensions[0], Dimensions[1])) {
                using (Graphics Graphics = Graphics.FromImage(Bitmap)) {
                    Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
                    Graphics.SmoothingMode = SmoothingMode.HighQuality;
                    Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
                    Graphics.CompositingQuality = CompositingQuality.HighQuality;
                    Graphics.DrawImage(Image, 0, 0, Dimensions[0], Dimensions[1]);
                };
                Bitmap.Save(FileName, JpegCodecInfo, EncoderParameters);
            };
        }
    }
}
Here's one of the images this produces: