私はストリームからモノクロ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 +コードよりも、それが早く、そうでない場合より高速にすることが可能であることを期待します置き換えることを意図しています。
ヒントと説明をいただきありがとうございます。私は、 'WriteSource()'はすべてが実際に起こったところであることをちょっと考えました。 'CacheOnLoad'と' CacheOnDemand'はかなりの違いはありません。 'Format32bppPBGRA'と' Format32bppPRGBA'の違いもありません。 'BitmapPaletteType.Custom'を試し、私が得た結果を見てみましょう。 –
'CacheOnLoad'はタイミングをまったく変えますか?全体的な実行時間を短縮することは期待できませんが、 'WriteSource'呼び出しにいくらかの影響があります。また、 'bitmapFrameEncode.SetPixelFormat(ref pixFormat)'の呼び出しの後に 'pixFormat'の値をチェックしたいかもしれません。エンコーダーで入力イメージのフォーマットがサポートされていない場合、保存中に変換が行われ、変換先のフォーマットが表示されます。それはセーブ自体が変換コストを負っているかどうかを教えてくれるでしょう。 – saucecontrol