Hoe roteer ik een afbeelding in WinForms

Ik wil één afbeelding in mijn applicatie hebben die ik kan draaien om richtingen aan te geven, zoals windrichting. Of zelfs de tijd. Welke code gebruik ik om de afbeelding te draaien? Bedankt

Update: ik gebruik .NET 2.0, Windows 2000, VS C# 2005


Antwoord 1, autoriteit 100%

Hier is een methode die u kunt gebruiken om een ​​afbeelding in C# te roteren:

/// <summary>
/// method to rotate an image either clockwise or counter-clockwise
/// </summary>
/// <param name="img">the image to be rotated</param>
/// <param name="rotationAngle">the angle (in degrees).
/// NOTE: 
/// Positive values will rotate clockwise
/// negative values will rotate counter-clockwise
/// </param>
/// <returns></returns>
public static Image RotateImage(Image img, float rotationAngle)
{
    //create an empty Bitmap image
    Bitmap bmp = new Bitmap(img.Width, img.Height);
    //turn the Bitmap into a Graphics object
    Graphics gfx = Graphics.FromImage(bmp);
    //now we set the rotation point to the center of our image
    gfx.TranslateTransform((float)bmp.Width / 2, (float)bmp.Height / 2);
    //now rotate the image
    gfx.RotateTransform(rotationAngle);
    gfx.TranslateTransform(-(float)bmp.Width / 2, -(float)bmp.Height / 2);
    //set the InterpolationMode to HighQualityBicubic so to ensure a high
    //quality image once it is transformed to the specified size
    gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;
    //now draw our new image onto the graphics object
    gfx.DrawImage(img, new Point(0, 0));
    //dispose of our Graphics object
    gfx.Dispose();
    //return the image
    return bmp;
}

Antwoord 2, autoriteit 51%

Dit is een oude thread en er zijn verschillende andere threads over C# WinForms-beeldrotatie, maar nu ik mijn oplossing heb bedacht, denk ik dat dit een even goede plek is om het te posten.

 /// <summary>
  /// Method to rotate an Image object. The result can be one of three cases:
  /// - upsizeOk = true: output image will be larger than the input, and no clipping occurs 
  /// - upsizeOk = false & clipOk = true: output same size as input, clipping occurs
  /// - upsizeOk = false & clipOk = false: output same size as input, image reduced, no clipping
  /// 
  /// A background color must be specified, and this color will fill the edges that are not 
  /// occupied by the rotated image. If color = transparent the output image will be 32-bit, 
  /// otherwise the output image will be 24-bit.
  /// 
  /// Note that this method always returns a new Bitmap object, even if rotation is zero - in 
  /// which case the returned object is a clone of the input object. 
  /// </summary>
  /// <param name="inputImage">input Image object, is not modified</param>
  /// <param name="angleDegrees">angle of rotation, in degrees</param>
  /// <param name="upsizeOk">see comments above</param>
  /// <param name="clipOk">see comments above, not used if upsizeOk = true</param>
  /// <param name="backgroundColor">color to fill exposed parts of the background</param>
  /// <returns>new Bitmap object, may be larger than input image</returns>
  public static Bitmap RotateImage(Image inputImage, float angleDegrees, bool upsizeOk, 
                                   bool clipOk, Color backgroundColor)
  {
     // Test for zero rotation and return a clone of the input image
     if (angleDegrees == 0f)
        return (Bitmap)inputImage.Clone();
     // Set up old and new image dimensions, assuming upsizing not wanted and clipping OK
     int oldWidth = inputImage.Width;
     int oldHeight = inputImage.Height;
     int newWidth = oldWidth;
     int newHeight = oldHeight;
     float scaleFactor = 1f;
     // If upsizing wanted or clipping not OK calculate the size of the resulting bitmap
     if (upsizeOk || !clipOk)
     {
        double angleRadians = angleDegrees * Math.PI / 180d;
        double cos = Math.Abs(Math.Cos(angleRadians));
        double sin = Math.Abs(Math.Sin(angleRadians));
        newWidth = (int)Math.Round(oldWidth * cos + oldHeight * sin);
        newHeight = (int)Math.Round(oldWidth * sin + oldHeight * cos);
     }
     // If upsizing not wanted and clipping not OK need a scaling factor
     if (!upsizeOk && !clipOk)
     {
        scaleFactor = Math.Min((float)oldWidth / newWidth, (float)oldHeight / newHeight);
        newWidth = oldWidth;
        newHeight = oldHeight;
     }
     // Create the new bitmap object. If background color is transparent it must be 32-bit, 
     //  otherwise 24-bit is good enough.
     Bitmap newBitmap = new Bitmap(newWidth, newHeight, backgroundColor == Color.Transparent ? 
                                      PixelFormat.Format32bppArgb : PixelFormat.Format24bppRgb);
     newBitmap.SetResolution(inputImage.HorizontalResolution, inputImage.VerticalResolution);
     // Create the Graphics object that does the work
     using (Graphics graphicsObject = Graphics.FromImage(newBitmap))
     {
        graphicsObject.InterpolationMode = InterpolationMode.HighQualityBicubic;
        graphicsObject.PixelOffsetMode = PixelOffsetMode.HighQuality;
        graphicsObject.SmoothingMode = SmoothingMode.HighQuality;
        // Fill in the specified background color if necessary
        if (backgroundColor != Color.Transparent)
           graphicsObject.Clear(backgroundColor);
        // Set up the built-in transformation matrix to do the rotation and maybe scaling
        graphicsObject.TranslateTransform(newWidth / 2f, newHeight / 2f);
        if (scaleFactor != 1f)
           graphicsObject.ScaleTransform(scaleFactor, scaleFactor);
        graphicsObject.RotateTransform(angleDegrees);
        graphicsObject.TranslateTransform(-oldWidth / 2f, -oldHeight / 2f);
        // Draw the result 
        graphicsObject.DrawImage(inputImage, 0, 0);
     }
     return newBitmap;
  }

