2016-04-05 6 views
0

私はストリームからモノクロTIFF画像を読み込み、テキストをレンダリングしてTIFF形式に戻してストリームとして保存するため、SharpDXでいくつかの汚れたGDI +ルーチンを置き換えました。SharpDX:BitmapFrameEncode.WriteSourceはいくつかの画像ではるかに時間がかかります

しかし、SharpDXコードは同じことを行うのにはるかに時間がかかります。私は何か間違っているのだろうかと思います。

  • RenderImageFromExistingImage
  • SaveRenderedImage

    using System; 
    using System.Diagnostics; 
    using System.IO; 
    using SharpDX; 
    using SharpDX.Direct2D1; 
    using SharpDX.DirectWrite; 
    using SharpDX.DXGI; 
    using SharpDX.WIC; 
    using Factory = SharpDX.Direct2D1.Factory; 
    using FactoryType = SharpDX.Direct2D1.FactoryType; 
    using PixelFormat = SharpDX.WIC.PixelFormat; 
    using WicBitmap = SharpDX.WIC.Bitmap; 
    
    public class ImageCreator2 
    { 
        private static ImagingFactory _wicFactory; 
        private static Factory _d2DFactory; 
        private static SharpDX.DirectWrite.Factory _dwFactory; 
        private int _imageWidth = 1000, _imageHeight = 500; 
        private readonly int _imageDpi = 96; 
    
        public ImageCreator2() 
        { 
         _wicFactory = new ImagingFactory(); 
         _d2DFactory = new Factory(FactoryType.SingleThreaded); 
         _dwFactory = new SharpDX.DirectWrite.Factory(SharpDX.DirectWrite.FactoryType.Shared); 
        } 
    
        private void RenderImage(WicRenderTarget renderTarget) 
        { 
         using (var blackBrush = new SolidColorBrush(renderTarget, Color4.Black)) 
         using (var tformat = new TextFormat(_dwFactory, "Arial", 30f)) 
         using (var tformat2 = new TextFormat(_dwFactory, "Arial", 11f)) 
         { 
          renderTarget.BeginDraw(); 
          renderTarget.Clear(Color.White); 
          renderTarget.DrawText("TEST", tformat, new RectangleF(300f, 30f, 100f, 20f), blackBrush); 
          renderTarget.DrawText("MORE TEST", tformat2, new RectangleF(30f, 150f, 100f, 20f), blackBrush); 
          renderTarget.DrawLine(new Vector2(0f, 25f), new Vector2(500f, 25f), blackBrush); 
          renderTarget.DrawLine(new Vector2(0f, 210f), new Vector2(500f, 210f), blackBrush); 
          renderTarget.EndDraw(); 
         } 
        } 
    
        public void BuildImageFromExistingImage(byte[] image, Stream systemStream) 
        { 
         using (var checkStream = new MemoryStream(image)) 
         using (
          var inDecoder = new BitmapDecoder(_wicFactory, checkStream, DecodeOptions.CacheOnDemand)) 
         using (var converter = new FormatConverter(_wicFactory)) 
         { 
          if (inDecoder.FrameCount > 0) 
          { 
           using (var frame = inDecoder.GetFrame(0)) 
           { 
            converter.Initialize(frame, PixelFormat.Format32bppPRGBA, BitmapDitherType.None, null, 0.0f, 
             BitmapPaletteType.MedianCut); 
            _imageWidth = converter.Size.Width; 
            _imageHeight = converter.Size.Height; 
           } 
          } 
          else 
          { 
           throw new Exception(); 
          } 
          var renderProperties = new RenderTargetProperties(
           RenderTargetType.Software, 
           new SharpDX.Direct2D1.PixelFormat(Format.Unknown, AlphaMode.Unknown), 
           _imageDpi, 
           _imageDpi, 
           RenderTargetUsage.None, 
           FeatureLevel.Level_DEFAULT); 
          using (var wicBitmap = new WicBitmap(
           _wicFactory, 
           converter, 
           BitmapCreateCacheOption.CacheOnDemand)) 
    
          using (
           var renderTarget = new WicRenderTarget(_d2DFactory, wicBitmap, 
            renderProperties)) 
          { 
           RenderImage(renderTarget); 
    
           using (
            var encoder = new BitmapEncoder(_wicFactory, 
             ContainerFormatGuids.Tiff)) 
           { 
            encoder.Initialize(systemStream); 
    
            using (var bitmapFrameEncode = new BitmapFrameEncode(encoder)) 
            { 
             var pixFormat = PixelFormat.Format32bppPRGBA; 
             bitmapFrameEncode.Initialize(); 
             bitmapFrameEncode.SetSize(_imageWidth, _imageHeight); 
             bitmapFrameEncode.SetResolution(96, 96); 
             bitmapFrameEncode.SetPixelFormat(ref pixFormat); 
    
             //This takes 30-40ms per image. 
             var watch = new Stopwatch(); 
             try 
             { 
              watch.Start(); 
              bitmapFrameEncode.WriteSource(wicBitmap); 
             } 
             finally 
             { 
              watch.Stop(); 
             } 
             Console.WriteLine("Saved real image in {0} ms.", 
              watch.Elapsed.TotalMilliseconds); 
    
             bitmapFrameEncode.Commit(); 
            } 
            encoder.Commit(); 
           } 
          } 
         } 
        } 
    
        public void SaveRenderedImage(Stream systemStream) 
        { 
         var renderProperties = new RenderTargetProperties(
          RenderTargetType.Default, 
          new SharpDX.Direct2D1.PixelFormat(Format.Unknown, AlphaMode.Unknown), 
          _imageDpi, 
          _imageDpi, 
          RenderTargetUsage.None, 
          FeatureLevel.Level_DEFAULT); 
    
         using (var wicBitmap = new WicBitmap(
          _wicFactory, 
          _imageWidth, 
          _imageHeight, 
          PixelFormat.Format32bppBGR, 
          BitmapCreateCacheOption.CacheOnDemand 
          )) 
         using (var renderTarget = new WicRenderTarget(_d2DFactory, wicBitmap, renderProperties)) 
         { 
          RenderImage(renderTarget); 
    
          using (
           var encoder = new BitmapEncoder(_wicFactory, 
            ContainerFormatGuids.Tiff)) 
          { 
           encoder.Initialize(systemStream); 
    
           using (var bitmapFrameEncode = new BitmapFrameEncode(encoder)) 
           { 
            bitmapFrameEncode.Initialize(); 
            bitmapFrameEncode.SetSize(_imageWidth, _imageHeight); 
            bitmapFrameEncode.SetResolution(_imageDpi, _imageDpi); 
            //This takes 8-10ms per image. 
            var watch = new Stopwatch(); 
            try 
            { 
             watch.Start(); 
             bitmapFrameEncode.WriteSource(wicBitmap); 
            } 
            finally 
            { 
             watch.Stop(); 
            } 
            Console.WriteLine("Saved generated image in {0} ms.", 
             watch.Elapsed.TotalMilliseconds); 
    
            bitmapFrameEncode.Commit(); 
           } 
           encoder.Commit(); 
          } 
         } 
        } 
    } 
    

彼らはほとんど同一であり、大体やる:あなたがここにサンプルから見ることができるように

、私は2つの異なる機能を持っています同じもの(最初のもの(RenderImageFromExistingImage)は既存の1000x500のバイナリTIFFイメージを使用します) 2番目のもの(SaveRenderedImage)は、同様のサイズのWICビットマップを最初から作成します。

(〜30ミリ秒)BitmapFrameEncode.WriteSourceによって取り込まれ、その時間の大部分で、約30-40ms実行することを要する既存の画像を撮影する機能。この関数は、置き換えられたGDI +コードと同等です。

スクラッチからWicBitmapを作成する機能は、それが置換GDI +関数とほぼ同じ時間であるBitmapFrameEncode.WriteSourceにかなりの時間を取ることなく、実行する8-10msをとります。唯一の違いは、この関数は私が必要とする既存のイメージを読み込んでいないことです。

なぜSaveRenderedImageに比べ、BuildImageFromExistingImageにとても遅い(IWICBitmapFrameEncode薄いラッパであるように見える)BitmapFrameEncode.WriteSourceですか?

私の推測では、D2Dが処理するピクセルフォーマットに変換するために、(FormatConverterを使用して)、着信画像に余分な変換を行っているので、BuildImageFromExistingImageが遅いことであり、これを行うための時間ペナルティがないことBitmapFrameEncode.WriteSourceが発生するまで再生されません。

