Esempio n. 1
0
        /// <summary>
        /// Run our application until the user quits.
        /// </summary>
        public void Run()
        {
            // Make window active and hide mouse cursor.
            window.PointerCursor = null;
            window.Activate();

            // Infinite loop to prevent the application from exiting.
            while (true)
            {
                // Dispatch all pending events in the queue.
                window.Dispatcher.ProcessEvents(CoreProcessEventsOption.ProcessAllIfPresent);

                // Quit if the users presses Escape key.
                if (window.GetAsyncKeyState(VirtualKey.Escape) == CoreVirtualKeyStates.Down)
                {
                    return;
                }

                // Set the Direct2D drawing target.
                d2dContext.Target = d2dTarget;

                // Clear the target.
                d2dContext.BeginDraw();
                d2dContext.Clear(Color.CornflowerBlue);

                // Draw a block of text that will be clipped against the specified layout rectangle.
                d2dContext.FillRectangle(new RectangleF(50, 50, 200, 200), backgroundBrush);
                d2dContext.DrawText("This text is long enough to overflow the designed region but will be clipped to the containing rectangle. Lorem ipsum dolor sit amet, consectetur adipiscing elit. ", textFormat, new RectangleF(50, 50, 200, 200), textBrush, DrawTextOptions.Clip);

                // Draw a block of text that will overflow the specified layout rectangle.
                d2dContext.FillRectangle(new RectangleF(50, 300, 200, 200), backgroundBrush);
                d2dContext.DrawText("However, this other text isn't going to be clipped: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean gravida dui id accumsan dictum.", textFormat, new RectangleF(50, 300, 200, 200), textBrush, DrawTextOptions.None);

                // Draw three lines of text with different measuring modes.
                d2dContext.FillRectangle(new RectangleF(300, 50, 400, 200), backgroundBrush);
                d2dContext.DrawText("MeasuringMode: Natural", textFormat, new RectangleF(300, 50, 400, 200), textBrush, DrawTextOptions.None, MeasuringMode.Natural);
                d2dContext.DrawText("MeasuringMode: GDI classic", textFormat, new RectangleF(300, 80, 400, 200), textBrush, DrawTextOptions.None, MeasuringMode.GdiClassic);
                d2dContext.DrawText("MeasuringMode: GDI natural", textFormat, new RectangleF(300, 110, 400, 200), textBrush, DrawTextOptions.None, MeasuringMode.GdiNatural);

                float layoutYOffset = (float)Math.Cos(layoutY) * 50.0f;

                // Draw moving text.
                d2dContext.FillRectangle(new RectangleF(300, 300, 400, 200), backgroundBrush);
                d2dContext.DrawTextLayout(new Vector2(300, 350 + layoutYOffset), textLayout1, textBrush);

                // Draw moving text without pixel snapping, thus giving a smoother movement.
                d2dContext.FillRectangle(new RectangleF(750, 300, 400, 200), backgroundBrush);
                d2dContext.DrawTextLayout(new Vector2(750, 350 + layoutYOffset), textLayout2, textBrush, DrawTextOptions.NoSnap);

                d2dContext.EndDraw();
                layoutY += 1.0f / 60.0f;

                // Present the current buffer to the screen.
                swapChain.Present(1, PresentFlags.None);
            }
        }
