Frage

Hey alle. Ich griff LockBits für 2D-Bitmap Bildrotation nach dem Aufstehen satt mit der langsamen Leistung und verrückte Verhalten der beiden Get / Set Pixel und RotateTransfom zu verwenden. So, hier ist der Code, den ich habe kommen mit, und nach meiner Rechnung, sollte es perfekt funktionieren. Es funktioniert nicht.

private static void InternalRotateImage(Bitmap originalBitmap, Bitmap rotatedBitmap, PointF centerPoint, float theta)
    {
        BitmapData originalData = originalBitmap.LockBits(
            new Rectangle(0, 0, originalBitmap.Width, originalBitmap.Height),
            ImageLockMode.ReadOnly,
            originalBitmap.PixelFormat);

        BitmapData rotatedData = rotatedBitmap.LockBits(
            new Rectangle(0, 0, rotatedBitmap.Width, rotatedBitmap.Height),
            ImageLockMode.WriteOnly,
            rotatedBitmap.PixelFormat);

        unsafe
        {
            byte[,] A = new byte[originalData.Height * 2, originalBitmap.Width * 2];
            byte[,] R = new byte[originalData.Height * 2, originalBitmap.Width * 2];
            byte[,] G = new byte[originalData.Height * 2, originalBitmap.Width * 2];
            byte[,] B = new byte[originalData.Height * 2, originalBitmap.Width * 2];

            for (int y = 0; y < originalData.Height; y++)
            {
                byte* row = (byte*)originalData.Scan0 + (y * originalData.Stride);
                for (int x = 0; x < originalData.Width; x++)
                {
                    B[y, x] = row[x * 4];
                    G[y, x] = row[x * 4 + 1];
                    R[y, x] = row[x * 4 + 2];
                    A[y, x] = row[x * 4 + 3];
                }
            }

            for (int y = 0; y < rotatedData.Height; y++)
            {
                byte* row = (byte*)rotatedData.Scan0 + (y * rotatedData.Stride);
                for (int x = 0; x < rotatedData.Width; x++)
                {
                    int newy = (int)Math.Abs((Math.Cos(theta) * (x - centerPoint.X) - Math.Sin(theta) * (y - centerPoint.Y) + centerPoint.X));
                    int newx = (int)Math.Abs((Math.Sin(theta) * (x - centerPoint.X) + Math.Cos(theta) * (y - centerPoint.Y) + centerPoint.Y));

                    row[x * 4] = B[newy, newx];
                    row[x * 4 + 1] = G[newy, newx];
                    row[x * 4 + 2] = R[newy, newx];
                    row[x * 4 + 3] = A[newy, newx];
                }
            }

        }
            originalBitmap.UnlockBits(originalData);
            rotatedBitmap.UnlockBits(rotatedData);
        }

Hat jemand irgendwelche Ideen? Ich bin frisch aus. Vielen Dank im Voraus!

EDIT: Dies ist, was ich am Ende mit (vielen Dank an Hans Passant):

private Image RotateImage(Image img, float rotationAngle)
    {
        Image image = new Bitmap(img.Width * 2, img.Height * 2);
        Graphics gfx = Graphics.FromImage(image);

        int center = (int)Math.Sqrt(img.Width * img.Width + img.Height * img.Height) / 2;
        gfx.TranslateTransform(center, center);
        gfx.RotateTransform(rotationAngle);
        gfx.DrawImage(img, -img.Width / 2, -img.Height / 2);

        return image;
    }

Es ist das gleiche wie sein, nur auf einer Pro-Bild-Basis, wie in eine Form gegenüber.

War es hilfreich?

Lösung

Sie graben sich ein tieferes Loch. Dies geht früh falsch, die Größe des gedrehten Bitmap ist nicht Breite x Höhe. Es ist auch sehr ineffizient. Sie brauchen, um RotateTransform geht, ist es wichtig, auch zu nutzen und Translatetransform des richtigen Bildzeichnungs Standort auswählen.

Hier ist ein Beispiel Windows-Anwendung Formulare, die sich dreht eine Bitmap um seinen Mittelpunkt, versetzt gerade genug, um den inneren Rand der Form zu berühren, wenn sie sich dreht. Werfen Sie einen Timer auf dem Formular, und fügen Sie eine Bildressource mit Project + Eigenschaften, Registerkarte Ressource. Nennen Sie es sample, es muss nicht quadratisch sein. Machen Sie den Code wie folgt aussehen:

public partial class Form1 : Form {
    private float mDegrees;
    private Image mBmp;
    public Form1() {
        InitializeComponent();
        mBmp = Properties.Resources.SampleImage;
        timer1.Enabled = true;
        timer1.Interval = 50;
        timer1.Tick += new System.EventHandler(this.timer1_Tick);
        this.DoubleBuffered = true;
    }
    private void timer1_Tick(object sender, EventArgs e) {
        mDegrees += 3.0F;
        this.Invalidate();
    }
    protected override void OnPaint(PaintEventArgs e) {
        int center = (int)Math.Sqrt(mBmp.Width * mBmp.Width + mBmp.Height * mBmp.Height) / 2;
        e.Graphics.TranslateTransform(center, center);
        e.Graphics.RotateTransform(mDegrees);
        e.Graphics.DrawImage(mBmp, -mBmp.Width/2, -mBmp.Height/2);
    }
}

Sie können viel schneller zeichnen durch eine Bitmap im 32bppPArgb Format erstellen, übersprungen ich diesen Schritt.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top