Dit is het resultaat van vele inspiratiebronnen, hier bij StackOverflow en elders. Het antwoord van Naveen op deze threadwas bijzonder nuttig.


Antwoord 3, autoriteit 44%

Eenvoudige methode:

public Image RotateImage(Image img)
{
    var bmp = new Bitmap(img);
    using (Graphics gfx = Graphics.FromImage(bmp))
    {
        gfx.Clear(Color.White);
        gfx.DrawImage(img, 0, 0, img.Width, img.Height);
    }
    bmp.RotateFlip(RotateFlipType.Rotate270FlipNone);
    return bmp;
}

Antwoord 4, autoriteit 12%

Ik heb dit artikel

gevonden

 /// <summary>
    /// Creates a new Image containing the same image only rotated
    /// </summary>
    /// <param name=""image"">The <see cref=""System.Drawing.Image"/"> to rotate
    /// <param name=""offset"">The position to rotate from.
    /// <param name=""angle"">The amount to rotate the image, clockwise, in degrees
    /// <returns>A new <see cref=""System.Drawing.Bitmap"/"> of the same size rotated.</see>
    /// <exception cref=""System.ArgumentNullException"">Thrown if <see cref=""image"/"> 
    /// is null.</see>
    public static Bitmap RotateImage(Image image, PointF offset, float angle)
    {
        if (image == null)
            throw new ArgumentNullException("image");
        //create a new empty bitmap to hold rotated image
        Bitmap rotatedBmp = new Bitmap(image.Width, image.Height);
        rotatedBmp.SetResolution(image.HorizontalResolution, image.VerticalResolution);
        //make a graphics object from the empty bitmap
        Graphics g = Graphics.FromImage(rotatedBmp);
        //Put the rotation point in the center of the image
        g.TranslateTransform(offset.X, offset.Y);
        //rotate the image
        g.RotateTransform(angle);
        //move the image back
        g.TranslateTransform(-offset.X, -offset.Y);
        //draw passed in image onto graphics object
        g.DrawImage(image, new PointF(0, 0));
        return rotatedBmp;
    }

Antwoord 5, autoriteit 12%

Ik heb een eenvoudige les geschreven voor het roteren van afbeeldingen. Het enige wat u hoeft te doen is het beeld en de rotatiehoek in Degree in te voeren. Hoek moet tussen -90 en +90 zijn.

