Beispiel #1
0
        private void cmdMeasureString_Click(object sender, EventArgs e)
        {
            //How to measure user's string...
            //this demostrate step-by-step

            //similar to ...  selectedTextPrinter.DrawString(printTextBuffer, x_pos, y_pos);
            string str = txtInputChar.Text;
            //
            Typeface typeface         = _basicOptions.Typeface;
            float    fontSizeInPoints = _basicOptions.FontSizeInPoints;

            var layout = new Typography.TextLayout.GlyphLayout();

            layout.Typeface          = typeface;
            layout.ScriptLang        = _basicOptions.ScriptLang;
            layout.PositionTechnique = _basicOptions.PositionTech;
            layout.EnableLigature    = false;// true
            layout.EnableComposition = true;

            //3.
            //3.1 : if you want GlyphPlanList too.
            //var resultGlyphPlanList = new Typography.TextLayout.GlyphPlanList();
            //Typography.TextLayout.MeasuredStringBox box = layout.LayoutAndMeasureString(str.ToCharArray(), 0, str.Length, _basicOptions.FontSizeInPoints, resultGlyphPlanList);

            //or
            //3.2 : only MeasuredStringBox
            Typography.TextLayout.MeasuredStringBox box =
                layout.LayoutAndMeasureString(
                    str.ToCharArray(), 0,
                    str.Length,
                    fontSizeInPoints);

            this.lblStringSize.Text = "measure (W,H)= (" + box.width.ToString() + "," + (box.AscendingInPx - box.DescendingInPx) + ") px";
        }
Beispiel #2
0
        public static MeasuredStringBox LayoutAndMeasureString(
            this GlyphLayout glyphLayout,
            char[] textBuffer,
            int startAt,
            int len,
            float fontSizeInPoints,
            bool snapToGrid = true)
        {
            //1. unscale layout, in design unit
            glyphLayout.Layout(textBuffer, startAt, len);


            //2. scale  to specific font size

            Typeface typeface = glyphLayout.Typeface;
            float    pxscale  = typeface.CalculateScaleToPixelFromPointSize(fontSizeInPoints);

            //....
            GenerateScaledGlyphPlans(
                glyphLayout,
                pxscale,
                snapToGrid,
                out float scaled_accumX);

            return(new MeasuredStringBox(
                       scaled_accumX,
                       typeface.Ascender * pxscale,
                       typeface.Descender * pxscale,
                       typeface.LineGap * pxscale,
                       Typography.OpenFont.Extensions.TypefaceExtensions.CalculateRecommendLineSpacing(typeface) * pxscale));
        }
Beispiel #3
0
        public static void MeasureString(
            this GlyphLayout glyphLayout,
            char[] textBuffer,
            int startAt,
            int len, out MeasuredStringBox strBox, float scale = 1)
        {
            //TODO: consider extension method
            List <GlyphPlan> outputGlyphPlans = glyphLayout._myGlyphPlans;

            outputGlyphPlans.Clear();
            glyphLayout.Layout(textBuffer, startAt, len, outputGlyphPlans);
            //
            int j = outputGlyphPlans.Count;

            Typeface currentTypeface = glyphLayout.Typeface;

            if (j == 0)
            {
                //not scale
                strBox = new MeasuredStringBox(0,
                                               currentTypeface.Ascender * scale,
                                               currentTypeface.Descender * scale,
                                               currentTypeface.LineGap * scale);
            }
            //get last one
            GlyphPlan lastOne = outputGlyphPlans[j - 1];

            strBox = new MeasuredStringBox((lastOne.x + lastOne.advX) * scale,
                                           currentTypeface.Ascender * scale,
                                           currentTypeface.Descender * scale,
                                           currentTypeface.LineGap * scale);
        }
