Изменение размера изображения в C # - алгоритм определения размеров изменения размера (высота и ширина) - PullRequest
5 голосов
/ 07 марта 2011

Мне нужно уменьшить изображение, высота или ширина которого больше заранее заданного значения в пикселях.

Я написал некоторый код, который смотрит на оригинальное изображение, проверяет, есть ли ширина,высота или высота и ширина больше, чем параметры Макс. ширина / Макс. высота.

Теперь мне нужно выяснить, к каким размерам необходимо изменить размер, основываясь на максимуме последнего значения.

Например: если изображение 900h x 300w и МАКС. Высота 700h, мне нужно изменить высоту до 700 и ширину до ???? <- это то, что мне нужно рассчитать .. </p>

Создание и сохранение файла изображения просты, и выходят за рамки этого поста:

// First I get the max height and width allowed:

int resizeMaxHeight =  int.Parse(Utility.GetConfigValue("ResizeMaxHeight")); // in config: 700px
int resizeMaxWidth =  int.Parse(Utility.GetConfigValue("ResizeMaxWidth"));  //  in config: 500px

// Save original: 
try
{
    filebase.SaveAs(savedFileName);
}
catch (System.IO.DirectoryNotFoundException ex)
{
    Logger.Instance.LogException(ex, 0, "FileTransfer");
}

// Determin original dimensions:
Image image = System.Drawing.Image.FromFile(Server.MapPath(savedFileName));

int resizeHeight, resizeWidth;
bool doResize = true;

// both height and width are greater than the allowed height and width:
if (image.Width > resizeMaxWidth && image.Height > resizeMaxHeight)
{
    if (image.Height > image.Width) 
        resizeHeight = resizeMaxHeight;
    else
        resizeWidth = resizeMaxWidth;
}
else if (image.Width > resizeMaxWidth)
{
    // width is too great, but height is ok
    resizeWidth = resizeMaxWidth;
}
else if (image.Height > resizeMaxHeight)
{
    // height is too great, but width is ok
    resizeHeight = resizeMaxHeight;
}
else
{
    // image is ok size, don't resize:
    doResize = false;
}

Создание эскиза: Это то, над чем я сейчас работаю ... не завершено:

if (doResize)
{
    ImageUtilities.ResizeImage(image, resizeWidth, resizeHeight);
}

Ответы [ 5 ]

14 голосов
/ 19 июня 2013

Решение, опубликованное Натаниэлем, на самом деле терпит неудачу, если высота изображения больше ширины изображения.Следующий пример дает правильный результат:

private Size ResizeFit(Size originalSize, Size maxSize)
{
    var widthRatio = (double)maxSize.Width / (double)originalSize.Width;
    var heightRatio = (double) maxSize.Height/(double) originalSize.Height;
    var minAspectRatio = Math.Min(widthRatio, heightRatio);
    if (minAspectRatio > 1)
        return originalSize;
    return new Size((int)(originalSize.Width*minAspectRatio), (int)(originalSize.Height*minAspectRatio));
}
7 голосов
/ 07 марта 2011

Вот два способа сделать этот расчет.В зависимости от того, как вы думаете о проблеме, один может казаться более интуитивным, чем другой.Они математически эквивалентны нескольким десятичным разрядам.

Оба безопасны для Math.Round, но только ConstrainVerbose выдает результаты, которые всегда меньше, чем maxWidth / maxHeight.

SizeF ConstrainConcise(int imageWidth, int imageHeight, int maxWidth, int maxHeight){
    // Downscale by the smallest ratio (never upscale)
    var scale = Math.Min(1, Math.Min(maxWidth / (float)imageWidth, maxHeight / (float) imageHeight));
    return new SizeF(scale * imageWidth, scale * imageHeight);
}