public class ImageRotator
{
    private readonly Bitmap image;
    public Image OriginalImage
    {
        get { return image; }
    }
    private ImageRotator(Bitmap image)
    {
        this.image = image;
    }
    private double GetRadian(double degree)
    {
        return degree * Math.PI / (double)180;
    }
    private Size CalculateSize(double angle)
    {
        double radAngle = GetRadian(angle);
        int width = (int)(image.Width * Math.Cos(radAngle) + image.Height * Math.Sin(radAngle));
        int height = (int)(image.Height * Math.Cos(radAngle) + image.Width * Math.Sin(radAngle));
        return new Size(width, height);
    }
    private PointF GetTopCoordinate(double radAngle)
    {
        Bitmap image = CurrentlyViewedMappedImage.BitmapImage;
        double topX = 0;
        double topY = 0;
        if (radAngle > 0)
        {
            topX = image.Height * Math.Sin(radAngle);
        }
        if (radAngle < 0)
        {
            topY = image.Width * Math.Sin(-radAngle);
        }
        return new PointF((float)topX, (float)topY);
    }
    public Bitmap RotateImage(double angle)
    {
        SizeF size = CalculateSize(radAngle);
        Bitmap rotatedBmp = new Bitmap((int)size.Width, (int)size.Height);
        Graphics g = Graphics.FromImage(rotatedBmp);
        g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
        g.CompositingQuality = CompositingQuality.HighQuality;
        g.SmoothingMode = SmoothingMode.HighQuality;
        g.PixelOffsetMode = PixelOffsetMode.HighQuality;
        g.TranslateTransform(topPoint.X, topPoint.Y);
        g.RotateTransform(GetDegree(radAngle));
        g.DrawImage(image, new RectangleF(0, 0, size.Width, size.Height));
        g.Dispose();
        return rotatedBmp;
    }
    public static class Builder
    {
        public static ImageRotator CreateInstance(Image image)
        {
            ImageRotator rotator = new ImageRotator(image as Bitmap);
            return rotator;
        }
    }
}

Antwoord 6, autoriteit 12%

Oude vraag, maar ik moest de opmerking van MrFox beantwoorden in het geaccepteerde antwoord. Als u een afbeelding roteert wanneer de grootte verandert, worden de randen van de afbeelding afgesneden. Een oplossing is om het origineel opnieuw te tekenen op een grotere afbeelding, gecentreerd, waarbij de afmetingen van de grotere afbeelding compenseren voor de noodzaak om de randen niet af te knippen. Ik wilde bijvoorbeeld de tegels van een spel onder een normale hoek kunnen ontwerpen, maar ze opnieuw tekenen in een hoek van 45 graden voor een isometrisch aanzicht.

Hier zijn voorbeeldafbeeldingen (gele randen zijn om het hier gemakkelijker te kunnen zien).

De originele afbeelding:
watertegel

De gecentreerde tegel in een grotere afbeelding:
voer hier de afbeeldingsbeschrijving in

De geroteerde afbeelding (waarbij u de grotere afbeelding roteert, niet het origineel):
voer hier de afbeeldingsbeschrijving in

De code (gedeeltelijk gebaseerd op dit antwoord in een andere vraag):

private Bitmap RotateImage(Bitmap rotateMe, float angle)
{
    //First, re-center the image in a larger image that has a margin/frame
    //to compensate for the rotated image's increased size
    var bmp = new Bitmap(rotateMe.Width + (rotateMe.Width / 2), rotateMe.Height + (rotateMe.Height / 2));
    using (Graphics g = Graphics.FromImage(bmp))
        g.DrawImageUnscaled(rotateMe, (rotateMe.Width / 4), (rotateMe.Height / 4), bmp.Width, bmp.Height);
    bmp.Save("moved.png");
    rotateMe = bmp;
    //Now, actually rotate the image
    Bitmap rotatedImage = new Bitmap(rotateMe.Width, rotateMe.Height);
    using (Graphics g = Graphics.FromImage(rotatedImage))
    {
        g.TranslateTransform(rotateMe.Width / 2, rotateMe.Height / 2);   //set the rotation point as the center into the matrix
        g.RotateTransform(angle);                                        //rotate
        g.TranslateTransform(-rotateMe.Width / 2, -rotateMe.Height / 2); //restore rotation point into the matrix
        g.DrawImage(rotateMe, new Point(0, 0));                          //draw the image on the new bitmap
    }
    rotatedImage.Save("rotated.png");
    return rotatedImage;
}

