Redimensionner l'image proportionnellement avec les contraintes MaxHeight et MaxWidth

124

Utilisation System.Drawing.Image.

Si la largeur ou la hauteur d'une image dépasse le maximum, elle doit être redimensionnée proportionnellement. Après redimensionnement, il doit s'assurer qu'aucune largeur ou hauteur ne dépasse toujours la limite.

La largeur et la hauteur seront redimensionnées jusqu'à ce qu'elles ne dépassent pas automatiquement le maximum et le minimum (taille la plus grande possible) et maintiennent également le rapport.

Sarawut Positwinyu
la source
@Sarawut Positwinyu - Mais quel rapport d'aspect voulez-vous?
Bibhu
Que voulez-vous qu'il se passe si une image ne peut pas être redimensionnée au maximum et au minimum de la hauteur et de la largeur et que le rapport hauteur / largeur est conservé?
Conrad Frix
@Bibhu Existe-t-il plusieurs types de rapport hauteur / largeur? je ne sais pas à ce sujet. Je veux juste que le rapport d'image soit similaire au rapport d'image original possible.
Sarawut Positwinyu
@Sarawut Positwinyu - regardez ce lien wiki pour en savoir plus sur les proportions. en.wikipedia.org/wiki/Aspect_ratio_%28image%29
Bibhu
1
@Sarawut Positwinyu Vous n'avez pas abusé du terme rapport hauteur / largeur. Ou si vous l'avez fait, vous êtes en bonne compagnie
Conrad Frix

Réponses:

300

Comme ça?

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;
}
Alex Aza
la source
7
@Alex belle utilisation de Math.Min (j'oublie toujours celui-là)
Conrad Frix
5
Je vous suggère d'utiliser une instruction using sur l'objet Graphics au moins pour économiser des ressources :)
Schalk
Je pense juste à un cas, je ne sais pas s'il est possible ou non qu'après avoir multiplié avec le rapport la largeur ou la hauteur puisse encore plus grande que la largeur maximale ou la hauteur maximale.
Sarawut Positwinyu
4
Assurez-vous également que vous utilisez System.Drawing.Image si vous utilisez asp.net.
Induster
1
@Smith - n'exécutez pas la méthode Save si vous n'avez pas besoin de sauvegarder l'image. C'est exactement ce que fait ma méthode ScaleImage - renvoie l'image sans l'enregistrer.
Alex Aza
5

Solution de travail:

Pour redimensionner l'image avec une taille inférieure à 100 Ko

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

Plus de référence sur http://net4attack.blogspot.com/

user806084
la source
5

Solution beaucoup plus longue, mais tient compte des scénarios suivants:

  1. L'image est-elle plus petite que le cadre de sélection?
  2. L'image et le cadre englobant sont-ils carrés?
  3. Est le carré de l'image et le cadre de sélection n'est pas
  4. L'image est-elle plus large et plus haute que le cadre de sélection
  5. L'image est-elle plus large que le cadre de sélection
  6. L'image est-elle plus haute que le cadre de sélection

    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;
            }
        }
    }
Ryan Mann
la source
1
Je pense qu'il y a quelques fautes de frappe dans lesquelles vous utilisez le rapport pour calculer la nouvelle hauteur de l'image redimensionnée. Corriger var nH = oH * r; Incorrect: var nH = oW * r;
wloescher
Corrigé, jamais commenté.
Ryan Mann