C# crop image from center

前端 未结 6 1697
我寻月下人不归
我寻月下人不归 2020-12-09 13:48

I am developing application using .NET(4.5) MVC(4.0) C#(5.0). i want to generate image thumbnail from image that i already have. Now requirement is like it should generate t

相关标签:
6条回答
  • 2020-12-09 14:43
    public Image ScaleImage(Image image, int maxWidth, int maxHeight)
    {
        var ratioX = (double)maxWidth / image.Width;
        var ratioY = (double)maxHeight / image.Height;
        var ratio = Math.Min(ratioX, ratioY);
    
        var newWidth = (int)(image.Width * ratio);
        var newHeight = (int)(image.Height * ratio);
    
        var newImage = new Bitmap(maxWidth, maxWidth);
        using (var graphics = Graphics.FromImage(newImage))
        {
            // Calculate x and y which center the image
            int y = (maxHeight/2) - newHeight / 2;
            int x = (maxWidth / 2) - newWidth / 2;
    
            // Draw image on x and y with newWidth and newHeight
            graphics.DrawImage(image, x, y, newWidth, newHeight);
        }
    
        return newImage;
    }
    
    0 讨论(0)
  • 2020-12-09 14:46

    Try this:

    bool SaveCroppedImage(Image image, int targetWidth, int targetHeight, string filePath)
    {
        ImageCodecInfo jpgInfo = ImageCodecInfo.GetImageEncoders().Where(codecInfo => codecInfo.MimeType == "image/jpeg").First();
        Image finalImage = image;
        System.Drawing.Bitmap bitmap = null;
        try
        {
            int left = 0;
            int top = 0;
            int srcWidth = targetWidth;
            int srcHeight = targetHeight;
            bitmap = new System.Drawing.Bitmap(targetWidth, targetHeight);
            double croppedHeightToWidth = (double)targetHeight / targetWidth;
            double croppedWidthToHeight = (double)targetWidth / targetHeight;
    
            if (image.Width > image.Height)
            {
                srcWidth = (int)(Math.Round(image.Height * croppedWidthToHeight));
                if (srcWidth < image.Width)
                {
                    srcHeight = image.Height;
                    left = (image.Width - srcWidth) / 2;
                }
                else
                {
                    srcHeight = (int)Math.Round(image.Height * ((double)image.Width / srcWidth));
                    srcWidth = image.Width;
                    top = (image.Height - srcHeight) / 2;
                }
            }
            else
            {
                srcHeight = (int)(Math.Round(image.Width * croppedHeightToWidth));
                if (srcHeight < image.Height)
                {
                    srcWidth = image.Width;
                    top = (image.Height - srcHeight) / 2;
                }
                else
                {
                    srcWidth = (int)Math.Round(image.Width * ((double)image.Height / srcHeight));
                    srcHeight = image.Height;
                    left = (image.Width - srcWidth) / 2;
                }
            }
            using (Graphics g = Graphics.FromImage(bitmap))
            {
                g.SmoothingMode = SmoothingMode.HighQuality;
                g.PixelOffsetMode = PixelOffsetMode.HighQuality;
                g.CompositingQuality = CompositingQuality.HighQuality;
                g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                g.DrawImage(image, new Rectangle(0, 0, bitmap.Width, bitmap.Height), new Rectangle(left, top, srcWidth, srcHeight), GraphicsUnit.Pixel);
            }
            finalImage = bitmap;
        }
        catch { }
        try
        {
            using (EncoderParameters encParams = new EncoderParameters(1))
            {
                encParams.Param[0] = new EncoderParameter(Encoder.Quality, (long)100);
                //quality should be in the range [0..100] .. 100 for max, 0 for min (0 best compression)
                finalImage.Save(filePath, jpgInfo, encParams);
                return true;
            }
        }
        catch { }
        if (bitmap != null)
        {
            bitmap.Dispose();
        }
        return false;
    }
    
    0 讨论(0)
  • 2020-12-09 14:47

    You need to get the ratio of the destination size against the actual size. Scale the shorter side until it touches the actual image size. Crop it starting from the center and scale it to the desired size.

    Here is the code:

    
    
     public static Image ResizeImage(Image imgToResize, Size destinationSize)
            {
                var originalWidth = imgToResize.Width;
                var originalHeight = imgToResize.Height;
    
                //how many units are there to make the original length
                var hRatio = (float)originalHeight/destinationSize.Height;
                var wRatio = (float)originalWidth/destinationSize.Width;
    
                //get the shorter side
                var ratio = Math.Min(hRatio, wRatio);
    
                var hScale = Convert.ToInt32(destinationSize.Height * ratio);
                var wScale = Convert.ToInt32(destinationSize.Width * ratio);
    
                //start cropping from the center
                var startX = (originalWidth - wScale)/2;
                var startY = (originalHeight - hScale)/2;
    
                //crop the image from the specified location and size
                var sourceRectangle = new Rectangle(startX, startY, wScale, hScale);
    
                //the future size of the image
                var bitmap = new Bitmap(destinationSize.Width, destinationSize.Height);
    
                //fill-in the whole bitmap
                var destinationRectangle = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
    
                //generate the new image
                using (var g = Graphics.FromImage(bitmap))
                {
                    g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                    g.DrawImage(imgToResize, destinationRectangle, sourceRectangle, GraphicsUnit.Pixel);
                }
    
                return bitmap;
    
            }
    
    
    

    Call it like this:

    
    var thumbImage = ImageHelper.ResizeImage(image, new Size(45, 45));
    thumbImage.Save(thumbFullPath);
    
    
    0 讨论(0)
  • 2020-12-09 14:50

    In your NuGet package, add this ImageFactory solution by James South. Everything you need is there. I wish I could buy James more beer.

    Sample usage:

    using (ImageFactory imgf = new ImageFactory(preserveExifData: true)) {
        imgf
            .Load(img)
            .Crop(rect)
            .Format(new JpegFormat { Quality = 100 })
            .Save(destination)
    }
    
    // given that :
    // 'img' is your Image object, could be an Image.FromFile() object or the likes
    // 'rect' is the size of your crop and that you have already did the math
    // new JpegFormat { Quality = 70 } is part of the package
    // and 'destination' is the destination path of your new image in your disk
    
    0 讨论(0)
  • 2020-12-09 14:53

    Also using the ImageFactory NuGet package, I recommend using the Resize Crop feature.

    See examples of this here

    using ImageProcessor;
    using ImageProcessor.Imaging;
    using System.Drawing;
    using System.IO;
    
    public static byte[] ResizeAndCrop(byte[] image, int width, int height)
        {
            using (var ms = new MemoryStream())
            {
                using (var imgf = new ImageFactory(true))
                    imgf
                        .Load(image)
                        .Resize(new ResizeLayer(new Size(width, height), ResizeMode.Crop))
                        .Save(ms);
                return ms.ToArray();
            }
        }
    

    This will take any image in its byte[] format and crop from the center.

    This is set by the anchorPosition parameter in the ResizeLayer which has a deafult value of AnchorPosition.Center

    new ResizeLayer(new Size(width, height), ResizeMode.Crop/*, AnchorPosition.Center*/)
    
    0 讨论(0)
  • 2020-12-09 14:54

    Done this a few times before, the trick is to fit the Height of the image first, the rescale the Width to the proportion that you had to reduce the Height, then repeat from the Width if it still doesnt fit by the Width, and reducing the newer scaled Height by that additional proportion. That way you have a thumbnail that always fits, possibly some whitespace in the X or Y, but the image is still to the same proportions, not stretched.

    int originalHeight;
    int originalWidth;
    int imageHeight;
    int imageWidth;
    int requiredHeight;
    int requiredWidth;
    double scale;
    
    if(originalHeight > requiredHeight)
    {
        scale = requiredHeight / originalHeight;
        imageHeight = requiredHeight;
        imageWidth = originalHeight * scale;
    }
    
    if(imageWidth > requiredWidth)
    {
        scale = requiredWidth / imageWidth;
        imageWidth = requiredWidth;
        imageHeight = imageHeight * scale;
    }
    

    And then drawing that Image into a new Bitmap of this size using Graphics object

    0 讨论(0)
提交回复
热议问题