WPF - 调整大小时位图图像上的工件
WPF - artifacts on bitmap image on resize
我正在 C# (WPF) 中实现错误扩散算法(颜色还原),并且我正在使用 writeableBitmap。
以下函数使用计算图像打开新的 window:
private void OpenNewWindow()
{
// TODO: Bug with image resizes
const int margin = 50;
currAlgWindow = new Window { Owner = this };
var w = algorithmBitmap.Width;
var h = algorithmBitmap.Height;
var canvas = new Canvas { Width = w + margin * 2, Height = h + margin * 2 };
var img = new Image { Source = algorithmBitmap };
Canvas.SetLeft(img, (canvas.Width - w) / 2);
Canvas.SetTop(img, (canvas.Height - h) / 2);
canvas.Children.Add(img);
currAlgWindow.SizeToContent = SizeToContent.WidthAndHeight;
currAlgWindow.Content = canvas;
currAlgWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner;
currAlgWindow.Show();
}
我遇到了我遇到过的最奇怪的问题,因为在调整新 Window 的大小时,分配的图像 发生了变化 ,即使没有 onSizeChanged
随处附加的事件。
示例:
1. currAlgWindow.Show()
之后的图片
2. 调整大小后的图像window。
3. 进一步调整大小后的图像
移动 window 也会稍微改变图像(刷新可见)。
所有问题都不会出现在原始图像上,只会出现在计算出的图像上。
我也提供算法代码:
public abstract class Algorithm
{
protected WriteableBitmap bitmap;
protected byte[] originalCopy;
protected int bytesPerPixel;
protected int width;
protected int height;
protected Algorithm()
{
}
public virtual WriteableBitmap Bitmap
{
get => bitmap;
set
{
bitmap = value;
bytesPerPixel = (bitmap.Format.BitsPerPixel + 7) / 8;
width = bitmap.PixelWidth;
height = bitmap.PixelHeight;
originalCopy = new byte[height * bitmap.BackBufferStride];
bitmap.CopyPixels(originalCopy, bitmap.BackBufferStride, 0);
}
}
public abstract void Apply(int Kr, int Kg, int Kb);
protected static int RoundToNeareastMultiple(int num, int multiple)
{
return (int)(((num + multiple / 2) / multiple) * multiple);
}
}
public class ErrorDiffusionDithering : Algorithm
{
public ErrorDiffusionDithering(WriteableBitmap imageBitmap)
{
this.Bitmap = imageBitmap;
}
public override void Apply(int Kr, int Kg, int Kb)
{
int itR = 255 / (Kr - 1);
int itG = 255 / (Kg - 1);
int itB = 255 / (Kb - 1);
var bmpRect = new System.Windows.Int32Rect(0, 0, width, height);
bitmap.WritePixels(bmpRect, originalCopy, bitmap.BackBufferStride, 0); // Copy cached original image
bitmap.Lock();
unsafe
{
byte* bmpArray = (byte*)bitmap.BackBuffer.ToPointer();
for (int i = 0; i < height; ++i)
{
byte* currPos = bmpArray + i * bitmap.BackBufferStride;
Position row = GetPos(i, height);
for (int j = 0; j < width; ++j)
{
Position col = GetPos(j, width);
byte newVal = RoundToNeareastMultiple(currPos[0], itB).ToByte();
PropagateError(currPos[0] - newVal, 0, currPos, row, col);
currPos[0] = newVal;
newVal = RoundToNeareastMultiple(currPos[1], itG).ToByte();
PropagateError(currPos[1] - newVal, 1, currPos, row, col);
currPos[1] = newVal;
newVal = RoundToNeareastMultiple(currPos[2], itR).ToByte();
PropagateError(currPos[2] - newVal, 2, currPos, row, col);
currPos[2] = newVal;
currPos += bytesPerPixel;
}
}
}
bitmap.AddDirtyRect(bmpRect);
bitmap.Unlock();
}
private unsafe void PropagateError(int error, int colorNum, byte* currPos, Position row, Position col)
{
// x - from left to right
// y - from top to bottom
int ind;
if (col != Position.Last)
{
ind = bytesPerPixel + colorNum;
// pixel[x + 1][y] := pixel[x + 1][y] + quant_error * 7 / 16
currPos[ind] = (currPos[ind] + ((error * 7) >> 4)).ToByte();
}
if (row != Position.Last)
{
if (col != Position.First)
{
ind = bitmap.BackBufferStride - bytesPerPixel + colorNum;
// pixel[x - 1][y + 1] := pixel[x - 1][y + 1] + quant_error * 3 / 16
currPos[ind] = (currPos[ind] + ((error * 3) >> 4)).ToByte();
}
ind = bitmap.BackBufferStride + colorNum;
// pixel[x][y + 1] := pixel[x][y + 1] + quant_error * 5 / 16
currPos[ind] = (currPos[ind] + ((error * 5) >> 4)).ToByte();
if (col != Position.Last)
{
ind = bitmap.BackBufferStride + bytesPerPixel + colorNum;
//pixel[x + 1][y + 1] := pixel[x + 1][y + 1] + quant_error * 1 / 16
currPos[ind] = (currPos[ind] + ((error * 1) >> 4)).ToByte();
}
}
}
private enum Position { First, Last, Other };
private Position GetPos(int r, int dim)
{
return r == dim - 1 ? Position.Last : r == 0 ? Position.First : Position.Other;
}
}
此外,您在此处看到的图片与我的计算机上的图片看起来不一样 - 就像将其保存为不同格式后,它以其他方式显示。
我还在另一台计算机上测试了应用程序,但没有出现问题。
我完全不知道问题的真正原因是什么 - 屏幕、系统、软件、代码?
我已经在其他计算机上测试过它并且工件消失了。
这是我的笔记本电脑矩阵的问题 - 它已被更换并且与我的笔记本电脑不完全兼容。
我正在 C# (WPF) 中实现错误扩散算法(颜色还原),并且我正在使用 writeableBitmap。
以下函数使用计算图像打开新的 window:
private void OpenNewWindow()
{
// TODO: Bug with image resizes
const int margin = 50;
currAlgWindow = new Window { Owner = this };
var w = algorithmBitmap.Width;
var h = algorithmBitmap.Height;
var canvas = new Canvas { Width = w + margin * 2, Height = h + margin * 2 };
var img = new Image { Source = algorithmBitmap };
Canvas.SetLeft(img, (canvas.Width - w) / 2);
Canvas.SetTop(img, (canvas.Height - h) / 2);
canvas.Children.Add(img);
currAlgWindow.SizeToContent = SizeToContent.WidthAndHeight;
currAlgWindow.Content = canvas;
currAlgWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner;
currAlgWindow.Show();
}
我遇到了我遇到过的最奇怪的问题,因为在调整新 Window 的大小时,分配的图像 发生了变化 ,即使没有 onSizeChanged
随处附加的事件。
示例:
1. currAlgWindow.Show()
之后的图片
2. 调整大小后的图像window。
3. 进一步调整大小后的图像
移动 window 也会稍微改变图像(刷新可见)。
所有问题都不会出现在原始图像上,只会出现在计算出的图像上。
我也提供算法代码:
public abstract class Algorithm
{
protected WriteableBitmap bitmap;
protected byte[] originalCopy;
protected int bytesPerPixel;
protected int width;
protected int height;
protected Algorithm()
{
}
public virtual WriteableBitmap Bitmap
{
get => bitmap;
set
{
bitmap = value;
bytesPerPixel = (bitmap.Format.BitsPerPixel + 7) / 8;
width = bitmap.PixelWidth;
height = bitmap.PixelHeight;
originalCopy = new byte[height * bitmap.BackBufferStride];
bitmap.CopyPixels(originalCopy, bitmap.BackBufferStride, 0);
}
}
public abstract void Apply(int Kr, int Kg, int Kb);
protected static int RoundToNeareastMultiple(int num, int multiple)
{
return (int)(((num + multiple / 2) / multiple) * multiple);
}
}
public class ErrorDiffusionDithering : Algorithm
{
public ErrorDiffusionDithering(WriteableBitmap imageBitmap)
{
this.Bitmap = imageBitmap;
}
public override void Apply(int Kr, int Kg, int Kb)
{
int itR = 255 / (Kr - 1);
int itG = 255 / (Kg - 1);
int itB = 255 / (Kb - 1);
var bmpRect = new System.Windows.Int32Rect(0, 0, width, height);
bitmap.WritePixels(bmpRect, originalCopy, bitmap.BackBufferStride, 0); // Copy cached original image
bitmap.Lock();
unsafe
{
byte* bmpArray = (byte*)bitmap.BackBuffer.ToPointer();
for (int i = 0; i < height; ++i)
{
byte* currPos = bmpArray + i * bitmap.BackBufferStride;
Position row = GetPos(i, height);
for (int j = 0; j < width; ++j)
{
Position col = GetPos(j, width);
byte newVal = RoundToNeareastMultiple(currPos[0], itB).ToByte();
PropagateError(currPos[0] - newVal, 0, currPos, row, col);
currPos[0] = newVal;
newVal = RoundToNeareastMultiple(currPos[1], itG).ToByte();
PropagateError(currPos[1] - newVal, 1, currPos, row, col);
currPos[1] = newVal;
newVal = RoundToNeareastMultiple(currPos[2], itR).ToByte();
PropagateError(currPos[2] - newVal, 2, currPos, row, col);
currPos[2] = newVal;
currPos += bytesPerPixel;
}
}
}
bitmap.AddDirtyRect(bmpRect);
bitmap.Unlock();
}
private unsafe void PropagateError(int error, int colorNum, byte* currPos, Position row, Position col)
{
// x - from left to right
// y - from top to bottom
int ind;
if (col != Position.Last)
{
ind = bytesPerPixel + colorNum;
// pixel[x + 1][y] := pixel[x + 1][y] + quant_error * 7 / 16
currPos[ind] = (currPos[ind] + ((error * 7) >> 4)).ToByte();
}
if (row != Position.Last)
{
if (col != Position.First)
{
ind = bitmap.BackBufferStride - bytesPerPixel + colorNum;
// pixel[x - 1][y + 1] := pixel[x - 1][y + 1] + quant_error * 3 / 16
currPos[ind] = (currPos[ind] + ((error * 3) >> 4)).ToByte();
}
ind = bitmap.BackBufferStride + colorNum;
// pixel[x][y + 1] := pixel[x][y + 1] + quant_error * 5 / 16
currPos[ind] = (currPos[ind] + ((error * 5) >> 4)).ToByte();
if (col != Position.Last)
{
ind = bitmap.BackBufferStride + bytesPerPixel + colorNum;
//pixel[x + 1][y + 1] := pixel[x + 1][y + 1] + quant_error * 1 / 16
currPos[ind] = (currPos[ind] + ((error * 1) >> 4)).ToByte();
}
}
}
private enum Position { First, Last, Other };
private Position GetPos(int r, int dim)
{
return r == dim - 1 ? Position.Last : r == 0 ? Position.First : Position.Other;
}
}
此外,您在此处看到的图片与我的计算机上的图片看起来不一样 - 就像将其保存为不同格式后,它以其他方式显示。
我还在另一台计算机上测试了应用程序,但没有出现问题。
我完全不知道问题的真正原因是什么 - 屏幕、系统、软件、代码?
我已经在其他计算机上测试过它并且工件消失了。
这是我的笔记本电脑矩阵的问题 - 它已被更换并且与我的笔记本电脑不完全兼容。