Lockbits طريقة دوران الصورة لا تعمل؟
سؤال
مرحبا جميعا. لقد لجأت إلى استخدام Lockbits لتناوب صورة Bitmap ثنائي الأبعاد بعد أن سئمت من الأداء البطيء والسلوك الغريب لكل من Get/Set Pixel ، و Rotatetransfom. لذا ، إليك الرمز الذي توصلت إليه ، وبالحاسام ، يجب أن يعمل بشكل مثالي. لا.
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);
}
أي شخص لديه أي أفكار؟ أنا جديد. شكرا مقدما!
تحرير: هذا ما انتهى بي الأمر باستخدامه (شكراً جزيلاً لـ 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;
}
إنه نفس الشيء مثله ، فقط على أساس كل صورة ، على عكس النموذج.
المحلول
أنت تحفر نفسك حفرة أعمق. هذا خطأ في وقت مبكر ، فإن حجم نقطية نقطية لا هو ارتفاع x. كما أنه غير فعال للغاية. تحتاج إلى الحصول على Rotatetransform ، من المهم أيضًا استخدام TranslateTransform واختيار موقع رسم الصورة الصحيح.
فيما يلي تطبيق نماذج من Windows يدور حول نقطة النقطات حول نقطة الوسط ، مع إزاحة ما يكفي لتلمس الحافة الداخلية للنموذج عند تدويره. قم بإسقاط مؤقت على النموذج وأضف مورد صورة مع خصائص Project + ، علامة تبويب الموارد. قم بتسمية SampleImage ، لا يجب أن تكون مربعة. اجعل الرمز يبدو هكذا:
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);
}
}
يمكنك جعل الرسم أسرع بكثير عن طريق إنشاء صورة نقطية بتنسيق 32BPPPPargB ، لقد تخطيت هذه الخطوة.