多线程图像处理程序返回类型错误:如何修正LockBits/GetSet方法?
解决LockBits和GetSet方法与ParameterizedThreadStart的返回类型冲突问题
看起来你踩了C#线程委托的一个常见坑:ParameterizedThreadStart要求绑定的方法必须是void返回类型,但你的LockBits和GetSet都返回了Bitmap,这就导致了编译器报错。别担心,调整起来很简单,我们可以利用你已经定义的ImageEventArgs事件来传递处理后的图片,替代直接返回值的方式。
具体修改步骤
1. 调整ImageManipulation中的方法签名
把两个方法的返回类型从Bitmap改成void,同时去掉末尾的return语句——因为线程启动的方法没法直接返回值,我们用事件来传递结果。
修改后的GetSet方法:
public void GetSet(object bmp) { Bitmap bmap = (Bitmap)bmp; Color theColor = new Color(); for (int i = 0; i < bmap.Width; i++) { for (int j = 0; j < bmap.Height; j++) { theColor = bmap.GetPixel(i, j); Color newColor = Color.FromArgb(theColor.R, theColor.G, 0); bmap.SetPixel(i, j, newColor); } } OnImageFinished(bmap); // 移除return bmap; 因为返回类型是void }
修改后的LockBits方法:
public void LockBits(object bmp) { Bitmap bmap = (Bitmap)bmp; unsafe { BitmapData bitmapData = bmap.LockBits(new Rectangle(0, 0, bmap.Width, bmap.Height), ImageLockMode.ReadWrite, bmap.PixelFormat); int bytesPerPixel = System.Drawing.Bitmap.GetPixelFormatSize(bmap.PixelFormat) / 8; int heightInPixels = bitmapData.Height; int widthInBytes = bitmapData.Width * bytesPerPixel; byte* PtrFirstPixel = (byte*)bitmapData.Scan0; Parallel.For(0, heightInPixels, y => { byte* currentLine = PtrFirstPixel + (y * bitmapData.Stride); for (int x = 0; x < widthInBytes; x = x + bytesPerPixel) { int oldBlue = currentLine[x]; int oldGreen = currentLine[x + 1]; int oldRed = currentLine[x + 2]; currentLine[x] = 0; currentLine[x + 1] = (byte)oldGreen; currentLine[x + 2] = (byte)oldRed; } }); bmap.UnlockBits(bitmapData); } OnImageFinished(bmap); // 移除return bmap; 因为返回类型是void }
2. 完善事件触发逻辑(如果还没做)
确保ImageManipulation类里有正确的事件定义和触发方法,这样才能把处理后的图片传递回UI层:
public class ImageManipulation { public event EventHandler<ImageEventArgs> ImageFinished; protected virtual void OnImageFinished(Bitmap bmp) { ImageFinished?.Invoke(this, new ImageEventArgs { bmap = bmp }); } // 其他方法... }
3. 在Form1中监听事件获取结果
因为现在方法不再直接返回Bitmap,你需要在Form1里监听ImageFinished事件来拿到处理后的图片,还要注意跨线程操作UI的问题:
public Form1() { InitializeComponent(); // 绑定事件处理方法 modifyRGB.ImageFinished += OnImageProcessed; } private void OnImageProcessed(object sender, ImageEventArgs e) { // 跨线程操作控件需要Invoke if (pictureBox1.InvokeRequired) { pictureBox1.Invoke(new Action(() => pictureBox1.Image = e.bmap)); } else { pictureBox1.Image = e.bmap; } // 这里也可以添加保存图片等其他逻辑 }
为什么这样改?
ParameterizedThreadStart的签名是固定的:void Method(object parameter),所以我们必须把方法改成void返回。而通过事件传递结果是线程中传递数据的标准做法,既符合委托要求,又能安全地把处理后的Bitmap传递回UI线程使用。
内容的提问来源于stack exchange,提问作者IscA
相关产品推荐
相关产品推荐

