Ridimensiona l'immagine proporzionalmente con i vincoli MaxHeight e MaxWidth


124

utilizzando System.Drawing.Image .

Se la larghezza o l'altezza di un'immagine supera il massimo, è necessario ridimensionarla proporzionalmente. Dopo il ridimensionamento, è necessario assicurarsi che né la larghezza né l'altezza superino ancora il limite.

La larghezza e l'altezza verranno ridimensionate fino a quando non vengono superate automaticamente al massimo e al minimo (la dimensione più grande possibile) e mantengono anche il rapporto.


@Sarawut Positwinyu - Ma che proporzioni vuoi?
Bibhu

Cosa vuoi che accada se un'immagine non può essere ridimensionata al massimo e al minimo dell'altezza e della larghezza e le proporzioni vengono mantenute?
Conrad Frix

@Bibhu Esistono molti tipi di proporzioni? non lo so. Voglio solo che le proporzioni dell'immagine siano simili a quelle possibili per l'annuncio del rapporto immagine originale.
Sarawut Positwinyu

@Sarawut Positwinyu - guarda questo collegamento wiki per ulteriori informazioni sulle proporzioni. en.wikipedia.org/wiki/Aspect_ratio_%28image%29
Bibhu

1
@Sarawut Positwinyu Non hai abusato del termine aspect ratio. O se l'hai fatto sei in buona compagnia
Conrad Frix

Risposte:


300

Come questo?

public static void Test()
{
    using (var image = Image.FromFile(@"c:\logo.png"))
    using (var newImage = ScaleImage(image, 300, 400))
    {
        newImage.Save(@"c:\test.png", ImageFormat.Png);
    }
}

public static 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(newWidth, newHeight);

    using (var graphics = Graphics.FromImage(newImage))
        graphics.DrawImage(image, 0, 0, newWidth, newHeight);

    return newImage;
}

7
@Alex buon uso di Math.Min (me ne dimentico sempre)
Conrad Frix,

5
Suggerirei di utilizzare un'istruzione using sull'oggetto Graphics almeno per risparmiare alcune risorse :)
Schalk

Sto solo pensando a un caso, non sono sicuro se sia possibile o meno che dopo aver moltiplicato con il rapporto la larghezza o l'altezza potrebbe ancora essere maggiore della larghezza massima o dell'altezza massima.
Sarawut Positwinyu

4
Assicurati inoltre di utilizzare System.Drawing.Image se utilizzi asp.net.
Induster

1
@Smith: non eseguire il metodo di salvataggio se non è necessario salvare l'immagine. Questo è esattamente ciò che fa il mio metodo ScaleImage: restituisce l'immagine senza salvarla.
Alex Aza

5

Soluzione di lavoro:

Per Ridimensiona immagine con dimensioni inferiori a 100 KB

WriteableBitmap bitmap = new WriteableBitmap(140,140);
bitmap.SetSource(dlg.File.OpenRead());
image1.Source = bitmap;

Image img = new Image();
img.Source = bitmap;
WriteableBitmap i;

do
{
    ScaleTransform st = new ScaleTransform();
    st.ScaleX = 0.3;
    st.ScaleY = 0.3;
    i = new WriteableBitmap(img, st);
    img.Source = i;
} while (i.Pixels.Length / 1024 > 100);

Ulteriori riferimenti su http://net4attack.blogspot.com/


5

Soluzione molto più lunga, ma tiene conto dei seguenti scenari:

  1. L'immagine è più piccola del riquadro di delimitazione?
  2. L'immagine e il riquadro di delimitazione sono quadrati?
  3. L'immagine è quadrata e il riquadro di delimitazione no
  4. L'immagine è più larga e più alta del riquadro di delimitazione
  5. L'immagine è più ampia del riquadro di delimitazione
  6. L'immagine è più alta del riquadro di delimitazione

    private Image ResizePhoto(FileInfo sourceImage, int desiredWidth, int desiredHeight)
    {
        //throw error if bouning box is to small
        if (desiredWidth < 4 || desiredHeight < 4)
            throw new InvalidOperationException("Bounding Box of Resize Photo must be larger than 4X4 pixels.");            
        var original = Bitmap.FromFile(sourceImage.FullName);
    
        //store image widths in variable for easier use
        var oW = (decimal)original.Width;
        var oH = (decimal)original.Height;
        var dW = (decimal)desiredWidth;
        var dH = (decimal)desiredHeight;
    
        //check if image already fits
        if (oW < dW && oH < dH)
            return original; //image fits in bounding box, keep size (center with css) If we made it bigger it would stretch the image resulting in loss of quality.
    
        //check for double squares
        if (oW == oH && dW == dH)
        {
            //image and bounding box are square, no need to calculate aspects, just downsize it with the bounding box
            Bitmap square = new Bitmap(original, (int)dW, (int)dH);
            original.Dispose();
            return square;
        }
    
        //check original image is square
        if (oW == oH)
        {
            //image is square, bounding box isn't.  Get smallest side of bounding box and resize to a square of that center the image vertically and horizontally with Css there will be space on one side.
            int smallSide = (int)Math.Min(dW, dH);
            Bitmap square = new Bitmap(original, smallSide, smallSide);
            original.Dispose();
            return square;
        }
    
        //not dealing with squares, figure out resizing within aspect ratios            
        if (oW > dW && oH > dH) //image is wider and taller than bounding box
        {
            var r = Math.Min(dW, dH) / Math.Min(oW, oH); //two dimensions so figure out which bounding box dimension is the smallest and which original image dimension is the smallest, already know original image is larger than bounding box
            var nH = oH * r; //will downscale the original image by an aspect ratio to fit in the bounding box at the maximum size within aspect ratio.
            var nW = oW * r;
            var resized = new Bitmap(original, (int)nW, (int)nH);
            original.Dispose();
            return resized;
        }
        else
        {
            if (oW > dW) //image is wider than bounding box
            {
                var r = dW / oW; //one dimension (width) so calculate the aspect ratio between the bounding box width and original image width
                var nW = oW * r; //downscale image by r to fit in the bounding box...
                var nH = oH * r;
                var resized = new Bitmap(original, (int)nW, (int)nH);
                original.Dispose();
                return resized;
            }
            else
            {
                //original image is taller than bounding box
                var r = dH / oH;
                var nH = oH * r;
                var nW = oW * r;
                var resized = new Bitmap(original, (int)nW, (int)nH);
                original.Dispose();
                return resized;
            }
        }
    }

1
Penso che ci siano un paio di errori di battitura in cui stai usando il rapporto per calcolare la nuova altezza per l'immagine ridimensionata. Correggere var nH = oH * r; Errato: var nH = oW * r;
wloescher

Risolto, ma mai commentato.
Ryan Mann
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.