private void BuildRects() { // Build character rects var fm = _paint.FontMetrics; SKTextAlign align = _paint.TextAlign; for (int li = 0; li < _skiaLines.Count; li++) { var line = _skiaLines[li]; float prevRight = TransformX(0, line.Width, align); double nextTop = line.Top + line.Height; if (li + 1 < _skiaLines.Count) { nextTop = _skiaLines[li + 1].Top; } for (int i = line.Start; i < line.Start + line.TextLength; i++) { float w = _paint.MeasureText(Text[i].ToString()); _rects.Add(new Rect( prevRight, line.Top, w, nextTop - line.Top)); prevRight += w; } } }
/// <summary> /// Draws a bitmap to the document and returns the height of the drawing, /// excluding the <paramref name="paddingBottom"/>. /// </summary> /// <param name="bitmap">The bitmap to draw onto the document.</param> /// <param name="align">The image alignment.</param> /// <param name="width">The desired width of the drawing.</param> /// <param name="height">The desired height of the drawing.</param> /// <param name="paddingBottom">Adds additional vertical "whitespace" below the bitmap.</param> private static float DrawBitmap(SKBitmap bitmap, SKTextAlign align, float width, float height, float paddingBottom = 15f) { CheckAndTriggerPageBreak(height); float imgXPos; switch (align) { case SKTextAlign.Left: default: imgXPos = MARGIN_LEFT; break; case SKTextAlign.Center: imgXPos = PAGE_WIDTH / 2 - width / 2; break; case SKTextAlign.Right: imgXPos = PAGE_WIDTH - MARGIN_LEFT - width; break; } SKRect rect = new SKRect(imgXPos, _yPos, imgXPos + width, _yPos + height); _canvas.DrawBitmap(bitmap, rect); _yPos += height + paddingBottom; return(rect.Height); }
private void BuildRects() { // Build character rects SKTextAlign align = _paint.TextAlign; for (int li = 0; li < _skiaLines.Count; li++) { var line = _skiaLines[li]; float prevRight = TransformX(0, line.Width, align); double nextTop = line.Top + line.Height; if (li + 1 < _skiaLines.Count) { nextTop = _skiaLines[li + 1].Top; } for (int i = line.Start; i < line.Start + line.TextLength; i++) { var w = line.IsEmptyTrailingLine ? 0 : _advances[i]; _rects.Add(new Rect( prevRight, line.Top, w, nextTop - line.Top)); prevRight += w; } } }
public static void DrawToBottom(SKCanvas c, BaseIcon icon, SKTextAlign align, string text) { if (string.IsNullOrEmpty(text)) { return; } using (var paint = new SKPaint { IsAntialias = true, FilterQuality = SKFilterQuality.High, Typeface = ChicTypefaces.BurbankBigRegularBlack, TextSize = icon.Height * (align == SKTextAlign.Left ? BOTTOM_TEXT_SIZE_RATIO : ChicRatios.Get(30)), Color = SKColors.White, TextAlign = align }) { var five = (int)(icon.Height * ChicRatios.Get(5)); if (align == SKTextAlign.Left) { c.DrawText(text, five, icon.Height - five, paint); } else { c.DrawText(text, icon.Width - five - (int)(icon.Height * ChicRatios.Get(27.5f)), icon.Height - five, paint); } } }
public StaticLayout(string source, SKPaint paint, int width, SKTextAlign alignment) { this.source = source; this.paint = paint; this.width = width; this.alignment = alignment; paint.MeasureText(source, ref this.textRect); paint.GetFontMetrics(out fontMetrics); }
public override void Draw(Diagram diagram) { // Select text alignment. int aVal = (int)Alignment; SKTextAlign alignment = SKTextAlign.Left; if (aVal % 3 == 2) { alignment = SKTextAlign.Right; } if (aVal % 3 == 1) { alignment = SKTextAlign.Center; } // Paint and style. SKFontStyle style = new SKFontStyle( Bold ? SKFontStyleWeight.Bold : SKFontStyleWeight.Normal, SKFontStyleWidth.Normal, Italic ? SKFontStyleSlant.Italic : SKFontStyleSlant.Upright ); SKPaint paint = new SKPaint { Color = Colour, IsAntialias = true, Typeface = SKTypeface.FromFamilyName(FontFamily, style), TextAlign = alignment, TextSize = FontSize }; TextWidth *= (paint.FontMetrics.MaxCharacterWidth / FontSize); // Compensation of font width. // Vertical alignment compensation. string[] lines = Content.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries); float comp = FontSize / 2; if (aVal < 3) { comp = FontSize; } else if (aVal > 5) { comp = 0; } for (int i = 0; i < lines.Length; i++) { diagram.DiagramSurface.Canvas.DrawText(lines[i], X, Y + comp + (i * FontSize), paint); } paint.Dispose(); }
public StaticLayout(string source, SKPaint paint, int width, SKTextAlign alignment) { this.source = source; this.paint = paint; this.width = width; this.alignment = alignment; paint.MeasureText("A,", ref this.highestLetterRect); paint.MeasureText(source, ref this.textRect); this.verticalInset = (float)(highestLetterRect.Height - this.textRect.Height); }
public static TextAlignment ToAvalonia(this SKTextAlign a) { switch (a) { default: case SKTextAlign.Left: return(TextAlignment.Left); case SKTextAlign.Center: return(TextAlignment.Center); case SKTextAlign.Right: return(TextAlignment.Right); } }
static public StringAlignment ToStringAlignment(this SKTextAlign align) { switch (align) { case SKTextAlign.Left: return(StringAlignment.Near); case SKTextAlign.Right: return(StringAlignment.Far); default: return(StringAlignment.Center); } }
public static AM.TextAlignment ToTextAlignment(this SKTextAlign textAlign) { switch (textAlign) { default: case SKTextAlign.Left: return(AM.TextAlignment.Left); case SKTextAlign.Center: return(AM.TextAlignment.Center); case SKTextAlign.Right: return(AM.TextAlignment.Right); } }
/// <summary> /// Convert Mapsforge Align to Skia SKTextAlign /// </summary> /// <param name="align">Mapsforge Align</param> /// <returns>Skia SKTextAlign</returns> public static SKTextAlign ToSkia(this Align align) { SKTextAlign result = SKTextAlign.Center; if (align == Align.Left) { result = SKTextAlign.Left; } if (align == Align.Right) { result = SKTextAlign.Right; } return(result); }
public StaticLayout get(int width, SKTextAlign alignment, string source, SKPaint paint) { if (this.layout == null || this.width != width || this.alignment != alignment || !this.source.Equals(source) || !this.paint.Equals(paint)) { if (this.layout != null) { this.layout.Dispose(); } this.width = width; this.alignment = alignment; this.source = source; this.paint = paint; this.layout = new StaticLayout(source, paint, width, alignment); } return(this.layout); }
public void DrawText(Point point, string text, Color color, Font font) { if (text is null) { return; } SKTextAlign ta = new SKTextAlign(); if (font.HorizontalAlignment == Renderable.HorizontalAlignment.Left) { ta = SKTextAlign.Left; } else if (font.HorizontalAlignment == Renderable.HorizontalAlignment.Center) { ta = SKTextAlign.Center; } else if (font.HorizontalAlignment == Renderable.HorizontalAlignment.Right) { ta = SKTextAlign.Right; } var paint = new SKPaint { Color = Convert(color), Typeface = SKTypeface.FromFamilyName(font.Name), TextSize = font.Size, TextAlign = ta, IsAntialias = true }; var bounds = new SKRect(); paint.MeasureText(text, ref bounds); if (font.VerticalAlignment == Renderable.VerticalAlignment.Top) { point.Y += bounds.Height; } else if (font.VerticalAlignment == Renderable.VerticalAlignment.Center) { point.Y += bounds.Height / 2; } Canvas.DrawText(text, Convert(point), paint); }
//[InlineData(SKTextAlign.Center)] //[InlineData(SKTextAlign.Right)] public void DrawTextBlobIsTheSameAsDrawText(SKTextAlign align) { var info = new SKImageInfo(300, 300); var text = "SkiaSharp"; byte[] textPixels; using (var bmp = new SKBitmap(info)) using (var canvas = new SKCanvas(bmp)) using (var paint = new SKPaint()) { paint.TextSize = 50; paint.TextAlign = align; canvas.Clear(SKColors.White); canvas.DrawText(text, 150, 175, paint); textPixels = bmp.Bytes; } byte[] glyphsPixels; using (var bmp = new SKBitmap(info)) using (var canvas = new SKCanvas(bmp)) using (var paint = new SKPaint()) { ushort[] glyphs; using (var glyphsp = new SKPaint()) glyphs = glyphsp.GetGlyphs(text); paint.TextSize = 50; paint.TextAlign = align; paint.TextEncoding = SKTextEncoding.GlyphId; canvas.Clear(SKColors.White); using (var builder = new SKTextBlobBuilder()) { builder.AddRun(paint, 0, 0, glyphs); canvas.DrawText(builder.Build(), 150, 175, paint); } glyphsPixels = bmp.Bytes; } Assert.Equal(textPixels, glyphsPixels); }
public static void DrawToBottom(SKCanvas c, BaseIcon icon, SKTextAlign align, string text) { if (string.IsNullOrEmpty(text)) { return; } using (var paint = new SKPaint { FilterQuality = SKFilterQuality.High, IsAntialias = true, Typeface = ChicTypefaces.BurbankBigRegularBlack, TextSize = BOTTOM_TEXT_SIZE, TextAlign = align, Color = SKColors.White }) if (align == SKTextAlign.Left) { c.DrawText(text, 5, icon.Height - 7, paint); } else { c.DrawText(text, icon.Width - 5, icon.Height - 7, paint); } }
private float TransformX(float originX, float lineWidth, SKTextAlign align) { float x = 0; if (align == SKTextAlign.Left) { x = originX; } else { double width = Constraint.Width > 0 && !double.IsPositiveInfinity(Constraint.Width) ? Constraint.Width : _bounds.Width; switch (align) { case SKTextAlign.Center: x = originX + (float)(width - lineWidth) / 2; break; case SKTextAlign.Right: x = originX + (float)(width - lineWidth); break; } } return(x); }
public SKText(SKTextAlign textAlign) { TextAlign = textAlign; }
/// <summary> /// Gets the absolute bounds of a given rectangle, aligned at a given position. /// </summary> /// <param name="x">The absolute x position.</param> /// <param name="y">The absolute y position.</param> /// <param name="bounds">The bounds of the rectangle.</param> /// <param name="horizontalAlignment">The alignment of the rectangle, relative to x/y.</param> /// <returns></returns> private static SKRect GetAbsolutePositionRect(float x, float y, SKRect bounds, SKTextAlign horizontalAlignment) { var captionBounds = new SKRect { Left = x + bounds.Left, Top = y + bounds.Top }; switch (horizontalAlignment) { case SKTextAlign.Left: captionBounds.Right = captionBounds.Left + bounds.Width; break; case SKTextAlign.Center: captionBounds.Right = captionBounds.Left + bounds.Width / 2; break; case SKTextAlign.Right: captionBounds.Right = captionBounds.Left - bounds.Width; break; } captionBounds.Bottom = captionBounds.Top + bounds.Height; return(captionBounds); }
private float TransformX(float originX, float lineWidth, SKTextAlign align) { float x = 0; if (align == SKTextAlign.Left) { x = originX; } else { double width = Constraint.Width > 0 && !double.IsPositiveInfinity(Constraint.Width) ? Constraint.Width : _size.Width; switch (align) { case SKTextAlign.Center: x = originX + (float)(width - lineWidth) / 2; break; case SKTextAlign.Right: x = originX + (float)(width - lineWidth); break; } } return x; }
public static void DrawCaptionLabels(this SKCanvas canvas, string label, SKColor labelColor, string value, SKColor valueColor, float textSize, SKPoint point, SKTextAlign horizontalAlignment, SKTypeface typeface) { var hasLabel = !string.IsNullOrEmpty(label); var hasValueLabel = !string.IsNullOrEmpty(value); if (hasLabel || hasValueLabel) { var hasOffset = hasLabel && hasValueLabel; var captionMargin = textSize * 0.60f; var space = hasOffset ? captionMargin : 0; if (hasLabel) { using (var paint = new SKPaint() { TextSize = textSize, IsAntialias = true, Color = labelColor, IsStroke = false, TextAlign = horizontalAlignment, Typeface = typeface }) { var bounds = new SKRect(); var text = label; paint.MeasureText(text, ref bounds); var y = point.Y - ((bounds.Top + bounds.Bottom) / 2) - space; canvas.DrawText(text, point.X, y, paint); } } if (hasValueLabel) { using (var paint = new SKPaint() { TextSize = textSize, IsAntialias = true, FakeBoldText = true, Color = valueColor, IsStroke = false, TextAlign = horizontalAlignment, Typeface = typeface }) { var bounds = new SKRect(); var text = value; paint.MeasureText(text, ref bounds); var y = point.Y - ((bounds.Top + bounds.Bottom) / 2) + space; canvas.DrawText(text, point.X, y, paint); } } } }
public static void DrawCaptionLabels(this SKCanvas canvas, string label, SKColor labelColor, TextDirection textDirection, float labelTextSpacing, string value, SKColor valueColor, float textSize, SKPoint point, SKTextAlign horizontalAlignment, SKTypeface typeface, out SKRect totalBounds) { var hasLabel = !string.IsNullOrEmpty(label); var hasValueLabel = !string.IsNullOrEmpty(value); totalBounds = new SKRect(); if (hasLabel || hasValueLabel) { var hasOffset = hasLabel && hasValueLabel; var captionMargin = textSize * 0.60f; var space = hasOffset ? captionMargin : 0; if (hasLabel) { using (var paint = new SKPaint { TextSize = textSize, IsAntialias = true, Color = labelColor, IsStroke = false, TextAlign = horizontalAlignment, Typeface = typeface }) { var bounds = new SKRect(); var text = label; paint.MeasureText(text, ref bounds); var y = point.Y - ((bounds.Top + bounds.Bottom) / 2) - space; RichString rs; if (typeface != null) { rs = new RichString() .FontFamily(typeface.FamilyName) .FontSize(textSize) .LetterSpacing(labelTextSpacing) .TextColor(labelColor) .TextDirection(textDirection) .Add(text); } else { rs = new RichString() .FontSize(textSize) .LetterSpacing(labelTextSpacing) .TextColor(labelColor) .TextDirection(textDirection) .Add(text); } rs.Paint(canvas, new SKPoint(point.X, y), new TextPaintOptions { IsAntialias = true, LcdRenderText = true }); var labelBounds = GetAbsolutePositionRect(point.X, y, bounds, horizontalAlignment); totalBounds = labelBounds.Standardized; } } if (hasValueLabel) { using (var paint = new SKPaint() { TextSize = textSize, IsAntialias = true, FakeBoldText = true, Color = valueColor, IsStroke = false, TextAlign = horizontalAlignment, Typeface = typeface }) { var bounds = new SKRect(); var text = value; paint.MeasureText(text, ref bounds); var y = point.Y - ((bounds.Top + bounds.Bottom) / 2) + space; canvas.DrawText(text, point.X, y, paint); var valueBounds = GetAbsolutePositionRect(point.X, y, bounds, horizontalAlignment); if (totalBounds.IsEmpty) { totalBounds = valueBounds; } else { totalBounds.Union(valueBounds); } } } } }
public static SKPaint CreateTextPaint(double fontSize, double width, Color color, SKTextAlign textAlign = SKTextAlign.Left) { var paint = new SKPaint { Style = SKPaintStyle.Fill, Color = color.ToSKColor(), StrokeWidth = (float)width, TextSize = (float)fontSize, TextAlign = textAlign, SubpixelText = true, IsAntialias = true, }; return(paint); }
// AddPathPositionedRun public void AddPathPositionedRun(ReadOnlySpan <ushort> glyphs, SKFont font, ReadOnlySpan <float> glyphWidths, ReadOnlySpan <SKPoint> glyphOffsets, SKPath path, SKTextAlign textAlign = SKTextAlign.Left) { using var pathMeasure = new SKPathMeasure(path); var contourLength = pathMeasure.Length; var textLength = glyphOffsets[glyphs.Length - 1].X + glyphWidths[glyphs.Length - 1]; var alignment = (int)textAlign * 0.5f; var startOffset = glyphOffsets[0].X + (contourLength - textLength) * alignment; var firstGlyphIndex = 0; var pathGlyphCount = 0; using var glyphTransforms = Utils.RentArray <SKRotationScaleMatrix> (glyphs.Length); // TODO: deal with multiple contours? for (var index = 0; index < glyphOffsets.Length; index++) { var glyphOffset = glyphOffsets[index]; var halfWidth = glyphWidths[index] * 0.5f; var pathOffset = startOffset + glyphOffset.X + halfWidth; // TODO: clip glyphs on both ends of paths if (pathOffset >= 0 && pathOffset < contourLength && pathMeasure.GetPositionAndTangent(pathOffset, out var position, out var tangent)) { if (pathGlyphCount == 0) { firstGlyphIndex = index; } var tx = tangent.X; var ty = tangent.Y; var px = position.X; var py = position.Y; // horizontally offset the position using the tangent vector px -= tx * halfWidth; py -= ty * halfWidth; // vertically offset the position using the normal vector (-ty, tx) var dy = glyphOffset.Y; px -= dy * ty; py += dy * tx; glyphTransforms.Span[pathGlyphCount++] = new SKRotationScaleMatrix(tx, ty, px, py); } } var glyphSubset = glyphs.Slice(firstGlyphIndex, pathGlyphCount); var positions = glyphTransforms.Span.Slice(0, pathGlyphCount); AddRotationScaleRun(glyphSubset, font, positions); }
public static SKPaint CreateTextPaint(SKTypeface font, int fontsize, SKColor color, SKTextAlign align = SKTextAlign.Left) { return(new SKPaint { Color = color, Typeface = font, IsAntialias = true, LcdRenderText = true, TextSize = fontsize, SubpixelText = true, DeviceKerningEnabled = true, FilterQuality = SKFilterQuality.High, HintingLevel = SKPaintHinting.Full, IsAutohinted = true, TextAlign = align, TextEncoding = SKTextEncoding.Utf32, IsLinearText = true }); }
public SKText(SKPoint location, SKTextAlign textAlign) { Location = location; TextAlign = textAlign; }
internal static SKTextBlob CreatePathPositioned(void *text, int length, SKTextEncoding encoding, SKFont font, SKPath path, SKTextAlign textAlign = SKTextAlign.Left, SKPoint origin = default) { if (font == null) { throw new ArgumentNullException(nameof(font)); } var count = font.CountGlyphs(text, length, encoding); if (count <= 0) { return(null); } // we use temporary arrays because we might only use part of the text using var glyphs = Utils.RentArray <ushort> (count); using var glyphWidths = Utils.RentArray <float> (glyphs.Length); using var glyphOffsets = Utils.RentArray <SKPoint> (glyphs.Length); font.GetGlyphs(text, length, encoding, glyphs); font.GetGlyphWidths(glyphs, glyphWidths, Span <SKRect> .Empty); font.GetGlyphPositions(glyphs, glyphOffsets, origin); using var builder = new SKTextBlobBuilder(); builder.AddPathPositionedRun(glyphs, font, glyphWidths, glyphOffsets, path, textAlign); return(builder.Build()); }
public extern static void sk_paint_set_text_align(sk_paint_t t, SKTextAlign align);
private SKText ReadTextSpans(XElement e, SKPoint xy, SKTextAlign textAlign, float baselineShift, SKPaint stroke, SKPaint fill) { var spans = new SKText(xy, textAlign); // textAlign is used for all spans within the <text> element. If different textAligns would be needed, it is necessary to use // several <text> elements instead of <tspan> elements var currentBaselineShift = baselineShift; fill.TextAlign = SKTextAlign.Left; // fixed alignment for all spans var nodes = e.Nodes().ToArray(); for (int i = 0; i < nodes.Length; i++) { var c = nodes[i]; bool isFirst = i == 0; bool isLast = i == nodes.Length - 1; if (c.NodeType == XmlNodeType.Text) { // TODO: check for preserve whitespace var textSegments = ((XText)c).Value.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries); var count = textSegments.Length; if (count > 0) { if (isFirst) { textSegments[0] = textSegments[0].TrimStart(); } if (isLast) { textSegments[count - 1] = textSegments[count - 1].TrimEnd(); } var text = WSRe.Replace(string.Concat(textSegments), " "); spans.Append(new SKTextSpan(text, fill.Clone(), baselineShift: currentBaselineShift)); } } else if (c.NodeType == XmlNodeType.Element) { var ce = (XElement)c; if (ce.Name.LocalName == "tspan") { // the current span may want to change the cursor position var x = ReadOptionalNumber(ce.Attribute("x")); var y = ReadOptionalNumber(ce.Attribute("y")); var text = ce.Value; //.Trim(); var spanFill = fill.Clone(); ReadFontAttributes(ce, spanFill); // Don't read text-anchor from tspans!, Only use enclosing text-anchor from text element! currentBaselineShift = ReadBaselineShift(ce); spans.Append(new SKTextSpan(text, spanFill, x, y, currentBaselineShift)); } } } return(spans); }
public static void DrawHorizontalText(this SKCanvas canvas, string text, float x, float y, float textSize, SKColor textColor, SKTextAlign textAlign, bool isBold = false) { using (var paint = new SKPaint()) { paint.TextSize = textSize; paint.Color = textColor; paint.IsAntialias = true; paint.FakeBoldText = isBold; var bounds = new SKRect(); paint.MeasureText(text, ref bounds); if (textAlign == SKTextAlign.Left) { x -= bounds.Width; } else if (textAlign == SKTextAlign.Right) { x += bounds.Width / 2; } else { paint.TextAlign = SKTextAlign.Center; } canvas.DrawText(text, x, y, paint); } }
public static void DrawCenteredMultilineText(SKCanvas canvas, string text, int maxLineCount, BaseIcon icon, SKTextAlign side, SKRect area, SKPaint paint) => DrawCenteredMultilineText(canvas, text, maxLineCount, icon.Width, 5, side, area, paint);
public static void DrawCenteredMultilineText(SKCanvas canvas, string text, int maxLineCount, int size, int margin, SKTextAlign align, SKRect area, SKPaint paint) { float lineHeight = paint.TextSize * 1.2f; List <Line> lines = SplitLines(text, paint, area.Width - margin); if (lines == null) { return; } if (lines.Count <= maxLineCount) { maxLineCount = lines.Count; } float height = maxLineCount * lineHeight; float y = area.MidY - height / 2; for (int i = 0; i < maxLineCount; i++) { Line line = lines[i]; y += lineHeight; float x = align switch { SKTextAlign.Center => area.MidX - line.Width / 2, SKTextAlign.Right => size - margin - line.Width, SKTextAlign.Left => margin, _ => area.MidX - line.Width / 2 }; string lineText = line.Value.TrimEnd(); canvas.DrawText(lineText, x, y, paint); } }