简体   繁体   English

C#从中心裁剪图像

[英]C# crop image from center

I am developing application using .NET(4.5) MVC(4.0) C#(5.0). 我正在使用.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 thumbnail of maximum square portion from center of image without stretching not whole image except image is square size. 现在的要求是它应该从图像中心生成最大方形部分的缩略图而不拉伸除了图像之外的整个图像是方形尺寸。

as per example my original image size :578x700 i want to generate thumbnail for placeholder size :200x150, 185x138, 140x140, 89x66, 80x80, 45x45, 28x28 根据示例我的原始图像大小:578x700我想生成占位符大小的缩略图:200x150,185x138,140x140,89x66,80x80,45x45,28x28

i had create my below code but didn't get exact result. 我创建了我的下面的代码,但没有得到确切的结果。 here is my core method that generate thumbnail 这是我生成缩略图的核心方法

    public string GenerateThumbnailFromImage(string imageFilePath, int thumbWidth, int thumbHeight)
    {
        try
        {
            //Check if file exist
            if (File.Exists(imageFilePath))
            {
                //bool preserveAspectRatio = true;
                string oldFilePath = imageFilePath;
                string folderPath = Path.GetDirectoryName(imageFilePath);
                string filename = Path.GetFileNameWithoutExtension(imageFilePath);

                //Rename file with thumbnail size
                filename = filename + "_" + thumbWidth.ToString() + Path.GetExtension(imageFilePath);
                imageFilePath = Path.Combine(folderPath, filename);


                using (Image image = Image.FromFile(oldFilePath))
                {
                    decimal originalWidth = image.Width;
                    decimal originalHeight = image.Height;
                    decimal requiredThumbWidth = thumbWidth;
                    decimal requiredThumbHeight = thumbHeight;
                    decimal startXPosition = 0;
                    decimal startYPosition = 0;
                    decimal screenWidth = originalWidth;
                    decimal screenHeight = originalHeight;
                    decimal ar = thumbWidth < thumbHeight 
                                     ? originalWidth / originalHeight
                                     : originalHeight / originalWidth;

                    //Define Starting Position for thumbnail generation
                    if (originalWidth > originalHeight)
                        startXPosition = (originalWidth - originalHeight) / 2;
                    else if (originalHeight > originalWidth)
                        startYPosition = (originalHeight - originalWidth) / 2;

                    if (thumbWidth>thumbHeight)
                    {
                        requiredThumbWidth = thumbWidth;
                        requiredThumbHeight = requiredThumbWidth*ar;
                    }
                    else if (thumbHeight>thumbWidth)
                    {
                        requiredThumbHeight = thumbHeight;
                        requiredThumbWidth = requiredThumbHeight*ar;
                    }
                    else
                    {
                        requiredThumbWidth = thumbWidth;
                        requiredThumbHeight = thumbWidth;
                    }

                    using (var bmp = new Bitmap((int)requiredThumbWidth, (int)requiredThumbHeight))
                    {
                        Graphics gr = Graphics.FromImage(bmp);
                        gr.SmoothingMode = SmoothingMode.HighQuality;
                        gr.CompositingQuality = CompositingQuality.HighQuality;
                        gr.InterpolationMode = InterpolationMode.High;
                        var rectDestination = new Rectangle(0, 0, (int)requiredThumbWidth, (int)requiredThumbHeight);

                        gr.DrawImage(image, rectDestination, (int)startXPosition, (int)startYPosition, (int)screenWidth, (int)screenHeight, GraphicsUnit.Pixel);
                        bmp.Save(imageFilePath);

                        return filename;
                    }
                }
            }
            return null;
        }
        catch (Exception ex)
        {
            GlobalUtil.HandleAndLogException(ex, this);
            throw ex;
        }
        finally
        {

        }
    }

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;
}

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);

Also using the ImageFactory NuGet package, I recommend using the Resize Crop feature. 同样使用ImageFactory NuGet包,我建议使用“ 调整大小裁剪”功能。

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. 这将采用其byte[]格式的任何图像并从中心裁剪。

This is set by the anchorPosition parameter in the ResizeLayer which has a deafult value of AnchorPosition.Center 这是由ResizeLayer中的anchorPosition参数设置的,该参数的deafult值为AnchorPosition.Center

new ResizeLayer(new Size(width, height), ResizeMode.Crop/*, AnchorPosition.Center*/)

In your NuGet package, add this ImageFactory solution by James South . 在您的NuGet包中,添加James South的 ImageFactory解决方案。 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

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. 这样你有一个总是适合的缩略图,可能是X或Y中的一些空格,但图像仍然是相同的比例,而不是拉伸。

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 然后使用Graphics对象将该Image绘制到此大小的新Bitmap

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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM