0

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);
   }

 }
4

2 に答える 2

1

私は自分の質問に対する答えを見つけました。

違いの原因:

JavaとC#の間のアルゴリズムの実行時間の違いは、qpuアクセラレーションではなく、メソッドGetPixel/SetPixelが最後になる時間によって引き起こされました。C#では、このメソッドは非常に長く続きます。

解決

Bitmapクラスには、ピクセルの色のプレーンデータのみを返すLockBitsメソッドがあります。Marshal.Copyを使用すると、要素をint [] []マトリックスにコピーし、マトリックスからビットマップに戻すことができます。実装されたメソッドはここにあります:http: //pastebin.com/SVX3w3tF

于 2013-03-20T16:53:49.110 に答える
0

厳密なビットマップベースのアプリケーションの場合、私はWinformsを使い続けます。

WPFは、ベクターグラフィックスと宣言型グラフィックスをはるかに対象としています。MSPaintのようなプログラムは、バッファーを使用して独自のアプリで埋めるハイブリッドウェイアプローチを採用します。つまり、GDI + API(Winforms)を活用します。

ビットマップを使用してアプリを高速化する方法がわかりません。

于 2013-03-17T15:22:29.627 に答える