【发布时间】:2019-11-26 18:16:32
【问题描述】:
我正在 C# (WPF) 中实现误差扩散算法(颜色减少),并且我正在使用 writeableBitmap。
以下函数使用计算图像打开新窗口:
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();
}
我遇到了我遇到过的最奇怪的问题,因为在调整新窗口的大小时,分配的图像更改,即使任何地方都没有附加onSizeChanged 事件。
示例:
1. 紧跟在currAlgWindow.Show()之后的图片
2. 调整窗口大小后的图像。
3. 进一步调整大小后的图片
移动窗口也会稍微改变图像(刷新可见)。
所有问题都不会出现在原始图像上,只会出现在计算出来的图像上。
我还提供算法代码:
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;
}
}
此外,您可以在此处看到的图片与在我的计算机上看到的图片不同 - 就像在将其保存为不同格式后,它会以其他方式显示。
我还在另一台计算机上测试了应用程序,但没有出现问题。
我完全不知道问题的真正原因是什么 - 屏幕、系统、软件、代码?
【问题讨论】:
-
var img = new Image { Source = algorithmBitmap, Strech = Stretch.None };禁用拉伸可能会影响您的图像。由于Image的默认值为 Uniform。 -
@Eldar 请注意,Canvas 不会调整其子元素的大小 - 即使它本身没有像这里那样的固定大小。 Image 元素永远不会被拉伸。
-
WriteableBitmap 是什么 PixelFormat?
-
“分配的图像更改” -- 请更具体。您是说 assignment 本身会发生变化吗?还是只是图像?无论哪种方式,以什么方式发生了变化,具体而言?根据布局配置,在调整容器大小时,以不同大小绘制图像并不罕见。您需要提供更多详细信息并包含一个可靠地重现问题的良好 minimal reproducible example。
-
我在图片上提供的方式发生了变化 - 它以不同的方式重绘。我具体做的是调整窗口的大小,图像被分配到。
标签: c# wpf windows canvas bitmap