Exemple #1
0
        public static GlyphRun Create(string text, Typeface typeface, double emSize, Vector centerOffset)
        {
            GlyphTypeface glyphTypeface;

            if (!typeface.TryGetGlyphTypeface(out glyphTypeface))
            {
                throw new ArgumentException(string.Format("{0}: no GlyphTypeface found", typeface.FontFamily));
            }

            var glyphIndices  = new ushort[text.Length];
            var advanceWidths = new double[text.Length];

            for (int i = 0; i < text.Length; i++)
            {
                var glyphIndex = glyphTypeface.CharacterToGlyphMap[text[i]];
                glyphIndices[i]  = glyphIndex;
                advanceWidths[i] = glyphTypeface.AdvanceWidths[glyphIndex] * emSize;
            }

            var glyphRun = new GlyphRun(glyphTypeface, 0, false, emSize, glyphIndices, new Point(), advanceWidths,
                                        null, null, null, null, null, null);
            var bbox           = glyphRun.ComputeInkBoundingBox();
            var baselineOrigin = new Point(centerOffset.X - bbox.X - bbox.Width / 2d, centerOffset.Y - bbox.Y - bbox.Height / 2d);

            return(new GlyphRun(glyphTypeface, 0, false, emSize, glyphIndices, baselineOrigin, advanceWidths,
                                null, null, null, null, null, null));
        }
Exemple #2
0
        /// <summary>
        /// Draw a GlyphRun.
        /// </summary>
        public void DrawGlyphRun(Brush foreground, GlyphRun glyphRun)
        {
            if (glyphRun != null)
            {
                foreground = ReduceBrush(foreground, glyphRun.ComputeInkBoundingBox());

                // foreground may be null, but glyphrun may still be a hyperlink
                _dc.DrawGlyphRun(foreground, glyphRun);
            }
        }
Exemple #3
0
        /// <summary>
        /// gets a bounding box holding the overall glyph run
        /// </summary>
        /// <param name="glyphRun"></param>
        /// <param name="origin">where the run will be centered</param>
        /// <returns></returns>
        public static Rect GetBoundingBox(this GlyphRun glyphRun, Point origin)
        {
            Rect   rect = glyphRun.ComputeInkBoundingBox();
            Matrix mat  = new Matrix();

            mat.Translate(origin.X, origin.Y);

            rect.Transform(mat);
            return(rect);
        }
Exemple #4
0
        /// <summary>
        /// 获取<see cref="GlyphRun"/>的Bounds
        /// </summary>
        /// <param name="run"></param>
        /// <returns></returns>
        public static Rect GetBounds(this GlyphRun run)
        {
            var box = run.ComputeInkBoundingBox();

            //相对于run.BuildGeometry().Bounds方法,run.ComputeInkBoundingBox()会多出一个厚度为1的框框,所以要减去
            if (box.Width >= 2 && box.Height >= 2)
            {
                box.Inflate(-1, -1);
            }

            return(box);
        }
Exemple #5
0
        public static void DrawGlyphRun(this DrawingContext drawingContext, Brush foreground, GlyphRun glyphRun,
                                        Point position, HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment)
        {
            var boundingBox = glyphRun.ComputeInkBoundingBox();

            switch (horizontalAlignment)
            {
            case HorizontalAlignment.Center:
                position.X -= boundingBox.Width / 2d;
                break;

            case HorizontalAlignment.Right:
                position.X -= boundingBox.Width;
                break;

            default:
                break;
            }

            switch (verticalAlignment)
            {
            case VerticalAlignment.Center:
                position.Y -= boundingBox.Height / 2d;
                break;

            case VerticalAlignment.Bottom:
                position.Y -= boundingBox.Height;
                break;

            default:
                break;
            }

            drawingContext.PushTransform(new TranslateTransform(position.X - boundingBox.X, position.Y - boundingBox.Y));
            drawingContext.DrawGlyphRun(foreground, glyphRun);
            drawingContext.Pop();
        }
