예제 #1
0
        public bool PrepareLetterDefinitions(string text)
        {
            List <char> newChars = new List <char>();

            FindNewCharacters(text, ref newChars);

            if (newChars.Count == 0)
            {
                return(false);
            }

            var newCharString = new string(newChars.ToArray());

            var glyphs      = _TextPaint.GetGlyphs(newCharString);
            var glyphWidths = _TextPaint.GetGlyphWidths(newCharString);

            for (int i = 0; i < glyphs.Length; i++)
            {
                FontLetterDefinition tempDef = new FontLetterDefinition();

                if (glyphs[i] == 0)
                {
                    _LetterDefinitions[newCharString[i]] = tempDef;
                }
                else
                {
                    tempDef.ValidDefinition = true;
                    tempDef.AdvanceX        = glyphWidths[i];

                    _LetterDefinitions[newCharString[i]] = tempDef;
                }
            }

            return(true);
        }
예제 #2
0
        /// <summary>
        /// Calculate any overhang for this text line
        /// </summary>
        /// <param name="right"></param>
        /// <param name="leftOverhang"></param>
        /// <param name="rightOverhang"></param>
        internal void UpdateOverhang(float right, ref float leftOverhang, ref float rightOverhang)
        {
            if (RunKind == FontRunKind.TrailingWhitespace)
            {
                return;
            }

            if (Glyphs.Length == 0)
            {
                return;
            }

            using (var paint = new SKPaint())
            {
                float glyphScale = 1;
                if (Style.FontVariant == FontVariant.SuperScript)
                {
                    glyphScale = 0.65f;
                }
                if (Style.FontVariant == FontVariant.SubScript)
                {
                    glyphScale = 0.65f;
                }

                paint.TextEncoding  = SKTextEncoding.GlyphId;
                paint.Typeface      = Typeface;
                paint.TextSize      = Style.FontSize * glyphScale;
                paint.SubpixelText  = true;
                paint.IsAntialias   = true;
                paint.LcdRenderText = false;

                unsafe
                {
                    fixed(ushort *pGlyphs = Glyphs.Underlying)
                    {
                        paint.GetGlyphWidths((IntPtr)(pGlyphs + Start), sizeof(ushort) * Glyphs.Length, out var bounds);
                        if (bounds != null)
                        {
                            for (int i = 0; i < bounds.Length; i++)
                            {
                                float gx = GlyphPositions[i].X;

                                var loh = -(gx + bounds[i].Left);
                                if (loh > leftOverhang)
                                {
                                    leftOverhang = loh;
                                }

                                var roh = (gx + bounds[i].Right + 1) - right;
                                if (roh > rightOverhang)
                                {
                                    rightOverhang = roh;
                                }
                            }
                        }
                    }
                }
            }
        }
예제 #3
0
        public void GetGlyphWidthsReturnsTheCorrectAmount()
        {
            var paint = new SKPaint();

            var widths = paint.GetGlyphWidths("Hello World!", out var bounds);

            Assert.Equal(widths.Length, bounds.Length);
        }
예제 #4
0
        private static void DrawSkia(SKCanvas canvas, SKImageInfo info, SKBitmap skBitmap, string text)
        {
            // get the screen density for scaling
            var scale      = 1f;
            var scaledSize = new SKSize(info.Width / scale, info.Height / scale);

            // handle the device screen density
            canvas.Scale(scale);

            // make sure the canvas is blank
            canvas.Clear(SKColors.Pink);

            var scaleBg    = skBitmap.Width * 1f / skBitmap.Height;
            var scalePanel = 16 * 1f / 9;
            var left       = 0f;
            var top        = 0f;
            var size       = new SKSize(0, 0);

            if (scaleBg > scalePanel)
            {
                size.Height = scaledSize.Height;
                size.Width  = size.Height * scaleBg;
                left        = (scaledSize.Width - size.Width) / 2;
            }
            else
            {
                //size.Width = scaledSize.Width;
                //size.Height = size.Width / scaleBg;
                //top = (scaledSize.Height - size.Height) / 2;
                size.Height = scaledSize.Height;
                size.Width  = size.Height * scaleBg;
                left        = (scaledSize.Width - size.Width) / 2;
            }

            canvas.DrawBitmap(skBitmap, new SKRect(left, top,
                                                   left + size.Width, top + size.Height));

            // draw some text
            var paint = new SKPaint
            {
                Color       = SKColors.Black,
                IsAntialias = true,
                Style       = SKPaintStyle.Fill,
                TextAlign   = SKTextAlign.Center,
                TextSize    = 50
            };
            var widths = paint.GetGlyphWidths(text);
            var total  = widths.Sum() / 2;
            //var coord = new SKPoint(scaledSize.Width / 2, (scaledSize.Height + paint.TextSize) / 2);
            var coord = new SKPoint(left + 20 + total, 20 + paint.TextSize);

            canvas.DrawText(text, coord, paint);
        }