Esempio n. 2
0
        static void over()
        {
            var inputPath  = "Input.png";
            var outputPath = "output.png";

            // 그래픽을 랜더링할 장비를 추가 - 3D or 2D
            var defaultDevice = new SharpDX.Direct3D11.Device(SharpDX.Direct3D.DriverType.Hardware,
                                                              d3d.DeviceCreationFlags.VideoSupport
                                                              | d3d.DeviceCreationFlags.BgraSupport
                                                              | d3d.DeviceCreationFlags.None);
            var d3dDevice  = defaultDevice.QueryInterface <d3d.Device1>(); //get a refer to the D3D 11.1 device
            var dxgiDevice = d3dDevice.QueryInterface <dxgi.Device1>();    //get a refer to the DXGI device
            var d2dDevice  = new d2.Device(dxgiDevice);

            // DeviceContext를 초기화. D2D 렌더링 타겟이 될 것이고 모든 렌더링 작업을 허용
            var d2dContext = new d2.DeviceContext(d2dDevice, d2.DeviceContextOptions.None);
            var dwFactory  = new dw.Factory();


            //D2D, WIC 둘 다 지원되는 픽셀 형식 지정
            var d2PixelFormat = new d2.PixelFormat(dxgi.Format.R8G8B8A8_UNorm, d2.AlphaMode.Premultiplied);
            //RGBA형식 사용
            var wicPixelFormat = wic.PixelFormat.Format32bppPRGBA;



            //이미지 로딩
            var imagingFactory = new wic.ImagingFactory2();
            var decoder        = new wic.PngBitmapDecoder(imagingFactory);
            var inputStream    = new wic.WICStream(imagingFactory, inputPath, NativeFileAccess.Read);

            decoder.Initialize(inputStream, wic.DecodeOptions.CacheOnLoad);



            //다이렉트2D가 사용할수 있도록 디코딩
            var formatConverter = new wic.FormatConverter(imagingFactory);

            formatConverter.Initialize(decoder.GetFrame(0), wicPixelFormat);


            //기본 이미지를 D2D이미지로 로드
            //var inputBitmap = d2.Bitmap1.FromWicBitmap(d2dContext, formatConverter, new d2.BitmapProperties1(d2PixelFormat));

            //이미지 크기 저장
            var inputImageSize = formatConverter.Size;
            var pixelWidth     = inputImageSize.Width;
            var pixelHeight    = inputImageSize.Height;


            //Effect1 : BitpmapSource - 디코딩된 이미지 데이터를 가져오고 BitmapSource 가져오기
            var bitmapSourceEffect = new d2.Effects.BitmapSource(d2dContext);

            bitmapSourceEffect.WicBitmapSource = formatConverter;



            // Effect 2 : GaussianBlur - bitmapsource에 가우시안블러 효과 적용
            var gaussianBlurEffect = new d2.Effects.GaussianBlur(d2dContext);

            gaussianBlurEffect.SetInput(0, bitmapSourceEffect.Output, true);
            gaussianBlurEffect.StandardDeviation = 5f;



            //overlay text setup
            var textFormat = new dw.TextFormat(dwFactory, "Arial", 15f);

            //draw a long text to show the automatic line wrapping
            var textToDraw = "sime ling text..." + "text" + "dddd";

            //create the text layout - this imroves the drawing performance for static text
            // as the glyph positions are precalculated
            //윤곽선 글꼴 데이터에서 글자 하나의 모양에 대한 기본 단위를 글리프(glyph)라고 한다
            var textLayout = new dw.TextLayout(dwFactory, textToDraw, textFormat, 300f, 1000f);

            SharpDX.Mathematics.Interop.RawColor4 color = new SharpDX.Mathematics.Interop.RawColor4(255, 255, 255, 1);
            var textBrush = new d2.SolidColorBrush(d2dContext, color);



            //여기서부터 다시

            //render target setup

            //create the d2d bitmap description using default flags and 96 DPI
            var d2dBitmapProps = new d2.BitmapProperties1(d2PixelFormat, 96, 96, d2.BitmapOptions.Target | d2.BitmapOptions.CannotDraw);

            //the render target
            var d2dRenderTarget = new d2.Bitmap1(d2dContext, new Size2(pixelWidth, pixelHeight), d2dBitmapProps);

            d2dContext.Target = d2dRenderTarget; //associate bitmap with the d2d context



            //Drawing

            //slow preparations - fast drawing
            d2dContext.BeginDraw();
            d2dContext.DrawImage(gaussianBlurEffect, new SharpDX.Mathematics.Interop.RawVector2(100f, 100f));
            d2dContext.DrawTextLayout(new SharpDX.Mathematics.Interop.RawVector2(50f, 50f), textLayout, textBrush);
            d2dContext.EndDraw();

            //Image save

            //delete the output file if it already exists
            if (System.IO.File.Exists(outputPath))
            {
                System.IO.File.Delete(outputPath);
            }

            //use the appropiate overload to write either to tream or to a file
            var stream = new wic.WICStream(imagingFactory, outputPath, NativeFileAccess.Write);

            //select the image encoding format HERE
            var encoder = new wic.PngBitmapEncoder(imagingFactory);

            encoder.Initialize(stream);

            var bitmapFrameEncode = new wic.BitmapFrameEncode(encoder);

            bitmapFrameEncode.Initialize();
            bitmapFrameEncode.SetSize(pixelWidth, pixelHeight);
            bitmapFrameEncode.SetPixelFormat(ref wicPixelFormat);

            //this is the trick to write d2d1 bitmap to WIC
            var imageEncoder = new wic.ImageEncoder(imagingFactory, d2dDevice);

            imageEncoder.WriteFrame(d2dRenderTarget, bitmapFrameEncode, new wic.ImageParameters(d2PixelFormat, 96, 96, 0, 0, pixelWidth, pixelHeight));

            bitmapFrameEncode.Commit();
            encoder.Commit();

            //cleanup

            //dispose everything and free used resources
            bitmapFrameEncode.Dispose();
            encoder.Dispose();
            stream.Dispose();
            textBrush.Dispose();
            textLayout.Dispose();
            textFormat.Dispose();
            formatConverter.Dispose();
            //gaussianBlurEffect.Dispose();
            bitmapSourceEffect.Dispose();
            d2dRenderTarget.Dispose();
            inputStream.Dispose();
            decoder.Dispose();
            d2dContext.Dispose();
            dwFactory.Dispose();
            imagingFactory.Dispose();
            d2dDevice.Dispose();
            dxgiDevice.Dispose();
            d3dDevice.Dispose();
            defaultDevice.Dispose();

            //save
            System.Diagnostics.Process.Start(outputPath);
        }
