WinForm中Graphics.DrawImage网格与Bitmap像素对齐异常求助
WinForm中Graphics.DrawImage网格偏移问题
在WinForm开发中使用Graphics.DrawImage时遇到以下问题:需要在可调整大小的Panel中显示Bitmap的指定区域(通过源矩形控制每次仅显示Bitmap的一部分),Bitmap像素因缩放被大幅放大后,为原始Bitmap像素绘制的网格在部分缩放级别下出现偏移。推测原因是DrawImage使用近似算法处理非整数的屏幕像素映射(比如单个Bitmap像素应占241.4个屏幕像素,无法精确实现),但无法复现该近似逻辑。需求是网格无需均匀间距,只需匹配DrawImage生成的实际像素尺寸差异。
测试代码
Bitmap CScopeBitmap; RectangleF VisibleBitmapPortion = new RectangleF(0, 0, 10, 20.75f); public Form1() { InitializeComponent(); CScopeBitmap = GenerateRandomBitmap(); panel1.Size = new Size(2414, 1002); } private void panel1_Paint(object sender, PaintEventArgs e) { e.Graphics.InterpolationMode = InterpolationMode.NearestNeighbor; e.Graphics.PixelOffsetMode = PixelOffsetMode.Half; e.Graphics.SmoothingMode = SmoothingMode.None; Rectangle destRect = panel1.ClientRectangle; RectangleF srcRect = VisibleBitmapPortion; e.Graphics.DrawImage( CScopeBitmap, destRect, srcRect, GraphicsUnit.Pixel ); float width = VisibleBitmapPortion.Width; float height = VisibleBitmapPortion.Height; float scaleX = panel1.ClientRectangle.Width / width; float scaleY = panel1.ClientRectangle.Height / height; Pen gridPen = Pens.Black; for (int x = 0; x < width; x++) { float posX = (float)(x * scaleX); e.Graphics.DrawLine(gridPen, posX, 0, posX, panel1.Height); } for (int y = 0; y < height; y++) { float posY = (float)(y * scaleY); e.Graphics.DrawLine(gridPen, 0, posY, panel1.Width, posY); } } public static Bitmap GenerateRandomBitmap() { Size bitmapSize = new Size(3000, 5005); int verticalResolution = 1; Bitmap bmp = new Bitmap(bitmapSize.Width, bitmapSize.Height, PixelFormat.Format24bppRgb); int width = bitmapSize.Width; int height = bitmapSize.Height; BitmapData bmpData = bmp.LockBits( new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, bmp.PixelFormat ); int bytesPerPixel = 3; // 24bpp int stride = bmpData.Stride; int byteCount = stride * bmpData.Height; byte[] pixels = new byte[byteCount]; Random rand = new Random(); for (int x = 0; x < width; x++) { int y = 0; while (y < height) { byte r = (byte)rand.Next(256); byte g = (byte)rand.Next(256); byte b = (byte)rand.Next(256); int blockHeight = Math.Min(verticalResolution, height - y); for (int dy = 0; dy < blockHeight; dy++) { int rowStart = (y + dy) * stride; int i = rowStart + x * bytesPerPixel; pixels[i + 0] = b; pixels[i + 1] = g; pixels[i + 2] = r; } y += verticalResolution; } } Marshal.Copy(pixels, 0, bmpData.Scan0, byteCount); bmp.UnlockBits(bmpData); return bmp; }
已尝试的解决方案
- 使用
Round、Ceiling、Floor等简单近似算法; - 实现累计误差的近似算法:
int[] ComputeSteps(int count, double step) { int[] result = new int[count]; int pos = 0; double err = 0.0; int baseStep = (int)Math.Floor(step); double frac = step - baseStep; for (int i = 0; i < count; i++) { int s = baseStep; err += frac; if (err >= 1.0) { s++; err -= 1.0; } pos += s; result[i] = pos; } return result; } - 手动创建变换矩阵后调用
DrawImage和DrawLine:Matrix m = new Matrix(); m.Translate(destRect.Left, destRect.Top); m.Scale( destRect.Width / srcRect.Width, destRect.Height / srcRect.Height ); m.Translate(-srcRect.Left, -srcRect.Top); e.Graphics.Transform = m; e.Graphics.DrawImage(CScopeBitmap, new Point(0,0)); Pen gridPen = new Pen(Color.Black, 1 / (destRect.Width / srcRect.Width)); for (int x = 0; x<VisibleBitmapPortion.Width; x++) { e.Graphics.DrawLine(gridPen, x, 0, x, panel1.Height); }
内容的提问来源于stack exchange,提问作者Khurt
相关产品推荐
相关产品推荐