私が間違っていることはありますか?または、WIC(Windows Imaging Components)はGDI +ベースの呼び出しと比べて遅いですか?

理想的には、私は早くそれを交換GDI +のコードのように最初のケース(BuildImageFromExistingImage)を必要とし、それがあるGDI +コードよりも、それが早く、そうでない場合より高速にすることが可能であることを期待します置き換えることを意図しています。

答えて

-1

Windows 7以降では、GDI +はWICエンコーダとデコーダを使用しているため、実際のエンコード手順に違いはありません。 2つの方法で同じピクセルが生成された場合、同じ速度でエンコードされ、その速度はGDI +と同じになります。

WriteSource()のように見えるかもしれませんが、あなたの例ではボトルネックですが、これは少し誤解を招くことです。WICはレイジーパイプラインを使用して処理します。つまり、実行するすべての手順は、ピクセルが要求されるまでCopyPixels()にコールされるまで遅延されます。あなたの場合は、CopyPixels()に決して電話することはないので、その電話はWriteSource()によって行われ、その時点ですべての処理が実行されます。

私はSharpDXにはあまり慣れていませんが、図面に使用するWicBitmapオブジェクトを作成するときは、おそらくBitmapCreateCacheOption.CacheOnLoadを使用したいと思います。エンコーダがビットマップをマテリアライズできるようにするということは、一度に1つのスキャンラインを実行することを意味し、おそらく描画パフォーマンスに悪影響を与えます。 CacheOnLoadオプションはビットマップを即座にマテリアライズするので、エンコード中ではなくその時にデコードされ変換されると思います。それ以外の場合は、ボトルネックを分離するのに役立ちます。

また、パフォーマンス上の問題が発生するかどうかはわかりませんが、BitmapPaletteType.MedianCutはインデックスカラーピクセルタイプにのみ使用することを意図しています。通常、量子化を必要としないときはBitmapPaletteType.Customを使用します。

最後に、わかっている限り、Direct2Dの標準ピクセル形式はPixelFormat.Format32bppPBGRAです。 PRGBAバリアントを使用すると、追加のオーバーヘッドが発生する可能性があります。

あなたのものに似た何かをしている例については、hereを参照してください。

+0

ヒントと説明をいただきありがとうございます。私は、 'WriteSource()'はすべてが実際に起こったところであることをちょっと考えました。 'CacheOnLoad'と' CacheOnDemand'はかなりの違いはありません。 'Format32bppPBGRA'と' Format32bppPRGBA'の違いもありません。 'BitmapPaletteType.Custom'を試し、私が得た結果を見てみましょう。 –

+0

'CacheOnLoad'はタイミングをまったく変えますか?全体的な実行時間を短縮することは期待できませんが、 'WriteSource'呼び出しにいくらかの影響があります。また、 'bitmapFrameEncode.SetPixelFormat(ref pixFormat)'の呼び出しの後に 'pixFormat'の値をチェックしたいかもしれません。エンコーダーで入力イメージのフォーマットがサポートされていない場合、保存中に変換が行われ、変換先のフォーマットが表示されます。それはセーブ自体が変換コストを負っているかどうかを教えてくれるでしょう。 – saucecontrol

関連する問題