41 votes

Redimensionner l'image pour l'adapter au cadre de sélection

Un problème facile, mais pour une raison quelconque, je ne peux tout simplement pas comprendre cela aujourd'hui.

J'ai besoin de redimensionner une image à la taille maximale possible qui tiendra dans une boîte englobante tout en conservant le rapport hauteur / largeur.

Fondamentalement, je cherche le code pour remplir cette fonction:

 void CalcNewDimensions(ref int w, ref int h, int MaxWidth, int MaxHeight);
 

Où w & h sont la hauteur et la largeur d'origine (entrée) et la nouvelle hauteur et largeur (sortie) et MaxWidth et MaxHeight définissent le cadre de délimitation dans lequel l'image doit s'insérer.

98voto

Shawn J. Goff Points 1582

Trouvez ce qui est plus petit: MaxWidth / w ou MaxHeight / h Puis multipliez w et h par ce nombre

Explication:

Vous devez trouver le facteur d'échelle qui rend l'image adaptée.

Pour trouver le facteur d'échelle, s, pour la largeur, alors s doit être tel que: s * w = MaxWidth. Par conséquent, le facteur d'échelle est MaxWidth / w.

De même pour la hauteur.

Celui qui nécessite le plus de mise à l'échelle (s plus petits) est le facteur par lequel vous devez mettre à l'échelle l'image entière.

28voto

Matt Warren Points 7297

Sur la base de la suggestion d'Eric, je ferais quelque chose comme ceci:

 private static Size ExpandToBound(Size image, Size boundingBox)
{       
    double widthScale = 0, heightScale = 0;
    if (image.Width != 0)
        widthScale = (double)boundingBox.Width / (double)image.Width;
    if (image.Height != 0)
        heightScale = (double)boundingBox.Height / (double)image.Height;                

    double scale = Math.Min(widthScale, heightScale);

    Size result = new Size((int)(image.Width * scale), 
                        (int)(image.Height * scale));
    return result;
}
 

J'aurais peut-être un peu exagéré sur les lancers, mais j'essayais juste de préserver la précision des calculs.

8voto

vocaro Points 1995

Pour effectuer un remplissage d'aspect au lieu d'un ajustement d'aspect, utilisez plutôt le rapport le plus élevé. Autrement dit, changez le code de Matt de Math.Min en Math.Max.

(Un remplissage d'aspect ne laisse aucune zone de délimitation vide mais peut mettre une partie de l'image en dehors des limites, tandis qu'un ajustement d'aspect ne laisse aucune image en dehors des limites mais peut laisser une partie de la zone de délimitation vide.)

7voto

Brian Chavez Points 2507

J'ai essayé le code de M. Warren, mais cela n'a pas produit de résultats fiables.

Par exemple,

 ExpandToBound(new Size(640,480), new Size(66, 999)).Dump();
// {Width=66, Height=49}

ExpandToBound(new Size(640,480), new Size(999,50)).Dump();
// {Width=66, Height=50}
 

Vous pouvez voir, hauteur = 49 et hauteur = 50 dans un autre.

Voici la mienne (version basée sur le code de M. Warren) sans la différence et un léger refactor:

 // Passing null for either maxWidth or maxHeight maintains aspect ratio while
//        the other non-null parameter is guaranteed to be constrained to
//        its maximum value.
//
//  Example: maxHeight = 50, maxWidth = null
//    Constrain the height to a maximum value of 50, respecting the aspect
//    ratio, to any width.
//
//  Example: maxHeight = 100, maxWidth = 90
//    Constrain the height to a maximum of 100 and width to a maximum of 90
//    whichever comes first.
//
private static Size ScaleSize( Size from, int? maxWidth, int? maxHeight )
{
   if ( !maxWidth.HasValue && !maxHeight.HasValue ) throw new ArgumentException( "At least one scale factor (toWidth or toHeight) must not be null." );
   if ( from.Height == 0 || from.Width == 0 ) throw new ArgumentException( "Cannot scale size from zero." );

   double? widthScale = null;
   double? heightScale = null;

   if ( maxWidth.HasValue )
   {
       widthScale = maxWidth.Value / (double)from.Width;
   }
   if ( maxHeight.HasValue )
   {
       heightScale = maxHeight.Value / (double)from.Height;
   }

   double scale = Math.Min( (double)(widthScale ?? heightScale),
                            (double)(heightScale ?? widthScale) );

   return new Size( (int)Math.Floor( from.Width * scale ), (int)Math.Ceiling( from.Height * scale ) );
}
 

5voto

Mennan Kara Points 4008

Le code suivant produit des résultats plus précis:

     public static Size CalculateResizeToFit(Size imageSize, Size boxSize)
    {
        // TODO: Check for arguments (for null and <=0)
        var widthScale = boxSize.Width / (double)imageSize.Width;
        var heightScale = boxSize.Height / (double)imageSize.Height;
        var scale = Math.Min(widthScale, heightScale);
        return new Size(
            (int)Math.Round((imageSize.Width * scale)),
            (int)Math.Round((imageSize.Height * scale))
            );
    }
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X