Antwoord 7, autoriteit 5%

Richard Cox heeft een goede oplossing voor deze https://stackoverflow.com/a/5200280/1171321die ik heb in het verleden gebruikt. Het is ook vermeldenswaard dat de DPI 96 moet zijn om dit correct te laten werken. Een aantal van de oplossingen op deze pagina werken helemaal niet.


Antwoord 8, autoriteit 5%

Het draaien van een afbeelding is één ding, de juiste beeldgrenzen in een andere. Hier is een code die iedereen kan helpen. Ik heb dit lang geleden gemaakt op basis van wat zoeken op internet.

   /// <summary>
    /// Rotates image in radian angle
    /// </summary>
    /// <param name="bmpSrc"></param>
    /// <param name="theta">in radian</param>
    /// <param name="extendedBitmapBackground">Because of rotation returned bitmap can have different boundaries from original bitmap. This color is used for filling extra space in bitmap</param>
    /// <returns></returns>
    public static Bitmap RotateImage(Bitmap bmpSrc, double theta, Color? extendedBitmapBackground = null)
    {
        theta = Convert.ToSingle(theta * 180 / Math.PI);
        Matrix mRotate = new Matrix();
        mRotate.Translate(bmpSrc.Width / -2, bmpSrc.Height / -2, MatrixOrder.Append);
        mRotate.RotateAt((float)theta, new Point(0, 0), MatrixOrder.Append);
        using (GraphicsPath gp = new GraphicsPath())
        {  // transform image points by rotation matrix
            gp.AddPolygon(new Point[] { new Point(0, 0), new Point(bmpSrc.Width, 0), new Point(0, bmpSrc.Height) });
            gp.Transform(mRotate);
            PointF[] pts = gp.PathPoints;
            // create destination bitmap sized to contain rotated source image
            Rectangle bbox = BoundingBox(bmpSrc, mRotate);
            Bitmap bmpDest = new Bitmap(bbox.Width, bbox.Height);
            using (Graphics gDest = Graphics.FromImage(bmpDest))
            {
                if (extendedBitmapBackground != null)
                {
                    gDest.Clear(extendedBitmapBackground.Value);
                }
                // draw source into dest
                Matrix mDest = new Matrix();
                mDest.Translate(bmpDest.Width / 2, bmpDest.Height / 2, MatrixOrder.Append);
                gDest.Transform = mDest;
                gDest.DrawImage(bmpSrc, pts);
                return bmpDest;
            }
        }
    }
    private static Rectangle BoundingBox(Image img, Matrix matrix)
    {
        GraphicsUnit gu = new GraphicsUnit();
        Rectangle rImg = Rectangle.Round(img.GetBounds(ref gu));
        // Transform the four points of the image, to get the resized bounding box.
        Point topLeft = new Point(rImg.Left, rImg.Top);
        Point topRight = new Point(rImg.Right, rImg.Top);
        Point bottomRight = new Point(rImg.Right, rImg.Bottom);
        Point bottomLeft = new Point(rImg.Left, rImg.Bottom);
        Point[] points = new Point[] { topLeft, topRight, bottomRight, bottomLeft };
        GraphicsPath gp = new GraphicsPath(points, new byte[] { (byte)PathPointType.Start, (byte)PathPointType.Line, (byte)PathPointType.Line, (byte)PathPointType.Line });
        gp.Transform(matrix);
        return Rectangle.Round(gp.GetBounds());
    }

Antwoord 9

Dit werkt zolang de afbeelding die u wilt roteren zich al in uw map Eigenschappen resources bevindt.

In gedeeltelijke les:

Bitmap bmp2;

OnLoad:

bmp2 = new Bitmap(Tycoon.Properties.Resources.save2);
            pictureBox6.SizeMode = PictureBoxSizeMode.StretchImage;
            pictureBox6.Image = bmp2;

Knop of Onclick

private void pictureBox6_Click(object sender, EventArgs e)
        {
            if (bmp2 != null)
            {
                bmp2.RotateFlip(RotateFlipType.Rotate90FlipNone);
                pictureBox6.Image = bmp2;
            }
        }

