private bool Ekranabas(SharpDX.Vector2 ekran, string yazi, System.Drawing.Color renk, TextFormat qfont) { TextLayout TL = new SharpDX.DirectWrite.TextLayout(fontFactory, yazi, qfont, float.MaxValue, float.MaxValue); device.DrawTextLayout(ekran, TL, (new SolidColorBrush(device, RawColorFromColor(renk))), DrawTextOptions.NoSnap); TL.Dispose(); return(true); }
protected override void OnRender(ChartControl chartControl, ChartScale chartScale) { // This sample should be used along side the help guide educational resource on this topic: // http://www.ninjatrader.com/support/helpGuides/nt8/en-us/?using_sharpdx_for_custom_chart_rendering.htm // Default plotting in base class. Uncomment if indicators holds at least one plot // in this case we would expect NOT to see the SMA plot we have as well in this sample script //base.OnRender(chartControl, chartScale); // 1.1 - SharpDX Vectors and Charting RenderTarget Coordinates // The SharpDX SDK uses "Vector2" objects to describe a two-dimensional point of a device (X and Y coordinates) SharpDX.Vector2 startPoint; SharpDX.Vector2 endPoint; // For our custom script, we need a way to determine the Chart's RenderTarget coordinates to draw our custom shapes // This info can be found within the NinjaTrader.Gui.ChartPanel class. // You can also use various chartScale and chartControl members to calculate values relative to time and price // However, those concepts will not be discussed or used in this sample // Notes: RenderTarget is always the full ChartPanel, so we need to be mindful which sub-ChartPanel we're dealing with // Always use ChartPanel X, Y, W, H - as chartScale and chartControl properties WPF units, so they can be drastically different depending on DPI set startPoint = new SharpDX.Vector2(ChartPanel.X, ChartPanel.Y); endPoint = new SharpDX.Vector2(ChartPanel.X + ChartPanel.W, ChartPanel.Y + ChartPanel.H); // These Vector2 objects are equivalent with WPF System.Windows.Point and can be used interchangeably depending on your requirements // For convenience, NinjaTrader provides a "ToVector2()" extension method to convert from WPF Points to SharpDX.Vector2 SharpDX.Vector2 startPoint1 = new System.Windows.Point(ChartPanel.X, ChartPanel.Y + ChartPanel.H).ToVector2(); SharpDX.Vector2 endPoint1 = new System.Windows.Point(ChartPanel.X + ChartPanel.W, ChartPanel.Y).ToVector2(); // SharpDX.Vector2 objects contain X/Y properties which are helpful to recalculate new properties based on the initial vector float width = endPoint.X - startPoint.X; float height = endPoint.Y - startPoint.Y; // Or you can recalculate a new vector from existing vector objects SharpDX.Vector2 center = (startPoint + endPoint) / 2; // Tip: This check is simply added to prevent the Indicator dialog menu from opening as a user clicks on the chart // The default behavior is to open the Indicator dialog menu if a user double clicks on the indicator // (i.e, the indicator falls within the RenderTarget "hit testing") // You can remove this check if you want the default behavior implemented if (!IsInHitTest) { // 1.2 - SharpDX Brush Resources // RenderTarget commands must use a special brush resource defined in the SharpDX.Direct2D1 namespace // These resources exist just like you will find in the WPF/Windows.System.Media namespace // such as SolidColorBrushes, LienarGraidentBrushes, RadialGradientBrushes, etc. // To begin, we will start with the most basic "Brush" type // Warning: Brush objects must be disposed of after they have been used SharpDX.Direct2D1.Brush areaBrushDx; SharpDX.Direct2D1.Brush smallAreaBrushDx; SharpDX.Direct2D1.Brush textBrushDx; // for convenience, you can simply convert a WPF Brush to a DXBrush using the ToDxBrush() extension method provided by NinjaTrader // This is a common approach if you have a Brush property created e.g., on the UI you wish to use in custom rendering routines areaBrushDx = areaBrush.ToDxBrush(RenderTarget); smallAreaBrushDx = smallAreaBrush.ToDxBrush(RenderTarget); textBrushDx = textBrush.ToDxBrush(RenderTarget); // However - it should be noted that this conversion process can be rather expensive // If you have many brushes being created, and are not tied to WPF resources // You should rather favor creating the SharpDX Brush directly: // Warning: SolidColorBrush objects must be disposed of after they have been used SharpDX.Direct2D1.SolidColorBrush customDXBrush = new SharpDX.Direct2D1.SolidColorBrush(RenderTarget, SharpDX.Color.DodgerBlue); // 1.3 - Using The RenderTarget // before executing chart commands, you have the ability to describe how the RenderTarget should render // for example, we can store the existing RenderTarget AntialiasMode mode // then update the AntialiasMode to be the quality of non-text primitives are rendered SharpDX.Direct2D1.AntialiasMode oldAntialiasMode = RenderTarget.AntialiasMode; RenderTarget.AntialiasMode = SharpDX.Direct2D1.AntialiasMode.Aliased; // Note: The code above stores the oldAntialiasMode as a best practices // i.e., if you plan on changing a property of the RenderTarget, you should plan to set it back // This is to make sure your requirements to no interfere with the function of another script // Additionally smoothing has some performance impacts // Once you have defined all the necessary requirements for you object // You can execute a command on the RenderTarget to draw specific shapes // e.g., we can now use the RenderTarget's DrawLine() command to render a line // using the start/end points and areaBrushDx objects defined before RenderTarget.DrawLine(startPoint, endPoint, areaBrushDx, 4); // Since rendering occurs in a sequential fashion, after you have executed a command // you can switch a property of the RenderTarget to meet other requirements // For example, we can draw a second line now which uses a different AntialiasMode // and the changes render on the chart for both lines from the time they received commands RenderTarget.AntialiasMode = SharpDX.Direct2D1.AntialiasMode.PerPrimitive; RenderTarget.DrawLine(startPoint1, endPoint1, areaBrushDx, 4); // 1.4 - Rendering Custom Shapes // SharpDX namespace consists of several shapes you can use to draw objects more complicated than lines // For example, we can use the RectangleF object to draw a rectangle that covers the entire chart area SharpDX.RectangleF rect = new SharpDX.RectangleF(startPoint.X, startPoint.Y, width, height); // The RenderTarget consists of two commands related to Rectangles. // The FillRectangle() method is used to "Paint" the area of a Rectangle RenderTarget.FillRectangle(rect, areaBrushDx); // and DrawRectangle() is used to "Paint" the outline of a Rectangle RenderTarget.DrawRectangle(rect, customDXBrush, 2); // Another example is an ellipse which can be used to draw circles // The ellipse center point can be used from the Vectors calculated earlier // The width and height an absolute 100 device pixels // To ensure that pixel coordinates work across all DPI devices, we use the NinjaTrader ChartingExteions methods // Which will convert the "100" value from WPF pixels to Device Pixels both vertically and horizontally int ellipseRadiusY = ChartingExtensions.ConvertToVerticalPixels(100, ChartControl.PresentationSource); int ellipseRadiusX = ChartingExtensions.ConvertToHorizontalPixels(100, ChartControl.PresentationSource); SharpDX.Direct2D1.Ellipse ellipse = new SharpDX.Direct2D1.Ellipse(center, ellipseRadiusX, ellipseRadiusY); // 1.5 - Complex Brush Types and Shapes // For this ellipse, we can use one of the more complex brush types "RadialGradientBrush" // Warning: RadialGradientBrush objects must be disposed of after they have been used SharpDX.Direct2D1.RadialGradientBrush radialGradientBrush; // However creating a RadialGradientBrush requires a few more properties than SolidColorBrush // First, you need to define the array gradient stops the brush will eventually use SharpDX.Direct2D1.GradientStop[] gradientStops = new SharpDX.Direct2D1.GradientStop[2]; // With the gradientStops array, we can describe the color and position of the individual gradients gradientStops[0].Color = SharpDX.Color.Goldenrod; gradientStops[0].Position = 0.0f; gradientStops[1].Color = SharpDX.Color.SeaGreen; gradientStops[1].Position = 1.0f; // then declare a GradientStopCollection from our render target that uses the gradientStops array defined just before // Warning: GradientStopCollection objects must be disposed of after they have been used SharpDX.Direct2D1.GradientStopCollection gradientStopCollection = new SharpDX.Direct2D1.GradientStopCollection(RenderTarget, gradientStops); // we also need to tell our RadialGradientBrush to match the size and shape of the ellipse that we will be drawing // for convenience, SharpDX provides a RadialGradientBrushProperties structure to help define these properties SharpDX.Direct2D1.RadialGradientBrushProperties radialGradientBrushProperties = new SharpDX.Direct2D1.RadialGradientBrushProperties { GradientOriginOffset = new SharpDX.Vector2(0, 0), Center = ellipse.Point, RadiusX = ellipse.RadiusY, RadiusY = ellipse.RadiusY }; // we now have everything we need to create a radial gradient brush radialGradientBrush = new SharpDX.Direct2D1.RadialGradientBrush(RenderTarget, radialGradientBrushProperties, gradientStopCollection); // Finally, we can use this radialGradientBrush to "Paint" the area of the ellipse RenderTarget.FillEllipse(ellipse, radialGradientBrush); // 1.6 - Simple Text Rendering // For rendering custom text to the Chart, there are a few ways you can approach depending on your requirements // The most straight forward way is to "borrow" the existing chartControl font provided as a "SimpleFont" class // Using the chartControl LabelFont, your custom object will also change to the user defined properties allowing // your object to match different fonts if defined by user. // The code below will use the chartControl Properties Label Font if it exists, // or fall back to a default property if it cannot obtain that value NinjaTrader.Gui.Tools.SimpleFont simpleFont = chartControl.Properties.LabelFont ?? new NinjaTrader.Gui.Tools.SimpleFont("Arial", 12); // the advantage of using a SimpleFont is they are not only very easy to describe // but there is also a convenience method which can be used to convert the SimpleFont to a SharpDX.DirectWrite.TextFormat used to render to the chart // Warning: TextFormat objects must be disposed of after they have been used SharpDX.DirectWrite.TextFormat textFormat1 = simpleFont.ToDirectWriteTextFormat(); // Once you have the format of the font, you need to describe how the font needs to be laid out // Here we will create a new Vector2() which draws the font according to the to top left corner of the chart (offset by a few pixels) SharpDX.Vector2 upperTextPoint = new SharpDX.Vector2(ChartPanel.X + 10, ChartPanel.Y + 20); // Warning: TextLayout objects must be disposed of after they have been used SharpDX.DirectWrite.TextLayout textLayout1 = new SharpDX.DirectWrite.TextLayout(NinjaTrader.Core.Globals.DirectWriteFactory, NinjaTrader.Custom.Resource.SampleCustomPlotUpperLeftCorner, textFormat1, ChartPanel.X + ChartPanel.W, textFormat1.FontSize); // With the format and layout of the text completed, we can now render the font to the chart RenderTarget.DrawTextLayout(upperTextPoint, textLayout1, textBrushDx, SharpDX.Direct2D1.DrawTextOptions.NoSnap); // 1.7 - Advanced Text Rendering // Font formatting and text layouts can get as complex as you need them to be // This example shows how to use a complete custom font unrelated to the existing user-defined chart control settings // Warning: TextLayout and TextFormat objects must be disposed of after they have been used SharpDX.DirectWrite.TextFormat textFormat2 = new SharpDX.DirectWrite.TextFormat(NinjaTrader.Core.Globals.DirectWriteFactory, "Century Gothic", FontWeight.Bold, FontStyle.Italic, 32f); SharpDX.DirectWrite.TextLayout textLayout2 = new SharpDX.DirectWrite.TextLayout(NinjaTrader.Core.Globals.DirectWriteFactory, NinjaTrader.Custom.Resource.SampleCustomPlotLowerRightCorner, textFormat2, 400, textFormat1.FontSize); // the textLayout object provides a way to measure the described font through a "Metrics" object // This allows you to create new vectors on the chart which are entirely dependent on the "text" that is being rendered // For example, we can create a rectangle that surrounds our font based off the textLayout which would dynamically change if the text used in the layout changed dynamically SharpDX.Vector2 lowerTextPoint = new SharpDX.Vector2(ChartPanel.W - textLayout2.Metrics.Width - 5, ChartPanel.Y + (ChartPanel.H - textLayout2.Metrics.Height)); SharpDX.RectangleF rect1 = new SharpDX.RectangleF(lowerTextPoint.X, lowerTextPoint.Y, textLayout2.Metrics.Width, textLayout2.Metrics.Height); // We can draw the Rectangle based on the TextLayout used above RenderTarget.FillRectangle(rect1, smallAreaBrushDx); RenderTarget.DrawRectangle(rect1, smallAreaBrushDx, 2); // And render the advanced text layout using the DrawTextLayout() method // Note: When drawing the same text repeatedly, using the DrawTextLayout() method is more efficient than using the DrawText() // because the text doesn't need to be formatted and the layout processed with each call RenderTarget.DrawTextLayout(lowerTextPoint, textLayout2, textBrushDx, SharpDX.Direct2D1.DrawTextOptions.NoSnap); // 1.8 - Cleanup // This concludes all of the rendering concepts used in the sample // However - there are some final clean up processes we should always provided before we are done // If changed, do not forget to set the AntialiasMode back to the default value as described above as a best practice RenderTarget.AntialiasMode = oldAntialiasMode; // We also need to make sure to dispose of every device dependent resource on each render pass // Failure to dispose of these resources will eventually result in unnecessary amounts of memory being used on the chart // Although the effects might not be obvious as first, if you see issues related to memory increasing over time // Objects such as these should be inspected first areaBrushDx.Dispose(); customDXBrush.Dispose(); gradientStopCollection.Dispose(); radialGradientBrush.Dispose(); smallAreaBrushDx.Dispose(); textBrushDx.Dispose(); textFormat1.Dispose(); textFormat2.Dispose(); textLayout1.Dispose(); textLayout2.Dispose(); } }
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); }
internal CCTexture2D CreateTextSprite(string text, CCFontDefinition textDefinition) { if (string.IsNullOrEmpty(text)) return new CCTexture2D(); int imageWidth; int imageHeight; var textDef = textDefinition; var contentScaleFactorWidth = CCLabel.DefaultTexelToContentSizeRatios.Width; var contentScaleFactorHeight = CCLabel.DefaultTexelToContentSizeRatios.Height; textDef.FontSize *= contentScaleFactorWidth; textDef.Dimensions.Width *= contentScaleFactorWidth; textDef.Dimensions.Height *= contentScaleFactorHeight; bool hasPremultipliedAlpha; var font = CreateFont(textDef.FontName, textDef.FontSize); var _currentFontSizeEm = textDef.FontSize; var _currentDIP = ConvertPointSizeToDIP(_currentFontSizeEm); // color var foregroundColor = Color4.White; // alignment var horizontalAlignment = textDef.Alignment; var verticleAlignement = textDef.LineAlignment; var textAlign = (CCTextAlignment.Right == horizontalAlignment) ? TextAlignment.Trailing : (CCTextAlignment.Center == horizontalAlignment) ? TextAlignment.Center : TextAlignment.Leading; var paragraphAlign = (CCVerticalTextAlignment.Bottom == vertAlignment) ? ParagraphAlignment.Far : (CCVerticalTextAlignment.Center == vertAlignment) ? ParagraphAlignment.Center : ParagraphAlignment.Near; // LineBreak var lineBreak = (CCLabelLineBreak.Character == textDef.LineBreak) ? WordWrapping.Wrap : (CCLabelLineBreak.Word == textDef.LineBreak) ? WordWrapping.Wrap : WordWrapping.NoWrap; // LineBreak // TODO: Find a way to specify the type of line breaking if possible. var dimensions = new CCSize(textDef.Dimensions.Width, textDef.Dimensions.Height); var layoutAvailable = true; if (dimensions.Width <= 0) { dimensions.Width = 8388608; layoutAvailable = false; } if (dimensions.Height <= 0) { dimensions.Height = 8388608; layoutAvailable = false; } var fontName = font.FontFamily.FamilyNames.GetString(0); var textFormat = new TextFormat(FactoryDWrite, fontName, _currentFontCollection, FontWeight.Regular, FontStyle.Normal, FontStretch.Normal, _currentDIP); textFormat.TextAlignment = textAlign; textFormat.ParagraphAlignment = paragraphAlign; var textLayout = new TextLayout(FactoryDWrite, text, textFormat, dimensions.Width, dimensions.Height); var boundingRect = new RectangleF(); // Loop through all the lines so we can find our drawing offsets var textMetrics = textLayout.Metrics; var lineCount = textMetrics.LineCount; // early out if something went wrong somewhere and nothing is to be drawn if (lineCount == 0) return new CCTexture2D(); // Fill out the bounding rect width and height so we can calculate the yOffset later if needed boundingRect.X = 0; boundingRect.Y = 0; boundingRect.Width = textMetrics.Width; boundingRect.Height = textMetrics.Height; if (!layoutAvailable) { if (dimensions.Width == 8388608) { dimensions.Width = boundingRect.Width; } if (dimensions.Height == 8388608) { dimensions.Height = boundingRect.Height; } } imageWidth = (int)dimensions.Width; imageHeight = (int)dimensions.Height; // Recreate our layout based on calculated dimensions so that we can draw the text correctly // in our image when Alignment is not Left. if (textAlign != TextAlignment.Leading) { textLayout.MaxWidth = dimensions.Width; textLayout.MaxHeight = dimensions.Height; } // Line alignment var yOffset = (CCVerticalTextAlignment.Bottom == verticleAlignement || boundingRect.Bottom >= dimensions.Height) ? dimensions.Height - boundingRect.Bottom // align to bottom : (CCVerticalTextAlignment.Top == verticleAlignement) ? 0 // align to top : (imageHeight - boundingRect.Bottom) * 0.5f; // align to center if (labelRenderer == null) labelRenderer = new CCLabel_Renderer81(); try { // The following code creates a .png stream in memory of our Bitmap and uses it to create our Textue2D Texture2D tex = null; using (var pngStream = labelRenderer.RenderLabelToStream(imageWidth, imageHeight, foregroundColor, new Vector2(boundingRect.X, yOffset), textLayout).Result) { // Create the Texture2D from the png stream tex = Texture2D.FromStream(CCDrawManager.SharedDrawManager.XnaGraphicsDevice, pngStream); } // Return our new CCTexture2D created from the Texture2D which will have our text drawn on it. return new CCTexture2D(tex); } catch (Exception exc) { CCLog.Log("CCLabel-Windows: Unable to create the backing image of our text. Message: {0}", exc.StackTrace); } finally { if (textFormat != null) { textFormat.Dispose(); textFormat = null; } if (textLayout != null) { textLayout.Dispose(); textLayout = null; } } // If we have reached here then something has gone wrong. return new CCTexture2D(); }
internal CCTexture2D CreateTextSprite(string text, CCFontDefinition textDefinition) { if (string.IsNullOrEmpty(text)) return new CCTexture2D(); int imageWidth; int imageHeight; var textDef = textDefinition; var contentScaleFactorWidth = CCLabel.DefaultTexelToContentSizeRatios.Width; var contentScaleFactorHeight = CCLabel.DefaultTexelToContentSizeRatios.Height; textDef.FontSize *= contentScaleFactorWidth; textDef.Dimensions.Width *= contentScaleFactorWidth; textDef.Dimensions.Height *= contentScaleFactorHeight; var font = CreateFont(textDef.FontName, textDef.FontSize); if (font == null) { CCLog.Log("Can not create font {0} with size {1}.", textDef.FontName, textDef.FontSize); return new CCTexture2D(); } var _currentFontSizeEm = textDef.FontSize; var _currentDIP = ConvertPointSizeToDIP(_currentFontSizeEm); // color var foregroundColor = Color4.White; // alignment var horizontalAlignment = textDef.Alignment; var verticleAlignement = textDef.LineAlignment; var textAlign = (CCTextAlignment.Right == horizontalAlignment) ? TextAlignment.Trailing : (CCTextAlignment.Center == horizontalAlignment) ? TextAlignment.Center : TextAlignment.Leading; var paragraphAlign = (CCVerticalTextAlignment.Bottom == vertAlignment) ? ParagraphAlignment.Far : (CCVerticalTextAlignment.Center == vertAlignment) ? ParagraphAlignment.Center : ParagraphAlignment.Near; // LineBreak var lineBreak = (CCLabelLineBreak.Character == textDef.LineBreak) ? WordWrapping.Wrap : (CCLabelLineBreak.Word == textDef.LineBreak) ? WordWrapping.Wrap : WordWrapping.NoWrap; // LineBreak // TODO: Find a way to specify the type of line breaking if possible. var dimensions = new CCSize(textDef.Dimensions.Width, textDef.Dimensions.Height); var layoutAvailable = true; if (dimensions.Width <= 0) { dimensions.Width = 8388608; layoutAvailable = false; } if (dimensions.Height <= 0) { dimensions.Height = 8388608; layoutAvailable = false; } var fontName = font.FontFamily.FamilyNames.GetString(0); var textFormat = new TextFormat(FactoryDWrite, fontName, _currentFontCollection, FontWeight.Regular, FontStyle.Normal, FontStretch.Normal, _currentDIP); textFormat.TextAlignment = textAlign; textFormat.ParagraphAlignment = paragraphAlign; var textLayout = new TextLayout(FactoryDWrite, text, textFormat, dimensions.Width, dimensions.Height); var boundingRect = new RectangleF(); // Loop through all the lines so we can find our drawing offsets var textMetrics = textLayout.Metrics; var lineCount = textMetrics.LineCount; // early out if something went wrong somewhere and nothing is to be drawn if (lineCount == 0) return new CCTexture2D(); // Fill out the bounding rect width and height so we can calculate the yOffset later if needed boundingRect.X = 0; boundingRect.Y = 0; boundingRect.Width = textMetrics.Width; boundingRect.Height = textMetrics.Height; if (!layoutAvailable) { if (dimensions.Width == 8388608) { dimensions.Width = boundingRect.Width; } if (dimensions.Height == 8388608) { dimensions.Height = boundingRect.Height; } } imageWidth = (int)dimensions.Width; imageHeight = (int)dimensions.Height; // Recreate our layout based on calculated dimensions so that we can draw the text correctly // in our image when Alignment is not Left. if (textAlign != TextAlignment.Leading) { textLayout.MaxWidth = dimensions.Width; textLayout.MaxHeight = dimensions.Height; } // Line alignment var yOffset = (CCVerticalTextAlignment.Bottom == verticleAlignement || boundingRect.Bottom >= dimensions.Height) ? dimensions.Height - boundingRect.Bottom // align to bottom : (CCVerticalTextAlignment.Top == verticleAlignement) ? 0 // align to top : (imageHeight - boundingRect.Bottom) * 0.5f; // align to center SharpDX.WIC.Bitmap sharpBitmap = null; WicRenderTarget sharpRenderTarget = null; SolidColorBrush solidBrush = null; try { // Select our pixel format var pixelFormat = SharpDX.WIC.PixelFormat.Format32bppPRGBA; // create our backing bitmap sharpBitmap = new SharpDX.WIC.Bitmap(FactoryImaging, imageWidth, imageHeight, pixelFormat, BitmapCreateCacheOption.CacheOnLoad); // Create the render target that we will draw to sharpRenderTarget = new WicRenderTarget(Factory2D, sharpBitmap, new RenderTargetProperties()); // Create our brush to actually draw with solidBrush = new SolidColorBrush(sharpRenderTarget, foregroundColor); // Begin the drawing sharpRenderTarget.BeginDraw(); if (textDefinition.isShouldAntialias) sharpRenderTarget.AntialiasMode = AntialiasMode.Aliased; // Clear it sharpRenderTarget.Clear(TransparentColor); // Draw the text to the bitmap sharpRenderTarget.DrawTextLayout(new Vector2(boundingRect.X, yOffset), textLayout, solidBrush); // End our drawing which will commit the rendertarget to the bitmap sharpRenderTarget.EndDraw(); // Debugging purposes //var s = "Label4"; //SaveToFile(@"C:\Xamarin\" + s + ".png", _bitmap, _renderTarget); // The following code creates a .png stream in memory of our Bitmap and uses it to create our Textue2D Texture2D tex = null; using (var memStream = new MemoryStream()) { using (var encoder = new PngBitmapEncoder(FactoryImaging, memStream)) using (var frameEncoder = new BitmapFrameEncode(encoder)) { frameEncoder.Initialize(); frameEncoder.WriteSource(sharpBitmap); frameEncoder.Commit(); encoder.Commit(); } // Create the Texture2D from the png stream tex = Texture2D.FromStream(CCDrawManager.SharedDrawManager.XnaGraphicsDevice, memStream); } // Return our new CCTexture2D created from the Texture2D which will have our text drawn on it. return new CCTexture2D(tex); } catch (Exception exc) { CCLog.Log("CCLabel-Windows: Unable to create the backing image of our text. Message: {0}", exc.StackTrace); } finally { if (sharpBitmap != null) { sharpBitmap.Dispose(); sharpBitmap = null; } if (sharpRenderTarget != null) { sharpRenderTarget.Dispose(); sharpRenderTarget = null; } if (solidBrush != null) { solidBrush.Dispose(); solidBrush = null; } if (textFormat != null) { textFormat.Dispose(); textFormat = null; } if (textLayout != null) { textLayout.Dispose(); textLayout = null; } } // If we have reached here then something has gone wrong. return new CCTexture2D(); }
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); }
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); }
protected override void OnRender(ChartControl chartControl, ChartScale chartScale) { // Tip: This check is simply added to prevent the Indicator dialog menu from opening as a user clicks on the chart // The default behavior is to open the Indicator dialog menu if a user double clicks on the indicator // (i.e, the indicator falls within the RenderTarget "hit testing") // You can remove this check if you want the default behavior implemented if (!IsInHitTest) { // 1.2 - SharpDX Brush Resources // RenderTarget commands must use a special brush resource defined in the SharpDX.Direct2D1 namespace // These resources exist just like you will find in the WPF/Windows.System.Media namespace // such as SolidColorBrushes, LienarGraidentBrushes, RadialGradientBrushes, etc. // To begin, we will start with the most basic "Brush" type // Warning: Brush objects must be disposed of after they have been used SharpDX.Direct2D1.Brush areaBrushDx; SharpDX.Direct2D1.Brush smallAreaBrushDx; SharpDX.Direct2D1.Brush textBrushDx; // for convenience, you can simply convert a WPF Brush to a DXBrush using the ToDxBrush() extension method provided by NinjaTrader // This is a common approach if you have a Brush property created e.g., on the UI you wish to use in custom rendering routines areaBrushDx = areaBrush.ToDxBrush(RenderTarget); smallAreaBrushDx = smallAreaBrush.ToDxBrush(RenderTarget); textBrushDx = textBrush.ToDxBrush(RenderTarget); // 1.3 - Using The RenderTarget // before executing chart commands, you have the ability to describe how the RenderTarget should render // for example, we can store the existing RenderTarget AntialiasMode mode // then update the AntialiasMode to be the quality of non-text primitives are rendered SharpDX.Direct2D1.AntialiasMode oldAntialiasMode = RenderTarget.AntialiasMode; RenderTarget.AntialiasMode = SharpDX.Direct2D1.AntialiasMode.Aliased; // 1.6 - Simple Text Rendering // For rendering custom text to the Chart, there are a few ways you can approach depending on your requirements // The most straight forward way is to "borrow" the existing chartControl font provided as a "SimpleFont" class // Using the chartControl LabelFont, your custom object will also change to the user defined properties allowing // your object to match different fonts if defined by user. // The code below will use the chartControl Properties Label Font if it exists, // or fall back to a default property if it cannot obtain that value NinjaTrader.Gui.Tools.SimpleFont simpleFont = chartControl.Properties.LabelFont ?? new NinjaTrader.Gui.Tools.SimpleFont("Arial", 12); // the advantage of using a SimpleFont is they are not only very easy to describe // but there is also a convenience method which can be used to convert the SimpleFont to a SharpDX.DirectWrite.TextFormat used to render to the chart // Warning: TextFormat objects must be disposed of after they have been used SharpDX.DirectWrite.TextFormat textFormat1 = simpleFont.ToDirectWriteTextFormat(); // Once you have the format of the font, you need to describe how the font needs to be laid out // Here we will create a new Vector2() which draws the font according to the to top left corner of the chart (offset by a few pixels) SharpDX.Vector2 upperTextPoint = new SharpDX.Vector2(ChartPanel.X + 10, ChartPanel.Y + 20); // Warning: TextLayout objects must be disposed of after they have been used SharpDX.DirectWrite.TextLayout textLayout1 = new SharpDX.DirectWrite.TextLayout(NinjaTrader.Core.Globals.DirectWriteFactory, NinjaTrader.Custom.Resource.SampleCustomPlotUpperLeftCorner, textFormat1, ChartPanel.X + ChartPanel.W, textFormat1.FontSize); // // With the format and layout of the text completed, we can now render the font to the chart // RenderTarget.DrawTextLayout(upperTextPoint, textLayout1, textBrushDx, // SharpDX.Direct2D1.DrawTextOptions.NoSnap); // // 1.7 - Advanced Text Rendering // // Font formatting and text layouts can get as complex as you need them to be // // This example shows how to use a complete custom font unrelated to the existing user-defined chart control settings // // Warning: TextLayout and TextFormat objects must be disposed of after they have been used SharpDX.DirectWrite.TextFormat textFormat2 = new SharpDX.DirectWrite.TextFormat(NinjaTrader.Core.Globals.DirectWriteFactory, "Century Gothic", FontWeight.Bold, FontStyle.Italic, 32f); SharpDX.DirectWrite.TextLayout textLayout2 = new SharpDX.DirectWrite.TextLayout(NinjaTrader.Core.Globals.DirectWriteFactory, NinjaTrader.Custom.Resource.SampleCustomPlotLowerRightCorner, textFormat2, 400, textFormat1.FontSize); // // the textLayout object provides a way to measure the described font through a "Metrics" object // // This allows you to create new vectors on the chart which are entirely dependent on the "text" that is being rendered // // For example, we can create a rectangle that surrounds our font based off the textLayout which would dynamically change if the text used in the layout changed dynamically SharpDX.Vector2 lowerTextPoint = new SharpDX.Vector2(ChartPanel.W - textLayout2.Metrics.Width - 5, ChartPanel.Y + (ChartPanel.H - textLayout2.Metrics.Height)); SharpDX.RectangleF rect1 = new SharpDX.RectangleF(lowerTextPoint.X, lowerTextPoint.Y, textLayout2.Metrics.Width, textLayout2.Metrics.Height); // // We can draw the Rectangle based on the TextLayout used above RenderTarget.FillRectangle(rect1, smallAreaBrushDx); // RenderTarget.DrawRectangle(rect1, smallAreaBrushDx, 2); // And render the advanced text layout using the DrawTextLayout() method // Note: When drawing the same text repeatedly, using the DrawTextLayout() method is more efficient than using the DrawText() // because the text doesn't need to be formatted and the layout processed with each call RenderTarget.DrawTextLayout(lowerTextPoint, textLayout2, textBrushDx, SharpDX.Direct2D1.DrawTextOptions.NoSnap); // 1.8 - Cleanup // This concludes all of the rendering concepts used in the sample // However - there are some final clean up processes we should always provided before we are done // If changed, do not forget to set the AntialiasMode back to the default value as described above as a best practice RenderTarget.AntialiasMode = oldAntialiasMode; // We also need to make sure to dispose of every device dependent resource on each render pass // Failure to dispose of these resources will eventually result in unnecessary amounts of memory being used on the chart // Although the effects might not be obvious as first, if you see issues related to memory increasing over time // Objects such as these should be inspected first areaBrushDx.Dispose(); // customDXBrush.Dispose(); // gradientStopCollection.Dispose(); //radialGradientBrush.Dispose(); smallAreaBrushDx.Dispose(); textBrushDx.Dispose(); textFormat1.Dispose(); textFormat2.Dispose(); textLayout1.Dispose(); textLayout2.Dispose(); } }
public void DrawText(string text, int font, int brush, float x, float y, bool bufferText = true) { if (bufferText) { var bufferPos = -1; for (var i = 0; i < _layoutContainer.Count; i++) { if (_layoutContainer[i].Text.Length != text.Length || _layoutContainer[i].Text != text) continue; bufferPos = i; break; } if (bufferPos == -1) { _layoutContainer.Add(new LayoutBuffer(text, new TextLayout(_fontFactory, text, _fontContainer[font], float.MaxValue, float.MaxValue))); bufferPos = _layoutContainer.Count - 1; } _device.DrawTextLayout(new RawVector2(x, y), _layoutContainer[bufferPos].TextLayout, _brushContainer[brush], DrawTextOptions.NoSnap); } else { var layout = new TextLayout(_fontFactory, text, _fontContainer[font], float.MaxValue, float.MaxValue); _device.DrawTextLayout(new RawVector2(x, y), layout, _brushContainer[brush]); layout.Dispose(); } }