Beispiel #4
0
        /// <summary>
        /// read latest layout output
        /// </summary>
        /// <param name="glyphLayout"></param>
        /// <param name="readDel"></param>
        public static void ReadOutput(this GlyphLayout glyphLayout, GlyphReadOutputDelegate readDel)
        {
            Typeface        typeface       = glyphLayout.Typeface;
            List <GlyphPos> glyphPositions = glyphLayout._glyphPositions;
            //3.read back
            int   finalGlyphCount = glyphPositions.Count;
            int   cx = 0;
            short cy = 0;

            PositionTechnique posTech    = glyphLayout.PositionTechnique;
            ushort            prev_index = 0;

            for (int i = 0; i < finalGlyphCount; ++i)
            {
                GlyphPos glyphPos = glyphPositions[i];
                //----------------------------------
                switch (posTech)
                {
                default: throw new NotSupportedException();

                case PositionTechnique.None:
                    readDel(i, new GlyphPlan(glyphPos.glyphIndex, cx, cy, glyphPos.advWidth));
                    break;

                case PositionTechnique.OpenFont:
                    readDel(i, new GlyphPlan(
                                glyphPos.glyphIndex,
                                cx + glyphPos.xoffset,
                                (short)(cy + glyphPos.yoffset),
                                glyphPos.advWidth));
                    break;

                case PositionTechnique.Kerning:

                    if (i > 0)
                    {
                        cx += typeface.GetKernDistance(prev_index, glyphPos.glyphIndex);
                    }
                    readDel(i, new GlyphPlan(
                                prev_index = glyphPos.glyphIndex,
                                cx,
                                cy,
                                glyphPos.advWidth));

                    break;
                }
                cx += glyphPos.advWidth;
            }
        }
Beispiel #5
0
        /// <summary>
        /// read latest layout output
        /// </summary>
        /// <param name="glyphLayout"></param>
        /// <param name="readDel"></param>
        public static void ReadOutput(this GlyphLayout glyphLayout, GlyphReadOutputDelegate readDel)
        {
            throw new NotSupportedException();

            //Typeface typeface = glyphLayout.Typeface;
            //List<GlyphPos> glyphPositions = glyphLayout._glyphPositions;
            ////3.read back
            //int finalGlyphCount = glyphPositions.Count;
            //int cx = 0;
            //short cy = 0;

            //PositionTechnique posTech = glyphLayout.PositionTechnique;
            //ushort prev_index = 0;
            //for (int i = 0; i < finalGlyphCount; ++i)
            //{

            //    GlyphPos glyphPos = glyphPositions[i];
            //    //----------------------------------
            //    switch (posTech)
            //    {
            //        default: throw new NotSupportedException();
            //        case PositionTechnique.None:
            //            readDel(i, new GlyphPlan(glyphPos.glyphIndex, cx, cy, glyphPos.AdvWidth));
            //            break;
            //        case PositionTechnique.OpenFont:
            //            readDel(i, new GlyphPlan(
            //                glyphPos.glyphIndex,
            //                cx + glyphPos.xoffset,
            //                (short)(cy + glyphPos.yoffset),
            //                glyphPos.AdvWidth));
            //            break;
            //        case PositionTechnique.Kerning:

            //            if (i > 0)
            //            {
            //                cx += typeface.GetKernDistance(prev_index, glyphPos.glyphIndex);
            //            }
            //            readDel(i, new GlyphPlan(
            //                 prev_index = glyphPos.glyphIndex,
            //               cx,
            //               cy,
            //               glyphPos.AdvWidth));

            //            break;
            //    }
            //    cx += glyphPos.AdvWidth;
            //}
        }
Beispiel #6
0
 public static void GenerateGlyphPlans(this GlyphLayout glyphLayout,
                                       char[] textBuffer,
                                       int startAt,
                                       int len,
                                       List <GlyphPlan> userGlyphPlanList,
                                       List <UserCharToGlyphIndexMap> charToGlyphMapList)
 {
     //generate glyph plan based on its current setting
     glyphLayout.Layout(textBuffer, startAt, len, userGlyphPlanList);
     //note that we print to userGlyphPlanList
     //----------------
     //3. user char to glyph index map
     if (charToGlyphMapList != null)
     {
         glyphLayout.ReadOutput(charToGlyphMapList);
     }
 }
