WinFormsでMsPaintのようなプログラムを作成し、それをWPFに移動することを考えています。
私は多くの記事を見てきましたが、コントロールを無効にすることになると、それがやりがいがあることは明らかです。この場合、これは非常に頻繁に発生します(例:ラインツール)。
私の友人の一人がJavaSwingを使って同じプログラムを作ったのですが、面白いことに出くわしました。閉じたスペースを埋めるために、同じアルゴリズム「FloodFill」を両方使用しています(バケットツール)。
彼のプログラムははるかに高速です。このアルゴリズムでは、BitMapでの計算が複雑になり、最後に1回だけ再描画されます。
私の質問は、Java Swingに存在するGPUアクセラレーションが原因である可能性があり、WinFormsはそれを利用していないということです。言い換えると、(GPUで高速化された)Wpfは、ビットマップ(表示されていない)での操作をWinFormsよりも高速にすることができますか?
複雑なBMP1000x1000でのコードMine12秒は次のとおりです。
public override void MyMouseDownSubscriber(object sender, System.Windows.Forms.MouseEventArgs e, System.Drawing.Pen pen)
{
// public void floodFill(BufferedImage image, Point node, Color targetColor, Color replacementColor) {
PictureBox canvas = (PictureBox)sender;
Bitmap image = (Bitmap) canvas.Image;
int width = image.Width;
int height = image.Height;
Color replacementColor = pen.Color;
Point node = e.Location;
Color targetColor = image.GetPixel(node.X, node.Y);
int target = targetColor.ToArgb();
if (targetColor != replacementColor)
{
Queue<Point> queue = new Queue<Point> ();
bool noMorePixelsLeft = false;
do
{
int x = node.X;
int y = node.Y;
while (x > 0 && image.GetPixel(x - 1, y).ToArgb() == target)
{
x--;
}
bool spanUp = false;
bool spanDown = false;
while (x < width && image.GetPixel(x, y).ToArgb() == target)
{
image.SetPixel(x, y, replacementColor);
if (!spanUp && y > 0 && image.GetPixel(x, y - 1).ToArgb() == target)
{
queue.Enqueue(new Point(x, y - 1));
spanUp = true;
}
else if (spanUp && y > 0 && image.GetPixel(x, y - 1).ToArgb() != target)
{
spanUp = false;
}
if (!spanDown && y < height - 1 && image.GetPixel(x, y + 1).ToArgb() == target)
{
queue.Enqueue(new Point(x, y + 1));
spanDown = true;
}
else if (spanDown && y < height - 1 && image.GetPixel(x, y + 1).ToArgb() != target)
{
spanDown = false;
}
x++;
}
noMorePixelsLeft = false;
if (queue.Count > 0)
{
node = queue.Dequeue();
noMorePixelsLeft = true;
}
else noMorePixelsLeft = false;
} while (noMorePixelsLeft);
canvas.Invalidate();
canvas.Update();
}
}
そして、複雑なBMP 1000x1000でのJavaSwing:0,5秒のもの
private void floodFill(BufferedImage image, Point startPoint, Color targetColor, Color replacementColor) {
int width = image.getWidth();
int height = image.getHeight();
int target = targetColor.getRGB();
int replacement = replacementColor.getRGB();
if (target != replacement) {
Deque<Point> queue = new LinkedList<>();
do {
int x = startPoint.x;
int y = startPoint.y;
while (x > 0 && image.getRGB(x - 1, y) == target) x--;
boolean spanUp = false;
boolean spanDown = false;
while (x < width && image.getRGB(x, y) == target) {
image.setRGB(x, y, replacement);
if (!spanUp && y > 0 && image.getRGB(x, y - 1) == target) {
queue.add(new Point(x, y - 1));
spanUp = true;
} else if (spanUp && y > 0 && image.getRGB(x, y - 1) != target) spanUp = false;
if (!spanDown && y < height - 1 && image.getRGB(x, y + 1) == target) {
queue.add(new Point(x, y + 1));
spanDown = true;
} else if (spanDown && y < height - 1 && image.getRGB(x, y + 1) != target) spanDown = false;
x++;
}
} while ((startPoint = queue.pollFirst()) != null);
}
}