[API Proposal]: Add ReadOnlySpan<char> overloads to System.Drawing.Graphics
See original GitHub issueBackground and motivation
When drawing strings manually in WinForms, new text is frequently created.
Since the methods System.Drawing.Graphics
and System.Drawing.GraphicsPath
only accept strings
String allocations occur frequently.
It would be better to add an overload that accepts ReadOnlySpan<char>
so that the buffer can be passed directly.
API Proposal
namespace System.Drawing
{
public sealed partial class Graphics : System.MarshalByRefObject, System.Drawing.IDeviceContext, System.IDisposable
{
// Existing:
public void DrawString(string? s, System.Drawing.Font font, System.Drawing.Brush brush, System.Drawing.PointF point) { }
public void DrawString(string? s, System.Drawing.Font font, System.Drawing.Brush brush, System.Drawing.PointF point, System.Drawing.StringFormat? format) { }
public void DrawString(string? s, System.Drawing.Font font, System.Drawing.Brush brush, System.Drawing.RectangleF layoutRectangle) { }
public void DrawString(string? s, System.Drawing.Font font, System.Drawing.Brush brush, System.Drawing.RectangleF layoutRectangle, System.Drawing.StringFormat? format) { }
public void DrawString(string? s, System.Drawing.Font font, System.Drawing.Brush brush, float x, float y) { }
public void DrawString(string? s, System.Drawing.Font font, System.Drawing.Brush brush, float x, float y, System.Drawing.StringFormat? format) { }
public System.Drawing.Region[] MeasureCharacterRanges(string? text, System.Drawing.Font font, System.Drawing.RectangleF layoutRect, System.Drawing.StringFormat? stringFormat) { throw null; }
public System.Drawing.SizeF MeasureString(string? text, System.Drawing.Font font) { throw null; }
public System.Drawing.SizeF MeasureString(string? text, System.Drawing.Font font, System.Drawing.PointF origin, System.Drawing.StringFormat? stringFormat) { throw null; }
public System.Drawing.SizeF MeasureString(string? text, System.Drawing.Font font, System.Drawing.SizeF layoutArea) { throw null; }
public System.Drawing.SizeF MeasureString(string? text, System.Drawing.Font font, System.Drawing.SizeF layoutArea, System.Drawing.StringFormat? stringFormat) { throw null; }
public System.Drawing.SizeF MeasureString(string? text, System.Drawing.Font font, System.Drawing.SizeF layoutArea, System.Drawing.StringFormat? stringFormat, out int charactersFitted, out int linesFilled) { throw null; }
public System.Drawing.SizeF MeasureString(string? text, System.Drawing.Font font, int width) { throw null; }
public System.Drawing.SizeF MeasureString(string? text, System.Drawing.Font font, int width, System.Drawing.StringFormat? format) { throw null; }
// Proposal
public void DrawString(ReadOnlySpan<char> s, System.Drawing.Font font, System.Drawing.Brush brush, System.Drawing.PointF point) { }
public void DrawString(ReadOnlySpan<char> s, System.Drawing.Font font, System.Drawing.Brush brush, System.Drawing.PointF point, System.Drawing.StringFormat? format) { }
public void DrawString(ReadOnlySpan<char> s, System.Drawing.Font font, System.Drawing.Brush brush, System.Drawing.RectangleF layoutRectangle) { }
public void DrawString(ReadOnlySpan<char> s, System.Drawing.Font font, System.Drawing.Brush brush, System.Drawing.RectangleF layoutRectangle, System.Drawing.StringFormat? format) { }
public void DrawString(ReadOnlySpan<char> s, System.Drawing.Font font, System.Drawing.Brush brush, float x, float y) { }
public void DrawString(ReadOnlySpan<char> s, System.Drawing.Font font, System.Drawing.Brush brush, float x, float y, System.Drawing.StringFormat? format) { }
public System.Drawing.Region[] MeasureCharacterRanges(ReadOnlySpan<char> text, System.Drawing.Font font, System.Drawing.RectangleF layoutRect, System.Drawing.StringFormat? stringFormat) { throw null; }
public System.Drawing.SizeF MeasureString(ReadOnlySpan<char> text, System.Drawing.Font font) { throw null; }
public System.Drawing.SizeF MeasureString(ReadOnlySpan<char> text, System.Drawing.Font font, System.Drawing.PointF origin, System.Drawing.StringFormat? stringFormat) { throw null; }
public System.Drawing.SizeF MeasureString(ReadOnlySpan<char> text, System.Drawing.Font font, System.Drawing.SizeF layoutArea) { throw null; }
public System.Drawing.SizeF MeasureString(ReadOnlySpan<char> text, System.Drawing.Font font, System.Drawing.SizeF layoutArea, System.Drawing.StringFormat? stringFormat) { throw null; }
public System.Drawing.SizeF MeasureString(ReadOnlySpan<char> text, System.Drawing.Font font, System.Drawing.SizeF layoutArea, System.Drawing.StringFormat? stringFormat, out int charactersFitted, out int linesFilled) { throw null; }
public System.Drawing.SizeF MeasureString(ReadOnlySpan<char> text, System.Drawing.Font font, int width) { throw null; }
public System.Drawing.SizeF MeasureString(ReadOnlySpan<char> text, System.Drawing.Font font, int width, System.Drawing.StringFormat? format) { throw null; }
}
public sealed partial class GraphicsPath : System.MarshalByRefObject, System.ICloneable, System.IDisposable
{
// Existing:
public void AddString(string s, System.Drawing.FontFamily family, int style, float emSize, System.Drawing.Point origin, System.Drawing.StringFormat? format) { }
public void AddString(string s, System.Drawing.FontFamily family, int style, float emSize, System.Drawing.PointF origin, System.Drawing.StringFormat? format) { }
public void AddString(string s, System.Drawing.FontFamily family, int style, float emSize, System.Drawing.Rectangle layoutRect, System.Drawing.StringFormat? format) { }
public void AddString(string s, System.Drawing.FontFamily family, int style, float emSize, System.Drawing.RectangleF layoutRect, System.Drawing.StringFormat? format) { }
// Proposal
public void AddString(ReadOnlySpan<char> s, System.Drawing.FontFamily family, int style, float emSize, System.Drawing.Point origin, System.Drawing.StringFormat? format) { }
public void AddString(ReadOnlySpan<char> s, System.Drawing.FontFamily family, int style, float emSize, System.Drawing.PointF origin, System.Drawing.StringFormat? format) { }
public void AddString(ReadOnlySpan<char> s, System.Drawing.FontFamily family, int style, float emSize, System.Drawing.Rectangle layoutRect, System.Drawing.StringFormat? format) { }
public void AddString(ReadOnlySpan<char> s, System.Drawing.FontFamily family, int style, float emSize, System.Drawing.RectangleF layoutRect, System.Drawing.StringFormat? format) { }
}
}
API Usage
It is possible to pass buffers on the stack.
GraphicsPath gp = new GraphicsPath();
...
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
var g = e.Graphics;
Span<char> buf = stackalloc char[512];
DateTime.Now.TryFormat(buf, out var writtern);
g.DrawString(buf, ...);
gp.AddString(buf, ...);
}
Alternative Designs
I can’t think of any.
Risks
I can’t think of any.
Issue Analytics
- State:
- Created a year ago
- Reactions:4
- Comments:9 (7 by maintainers)
Top Results From Across the Web
TextRenderer.MeasureText Method (System.Windows. ...
You can manipulate how the text is drawn by using one of the DrawText(IDeviceContext, ReadOnlySpan<Char>, Font, Rectangle, Color, TextFormatFlags) overloads ...
Read more >CA1846: Prefer AsSpan over Substring - .NET
Many APIs that accept strings also have overloads that accept a ReadOnlySpan<System.Char> argument. When such overloads are available, ...
Read more >Basics & Requirements
First, add a using directive for the underlying subsystem you want to use. For example, you probably want to use one or more...
Read more >https://raw.githubusercontent.com/dotnet/samples/m...
Drawing System.Drawing.Common needs netfx and netstandard configurations Right now it has only ... Proposed Api Adds extra .ctor overload + param to ...
Read more >Is there a way to use the ReadOnlySpan<char> overloads ...
I have a NetStandard2.0 class library. I have imported the System.Memory nuget package, which means I can use Span<T> inside it.
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
Seems rational. Would just need to double check that the underlying GDI+ APIs all take a length (and not a null-terminated string). I believe that is the case…
Verified this on .NET 8.0 latest build: 8.0.100-preview.4.23179.4, has been added
ReadOnlySpan<char>
overloads toGraphics.DrawString
.