Beispiel #7
0
        static void GenerateScaledGlyphPlans(this GlyphLayout glyphLayout,
                                             float pxscale,
                                             bool snapToGrid,
                                             out float accumW)
        {
            //user can implement this with some 'PixelScaleEngine'
            IGlyphPositions glyphPositions = glyphLayout.ResultUnscaledGlyphPositions;

            accumW = 0; //acummulate Width

            if (snapToGrid)
            {
                int finalGlyphCount = glyphPositions.Count;
                for (int i = 0; i < finalGlyphCount; ++i)
                {
                    short  offsetX, offsetY, advW; //all from pen-pos
                    ushort glyphIndex = glyphPositions.GetGlyph(i,
                                                                out ushort input_offset,
                                                                out offsetX,
                                                                out offsetY,
                                                                out advW);

                    float scaled_advW = (short)Math.Round(advW * pxscale);
                    accumW += scaled_advW;
                }
            }
            else
            {
                //not snap to grid
                //scaled but not snap to grid
                int finalGlyphCount = glyphPositions.Count;
                for (int i = 0; i < finalGlyphCount; ++i)
                {
                    short  offsetX, offsetY, advW; //all from pen-pos
                    ushort glyphIndex = glyphPositions.GetGlyph(i,
                                                                out ushort input_offset,
                                                                out offsetX,
                                                                out offsetY,
                                                                out advW);
                    accumW += advW * pxscale;
                }
            }
        }
