Silverlight Rotate & Scale une image bitmap pour tenir dans un rectangle sans recadrage

Je dois faire pivoter un WriteableBitmap et le réduire ou le réduire avant qu’il ne soit rogné.

Mon code actuel va pivoter mais rogner les bords si la hauteur est supérieure à la largeur

Je suppose que j’ai besoin d’échelle?

public WriteableBitmap Rotate(WriteableBitmap Source, double Angle) { RotateTransform rt = new RotateTransform(); rt.Angle = Angle; TransformGroup transform = new TransformGroup(); transform.Children.Add(rt); Image tempImage2 = new Image(); WriteableBitmap wb; rt.CenterX = Source.PixelWidth / 2; rt.CenterY = Source.PixelHeight / 2; tempImage2.Width = Source.PixelWidth; tempImage2.Height = Source.PixelHeight; wb = new WriteableBitmap((int)(Source.PixelWidth), Source.PixelHeight); tempImage2.Source = Source; tempImage2.UpdateLayout(); wb.Render(tempImage2, transform); wb.Invalidate(); return wb; } 

Comment puis-je réduire l’image pour qu’elle ne soit pas recadrée? Ou y a-t-il un autre moyen?

Vous devez calculer la mise à l’échelle en fonction de la rotation des coins par rapport au centre.

Si l’image est un carré, un seul coin est nécessaire, mais pour un rectangle, vous devez vérifier 2 coins afin de voir si un bord vertical ou horizontal est recouvert. Cette vérification est une comparaison linéaire du dépassement de la hauteur et de la largeur du rectangle.

Cliquez ici pour voir l’application de test créée pour cette réponse (image ci-dessous):

entrez la description de l'image ici

 double CalculateConstraintScale(double rotation, int pixelWidth, int pixelHeight) 

Le pseudo-code est le suivant (code C # réel à la fin):

  • Convertir l’angle de rotation en radians
  • Calculer le “rayon” du centre du rectangle à un coin
  • Conversion de la position du coin BR en coordonnées polaires
  • Conversion de la position du coin BL en coordonnées polaires
  • Appliquer la rotation aux deux coordonnées polaires
  • Convertir les nouvelles positions en coordonnées cartésiennes (valeur ABS)
  • Trouvez la plus grande des 2 positions horizontales
  • Trouvez la plus grande des 2 positions verticales
  • Calculer le changement de delta pour la taille horizontale
  • Calculer le changement de delta pour la taille verticale
  • Retour largeur / 2 / x si le changement horizontal est plus grand
  • Hauteur de retour / 2 / an si le changement vertical est supérieur

Le résultat est un multiplicateur qui réduira l’image pour l’adapter au rectangle d’origine, quelle que soit la rotation.

** Remarque: Bien qu’il soit possible d’effectuer une grande partie des calculs en utilisant des opérations masortingcielles, il n’y a pas assez de calculs pour le justifier. J’ai aussi pensé que cela ferait un meilleur exemple à partir de principes premiers. *

Code C #:

  ///  /// Calculate the scaling required to fit a rectangle into a rotation of that same rectangle ///  /// Rotation in degrees /// Width in pixels /// Height in pixels /// A scaling value between 1 and 0 /// Released to the public domain 2011 - David Johnston (HiTech Magic Ltd) private double CalculateConstraintScale(double rotation, int pixelWidth, int pixelHeight) { // Convert angle to radians for the math lib double rotationRadians = rotation * PiDiv180; // Centre is half the width and height double width = pixelWidth / 2.0; double height = pixelHeight / 2.0; double radius = Math.Sqrt(width * width + height * height); // Convert BR corner into polar coordinates double angle = Math.Atan(height / width); // Now create the matching BL corner in polar coordinates double angle2 = Math.Atan(height / -width); // Apply the rotation to the points angle += rotationRadians; angle2 += rotationRadians; // Convert back to rectangular coordinate double x = Math.Abs(radius * Math.Cos(angle)); double y = Math.Abs(radius * Math.Sin(angle)); double x2 = Math.Abs(radius * Math.Cos(angle2)); double y2 = Math.Abs(radius * Math.Sin(angle2)); // Find the largest extents in X & Y x = Math.Max(x, x2); y = Math.Max(y, y2); // Find the largest change (pixel, not ratio) double deltaX = x - width; double deltaY = y - height; // Return the ratio that will bring the largest change into the region return (deltaX > deltaY) ? width / x : height / y; } 

Exemple d’utilisation:

  private WriteableBitmap GenerateConstrainedBitmap(BitmapImage sourceImage, int pixelWidth, int pixelHeight, double rotation) { double scale = CalculateConstraintScale(rotation, pixelWidth, pixelHeight); // Create a transform to render the image rotated and scaled var transform = new TransformGroup(); var rt = new RotateTransform() { Angle = rotation, CenterX = (pixelWidth / 2.0), CenterY = (pixelHeight / 2.0) }; transform.Children.Add(rt); var st = new ScaleTransform() { ScaleX = scale, ScaleY = scale, CenterX = (pixelWidth / 2.0), CenterY = (pixelHeight / 2.0) }; transform.Children.Add(st); // Resize to specified target size var tempImage = new Image() { Stretch = Stretch.Fill, Width = pixelWidth, Height = pixelHeight, Source = sourceImage, }; tempImage.UpdateLayout(); // Render to a writeable bitmap var writeableBitmap = new WriteableBitmap(pixelWidth, pixelHeight); writeableBitmap.Render(tempImage, transform); writeableBitmap.Invalidate(); return writeableBitmap; } 

J’ai publié un test du code sur mon site Web afin que vous puissiez l’essayer en temps réel – cliquez pour l’essayer