public override void DrawFromGlyphPlans(GlyphPlanSequence seq, int startAt, int len, float x, float y) { UpdateVisualOutputSettings(); //draw data in glyph plan //3. render each glyph float sizeInPoints = this.FontSizeInPoints; float pxscale = _currentTypeface.CalculateScaleToPixelFromPointSize(sizeInPoints); // _glyphMeshCollections.SetCacheInfo(this.Typeface, sizeInPoints, this.HintTechnique); //this draw a single line text span*** Graphics g = this.TargetGraphics; float cx = 0; float cy = 0; float baseline = y; var snapToPxScale = new GlyphPlanSequenceSnapPixelScaleLayout(seq, startAt, len, pxscale); while (snapToPxScale.Read()) { if (!_glyphMeshCollections.TryGetCacheGlyph(snapToPxScale.CurrentGlyphIndex, out GraphicsPath foundPath)) { //if not found then create a new one _currentGlyphPathBuilder.BuildFromGlyphIndex(snapToPxScale.CurrentGlyphIndex, sizeInPoints); _txToGdiPath.Reset(); _currentGlyphPathBuilder.ReadShapes(_txToGdiPath); foundPath = _txToGdiPath.ResultGraphicsPath; //register _glyphMeshCollections.RegisterCachedGlyph(snapToPxScale.CurrentGlyphIndex, foundPath); } //------ //then move pen point to the position we want to draw a glyph cx = (float)Math.Round(snapToPxScale.ExactX + x); cy = (float)Math.Floor(snapToPxScale.ExactY + baseline); g.TranslateTransform(cx, cy); if (FillBackground) { g.FillPath(_fillBrush, foundPath); } if (DrawOutline) { g.DrawPath(_outlinePen, foundPath); } //and then we reset back *** g.TranslateTransform(-cx, -cy); } }
} // End Function GetExistingOrCreateGraphicsPath // public override void DrawFromGlyphPlans(GlyphPlanSequence glyphPlanList, int startAt, int len, float left, float top) public override void DrawFromGlyphPlans(GlyphPlanSequence seq, int startAt, int len, float x, float y) { UpdateVisualOutputSettings(); //draw data in glyph plan //3. render each glyph float sizeInPoints = this.FontSizeInPoints; float pxscale = _currentTypeface.CalculateScaleToPixelFromPointSize(sizeInPoints); Typeface typeface = this.Typeface; _glyphMeshCollections.SetCacheInfo(typeface, sizeInPoints, this.HintTechnique); //this draw a single line text span*** SvgGraphics g = this.TargetGraphics; float baseline = y; GlyphPlanSequenceSnapPixelScaleLayout snapToPxScale = new GlyphPlanSequenceSnapPixelScaleLayout(seq, startAt, len, pxscale); COLR colrTable = typeface.COLRTable; CPAL cpalTable = typeface.CPALTable; bool canUseColorGlyph = EnableColorGlyph && colrTable != null && cpalTable != null; while (snapToPxScale.Read()) { ushort glyphIndex = snapToPxScale.CurrentGlyphIndex; if (canUseColorGlyph && colrTable.LayerIndices.TryGetValue(glyphIndex, out ushort colorLayerStart)) { ushort colorLayerCount = colrTable.LayerCounts[glyphIndex]; for (int c = colorLayerStart; c < colorLayerStart + colorLayerCount; ++c) { SvgPath path = GetExistingOrCreateGraphicsPath(colrTable.GlyphLayers[c]); if (path == null) { #if DEBUG System.Diagnostics.Debug.WriteLine("gdi_printer: no path?"); #endif continue; } // End if (path == null) //then move pen point to the position we want to draw a glyph float cx = (float)System.Math.Round(snapToPxScale.ExactX + x); float cy = (float)System.Math.Floor(snapToPxScale.ExactY + baseline); int palette = 0; // FIXME: assume palette 0 for now cpalTable.GetColor( cpalTable.Palettes[palette] + colrTable.GlyphPalettes[c], //index out byte red, out byte green, out byte blue, out byte alpha); g.TranslateTransform(cx, cy); _fillBrush.Color = SvgColor.ToWebRgb(red, green, blue); if (FillBackground) { g.FillPath(_fillBrush, path); } if (DrawOutline) { g.DrawPath(_outlinePen, path); } // and then we reset back g.TranslateTransform(-cx, -cy); } // Next c } else { SvgPath path = GetExistingOrCreateGraphicsPath(glyphIndex); if (path == null) { #if DEBUG System.Diagnostics.Debug.WriteLine("gdi_printer: no path?"); #endif continue; } //------ //then move pen point to the position we want to draw a glyph float cx = (float)System.Math.Round(snapToPxScale.ExactX + x); float cy = (float)System.Math.Floor(snapToPxScale.ExactY + baseline); g.TranslateTransform(cx, cy); if (FillBackground) { g.FillPath(_fillBrush, path); } if (DrawOutline) { g.DrawPath(_outlinePen, path); } // and then we reset back g.TranslateTransform(-cx, -cy); } // End else } // Whend } // End Sub DrawFromGlyphPlans
public override void DrawFromGlyphPlans(GlyphPlanSequence seq, int startAt, int len, float left, float top) { if (StartDrawOnLeftTop) { //version 2 //offset y down top += this.FontLineSpacingPx; } float fontSizePoint = this.FontSizeInPoints; float scale = _currentTypeface.CalculateScaleToPixelFromPointSize(fontSizePoint); //4. render each glyph float ox = _painter.OriginX; float oy = _painter.OriginY; Typography.OpenFont.Tables.COLR colrTable = _currentTypeface.COLRTable; Typography.OpenFont.Tables.CPAL cpalTable = _currentTypeface.CPALTable; bool hasColorGlyphs = (colrTable != null) && (cpalTable != null); //--------------------------------------------------- _glyphMeshStore.SetHintTechnique(this.HintTechnique); _glyphMeshStore.SetFont(_currentTypeface, fontSizePoint); _glyphMeshStore.SimulateOblique = this.SimulateSlant; //--------------------------------------------------- if (_currentTypeface.HasSvgTable()) { _glyphSvgStore.SetCurrentTypeface(_currentTypeface); int seqLen = seq.Count; if (len > seqLen) { len = seqLen; } var snapToPx = new GlyphPlanSequenceSnapPixelScaleLayout(seq, startAt, len, scale); while (snapToPx.Read()) { _painter.SetOrigin((float)Math.Round(left + snapToPx.ExactX) + 0.33f, (float)Math.Floor(top + snapToPx.ExactY)); GlyphBitmap glyphBmp = _glyphSvgStore.GetGlyphBitmap(snapToPx.CurrentGlyphIndex); //how to draw the image //1. if (glyphBmp != null) { _painter.DrawImage(glyphBmp.Bitmap); } } } else if (_currentTypeface.IsBitmapFont) { //check if we have exported all the glyph bitmap //to some 'ready' form? //if not then create it _glyphBitmapStore.SetCurrentTypeface(_currentTypeface); int seqLen = seq.Count; if (len > seqLen) { len = seqLen; } var snapToPx = new GlyphPlanSequenceSnapPixelScaleLayout(seq, startAt, len, scale); while (snapToPx.Read()) { _painter.SetOrigin((float)Math.Round(left + snapToPx.ExactX) + 0.33f, (float)Math.Floor(top + snapToPx.ExactY)); GlyphBitmap glyphBmp = _glyphBitmapStore.GetGlyphBitmap(snapToPx.CurrentGlyphIndex); //how to draw the image //1. _painter.DrawImage(glyphBmp.Bitmap); } } else { if (!hasColorGlyphs) { bool savedUseLcdMode = _painter.UseSubPixelLcdEffect; //save,restore later RenderQuality savedRederQuality = _painter.RenderQuality; _painter.RenderQuality = RenderQuality.HighQuality; _painter.UseSubPixelLcdEffect = true; int seqLen = seq.Count; if (len > seqLen) { len = seqLen; } var snapToPx = new GlyphPlanSequenceSnapPixelScaleLayout(seq, startAt, len, scale); while (snapToPx.Read()) { _painter.SetOrigin((float)Math.Round(left + snapToPx.ExactX) + 0.33f, (float)Math.Floor(top + snapToPx.ExactY)); _painter.Fill(_glyphMeshStore.GetGlyphMesh(snapToPx.CurrentGlyphIndex)); } //restore _painter.RenderQuality = savedRederQuality; _painter.UseSubPixelLcdEffect = savedUseLcdMode; } else { //------------- //this glyph has color information //------------- Color originalFillColor = _painter.FillColor; int seqLen = seq.Count; if (len > seqLen) { len = seqLen; } var snapToPx = new GlyphPlanSequenceSnapPixelScaleLayout(seq, startAt, len, scale); while (snapToPx.Read()) { _painter.SetOrigin((float)Math.Round(left + snapToPx.ExactX), (float)Math.Floor(top + snapToPx.ExactY)); ushort colorLayerStart; if (colrTable.LayerIndices.TryGetValue(snapToPx.CurrentGlyphIndex, out colorLayerStart)) { //TODO: optimize this //we found color info for this glyph ushort colorLayerCount = colrTable.LayerCounts[snapToPx.CurrentGlyphIndex]; byte r, g, b, a; for (int c = colorLayerStart; c < colorLayerStart + colorLayerCount; ++c) { ushort gIndex = colrTable.GlyphLayers[c]; int palette = 0; // FIXME: assume palette 0 for now cpalTable.GetColor( cpalTable.Palettes[palette] + colrTable.GlyphPalettes[c], //index out r, out g, out b, out a); //----------- _painter.FillColor = new Color(r, g, b);//? a component _painter.Fill(_glyphMeshStore.GetGlyphMesh(gIndex)); } } else { //----------------------------------- //TODO: review here *** //PERFORMANCE revisit here //if we have create a vxs we can cache it for later use? //----------------------------------- _painter.Fill(_glyphMeshStore.GetGlyphMesh(snapToPx.CurrentGlyphIndex)); } } _painter.FillColor = originalFillColor; //restore color } } //restore prev origin _painter.SetOrigin(ox, oy); }
void RenderAndShowMeasureBox() { bool flipY = chkFlipY.Checked; //set some Gdi+ props... _g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; _g.Clear(Color.White); Typography.OpenFont.Typeface typeface = _currentTextPrinter.Typeface; Typography.OpenFont.Extensions.TypefaceExtensions.UpdateAllCffGlyphBounds(typeface); float pxscale = typeface.CalculateScaleToPixelFromPointSize(_currentTextPrinter.FontSizeInPoints); int lineSpacing = (int)System.Math.Ceiling((double)typeface.CalculateLineSpacing(LineSpacingChoice.TypoMetric) * pxscale); if (flipY) { //credit: //http://stackoverflow.com/questions/1485745/flip-coordinates-when-drawing-to-control _g.ScaleTransform(1.0F, -1.0F); // Flip the Y-Axis _g.TranslateTransform(0.0F, -500); // Translate the drawing area accordingly } //-------------------------------- //textspan measurement sample //-------------------------------- _currentTextPrinter.HintTechnique = (HintTechnique)lstHintList.SelectedItem; _currentTextPrinter.PositionTechnique = (PositionTechnique)cmbPositionTech.SelectedItem; _currentTextPrinter.UpdateGlyphLayoutSettings(); //render at specific pos float x_pos = 0, y_pos = lineSpacing * 2; char[] textBuffer = txtInputChar.Text.ToCharArray(); //Example 1: this is a basic draw sample _currentTextPrinter.FillColor = Color.Black; _currentTextPrinter.TargetGraphics = _g; //_currentTextPrinter.DrawString( // textBuffer, // 0, // textBuffer.Length, // x_pos, // y_pos // ); // //-------------------------------------------------- //Example 2: print glyph plan to 'user' list-> then draw it (or hold it/ not draw) //you can create you own class to hold userGlyphPlans.*** //2.1 if (chkEnableMultiTypefaces.Checked) { _ftmGlyphPlansList.Clear(); _currentTextPrinter.GenerateGlyphPlans(textBuffer, 0, textBuffer.Length, _ftmGlyphPlansList); //2.2 //and we can print the formatted glyph plan later. y_pos -= lineSpacing;//next line _currentTextPrinter.FillColor = Color.Red; _currentTextPrinter.DrawFromFormattedGlyphPlans( _ftmGlyphPlansList, x_pos, y_pos ); //-------------------------------------------------- //Example 3: MeasureString //3.1 use data in formatted_glyph_plan_list to measure string => OK, OR //3.2 use another 'light-weight' text printer to measure string (without drawing actual string) //3.1 _currentTextPrinter.MeasureGlyphPlanList(_ftmGlyphPlansList, out int measureWidth); _g.DrawRectangle(Pens.Red, x_pos, y_pos, measureWidth, 30); float baseline = y_pos; //3.2 draw each glyph bounds { int m = _ftmGlyphPlansList.Count; for (int i = 0; i < m; ++i) { FormattedGlyphPlanSeq seq = _ftmGlyphPlansList[i]; ResolvedFont resolvedFont = seq.ResolvedFont; Typeface localTypeface = resolvedFont.Typeface; pxscale = resolvedFont.GetScaleToPixelFromPointInSize(); GlyphPlanSequence glyph_seq = seq.Seq; var snapToPxScale = new GlyphPlanSequenceSnapPixelScaleLayout(seq.Seq, 0, glyph_seq.Count, pxscale); x_pos += (resolvedFont.WhitespaceWidth * seq.PrefixWhitespaceCount); int nn = 0;/// while (snapToPxScale.Read()) { //float cx = (float)Math.Round(snapToPxScale.ExactX + x_pos); //float cy = (float)Math.Floor(snapToPxScale.ExactY + baseline); UnscaledGlyphPlan glyphPlan = glyph_seq[nn]; Glyph glyph = localTypeface.GetGlyph(glyphPlan.glyphIndex); Bounds b = glyph.Bounds; // float xmin = b.XMin * pxscale; float ymin = b.YMin * pxscale; // float xmax = b.XMax * pxscale; float ymax = b.YMax * pxscale; // float glyph_x = x_pos + (glyphPlan.OffsetX * pxscale); _g.DrawRectangle(Pens.Red, glyph_x + xmin, y_pos + ymin, xmax - xmin, ymax - ymin); x_pos += glyphPlan.AdvanceX * pxscale; nn++; } x_pos += (resolvedFont.WhitespaceWidth * seq.PostfixWhitespaceCount); } } _ftmGlyphPlansList.Clear(); } else { _reusableUnscaledGlyphPlanList.Clear(); _currentTextPrinter.GenerateGlyphPlans(textBuffer, 0, textBuffer.Length, _reusableUnscaledGlyphPlanList); //2.2 //and we can print the formatted glyph plan later. y_pos -= lineSpacing;//next line _currentTextPrinter.FillColor = Color.Red; // GlyphPlanSequence seq = new GlyphPlanSequence(_reusableUnscaledGlyphPlanList); _currentTextPrinter.DrawFromGlyphPlans( seq, x_pos, y_pos ); //-------------------------------------------------- //Example 3: MeasureString float descending_px = _currentTextPrinter.FontDescedingPx; float ascending_px = _currentTextPrinter.FontAscendingPx; float lineSpacing_px = _currentTextPrinter.FontLineSpacingPx; float clippedHeight_px = _currentTextPrinter.FontClipHeightPx; _currentTextPrinter.MeasureGlyphPlanSeq(seq, out int textspanW); UnscaledGlyphPlanList glyphPlans = new UnscaledGlyphPlanList(); _currentTextPrinter.GenerateGlyphPlans(textBuffer, 0, textBuffer.Length, glyphPlans); int j = glyphPlans.Count; float backup_xpos = x_pos; for (int i = 0; i < j; ++i) { UnscaledGlyphPlan glyphPlan = glyphPlans[i]; Glyph glyph = typeface.GetGlyph(glyphPlan.glyphIndex); // Bounds b = glyph.Bounds; // float xmin = b.XMin * pxscale; float ymin = b.YMin * pxscale; // float xmax = b.XMax * pxscale; float ymax = b.YMax * pxscale; // float glyph_x = x_pos + (glyphPlan.OffsetX * pxscale); _g.DrawRectangle(Pens.Red, glyph_x + xmin, y_pos + ymin, xmax - xmin, ymax - ymin); x_pos += glyphPlan.AdvanceX * pxscale; } x_pos = backup_xpos; _g.FillRectangle(Brushes.Red, new RectangleF(0, 0, 5, 5));//reference point(0,0) _g.FillRectangle(Brushes.Green, new RectangleF(x_pos, y_pos, 3, 3)); float x_pos2 = x_pos + textspanW + 10; _g.DrawRectangle(Pens.Black, x_pos, y_pos + descending_px, textspanW, clippedHeight_px); _g.DrawRectangle(Pens.Red, x_pos, y_pos + descending_px, textspanW, lineSpacing_px); _g.DrawLine(Pens.Blue, x_pos, y_pos, x_pos2, y_pos); //baseline _g.DrawLine(Pens.Green, x_pos, y_pos + descending_px, x_pos2, y_pos + descending_px); //descending _g.DrawLine(Pens.Magenta, x_pos, y_pos + ascending_px, x_pos2, y_pos + ascending_px); //ascending ////------------ ////draw another line (for reference) y_pos -= lineSpacing;//next line _currentTextPrinter.FillColor = Color.Black; _currentTextPrinter.DrawFromGlyphPlans( new GlyphPlanSequence(_reusableUnscaledGlyphPlanList), x_pos, y_pos ); } //transform back if (flipY) { _g.ScaleTransform(1.0F, -1.0F); // Flip the Y-Axis _g.TranslateTransform(0.0F, -500); // Translate the drawing area accordingly } //--------- //txtMsgInfo.Text = "choice:" + choice.ToString() + "=" + lineSpacing.ToString(); }