SizeF ConstrainVerbose(int imageWidth, int imageHeight, int maxWidth, int maxHeight){
    // Coalculate the aspect ratios of the image and bounding box
    var maxAspect = (float) maxWidth / (float) maxHeight;
    var aspect =  (float) imageWidth / (float) imageHeight;
    // Bounding box aspect is narrower
    if (maxAspect <= aspect && imageWidth > maxWidth)
    {
        // Use the width bound and calculate the height
        return new SizeF(maxWidth, Math.Min(maxHeight, maxWidth / aspect));
    }
    else if (maxAspect > aspect && imageHeight > maxHeight)
    {
        // Use the height bound and calculate the width
        return new SizeF(Math.Min(maxWidth, maxHeight * aspect), maxHeight);
    }else{
        return new SizeF(imageWidth, imageHeight);
    }
}

Здесь тест на грубую силу

6 голосов
/ 07 марта 2011

Вы можете избежать вычисления соотношения сторон (и использовать двойные числа), используя несколько целочисленных приемов.

// You have the new height, you need the new width
int orgHeight = 1200;
int orgWidth = 1920;

int newHeight = 400;
int newWidth = (newHeight * orgWidth) / orgHeight; // 640

или ...

// You have the new width, you need the new height.
int orgWidth = 1920;
int orgHeight = 1200;

int newWidth = 800;
int newHeight = (newWidth * orgHeight) / orgWidth; // 500

В следующем примере будет изменен размеризображение по любому желаемому прямоугольнику (desWidth и desHeight) и центрируйте изображение в этом прямоугольнике.

static Image ResizeImage(Image image, int desWidth, int desHeight)
{
    int x, y, w, h;

    if (image.Height > image.Width)
    {
        w = (image.Width * desHeight) / image.Height;
        h = desHeight;
        x = (desWidth - w) / 2;
        y = 0;
    }
    else
    {
        w = desWidth;
        h = (image.Height * desWidth) / image.Width;
        x = 0;
        y = (desHeight - h) / 2;
    }

    var bmp = new Bitmap(desWidth, desHeight);

    using (Graphics g = Graphics.FromImage(bmp))
    {
        g.CompositingQuality = CompositingQuality.HighQuality;
        g.InterpolationMode = InterpolationMode.HighQualityBicubic;
        g.DrawImage(image, x, y, w, h);
    }

    return bmp;
}
2 голосов
/ 07 марта 2011

Я сделал нечто похожее для растровых изображений, но идея та же:

1. get image height and width
2. get current screen resolution
3. calculate aspect ratio (ASR) from image size

Handle following cases:

4. if ASR >=1 and image width > image height
    if image width > screen width {}
        if image height > screen height {}
        else if image width > screen width {}
    else {}
   else
    if image height > screen height {}
    else if image width > screen width {}
    else {}

// SCREEN_SIZE настраивается; Defs.SCREEN_SIZE = 100; // и boolPixelAR имеет значение true;