Beispiel #8
0
        /// <summary>
        /// read latest layout output into outputGlyphPlanList
        /// </summary>
        public static void ReadOutput(this GlyphLayout glyphLayout, List <GlyphPlan> outputGlyphPlanList)
        {
            GlyphPosStream glyphPositions  = glyphLayout._glyphPositions; //from opentype's layout result,
            int            finalGlyphCount = glyphPositions.Count;
            //------------------------
            IPixelScaleLayout pxscaleLayout = glyphLayout.PxScaleLayout;

            if (pxscaleLayout != null)
            {
                //use custom pixel scale layout engine

                pxscaleLayout.SetFont(glyphLayout.Typeface, glyphLayout.FontSizeInPoints);
                pxscaleLayout.Layout(glyphPositions, outputGlyphPlanList);
            }
            else
            {
                //default scale
                float  pxscale = glyphLayout.PixelScale;
                double cx      = 0;
                short  cy      = 0;
                for (int i = 0; i < finalGlyphCount; ++i)
                {
                    GlyphPos glyph_pos = glyphPositions[i];
                    float    advW      = glyph_pos.advanceW * pxscale;
                    float    exact_x   = (float)(cx + glyph_pos.OffsetX * pxscale);
                    float    exact_y   = (float)(cy + glyph_pos.OffsetY * pxscale);

                    outputGlyphPlanList.Add(new GlyphPlan(
                                                glyph_pos.glyphIndex,
                                                exact_x,
                                                exact_y,
                                                advW));
                    cx += advW;
                }
            }
        }
 public EditableTextBlockLayoutEngine()
 {
     _textBlockLexer = new TextBlockLexer();
     _glyphLayout    = new GlyphLayout();
     FontSizeInPts   = 10;
 }
        //static void ConcatMeasureBox(ref float accumW, ref float accumH, ref MeasuredStringBox measureBox)
        //{
        //    accumW += measureBox.width;
        //    float h = measureBox.CalculateLineHeight();
        //    if (h > accumH)
        //    {
        //        accumH = h;
        //    }
        //}



        public static MeasuredStringBox LayoutAndMeasureString(
            this GlyphLayout glyphLayout,
            char[] textBuffer,
            int startAt,
            int len,
            float fontSizeInPoints,
            float limitW    = -1,//-1 unlimit scaled width (px)
            bool snapToGrid = true)
        {
            //1. unscale layout, in design unit
            glyphLayout.Layout(textBuffer, startAt, len);

            //2. scale  to specific font size

            Typeface typeface = glyphLayout.Typeface;
            float    pxscale  = typeface.CalculateScaleToPixelFromPointSize(fontSizeInPoints);

            //....
            float scaled_accumX = 0;

            if (limitW < 0)
            {
                //no limit
                scaled_accumX = MeasureGlyphPlans(
                    glyphLayout,
                    pxscale,
                    snapToGrid);

                return(new MeasuredStringBox(
                           scaled_accumX,
                           typeface.Ascender,
                           typeface.Descender,
                           typeface.LineGap,
                           typeface.ClipedAscender,
                           typeface.ClipedDescender,
                           pxscale));
            }
            else if (limitW > 0)
            {
                scaled_accumX = MeasureGlyphPlanWithLimitWidth(
                    glyphLayout,
                    pxscale,
                    limitW,
                    snapToGrid,
                    out int stopAtChar);

                var mstrbox = new MeasuredStringBox(
                    scaled_accumX,
                    typeface.Ascender,
                    typeface.Descender,
                    typeface.LineGap,
                    typeface.ClipedAscender,
                    typeface.ClipedDescender,
                    pxscale);

                mstrbox.StopAt = (ushort)stopAtChar;
                return(mstrbox);
            }
            else
            {
                return(new MeasuredStringBox(
                           0,
                           typeface.Ascender,
                           typeface.Descender,
                           typeface.LineGap,
                           typeface.ClipedAscender,
                           typeface.ClipedDescender,
                           pxscale));
            }
        }
        static float MeasureGlyphPlanWithLimitWidth(this GlyphLayout glyphLayout,
                                                    float pxscale,
                                                    float limitWidth,
                                                    bool snapToGrid,
                                                    out int stopAtGlyphIndex)
        {
            //user can implement this with some 'PixelScaleEngine'
            IGlyphPositions glyphPositions = glyphLayout.ResultUnscaledGlyphPositions;
            float           accumW         = 0; //acummulate Width

            stopAtGlyphIndex = 0;

            if (snapToGrid)
            {
                int finalGlyphCount = glyphPositions.Count;
                for (int i = 0; i < finalGlyphCount; ++i)
                {
                    //all from pen-pos
                    ushort glyphIndex = glyphPositions.GetGlyph(i,
                                                                out ushort input_offset,
                                                                out short offsetX,
                                                                out short offsetY,
                                                                out short advW);

                    stopAtGlyphIndex = i; //***
                    //
                    short w = (short)Math.Round(advW * pxscale);
                    if (accumW + w > limitWidth)
                    {
                        //stop
                        break;
                    }
                    else
                    {
                        accumW += w;
                    }
                }
            }
            else
            {
                //not snap to grid
                //scaled but not snap to grid
                int finalGlyphCount = glyphPositions.Count;
                for (int i = 0; i < finalGlyphCount; ++i)
                {
                    //all from pen-pos
                    ushort glyphIndex = glyphPositions.GetGlyph(i,
                                                                out ushort input_offset,
                                                                out short offsetX,
                                                                out short offsetY,
                                                                out short advW);


                    stopAtGlyphIndex = i; //***

                    float w = advW * pxscale;
                    if (accumW + w > limitWidth)
                    {
                        //stop
                        break;
                    }
                    else
                    {
                        accumW += w;
                    }
                }
            }
            return(accumW);


            ////measure string
            //if (str.Length < 1)
            //{
            //    charFitWidth = 0;
            //}

            //_reusableMeasureBoxList.Clear(); //reset


            //float pxscale = _currentTypeface.CalculateScaleToPixelFromPointSize(_fontSizeInPts);
            ////NOET:at this moment, simple operation
            ////may not be simple...
            ////-------------------
            ////input string may contain more than 1 script lang
            ////user can parse it by other parser
            ////but in this code, we use our Typography' parser
            ////-------------------
            ////user must setup the CustomBreakerBuilder before use

            //int cur_startAt = startAt;
            //float accumW = 0;

            //float acc_x = 0;//accum_x
            //float acc_y = 0;//accum_y
            //float g_x = 0;
            //float g_y = 0;
            //float x = 0;
            //float y = 0;
            //foreach (Typography.TextLayout.BreakSpan breakSpan in BreakToLineSegments(str, startAt, len))
            //{

            //    //measure string at specific px scale
            //    _glyphLayout.Layout(str, breakSpan.startAt, breakSpan.len);
            //    //

            //    _reusableGlyphPlanList.Clear();
            //    _glyphLayout.GenerateUnscaledGlyphPlans(_reusableGlyphPlanList);
            //    //measure ...


            //    //measure each glyph
            //    //limit at specific width
            //    int glyphCount = _reusableGlyphPlanList.Count;



            //    for (int i = 0; i < glyphCount; ++i)
            //    {
            //        UnscaledGlyphPlan glyphPlan = _reusableGlyphPlanList[i];

            //        float ngx = acc_x + (float)Math.Round(glyphPlan.OffsetX * pxscale);
            //        float ngy = acc_y + (float)Math.Round(glyphPlan.OffsetY * pxscale);
            //        //NOTE:
            //        // -glyphData.TextureXOffset => restore to original pos
            //        // -glyphData.TextureYOffset => restore to original pos
            //        //--------------------------
            //        g_x = (float)(x + (ngx)); //ideal x
            //        g_y = (float)(y + (ngy));
            //        float g_w = (float)Math.Round(glyphPlan.AdvanceX * pxscale);
            //        acc_x += g_w;
            //        //g_x = (float)Math.Round(g_x);
            //        g_y = (float)Math.Floor(g_y);

            //        float right = g_x + g_w;

            //        if (right >= accumW)
            //        {
            //            //stop here at this glyph
            //            charFit = i - 1;
            //            //TODO: review this
            //            charFitWidth = (int)System.Math.Round(accumW);
            //            return;
            //        }
            //        else
            //        {
            //            accumW = right;
            //        }
            //    }
            //}

            //charFit = 0;
            //charFitWidth = 0;
        }