Exemple #6
0
        /// <summary>
        /// Draw all formatted glyphruns
        /// </summary>
        /// <returns>drawing bounding box</returns>
        public Rect Draw(
            DrawingContext drawingContext,
            Point currentOrigin
            )
        {
            Rect inkBoundingBox = Rect.Empty;

            Debug.Assert(_glyphs != null);

            foreach (Glyphs glyphs in _glyphs)
            {
                GlyphRun glyphRun = glyphs.CreateGlyphRun(currentOrigin, _rightToLeft);
                Rect     boundingBox;

                if (glyphRun != null)
                {
                    boundingBox = glyphRun.ComputeInkBoundingBox();

                    if (drawingContext != null)
                    {
                        // Emit glyph run background.
                        glyphRun.EmitBackground(drawingContext, glyphs.BackgroundBrush);

                        drawingContext.PushGuidelineY1(currentOrigin.Y);
                        try
                        {
                            drawingContext.DrawGlyphRun(glyphs.ForegroundBrush, glyphRun);
                        }
                        finally
                        {
                            drawingContext.Pop();
                        }
                    }
                }
                else
                {
                    boundingBox = Rect.Empty;
                }

                if (!boundingBox.IsEmpty)
                {
                    // glyph run's ink bounding box is relative to its origin
                    boundingBox.X += glyphRun.BaselineOrigin.X;
                    boundingBox.Y += glyphRun.BaselineOrigin.Y;
                }

                // accumulate overall ink bounding box
                inkBoundingBox.Union(boundingBox);

                if (_rightToLeft)
                {
                    currentOrigin.X -= glyphs.Width;
                }
                else
                {
                    currentOrigin.X += glyphs.Width;
                }
            }

            return(inkBoundingBox);
        }