예제 #5
0
        public void GetGlyphWidthsAreCorrect()
        {
            var paint = new SKPaint();

            var widths = paint.GetGlyphWidths("Hello World!", out var bounds);

            // make sure the 'l' glyphs are the same width
            Assert.True(widths[2] > 0);
            Assert.True(widths[2] == widths[3]);
            Assert.True(widths[2] == widths[9]);

            // make sure the 'l' bounds are the same size
            Assert.False(bounds[2].IsEmpty);
            Assert.True(bounds[2] == bounds[3]);
            Assert.True(bounds[2] == bounds[9]);

            // make sure the 'l' and 'W' glyphs are NOT the same width
            Assert.True(widths[2] != widths[6]);

            // make sure the 'l' and 'W' bounds are NOT the same width
            Assert.True(bounds[2] != bounds[6]);
        }
예제 #6
0
        /// <summary>
        /// Constructs a new TextShaper
        /// </summary>
        /// <param name="typeface">The typeface of this shaper</param>
        private TextShaper(SKTypeface typeface)
        {
            // Store typeface
            _typeface = typeface;

            // Load the typeface stream to a HarfBuzz font
            int index;

            using (var blob = GetHarfBuzzBlob(typeface.OpenStream(out index)))
                using (var face = new Face(blob, (uint)index))
                {
                    face.UnitsPerEm = typeface.UnitsPerEm;

                    _font = new HarfBuzzSharp.Font(face);
                    _font.SetScale(overScale, overScale);
                    _font.SetFunctionsOpenType();
                }

            // Get font metrics for this typeface
            using (var paint = new SKPaint())
            {
                paint.Typeface = typeface;
                paint.TextSize = overScale;
                _fontMetrics   = paint.FontMetrics;

                // This is a temporary hack until SkiaSharp exposes
                // a way to check if a font is fixed pitch.  For now
                // we just measure and `i` and a `w` and see if they're
                // the same width.
                float[] widths = paint.GetGlyphWidths("iw", out var rects);
                _isFixedPitch = widths != null && widths.Length > 1 && widths[0] == widths[1];
                if (_isFixedPitch)
                {
                    _fixedCharacterWidth = widths[0];
                }
            }
        }
예제 #7
0
        internal unsafe void Run()
        {
            if (!needRun)
            {
                return;
            }

            lines.Clear();

            //设置paint参数
            var paint = new SKPaint();

            paint.TextEncoding = SKTextEncoding.Utf16;
            font.ApplyToSKPaint(paint, GraphicsUnit.Pixel, dpi); //注意目标类型为像素
            //测量FontMetric
            SKFontMetrics metrics = font.FontMetrics;

            //根据文字排版方向确认限宽及限高
            float maxWidth  = Math.Min(32767, IsVertical ? height : width); //TODO:
            float maxHeight = IsVertical ? width : height;

            //TODO:计算高度不满足一行的情况

            fixed(char *ptr = Text)
            {
                byte *textPtr      = (byte *)ptr;
                byte *startTextPtr = (byte *)ptr;

                int   totalBytes = text.Length * 2;
                int   leftBytes  = totalBytes;
                float y          = 0;

                while (true)
                {
                    //根据是否允许换行,调用不同的breakText方法
                    var measuredWidth = 0f;
                    var lineBytes     = (int)paint.BreakText(new IntPtr(startTextPtr), new IntPtr(leftBytes), maxWidth, out measuredWidth);
                    //var lineBytes = SkiaApi.sk_paint_break_text_icu(paint, new IntPtr(startTextPtr), leftBytes, maxWidth, null); //TODO:***** fix maxWidth

                    var newLine = new TextLayoutLine(this);
                    newLine.startByteIndex = (int)(startTextPtr - textPtr);
                    newLine.byteLength     = lineBytes;
                    newLine.widths         = paint.GetGlyphWidths(new IntPtr(startTextPtr), lineBytes);
                    //newLine.startCharIndex = 0; //TODO:

                    //根据对齐方式计算Line的offsetX值
                    if (stringFormat != null && stringFormat.Alignment != StringAlignment.Near)
                    {
                        //计算当前行Ink总宽度
                        float lineInkWidth = 0f;
                        for (int i = 0; i < newLine.widths.Length; i++)
                        {
                            lineInkWidth += newLine.widths[i];
                        }
                        float lineSpace = width - lineInkWidth;
                        if (lineSpace > 0f)
                        {
                            if (stringFormat.Alignment == StringAlignment.Center)
                            {
                                newLine.offsetX = lineSpace / 2f;
                            }
                            else if (stringFormat.Alignment == StringAlignment.Far)
                            {
                                newLine.offsetX = lineSpace;
                            }
                        }
                    }
                    //添加新行
                    lines.Add(newLine);

                    //判断是否允许换行,不允许直接退出循环
                    if (IsNoWrap)
                    {
                        break;
                    }

                    //计算下一行高度是否超出限高
                    y = y - metrics.Ascent + metrics.Descent + metrics.Leading;
                    if ((y - metrics.Ascent + metrics.Descent) > maxHeight)
                    {
                        break;
                    }

                    //偏移剩余部分,并判断是否全部计算完毕
                    startTextPtr += lineBytes;
                    if ((int)(startTextPtr - textPtr) >= totalBytes)
                    {
                        break;
                    }
                    leftBytes -= lineBytes;
                }
            }

            //根据对齐方式计算offsetY的值
            CalcOffsetY();

            needRun = false;
        }