Antwoord 10

Je kunt het gemakkelijk doen door deze methode aan te roepen:

public static Bitmap RotateImage(Image image, float angle)
{
    if (image == null)
        throw new ArgumentNullException("image");
    PointF offset = new PointF((float)image.Width / 2, (float)image.Height / 2);
    //create a new empty bitmap to hold rotated image
    Bitmap rotatedBmp = new Bitmap(image.Width, image.Height);
    rotatedBmp.SetResolution(image.HorizontalResolution, image.VerticalResolution);
    //make a graphics object from the empty bitmap
    Graphics g = Graphics.FromImage(rotatedBmp);
    //Put the rotation point in the center of the image
    g.TranslateTransform(offset.X, offset.Y);
    //rotate the image
    g.RotateTransform(angle);
    //move the image back
    g.TranslateTransform(-offset.X, -offset.Y);
    //draw passed in image onto graphics object
    g.DrawImage(image, new PointF(0, 0));
    return rotatedBmp;
}

vergeet niet een verwijzing naar System.Drawing.dll toe te voegen aan uw project

Voorbeeld van deze methode-aanroep:

Image image = new Bitmap("waves.png");
Image newImage = RotateImage(image, 360);
newImage.Save("newWaves.png");

Antwoord 11

Ik heb de functie van Mr.net_progaangepast, die alleen de afbeeldingsbox krijgt en de afbeelding erin draait .

   public static void RotateImage(PictureBox picBox)
    {
        Image img = picBox.Image;
        var bmp = new Bitmap(img);
        using (Graphics gfx = Graphics.FromImage(bmp))
        {
            gfx.Clear(Color.White);
            gfx.DrawImage(img, 0, 0, img.Width, img.Height);
        }
        bmp.RotateFlip(RotateFlipType.Rotate270FlipNone);
        picBox.Image = bmp;
    }

Antwoord 12

Deze oplossing gaat ervan uit dat u de afbeelding in een afbeeldingskader wilt tekenen en dat de oriëntatie van de afbeelding de muisbewegingen over dit afbeeldingskader zal volgen. Er is geen afbeelding toegewezen aan de afbeeldingsbox. In plaats daarvan haal ik de afbeelding uit een projectbron.

private float _angle;
public Form1()
{
    InitializeComponent();
}
private void PictureBox_MouseMove(object sender, MouseEventArgs e)
{
    (float centerX, float centerY) = GetCenter(pictureBox1.ClientRectangle);
    _angle = (float)(Math.Atan2(e.Y - centerY, e.X - centerX) * 180.0 / Math.PI);
    pictureBox1.Invalidate(); // Triggers redrawing
}
private void PictureBox_Paint(object sender, PaintEventArgs e)
{
    Bitmap image = Properties.Resources.ExampleImage;
    float scale = (float)pictureBox1.Width / image.Width;
    (float centerX, float centerY) = GetCenter(e.ClipRectangle);
    e.Graphics.TranslateTransform(centerX, centerY);
    e.Graphics.RotateTransform(_angle);
    e.Graphics.TranslateTransform(-centerX, -centerY);
    e.Graphics.ScaleTransform(scale, scale);
    e.Graphics.DrawImage(image, 0, 0);
}
// Uses C# 7.0 value tuples / .NET Framework 4.7.
// For previous versions, return a PointF instead.
private static (float, float) GetCenter(Rectangle rect)
{
    float centerX = (rect.Left + rect.Right) * 0.5f;
    float centerY = (rect.Top + rect.Bottom) * 0.5f;
    return (centerX, centerY);
}

Zorg ervoor dat u de muisgebeurtenishandlers PictureBox_MouseMoveen PictureBox_Paintselecteert in het eigenschappenvenster van het afbeeldingsvak voor deze gebeurtenissen, nadat u deze code in het formulier hebt gekopieerd/plakt .

Opmerking: u kunt ook een eenvoudig Panelof een ander besturingselement gebruiken, zoals een label; de PictureBoxheeft echter het voordeel om standaard dubbele buffering te gebruiken, waardoor flikkeren wordt geëlimineerd.

Other episodes