Exemple #7
0
        private void Test2()
        {
            //Glyph系クラス
            GlyphRun        glyphRun;
            GlyphRunDrawing glyphRunDrawing;
            Glyphs          glyphs;
            GlyphTypeface   glyphTypeface;

            FontFamily fontFamily = new FontFamily("Meiryo UI");
            var        typefaces  = fontFamily.GetTypefaces();
            Uri        myFontUri  = null;

            foreach (var face in typefaces)
            {
                face.TryGetGlyphTypeface(out GlyphTypeface gType);
                myFontUri = gType.FontUri;
                break;
            }

            glyphs                     = new();
            glyphs.FontUri             = myFontUri;
            glyphs.FontRenderingEmSize = 100;
            //glyphs.StyleSimulations = StyleSimulations.BoldItalicSimulation;
            glyphs.UnicodeString = "(ゆっくり)";
            glyphs.Fill          = Brushes.MediumOrchid;
            //glyphs.BidiLevel = 1;
            //glyphs.IsSideways = true;
            GlyphRun gRun      = glyphs.ToGlyphRun();
            var      chars     = gRun.Characters;
            var      clustre   = gRun.ClusterMap;
            var      box       = gRun.ComputeAlignmentBox();
            var      inkBox    = gRun.ComputeInkBoundingBox();
            var      dfName    = gRun.DeviceFontName;
            var      inside    = gRun.GetCaretCharacterHitFromDistance(100, out bool isindside);
            var      hit       = gRun.GetNextCaretCharacterHit(new System.Windows.Media.TextFormatting.CharacterHit());
            var      gInd      = gRun.GlyphIndices;
            var      gOffset   = gRun.GlyphOffsets;
            var      gTypeface = gRun.GlyphTypeface;

            MyGrid.Children.Add(glyphs);

            DrawingVisual dv = new();

            //dv.Offset = new Vector(0, -100);

            using (var dc = dv.RenderOpen())
            {
                //dc.DrawRectangle(Brushes.MediumBlue, null, new Rect(0, 0, 500, 500));
                //dc.DrawRectangle(Brushes.MediumBlue, null, new Rect(0, 0, box.Width, box.Height));
                dc.DrawGlyphRun(Brushes.MediumAquamarine, gRun);
            }
            Rect r3                   = dv.Drawing.Bounds;
            Rect r                    = dv.ContentBounds;
            Rect r2                   = dv.DescendantBounds;
            var  geo                  = gRun.BuildGeometry();
            Rect rectGeo1             = geo.Bounds;
            Rect rectGeo2             = geo.GetRenderBounds(null);
            RenderTargetBitmap bitmap = new((int)box.Width, (int)box.Height, 96, 96, PixelFormats.Pbgra32);

            bitmap.Render(dv);

            glyphRunDrawing   = new(Brushes.MediumAquamarine, gRun);
            MyGrid.Background = new DrawingBrush(glyphRunDrawing);
            //Glyphs
            //FontUri               フォント
            //FontRenderingEmSize   フォントサイズみたいなもの
            //StyleSimulations      太字と斜体の指定
            //BidiLevel             文字を並べる向きの指定、0or偶数で左から、奇数で右からになる
            //ToGlyphRun()          GlyphRun作成

            //GlyphRun クラス (System.Windows.Media) | Microsoft Docs
            //https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.media.glyphrun?view=net-6.0
            //  同じ描画スタイルが設定され、サイズ、フォント、およびフォントの書体が同じである一連のグリフを表します。
            //GlyphRunDrawingと組み合わせて使う

            //プロパティ
            //AdvanceWidths
            //グリフ インデックスに対応するアドバンス幅を表す Double 値の一覧を取得または設定します。

            //BaselineOrigin    Point
            //GlyphRun のベースライン原点を取得または設定します。

            //BidiLevel     Int32
            //GlyphRun の双方向の入れ子レベルを取得または設定します。

            //CaretStops    bool
            //GlyphRun を表す Unicode で UTF16 コード ポイント毎にキャレット ストップがあるかどうかを決定する Boolean 値の一覧を取得または設定します。

            //Characters    List<Char>
            //GlyphRun の Unicode を表す UTF16 コード ポイントの一覧を取得または設定します。

            //ClusterMap    List<Uint16>
            //GlyphRun の文字をグリフ インデックスにマップする UInt16 値の一覧を取得または設定します。

            //DeviceFontName    string
            //GlyphRun が最適化される対象の、デバイス固有のフォントを取得または設定します。

            //FontRenderingEmSize   double
            //GlyphRun のレンダリングに使用する全角サイズを取得または設定します。

            //GlyphIndices      list<Uint16>
            //描画物理フォントのグリフ インデックスを表す UInt16 値の配列を取得または設定します。

            //GlyphOffsets      List<point>
            //GlyphRun のグリフのオフセットを表す Point 値の配列を取得または設定します。

            //GlyphTypeface     GlyphTypeface
            //GlyphTypeface の GlyphRun を取得または設定します。

            //IsHitTestable     bool
            //GlyphRun 内に有効なキャレット文字ヒットがあるかどうかを示す値を取得します。

            //IsSideways        bool
            //グリフを回転するかどうかを示す値を取得または設定します。

            //Language          XmlLanguage
            //XmlLanguage の GlyphRun を取得または設定します。

            //PixelsPerDip      Single
            //テキストを表示する PixelsPerDip を取得または設定します。


            //メソッド
            //BuildGeometry
            //  GlyphRunのジオメトリを取得します。
            //ComputeAlignmentBox   Rect
            //  GlyphRunの配置ボックスを取得します。
            //ComputeInkBoundingBox Rect
            //  GlyphRunのインク境界ボックスを取得します。
            //GetCaretCharacterHitFromDistance(Double, Boolean) CharacterHitグリフラン内でヒットした文字に関する情報を表します。
            //  GlyphRunのキャレットの文字ヒットを表すCharacterHit値を取得します。
            //GetDistanceFromCaretCharacterHit(CharacterHit) double
            //  GlyphRunの前縁から、指定された文字ヒットを含むキャレットストップの前縁または後縁までのオフセットを取得します。
            //GetNextCaretCharacterHit(CharacterHit) CharacterHit
            //  GlyphRunで論理方向にヒットした次の有効なキャレット文字を取得します。
            //GetPreviousCaretCharacterHit(CharacterHit) CharacterHit
            //  GlyphRunで論理方向にヒットした前の有効なキャレット文字を取得します。
        }