Beispiel #12
0
 public static void Layout(this GlyphLayout glyphLayout, char[] str, int startAt, int len, GlyphReadOutputDelegate readDel)
 {
     glyphLayout.Layout(str, startAt, len);
     glyphLayout.ReadOutput(readDel);
 }
Beispiel #13
0
 public static void Layout(this GlyphLayout glyphLayout, char[] str, int startAt, int len, List <GlyphPlan> outputGlyphList)
 {
     glyphLayout.Layout(str, startAt, len);
     glyphLayout.ReadOutput(outputGlyphList);
 }
Beispiel #14
0
 /// <summary>
 /// read UserCharToGlyphIndexMap from latest layout output
 /// </summary>
 /// <param name="glyphLayout"></param>
 /// <param name="outputGlyphPlanList"></param>
 public static void ReadOutput(this GlyphLayout glyphLayout, List <UserCharToGlyphIndexMap> outputGlyphPlanList)
 {
     outputGlyphPlanList.AddRange(glyphLayout._inputGlyphs._mapUserCharToGlyphIndics);
 }
 /// <summary>
 /// read latest layout output into outputGlyphPlanList
 /// </summary>
 /// <param name="glyphLayout"></param>
 /// <param name="outputGlyphPlanList"></param>
 public static void dbugReadOutput(this GlyphLayout glyphLayout, List <UserCharToGlyphIndexMap> outputGlyphPlanList)
 {
     //TODO: review here
     outputGlyphPlanList.AddRange(glyphLayout._inputGlyphs._mapUserCharToGlyphIndices);
 }