Esempio n. 3
0
        static void Main()
        {
            // input and output files are supposed to be in the program folder
            var inputPath  = "Input.png";
            var outputPath = "Output.png";

            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            // INITIALIZATION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            // initialize the D3D device which will allow to render to image any graphics - 3D or 2D
            var defaultDevice = new SharpDX.Direct3D11.Device(SharpDX.Direct3D.DriverType.Hardware,
                                                              d3d.DeviceCreationFlags.VideoSupport
                                                              | d3d.DeviceCreationFlags.BgraSupport
                                                              | d3d.DeviceCreationFlags.Debug); // take out the Debug flag for better performance

            var d3dDevice  = defaultDevice.QueryInterface <d3d.Device1>();                      // get a reference to the Direct3D 11.1 device
            var dxgiDevice = d3dDevice.QueryInterface <dxgi.Device>();                          // get a reference to DXGI device

            var d2dDevice = new d2.Device(dxgiDevice);                                          // initialize the D2D device

            var imagingFactory = new wic.ImagingFactory2();                                     // initialize the WIC factory

            // initialize the DeviceContext - it will be the D2D render target and will allow all rendering operations
            var d2dContext = new d2.DeviceContext(d2dDevice, d2.DeviceContextOptions.None);

            var dwFactory = new dw.Factory();

            // specify a pixel format that is supported by both D2D and WIC
            var d2PixelFormat = new d2.PixelFormat(dxgi.Format.R8G8B8A8_UNorm, d2.AlphaMode.Premultiplied);
            // if in D2D was specified an R-G-B-A format - use the same for wic
            var wicPixelFormat = wic.PixelFormat.Format32bppPRGBA;

            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            // IMAGE LOADING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            var decoder     = new wic.PngBitmapDecoder(imagingFactory);                            // we will load a PNG image
            var inputStream = new wic.WICStream(imagingFactory, inputPath, NativeFileAccess.Read); // open the image file for reading

            decoder.Initialize(inputStream, wic.DecodeOptions.CacheOnLoad);

            // decode the loaded image to a format that can be consumed by D2D
            var formatConverter = new wic.FormatConverter(imagingFactory);

            formatConverter.Initialize(decoder.GetFrame(0), wicPixelFormat);

            // load the base image into a D2D Bitmap
            //var inputBitmap = d2.Bitmap1.FromWicBitmap(d2dContext, formatConverter, new d2.BitmapProperties1(d2PixelFormat));

            // store the image size - output will be of the same size
            var inputImageSize = formatConverter.Size;
            var pixelWidth     = inputImageSize.Width;
            var pixelHeight    = inputImageSize.Height;

            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            // EFFECT SETUP ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            // Effect 1 : BitmapSource - take decoded image data and get a BitmapSource from it
            var bitmapSourceEffect = new d2.Effects.BitmapSource(d2dContext);

            bitmapSourceEffect.WicBitmapSource = formatConverter;

            // Effect 2 : GaussianBlur - give the bitmapsource a gaussian blurred effect
            var gaussianBlurEffect = new d2.Effects.GaussianBlur(d2dContext);

            gaussianBlurEffect.SetInput(0, bitmapSourceEffect.Output, true);
            gaussianBlurEffect.StandardDeviation = 5f;

            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            // OVERLAY TEXT SETUP ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            var textFormat = new dw.TextFormat(dwFactory, "Arial", 15f); // create the text format of specified font configuration

            // draw a long text to show the automatic line wrapping
            var textToDraw = "Some long text to show the drawing of preformatted "
                             + "glyphs using DirectWrite on the Direct2D surface."
                             + " Notice the automatic wrapping of line if it exceeds desired width.";

            // create the text layout - this improves the drawing performance for static text
            // as the glyph positions are precalculated
            var textLayout = new dw.TextLayout(dwFactory, textToDraw, textFormat, 300f, 1000f);

            var textBrush = new d2.SolidColorBrush(d2dContext, Color.LightGreen);

            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            // RENDER TARGET SETUP ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            // create the d2d bitmap description using default flags (from SharpDX samples) and 96 DPI
            var d2dBitmapProps = new d2.BitmapProperties1(d2PixelFormat, 96, 96, d2.BitmapOptions.Target | d2.BitmapOptions.CannotDraw);

            // the render target
            var d2dRenderTarget = new d2.Bitmap1(d2dContext, new Size2(pixelWidth, pixelHeight), d2dBitmapProps);

            d2dContext.Target = d2dRenderTarget; // associate bitmap with the d2d context

            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            // DRAWING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            // slow preparations - fast drawing:
            d2dContext.BeginDraw();
            d2dContext.DrawImage(gaussianBlurEffect);
            d2dContext.DrawTextLayout(new Vector2(5f, 5f), textLayout, textBrush);
            d2dContext.EndDraw();

            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            // IMAGE SAVING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            // delete the output file if it already exists
            if (System.IO.File.Exists(outputPath))
            {
                System.IO.File.Delete(outputPath);
            }

            // use the appropiate overload to write either to stream or to a file
            var stream = new wic.WICStream(imagingFactory, outputPath, NativeFileAccess.Write);

            // select the image encoding format HERE
            var encoder = new wic.PngBitmapEncoder(imagingFactory);

            encoder.Initialize(stream);

            var bitmapFrameEncode = new wic.BitmapFrameEncode(encoder);

            bitmapFrameEncode.Initialize();
            bitmapFrameEncode.SetSize(pixelWidth, pixelHeight);
            bitmapFrameEncode.SetPixelFormat(ref wicPixelFormat);

            // this is the trick to write D2D1 bitmap to WIC
            var imageEncoder = new wic.ImageEncoder(imagingFactory, d2dDevice);

            imageEncoder.WriteFrame(d2dRenderTarget, bitmapFrameEncode, new wic.ImageParameters(d2PixelFormat, 96, 96, 0, 0, pixelWidth, pixelHeight));

            bitmapFrameEncode.Commit();
            encoder.Commit();

            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            // CLEANUP ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            // dispose everything and free used resources

            bitmapFrameEncode.Dispose();
            encoder.Dispose();
            stream.Dispose();
            textBrush.Dispose();
            textLayout.Dispose();
            textFormat.Dispose();
            formatConverter.Dispose();
            gaussianBlurEffect.Dispose();
            bitmapSourceEffect.Dispose();
            d2dRenderTarget.Dispose();
            inputStream.Dispose();
            decoder.Dispose();
            d2dContext.Dispose();
            dwFactory.Dispose();
            imagingFactory.Dispose();
            d2dDevice.Dispose();
            dxgiDevice.Dispose();
            d3dDevice.Dispose();
            defaultDevice.Dispose();

            // show the result
            System.Diagnostics.Process.Start(outputPath);
        }