Exemple #8
0
        /// <summary>
        /// Draw glyphrun
        /// </summary>
        /// <param name="drawingContext">The drawing context to draw into </param>
        /// <param name="foregroundBrush">
        /// The foreground brush of the glyphrun. Pass in "null" to draw the
        /// glyph run with the foreground in TextRunProperties.
        /// </param>
        /// <param name="glyphRun">The GlyphRun to be drawn </param>
        /// <returns>bounding rectangle of drawn glyphrun</returns>
        /// <Remarks>
        /// TextEffect drawing code may use a different foreground brush for the text.
        /// </Remarks>
        internal Rect DrawGlyphRun(
            DrawingContext drawingContext,
            Brush foregroundBrush,
            GlyphRun glyphRun
            )
        {
            Debug.Assert(_shapeable != null);

            Rect inkBoundingBox = glyphRun.ComputeInkBoundingBox();

            if (!inkBoundingBox.IsEmpty)
            {
                // glyph run's ink bounding box is relative to its origin
                inkBoundingBox.X += glyphRun.BaselineOrigin.X;
                inkBoundingBox.Y += glyphRun.BaselineOrigin.Y;
            }

            if (drawingContext != null)
            {
                int pushCount = 0;              // the number of push we do
                try
                {
                    if (_textEffects != null)
                    {
                        // we need to push in the same order as they are set
                        for (int i = 0; i < _textEffects.Count; i++)
                        {
                            // get the text effect by its index
                            TextEffect textEffect = _textEffects[i];

                            if (textEffect.Transform != null && textEffect.Transform != Transform.Identity)
                            {
                                drawingContext.PushTransform(textEffect.Transform);
                                pushCount++;
                            }

                            if (textEffect.Clip != null)
                            {
                                drawingContext.PushClip(textEffect.Clip);
                                pushCount++;
                            }

                            if (textEffect.Foreground != null)
                            {
                                // remember the out-most non-null brush
                                // this brush will be used to draw the glyph run
                                foregroundBrush = textEffect.Foreground;
                            }
                        }
                    }

                    _shapeable.Draw(drawingContext, foregroundBrush, glyphRun);
                }
                finally
                {
                    for (int i = 0; i < pushCount; i++)
                    {
                        drawingContext.Pop();
                    }
                }
            }

            return(inkBoundingBox);
        }
Exemple #9
0
            private void InitializeMetrics()
            {
                Contract.Requires(_typeface != null, "Typeface cannot be null.");
                Contract.Requires(_mapping != null, "Mapping cannot be null.");
                Contract.Requires(_transform != null, "Transform must be initialized first.");

                ushort glyph = _mapping.Glyph.GetValueOrDefault();

                checked
                {
                    _emHeight   = (ushort)Round(_typeface.Height * _emSize);
                    _emBaseline = (short)Round(_typeface.Baseline * _emSize);
                }

                // System.Diagnostics.Debug.WriteLine("{2}: {0} {1}",
                // _typeface.LeftSideBearings[glyph] * _emSize,
                // _typeface.RightSideBearings[glyph] * _emSize, (char)(int)_mapping.Character);

                if (_antialiasLevel == AntialiasingLevel.None)
                {
                    _emSideBearing = new Int32Thickness(
                        Round(_typeface.LeftSideBearings[glyph] * _emSize),
                        Round(_typeface.TopSideBearings[glyph] * _emSize),
                        Round(_typeface.RightSideBearings[glyph] * _emSize),
                        Round(_typeface.BottomSideBearings[glyph] * _emSize)
                        );
                }
                else
                {
                    _emSideBearing = new Int32Thickness(
                        Floor(_typeface.LeftSideBearings[glyph] * _emSize),
                        Floor(_typeface.TopSideBearings[glyph] * _emSize),
                        Floor(_typeface.RightSideBearings[glyph] * _emSize),
                        Floor(_typeface.BottomSideBearings[glyph] * _emSize)
                        );
                }

                Rect advance            = new Rect(new Size(_typeface.AdvanceWidths[glyph], _typeface.AdvanceHeights[glyph]));
                Rect advanceTransformed = _transform.TransformBounds(advance);

                _emAdvance = new Int32Vector(
                    Round(advanceTransformed.Width * _emSize),
                    Round(advanceTransformed.Height * _emSize)
                    );

                if (!_transform.Value.IsIdentity)
                {
                    Rect boundBox   = _run.ComputeInkBoundingBox();
                    Rect advanceBox = boundBox.Add(_emSideBearing);

                    Rect boundBoxTransformed   = _transform.TransformBounds(boundBox);
                    Rect advanceBoxTransformed = _transform.TransformBounds(advanceBox);

                    Thickness bearingTransformed = boundBox.Subtract(advanceBox);

                    _emSideBearing = new Int32Thickness(
                        Round(bearingTransformed.Left),
                        Round(bearingTransformed.Top),
                        Round(bearingTransformed.Right),
                        Round(bearingTransformed.Bottom)
                        );
                }
            }