4

我正在使用 .NET(4.5) MVC(4.0) C#(5.0) 开发应用程序。我想从我已经拥有的图像中生成图像缩略图。现在的要求就像它应该从图像中心生成最大正方形部分的缩略图,而不拉伸不是整个图像,除非图像是正方形大小。

例如,我的原始图像尺寸:578x700 我想为占位符尺寸生成缩略图:200x150、185x138、140x140、89x66、80x80、45x45、28x28

我已经创建了下面的代码,但没有得到确切的结果。这是我生成缩略图的核心方法

    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
        {

        }
    }
4

6 回答 6

14

您需要获取目标大小与实际大小的比率。缩放较短的一侧,直到它接触到实际的图像尺寸。从中心开始裁剪并缩放到所需的大小。

这是代码:



 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;

        }


像这样称呼它:


var thumbImage = ImageHelper.ResizeImage(image, new Size(45, 45));
thumbImage.Save(thumbFullPath);

于 2014-11-27T06:28:53.303 回答
8

尝试这个:

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;
}
于 2013-11-17T20:13:06.620 回答
4

在您的 NuGet 包中,添加James South的这个ImageFactory解决方案。你需要的一切都在那里。我希望我可以给詹姆斯买更多的啤酒。

示例用法:

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
于 2017-09-18T20:32:10.790 回答
3

同样使用 ImageFactory NuGet 包,我建议使用Resize Crop功能。

在此处查看示例

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

这将采用其byte[]格式并从中心裁剪任何图像。

这是由 ResizeLayer 中的 anchorPosition 参数设置的,其默认值为 AnchorPosition.Center

new ResizeLayer(new Size(width, height), ResizeMode.Crop/*, AnchorPosition.Center*/)
于 2018-01-20T06:55:17.253 回答
2
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;
}
于 2017-06-21T18:15:46.430 回答
1

之前做过几次,诀窍是首先适合图像的高度,将宽度重新缩放到您必须减少高度的比例,然后如果仍然不适合宽度,则从宽度重复,并减少新的按该额外比例缩放的高度。这样你就有了一个总是适合的缩略图,可能在 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;
}

然后使用对象将其绘制ImageBitmap这个大小的新Graphics对象

于 2013-08-02T10:33:36.337 回答