Попробуйте следующий код:

            // PERCENTAGE OF IMAGE -> TODO: Configurable? IMAZE ZOOM / SCREEN PERCENTAGE
            Double HScale = __bmp.Width;// *Defs.SCREEN_SIZE / 100;
            Double VScale = __bmp.Height;// *Defs.SCREEN_SIZE / 100;
            Double __aspectRatio;
            Double __screenRatio = _currentScreenSize.Width / _currentScreenSize.Height;

            // PERCENTAGE OF SCREEN
            if (!_boolPixelAR) {
                HScale = _currentScreenSize.Width * Defs.SCREEN_SIZE / 100;
                VScale = _currentScreenSize.Height * Defs.SCREEN_SIZE / 100;
            }
            else {
                __aspectRatio = HScale / VScale;
                if( __aspectRatio >= 1)
                    if (HScale >= _currentScreenSize.Width) {  // Long Edge is WIDTH. For 100%, HScale = WIDTH
                        VScale = ((VScale * _currentScreenSize.Width) / HScale) * Defs.SCREEN_SIZE / 100;
                        HScale = _currentScreenSize.Width * Defs.SCREEN_SIZE / 100;

                        if (VScale > _currentScreenSize.Height) {                  // Long Edge is HEIGHT. For 100%, VScale = HEIGHT
                            //__aspectRatio = VScale / HScale;
                            HScale = ((HScale * _currentScreenSize.Height) / VScale) * Defs.SCREEN_SIZE / 100;
                            VScale = _currentScreenSize.Height * Defs.SCREEN_SIZE / 100;
                        }
                    }
                    else if (VScale > _currentScreenSize.Height) {                  // Long Edge is HEIGHT. For 100%, VScale = HEIGHT
                        //__aspectRatio = VScale / HScale;
                        HScale = ((HScale * _currentScreenSize.Height) / VScale) * Defs.SCREEN_SIZE / 100;
                        VScale = _currentScreenSize.Height * Defs.SCREEN_SIZE / 100;
                    } 
                    else {
                        //Do nothing... Just set Zoom.
                        HScale = HScale * Defs.SCREEN_SIZE / 100;
                        VScale = VScale * Defs.SCREEN_SIZE / 100;
                    }
                else 
                    if (VScale > _currentScreenSize.Height) {                  // Long Edge is HEIGHT. For 100%, VScale = HEIGHT
                        //__aspectRatio = VScale / HScale;
                        HScale = ((HScale * _currentScreenSize.Height) / VScale) * Defs.SCREEN_SIZE / 100;
                        VScale = _currentScreenSize.Height * Defs.SCREEN_SIZE / 100;
                    }
                    else if (HScale >= _currentScreenSize.Width) {  // Long Edge is WIDTH. For 100%, HScale = WIDTH
                        VScale = ((VScale * _currentScreenSize.Width) / HScale) * Defs.SCREEN_SIZE / 100;
                        HScale = _currentScreenSize.Width * Defs.SCREEN_SIZE / 100;
                    } 
                    else {
                        //Do nothing... Just set Zoom.
                        HScale = HScale * Defs.SCREEN_SIZE / 100;
                        VScale = VScale * Defs.SCREEN_SIZE / 100;
                    }

                ////__aspectRatio = VScale / HScale;
                //HScale = ((HScale * _currentScreenSize.Height) / VScale) * Defs.SCREEN_SIZE / 100;
                //VScale = _currentScreenSize.Height * Defs.SCREEN_SIZE / 100;
            }

            Bitmap scaledBmp = GraphicsFactory.ResizeImage(
                                        __bmp,
                                        Convert.ToInt32(HScale),
                                        Convert.ToInt32(VScale));
0 голосов
/ 07 октября 2015

Для подгонки изображения под новый размер требуется две операции:

  1. Изменить размер - изменить размер исходного изображения, чтобы оно соответствовало точно одному размеру (ширина или высота - размер с меньшим соотношением)

  2. Обрезать - обрезать результат предыдущей операции до целевых размеров

Вот небольшой пример:

    private static Image Resize(Image img, int width, int height)
    {
        Bitmap b = new Bitmap(width, height);
        using (Graphics g = Graphics.FromImage((Image)b))
        {
            g.DrawImage(img, 0, 0, width, height);
        }

        return (Image)b;
    }

    public static Image Crop(Image image, int width, int height)
    {
        int cropx = image.Width > width ? image.Width / 2 - width / 2 : 0;
        int cropy = image.Height > height ? image.Height / 2 - height / 2 : 0;
        width = image.Width > width ? width : image.Width;
        height = image.Height > height ? height : image.Height;

        Rectangle cropRect = new Rectangle(cropx, cropy, width, height);

        var target = new Bitmap(cropRect.Width, cropRect.Height);

        using (Graphics g = Graphics.FromImage(target))
        {
            g.DrawImage(image, new Rectangle(0, 0, target.Width, target.Height), cropRect, GraphicsUnit.Pixel);
        }

        return target;
    }

    public static Image FitToSize(Image image, int width, int height)
    {
        var wratio = 1.0 * image.Width / width;
        var hratio = 1.0 * image.Height / height;

        int wresize;
        int hresize;

        if (wratio >= hratio && wratio > 1)
        {
            wresize = (int)Math.Round((double)image.Width / hratio);
            hresize = height;

            image = Resize(image, wresize, hresize);
            image = Crop(image, width, height);  
        }
        else if (hratio >= wratio && hratio > 1)
        {
            hresize = (int)Math.Round((double)image.Height / wratio);
            wresize = width;

            image = Resize(image, wresize, hresize);
            image = Crop(image, width, height);
        }
        return image;

    }
...