Esempio n. 4
0
        static void Main()
        {
            // input and output files are supposed to be in the program folder
            var inputPath = "Input.png";
            var outputPath = "Output.png";

            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            // INITIALIZATION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            // initialize the D3D device which will allow to render to image any graphics - 3D or 2D
            var defaultDevice = new SharpDX.Direct3D11.Device(SharpDX.Direct3D.DriverType.Hardware,
                                                              d3d.DeviceCreationFlags.VideoSupport
                                                              | d3d.DeviceCreationFlags.BgraSupport
                                                              | d3d.DeviceCreationFlags.Debug); // take out the Debug flag for better performance

            var d3dDevice = defaultDevice.QueryInterface<d3d.Device1>(); // get a reference to the Direct3D 11.1 device
            var dxgiDevice = d3dDevice.QueryInterface<dxgi.Device>(); // get a reference to DXGI device

            var d2dDevice = new d2.Device(dxgiDevice); // initialize the D2D device

            var imagingFactory = new wic.ImagingFactory2(); // initialize the WIC factory

            // initialize the DeviceContext - it will be the D2D render target and will allow all rendering operations
            var d2dContext = new d2.DeviceContext(d2dDevice, d2.DeviceContextOptions.None);

            var dwFactory = new dw.Factory();

            // specify a pixel format that is supported by both D2D and WIC
            var d2PixelFormat = new d2.PixelFormat(dxgi.Format.R8G8B8A8_UNorm, d2.AlphaMode.Premultiplied);
            // if in D2D was specified an R-G-B-A format - use the same for wic
            var wicPixelFormat = wic.PixelFormat.Format32bppPRGBA;

            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            // IMAGE LOADING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            var decoder = new wic.PngBitmapDecoder(imagingFactory); // we will load a PNG image
            var inputStream = new wic.WICStream(imagingFactory, inputPath, NativeFileAccess.Read); // open the image file for reading
            decoder.Initialize(inputStream, wic.DecodeOptions.CacheOnLoad);

            // decode the loaded image to a format that can be consumed by D2D
            var formatConverter = new wic.FormatConverter(imagingFactory);
            formatConverter.Initialize(decoder.GetFrame(0), wicPixelFormat);

            // load the base image into a D2D Bitmap
            //var inputBitmap = d2.Bitmap1.FromWicBitmap(d2dContext, formatConverter, new d2.BitmapProperties1(d2PixelFormat));

            // store the image size - output will be of the same size
            var inputImageSize = formatConverter.Size;
            var pixelWidth = inputImageSize.Width;
            var pixelHeight = inputImageSize.Height;

            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            // EFFECT SETUP ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            // Effect 1 : BitmapSource - take decoded image data and get a BitmapSource from it
            var bitmapSourceEffect = new d2.Effects.BitmapSource(d2dContext);
            bitmapSourceEffect.WicBitmapSource = formatConverter;

            // Effect 2 : GaussianBlur - give the bitmapsource a gaussian blurred effect
            var gaussianBlurEffect = new d2.Effects.GaussianBlur(d2dContext);
            gaussianBlurEffect.SetInput(0, bitmapSourceEffect.Output, true);
            gaussianBlurEffect.StandardDeviation = 5f;

            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            // OVERLAY TEXT SETUP ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            var textFormat = new dw.TextFormat(dwFactory, "Arial", 15f); // create the text format of specified font configuration

            // draw a long text to show the automatic line wrapping
            var textToDraw = "Some long text to show the drawing of preformatted "
                             + "glyphs using DirectWrite on the Direct2D surface."
                             + " Notice the automatic wrapping of line if it exceeds desired width.";

            // create the text layout - this improves the drawing performance for static text
            // as the glyph positions are precalculated
            var textLayout = new dw.TextLayout(dwFactory, textToDraw, textFormat, 300f, 1000f);

            var textBrush = new d2.SolidColorBrush(d2dContext, Color.LightGreen);

            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            // RENDER TARGET SETUP ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            // create the d2d bitmap description using default flags (from SharpDX samples) and 96 DPI
            var d2dBitmapProps = new d2.BitmapProperties1(d2PixelFormat, 96, 96, d2.BitmapOptions.Target | d2.BitmapOptions.CannotDraw);

            // the render target
            var d2dRenderTarget = new d2.Bitmap1(d2dContext, new Size2(pixelWidth, pixelHeight), d2dBitmapProps);
            d2dContext.Target = d2dRenderTarget; // associate bitmap with the d2d context

            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            // DRAWING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            // slow preparations - fast drawing:
            d2dContext.BeginDraw();
            d2dContext.DrawImage(gaussianBlurEffect);
            d2dContext.DrawTextLayout(new Vector2(5f, 5f), textLayout, textBrush);
            d2dContext.EndDraw();

            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            // IMAGE SAVING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            // delete the output file if it already exists
            if (System.IO.File.Exists(outputPath)) System.IO.File.Delete(outputPath);

            // use the appropiate overload to write either to stream or to a file
            var stream = new wic.WICStream(imagingFactory, outputPath, NativeFileAccess.Write);

            // select the image encoding format HERE
            var encoder = new wic.PngBitmapEncoder(imagingFactory);
            encoder.Initialize(stream);

            var bitmapFrameEncode = new wic.BitmapFrameEncode(encoder);
            bitmapFrameEncode.Initialize();
            bitmapFrameEncode.SetSize(pixelWidth, pixelHeight);
            bitmapFrameEncode.SetPixelFormat(ref wicPixelFormat);

            // this is the trick to write D2D1 bitmap to WIC
            var imageEncoder = new wic.ImageEncoder(imagingFactory, d2dDevice);
            imageEncoder.WriteFrame(d2dRenderTarget, bitmapFrameEncode, new wic.ImageParameters(d2PixelFormat, 96, 96, 0, 0, pixelWidth, pixelHeight));

            bitmapFrameEncode.Commit();
            encoder.Commit();

            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            // CLEANUP ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            // dispose everything and free used resources

            bitmapFrameEncode.Dispose();
            encoder.Dispose();
            stream.Dispose();
            textBrush.Dispose();
            textLayout.Dispose();
            textFormat.Dispose();
            formatConverter.Dispose();
            gaussianBlurEffect.Dispose();
            bitmapSourceEffect.Dispose();
            d2dRenderTarget.Dispose();
            inputStream.Dispose();
            decoder.Dispose();
            d2dContext.Dispose();
            dwFactory.Dispose();
            imagingFactory.Dispose();
            d2dDevice.Dispose();
            dxgiDevice.Dispose();
            d3dDevice.Dispose();
            defaultDevice.Dispose();

            // show the result
            System.Diagnostics.Process.Start(outputPath);
        }