void LayoutWithoutHorizontalFitAlign(IGlyphPositions posStream, GlyphPlanList outputGlyphPlanList) { //the default OpenFont layout without fit-to-writing alignment int finalGlyphCount = posStream.Count; float pxscale = _typeface.CalculateScaleToPixelFromPointSize(this._fontSizeInPoints); double cx = 0; short cy = 0; for (int i = 0; i < finalGlyphCount; ++i) { short offsetX, offsetY, advW; //all from pen-pos ushort glyphIndex = posStream.GetGlyph(i, out offsetX, out offsetY, out advW); float s_advW = advW * pxscale; float exact_x = (float)(cx + offsetX * pxscale); float exact_y = (float)(cy + offsetY * pxscale); //outputGlyphPlanList.Append(new GlyphPlan( // glyphIndex, // exact_x, // exact_y, // advW)); //old? outputGlyphPlanList.Append(new GlyphPlan( glyphIndex, exact_x, exact_y, s_advW)); cx += s_advW; } }
/// <summary> /// always create new vxs for this glyph, no caching /// </summary> /// <param name="glyphIndex"></param> /// <returns></returns> public VertexStore GetNewUnFlattenVxs(ushort glyphIndex) { _currentGlyphBuilder.BuildFromGlyphIndex(glyphIndex, _currentFontSizeInPoints); DynamicOutline dynamicOutline = _currentGlyphBuilder.LatestGlyphFitOutline; //----------------------------------- _tovxs.Reset(); float pxscale = _currentTypeface.CalculateScaleToPixelFromPointSize(_currentFontSizeInPoints); if (dynamicOutline != null) { //TODO: review dynamic outline dynamicOutline.GenerateOutput(new ContourToGlyphTranslator(_tovxs), pxscale); //version 3 using (Tools.BorrowVxs(out var v1)) { _tovxs.WriteUnFlattenOutput(v1, 1); return(FlipGlyphUpward ? v1.CreateTrim(s_flipY) : v1.CreateTrim()); } } else { using (Tools.BorrowVxs(out var v1)) { _currentGlyphBuilder.ReadShapes(_tovxs); _tovxs.WriteUnFlattenOutput(v1, 1); //write to temp buffer first //then return(FlipGlyphUpward ? v1.CreateTrim(s_flipY) : v1.CreateTrim()); } } }
/// <summary> /// get from cache or create a new one /// </summary> /// <param name="reqFont"></param> /// <returns></returns> public SimpleFontAtlas GetFontAtlas(RequestFont reqFont, out GLBitmap glBmp) { int fontKey = reqFont.FontKey; SimpleFontAtlas fontAtlas; if (!_createdAtlases.TryGetValue(fontKey, out fontAtlas)) { Typeface resolvedTypeface = textServices.ResolveTypeface(reqFont); //if we don't have //the create it SimpleFontAtlasBuilder atlasBuilder = null; var textureGen = new GlyphTextureBitmapGenerator(); textureGen.CreateTextureFontFromScriptLangs( resolvedTypeface, reqFont.SizeInPoints, _textureKind, _currentScriptLangs, (glyphIndex, glyphImage, outputAtlasBuilder) => { if (outputAtlasBuilder != null) { //finish atlasBuilder = outputAtlasBuilder; } } ); GlyphImage totalGlyphsImg = atlasBuilder.BuildSingleImage(); //create atlas fontAtlas = atlasBuilder.CreateSimpleFontAtlas(); fontAtlas.TotalGlyph = totalGlyphsImg; #if DEBUG //save glyph image for debug //PixelFarm.Agg.ActualImage.SaveImgBufferToPngFile( // totalGlyphsImg.GetImageBuffer(), // totalGlyphsImg.Width * 4, // totalGlyphsImg.Width, totalGlyphsImg.Height, // "d:\\WImageTest\\total_" + reqFont.Name + "_" + reqFont.SizeInPoints + ".png"); #endif //cache the atlas _createdAtlases.Add(fontKey, fontAtlas); // //calculate some commonly used values fontAtlas.SetTextureScaleInfo( resolvedTypeface.CalculateScaleToPixelFromPointSize(fontAtlas.OriginalFontSizePts), resolvedTypeface.CalculateScaleToPixelFromPointSize(reqFont.SizeInPoints)); //TODO: review here, use scaled or unscaled values fontAtlas.SetCommonFontMetricValues( resolvedTypeface.Ascender, resolvedTypeface.Descender, resolvedTypeface.LineGap, resolvedTypeface.CalculateRecommendLineSpacing()); } glBmp = _loadedGlyphs.GetOrCreateNewOne(fontAtlas); return(fontAtlas); }
protected override void OnFontSizeChanged() { //update some font matrix property if (_currentTypeface != null) { float pointToPixelScale = _currentTypeface.CalculateScaleToPixelFromPointSize(this.FontSizeInPoints); this.FontAscendingPx = _currentTypeface.Ascender * pointToPixelScale; this.FontDescedingPx = _currentTypeface.Descender * pointToPixelScale; this.FontLineGapPx = _currentTypeface.LineGap * pointToPixelScale; this.FontLineSpacingPx = FontAscendingPx - FontDescedingPx + FontLineGapPx; } }
/// <summary> /// get glyph mesh from current font setting /// </summary> /// <param name="glyphIndex"></param> /// <returns></returns> public VertexStore GetGlyphMesh(ushort glyphIndex) { GlyphMeshData glyphMeshData = InternalGetGlyphMesh(glyphIndex); if (glyphMeshData.vxsStore == null) { //build vxs _tovxs.Reset(); float pxscale = _currentTypeface.CalculateScaleToPixelFromPointSize(_currentFontSizeInPoints); GlyphDynamicOutline dynamicOutline = glyphMeshData.dynamicOutline; if (dynamicOutline != null) { dynamicOutline.GenerateOutput(_tovxs, pxscale); glyphMeshData.vxsStore = new VertexStore(); _tovxs.WriteOutput(glyphMeshData.vxsStore, _vxsPool); } else { //no dynamic outline glyphMeshData.vxsStore = new VertexStore(); _currentGlyphBuilder.ReadShapes(_tovxs); //TODO: review here, //float pxScale = _glyphPathBuilder.GetPixelScale(); _tovxs.WriteOutput(glyphMeshData.vxsStore, _vxsPool); } } return(glyphMeshData.vxsStore); }
/// <summary> /// get glyph mesh from current font setting /// </summary> /// <param name="glyphIndex"></param> /// <returns></returns> public VertexStore GetGlyphMesh(ushort glyphIndex) { GlyphMeshData glyphMeshData = InternalGetGlyphMesh(glyphIndex); if (glyphMeshData.vxsStore == null) { //build vxs _tovxs.Reset(); float pxscale = _currentTypeface.CalculateScaleToPixelFromPointSize(_currentFontSizeInPoints); GlyphDynamicOutline dynamicOutline = glyphMeshData.dynamicOutline; if (dynamicOutline != null) { dynamicOutline.GenerateOutput(_tovxs, pxscale); //version 3 if (_flipGlyphUpward) { _vxs1.Clear(); //write to temp buffer first _tovxs.WriteOutput(_vxs1); VertexStore vxs = new VertexStore(); PixelFarm.Agg.VertexStoreTransformExtensions.TransformToVxs(_invertY, _vxs1, vxs); //then glyphMeshData.vxsStore = vxs; } else { glyphMeshData.vxsStore = new VertexStore(); _tovxs.WriteOutput(glyphMeshData.vxsStore); } } else { if (_flipGlyphUpward) { _vxs1.Clear(); //write to temp buffer first _currentGlyphBuilder.ReadShapes(_tovxs); _tovxs.WriteOutput(_vxs1); VertexStore vxs = new VertexStore(); PixelFarm.Agg.VertexStoreTransformExtensions.TransformToVxs(_invertY, _vxs1, vxs); //then glyphMeshData.vxsStore = vxs; } else { //no dynamic outline _currentGlyphBuilder.ReadShapes(_tovxs); //TODO: review here, //float pxScale = _glyphPathBuilder.GetPixelScale(); glyphMeshData.vxsStore = new VertexStore(); _tovxs.WriteOutput(glyphMeshData.vxsStore); } } } return(glyphMeshData.vxsStore); }
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)); }
public static double GetAscent(string fontFamily, double fontSize) { Typeface typeFace = GetTypeFace(fontFamily); var scale = typeFace.CalculateScaleToPixelFromPointSize((float)fontSize); return(typeFace.Ascender * scale); }
public static double GetLineHeight(string fontFamily, double fontSize) { Typeface typeFace = GetTypeFace(fontFamily); var scale = typeFace.CalculateScaleToPixelFromPointSize((float)fontSize); return((typeFace.Ascender - typeFace.Descender + typeFace.LineGap) * scale); }
public static float GetScale(string fontFamily, double fontSize) { Typeface typeFace = GetTypeFace(fontFamily); var scale = typeFace.CalculateScaleToPixelFromPointSize((float)fontSize); return(scale); }
float ITextService.MeasureBlankLineHeight(RequestFont font) { Typeface typeface = ResolveTypeface(font); return((int)(Math.Round(typeface.CalculateMaxLineClipHeight() * typeface.CalculateScaleToPixelFromPointSize(font.SizeInPoints)))); }
// public void CalculateUserCharGlyphAdvancePos(ref TextBufferSpan textBufferSpan, ILineSegmentList lineSegs, RequestFont font, int[] outputUserInputCharAdvance, out int outputTotalW, out int lineHeight) { //layout //from font //resolve for typeface // Typeface typeface = ResolveTypeface(font); _txtServices.SetCurrentFont(typeface, font.SizeInPoints); MyLineSegmentList mylineSegs = (MyLineSegmentList)lineSegs; float scale = typeface.CalculateScaleToPixelFromPointSize(font.SizeInPoints); outputTotalW = 0; int j = mylineSegs.Count; int pos = 0; //start at 0 _reusableTextBuffer.SetRawCharBuffer(textBufferSpan.GetRawCharBuffer()); for (int i = 0; i < j; ++i) { //get each segment MyLineSegment lineSeg = (MyLineSegment)mylineSegs.GetSegment(i); //each line seg may has different script lang _txtServices.CurrentScriptLang = lineSeg.scriptLang; // //CACHING ...., reduce number of GSUB/GPOS // //we cache used line segment for a while //we ask for caching context for a specific typeface and font size GlyphPlanSequence seq = _txtServices.GetUnscaledGlyphPlanSequence(_reusableTextBuffer, lineSeg.StartAt, lineSeg.Length); int seqLen = seq.Count; for (int s = 0; s < seqLen; ++s) { UnscaledGlyphPlan glyphPlan = seq[s]; double actualAdvX = glyphPlan.AdvanceX; outputTotalW += outputUserInputCharAdvance[pos + glyphPlan.input_cp_offset] += (int)Math.Round(actualAdvX * scale); } pos += lineSeg.Length; } // lineHeight = (int)Math.Round(typeface.CalculateRecommendLineSpacing() * scale); _reusableTextBuffer.SetRawCharBuffer(null); }
public void DrawString(RenderVxFormattedString renderVx, double x, double y) { //TODO: review here float ox = _painter.OriginX; float oy = _painter.OriginY; //1. update some props.. //2. update current type face UpdateGlyphLayoutSettings(); _glyphMeshStore.SetFont(_currentTypeface, this.FontSizeInPoints); _glyphMeshStore.SimulateOblique = this.SimulateSlant; //3. layout glyphs with selected layout technique //TODO: review this again, we should use pixel? float fontSizePoint = this.FontSizeInPoints; float scale = _currentTypeface.CalculateScaleToPixelFromPointSize(fontSizePoint); RenderVxGlyphPlan[] glyphPlans = renderVx.GlyphList; int j = glyphPlans.Length; //--------------------------------------------------- //consider use cached glyph, to increase performance //GlyphPosPixelSnapKind x_snap = this.GlyphPosPixelSnapX; //GlyphPosPixelSnapKind y_snap = this.GlyphPosPixelSnapY; float g_x = 0; float g_y = 0; float baseY = (int)y; for (int i = 0; i < j; ++i) { RenderVxGlyphPlan glyphPlan = glyphPlans[i]; //----------------------------------- //TODO: review here *** //PERFORMANCE revisit here //if we have create a vxs we can cache it for later use? //----------------------------------- VertexStore vxs = _glyphMeshStore.GetGlyphMesh(glyphPlan.glyphIndex); g_x = (float)(glyphPlan.x * scale + x); g_y = (float)glyphPlan.y * scale; _painter.SetOrigin(g_x, g_y); _painter.Fill(vxs); } //restore prev origin _painter.SetOrigin(ox, oy); }
float ITextService.MeasureBlankLineHeight(RequestFont font) { LineSpacingChoice sel_linespcingChoice; Typeface typeface = ResolveTypeface(font); return((int)(Math.Round(typeface.CalculateRecommendLineSpacing(out sel_linespcingChoice) * typeface.CalculateScaleToPixelFromPointSize(font.SizeInPoints)))); }
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); } }
public NOpenFont(NOpenFontFace ownerFace, float sizeInPoints, FontStyle style) { this.ownerFace = ownerFace; this.sizeInPoints = sizeInPoints; this.style = style; this.typeFace = ownerFace.Typeface; //calculate scale *** scale = typeFace.CalculateScaleToPixelFromPointSize(sizeInPoints); }
public NOpenFont(NOpenFontFace ownerFace, float sizeInPoints, FontStyle style) { _ownerFace = ownerFace; _sizeInPoints = sizeInPoints; _style = style; _typeFace = ownerFace.Typeface; //calculate scale *** _scale = _typeFace.CalculateScaleToPixelFromPointSize(sizeInPoints); _recommendLineSpacing = _typeFace.CalculateRecommendLineSpacing() * _scale; }
void SetCurrentFontInfo(Typeface typeface, float sizeInPoints) { _typeface = typeface; _sizeInPoints = sizeInPoints; //please note that DPI effect glyph size //TODO: //1. add information about dpi to generated texture //2. when dpi is changed we need to use correct texture for that dpi _currentDPI = Typeface.DefaultDpi; _px_scale = _typeface.CalculateScaleToPixelFromPointSize(_sizeInPoints, (int)_currentDPI); }
public Typeface ResolveTypeface(RequestFont font) { //from user's request font //resolve to actual Typeface //get data from... //cache level-1 (attached inside the request font) Typeface typeface = PixelFarm.Drawing.Internal.RequestFontCacheAccess.GetActualFont <Typeface>(font, _system_id); if (typeface != null) { return(typeface); } // //cache level-2 (stored in this Ifonts) if (!_resolvedTypefaceCache.TryGetValue(font.FontKey, out typeface)) { //not found ask the typeface store to load that font //.... typeface = _txtServices.GetTypeface(font.Name, font.Style.ConvToInstalledFontStyle()); if (typeface == null) { throw new NotSupportedException(); } // //cache here (level-1) _resolvedTypefaceCache.Add(font.FontKey, typeface); } //and cache into level-0 float pxSize = Typeface.ConvPointsToPixels(font.SizeInPoints); float pxscale = typeface.CalculateScaleToPixelFromPointSize(font.SizeInPoints); float recommedLineSpacingInPx = typeface.CalculateRecommendLineSpacing() * pxscale; float descentInPx = typeface.Descender * pxscale; float ascentInPx = typeface.Ascender * pxscale; float lineGapInPx = typeface.LineGap * pxscale; PixelFarm.Drawing.Internal.RequestFontCacheAccess.SetActualFont(font, _system_id, typeface); PixelFarm.Drawing.Internal.RequestFontCacheAccess.SetGeneralFontMetricInfo(font, pxSize, ascentInPx, descentInPx, lineGapInPx, recommedLineSpacingInPx); TextBufferSpan w = new TextBufferSpan(new char[] { ' ' }); Size whiteSpaceW = MeasureString(ref w, font); PixelFarm.Drawing.Internal.RequestFontCacheAccess.SetWhitespaceWidth(font, _system_id, whiteSpaceW.Width); return(typeface); }
public ResolvedFont(Typeface typeface, float sizeInPoints) { Typeface = typeface; if (typeface != null) { _px_scale = typeface.CalculateScaleToPixelFromPointSize(sizeInPoints); _ws = (int)Math.Round(typeface.GetWhitespaceWidth() * _px_scale); Name = typeface.Name; } SizeInPoints = sizeInPoints; RuntimeResolvedKey = CalculateGetHasCode( TypefaceExtensions.GetCustomTypefaceKey(typeface), sizeInPoints); }
public void ChangeFont(RequestFont font) { if (_font == font) { return; } //font has been changed, //resolve for the new one //check if we have this texture-font atlas in our MySimpleGLBitmapFontManager //if not-> request the MySimpleGLBitmapFontManager to create a newone _fontAtlas = _myGLBitmapFontMx.GetFontAtlas(font, out _glBmp); _font = font; Typeface typeface = _textServices.ResolveTypeface(font); _px_scale = typeface.CalculateScaleToPixelFromPointSize(font.SizeInPoints); }
public void ChangeFont(RequestFont font) { if (_font == font || (_font != null && _font.FontKey == font.FontKey)) { //not change -> then return return; } //_loadedFont = _loadFonts.RegisterFont(font); //System.Diagnostics.Debug.WriteLine(font.Name + font.SizeInPoints); //LoadedFont loadFont = _loadFonts.RegisterFont(font); //font has been changed, //resolve for the new one //check if we have this texture-font atlas in our MySimpleGLBitmapFontManager //if not-> request the MySimpleGLBitmapFontManager to create a newone _fontAtlas = _myGLBitmapFontMx.GetFontAtlas(font, out _glBmp); _font = font; Typeface typeface = _textServices.ResolveTypeface(font); _px_scale = typeface.CalculateScaleToPixelFromPointSize(font.SizeInPoints); }
public override float GetScale(float pointSize) => _typeface.CalculateScaleToPixelFromPointSize(pointSize);
public void CalculateUserCharGlyphAdvancePos(ref TextBufferSpan textBufferSpan, ILineSegmentList lineSegs, RequestFont font, int[] outputUserInputCharAdvance, out int outputTotalW, out int lineHeight) { //layout //from font //resolve for typeface // Typeface typeface = ResolveTypeface(font); _txtServices.SetCurrentFont(typeface, font.SizeInPoints); MyLineSegmentList mylineSegs = (MyLineSegmentList)lineSegs; float scale = typeface.CalculateScaleToPixelFromPointSize(font.SizeInPoints); outputTotalW = 0; int j = mylineSegs.Count; int pos = 0; //start at 0 _reusableTextBuffer.SetRawCharBuffer(textBufferSpan.GetRawCharBuffer()); for (int i = 0; i < j; ++i) { //userGlyphPlanList.Clear(); //userCharToGlyphMapList.Clear(); //get each segment MyLineSegment lineSeg = mylineSegs.GetSegment(i); //each line seg may has different script lang _txtServices.CurrentScriptLang = lineSeg.scriptLang; // //CACHING ...., reduce number of GSUB/GPOS // //we cache used line segment for a while //we ask for caching context for a specific typeface and font size GlyphPlanSequence seq = _txtServices.GetUnscaledGlyphPlanSequence(_reusableTextBuffer, lineSeg.StartAt, lineSeg.Length); //IMPORTANT //num of glyph may more or less than original user input char buffer // //float g_x = 0; //float g_y = 0; //int baseY = (int)Math.Round(y); //int n = glyphPlanSeq.len; //int endBefore = glyphPlanSeq.startAt + n; ////*** //_glsx.SetAssociatedTextureInfo(_glBmp); //List<float> vboBufferList = new List<float>(); //List<ushort> indexList = new List<ushort>(); //for (int i = glyphPlanSeq.startAt; i < endBefore; ++i) //{ // GlyphPlanList glyphPlanList = GlyphPlanSequence.UnsafeGetInteralGlyphPlanList(glyphPlanSeq); // GlyphPlan glyph = glyphPlanList[i]; // Typography.Rendering.TextureGlyphMapData glyphData; // if (!_fontAtlas.TryGetGlyphDataByCodePoint(glyph.glyphIndex, out glyphData)) // { // //if no glyph data, we should render a missing glyph *** // continue; // } // //if (scaleFromTexture != 1) // //{ // //} // //-------------------------------------- // //TODO: review precise height in float // //-------------------------------------- // PixelFarm.Drawing.Rectangle srcRect = ConvToRect(glyphData.Rect); // g_x = (float)(x + (glyph.ExactX * scale - glyphData.TextureXOffset) * scaleFromTexture); //ideal x // g_y = (float)(y + (glyph.ExactY * scale - glyphData.TextureYOffset + srcRect.Height) * scaleFromTexture); // //for sharp glyph // //we adjust g_x,g_y to integer value // //float g_y2 = (float)Math.Floor(g_y); // g_x = (float)Math.Round(g_x); // g_y = (float)Math.Floor(g_y); // switch (textureKind) // { // case TextureKind.Msdf: // _glsx.DrawSubImageWithMsdf(_glBmp, // ref srcRect, // g_x, // g_y, // scaleFromTexture); // break; // case TextureKind.StencilGreyScale: // //stencil gray scale with fill-color // _glsx.DrawGlyphImageWithStecil(_glBmp, // ref srcRect, // g_x, // g_y, // scaleFromTexture); // break; // case TextureKind.Bitmap: // _glsx.DrawSubImage(_glBmp, // ref srcRect, // g_x, // g_y, // scaleFromTexture); // break; // case TextureKind.StencilLcdEffect: // _glsx.WriteVboToList( // vboBufferList, // indexList, // ref srcRect, // g_x, // g_y, // scaleFromTexture); // break; // } //} ////--------- int seqLen = seq.Count; for (int s = 0; s < seqLen; ++s) { UnscaledGlyphPlan glyphPlan = seq[s]; double actualAdvX = glyphPlan.AdvanceX; outputTotalW += outputUserInputCharAdvance[pos + glyphPlan.input_cp_offset] += (int)Math.Round(actualAdvX * scale); } pos += lineSeg.Length; } // lineHeight = (int)Math.Round(typeface.CalculateRecommendLineSpacing() * scale); _reusableTextBuffer.SetRawCharBuffer(null); }
public void RenderChar(char testChar, HintTechnique hint) { builder.SetHintTechnique(hint); #if DEBUG GlyphBoneJoint.dbugTotalId = 0;//reset builder.dbugAlwaysDoCurveAnalysis = true; #endif _infoView.Clear(); _latestHint = hint; _testChar = testChar; //---------------------------------------------------- // builder.Build(testChar, _sizeInPoint); var txToVxs1 = new GlyphTranslatorToVxs(); builder.GlyphDynamicEdgeOffset = this.GlyphEdgeOffset; builder.ReadShapes(txToVxs1); #if DEBUG var ps = txToVxs1.dbugGetPathWriter(); _infoView.ShowOrgBorderInfo(ps.Vxs); #endif PixelFarm.Drawing.VertexStore vxs = new PixelFarm.Drawing.VertexStore(); txToVxs1.WriteOutput(vxs); //---------------------------------------------------- //---------------------------------------------------- painter.UseSubPixelLcdEffect = this.UseLcdTechnique; //5. use PixelFarm's Agg to render to bitmap... //5.1 clear background painter.Clear(PixelFarm.Drawing.Color.White); RectD bounds = new RectD(); BoundingRect.GetBoundingRect(new PixelFarm.Drawing.VertexStoreSnap(vxs), ref bounds); //---------------------------------------------------- float scale = _typeface.CalculateScaleToPixelFromPointSize(_sizeInPoint); _pxscale = scale; this._infoView.PxScale = scale; var left2 = 0; int floor_1 = (int)left2; float diff = left2 - floor_1; //---------------------------------------------------- if (OffsetMinorX) { MinorOffsetInfo = left2.ToString() + " =>" + floor_1 + ",diff=" + diff; } else { MinorOffsetInfo = left2.ToString(); } //5. use PixelFarm's Agg to render to bitmap... //5.1 clear background painter.Clear(PixelFarm.Drawing.Color.White); if (FillBackGround) { //5.2 painter.FillColor = PixelFarm.Drawing.Color.Black; float xpos = 5;// - diff; if (OffsetMinorX) { xpos -= diff; } painter.SetOrigin(xpos, 10); painter.Fill(vxs); } if (DrawBorder) { //5.4 painter.StrokeColor = PixelFarm.Drawing.Color.Green; //user can specific border width here... //5.5 painter.Draw(vxs); //-------------- int markOnVertexNo = _infoView.DebugMarkVertexCommand; double x, y; vxs.GetVertex(markOnVertexNo, out x, out y); painter.FillRect(x, y, 4, 4, PixelFarm.Drawing.Color.Red); //-------------- _infoView.ShowFlatternBorderInfo(vxs); //-------------- } #if DEBUG builder.dbugAlwaysDoCurveAnalysis = false; #endif if (ShowTess) { RenderTessTesult(); } //if (DrawDynamicOutline) //{ // GlyphDynamicOutline dynamicOutline = builder.LatestGlyphFitOutline; // WalkDynamicOutline(painter, dynamicOutline, scale, DrawRegenerateOutline); //} }
public void CalculateUserCharGlyphAdvancePos(ref TextBufferSpan textBufferSpan, ILineSegmentList lineSegs, RequestFont font, int[] outputUserInputCharAdvance, out int outputTotalW, out int lineHeight) { //layout //from font //resolve for typeface // Typeface typeface = ResolveTypeface(font); _typographyTxtServices.SetCurrentFont(typeface, font.SizeInPoints); MyLineSegmentList mylineSegs = (MyLineSegmentList)lineSegs; float scale = typeface.CalculateScaleToPixelFromPointSize(font.SizeInPoints); outputTotalW = 0; int j = mylineSegs.Count; int pos = 0; //start at 0 _reusableTextBuffer.SetRawCharBuffer(textBufferSpan.GetRawCharBuffer()); for (int i = 0; i < j; ++i) { //userGlyphPlanList.Clear(); //userCharToGlyphMapList.Clear(); //get each segment MyLineSegment lineSeg = mylineSegs.GetSegment(i); //each line seg may has different script lang _typographyTxtServices.CurrentScriptLang = lineSeg.scriptLang; // //CACHING ...., reduce number of GSUB/GPOS // //we cache used line segment for a while //we ask for caching context for a specific typeface and font size GlyphPlanSequence seq = _typographyTxtServices.GetUnscaledGlyphPlanSequence(_reusableTextBuffer, lineSeg.StartAt, lineSeg.Length); GlyphPlanList planList = GlyphPlanSequence.UnsafeGetInteralGlyphPlanList(seq); //IMPORTANT //num of glyph may more or less than original user input char buffer // int endAt = seq.startAt + seq.len; int seq_startAt = seq.startAt; for (int s = seq_startAt; s < endAt; ++s) { GlyphPlan glyphPlan = planList[s]; float tx = glyphPlan.ExactX; float ty = glyphPlan.ExactY; double actualAdvX = glyphPlan.AdvanceX; outputTotalW += outputUserInputCharAdvance[pos + glyphPlan.input_cp_offset] += (int)Math.Round(actualAdvX * scale); } pos += lineSeg.Length; } // lineHeight = (int)Math.Round(typeface.CalculateRecommendLineSpacing() * scale); _reusableTextBuffer.SetRawCharBuffer(null); }
//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)); } }
public override float GetScale(float pointSize) { return(typeface.CalculateScaleToPixelFromPointSize(pointSize)); }
public void Layout(IGlyphPositions posStream, PxScaledGlyphPlanList outputGlyphPlanList) { float pxscale = _typeface.CalculateScaleToPixelFromPointSize(this._fontSizeInPoints); if (!UseWithLcdSubPixelRenderingTechnique) { //layout without fit to alignment direction GlyphLayoutExtensions.GenerateGlyphPlans(posStream, pxscale, false, outputGlyphPlanList); return; //early exit } //------------------------------ int finalGlyphCount = posStream.Count; #if DEBUG float dbug_onepx = 1 / pxscale; #endif // int cx = 0; short cy = 0; // //at this state, we need exact info at this specific pxscale // _glyphMeshStore.SetFont(_typeface, this._fontSizeInPoints); FineABC current_ABC = new FineABC(); FineABC prev_ABC = new FineABC(); for (int i = 0; i < finalGlyphCount; ++i) { short input_offset, offsetX, offsetY, advW; //all from pen-pos ushort glyphIndex = posStream.GetGlyph(i, out input_offset, out offsetX, out offsetY, out advW); GlyphControlParameters controlPars = _glyphMeshStore.GetControlPars(glyphIndex); current_ABC.SetData(pxscale, controlPars, offsetX, offsetY, (ushort)advW); //------------------------------------------------------------- if (i > 0) { //inter-glyph space //ideal space float ideal_space = prev_ABC.s_c + current_ABC.s_a; //actual space float actual_space = prev_ABC.m_c + current_ABC.m_a; if (ideal_space < 0) { //f-f //f-o if (prev_ABC.s_c < 0) { ideal_space = 0 + current_ABC.s_a; } if (ideal_space < 0) { ideal_space = 0; } } if (ideal_space >= 0) { //m-a //i-i //o-p if (actual_space > 1.5 && actual_space - 0.5 > ideal_space) { cx--; } else { if (actual_space < ideal_space) { if (prev_ABC.final_advW + prev_ABC.m_c_adjust < prev_ABC.m_max) { cx += current_ABC.m_a_adjust; } } else { if (prev_ABC.final_advW - prev_ABC.m_c + prev_ABC.m_c_adjust > prev_ABC.m_max) { cx += prev_ABC.m_c_adjust; } } } } else { //this should not occur? } } //------------------------------------------------------------- //TODO: review here again*** float exact_x = (float)(cx + current_ABC.s_offsetX); float exact_y = (float)(cy + current_ABC.s_offsetY); //check if the current position can create a sharp glyph int exact_x_floor = (int)exact_x; float x_offset_to_fit = current_ABC.s_avg_x_ToFit; float final_x = exact_x_floor + x_offset_to_fit; if (UseWithLcdSubPixelRenderingTechnique) { final_x += 0.33f; } outputGlyphPlanList.Append(new PxScaledGlyphPlan( input_offset, glyphIndex, (short)current_ABC.final_advW, (short)Math.Round(current_ABC.s_offsetX), (short)Math.Round(current_ABC.s_offsetY) )); // // cx += current_ABC.final_advW; //----------------------------------------------- prev_ABC = current_ABC;//copy current to prev #if DEBUG prev_ABC.dbugIsPrev = true; #endif // Console.WriteLine(exact_x + "+" + (x_offset_to_fit) + "=>" + final_x); } }
void CreateTextureFontFromGlyphIndices( Typeface typeface, float sizeInPoint, HintTechnique hintTechnique, SimpleFontAtlasBuilder atlasBuilder, bool applyFilter, ushort[] glyphIndices) { //sample: create sample msdf texture //------------------------------------------------------------- var builder = new GlyphPathBuilder(typeface); builder.SetHintTechnique(hintTechnique); // if (atlasBuilder.TextureKind == TextureKind.Msdf) { MsdfGenParams msdfGenParams = new MsdfGenParams(); int j = glyphIndices.Length; for (int i = 0; i < j; ++i) { ushort gindex = glyphIndices[i]; //create picture with unscaled version set scale=-1 //(we will create glyph contours and analyze them) builder.BuildFromGlyphIndex(gindex, -1); var glyphToContour = new GlyphContourBuilder(); builder.ReadShapes(glyphToContour); //msdfgen with scale the glyph to specific shapescale msdfGenParams.shapeScale = 1f / 64; //as original GlyphImage glyphImg = MsdfGlyphGen.CreateMsdfImage(glyphToContour, msdfGenParams); // atlasBuilder.AddGlyph(gindex, glyphImg); } } else { AggGlyphTextureGen aggTextureGen = new AggGlyphTextureGen(); aggTextureGen.TextureKind = atlasBuilder.TextureKind; //create reusable agg painter*** //assume each glyph size= 2 * line height //TODO: review here again... int tmpMemBmpHeight = (int)(2 * typeface.CalculateRecommendLineSpacing() * typeface.CalculateScaleToPixelFromPointSize(sizeInPoint)); //create glyph img using (PixelFarm.CpuBlit.MemBitmap tmpMemBmp = new PixelFarm.CpuBlit.MemBitmap(tmpMemBmpHeight, tmpMemBmpHeight)) //square { //draw a glyph into tmpMemBmp and then copy to a GlyphImage aggTextureGen.Painter = PixelFarm.CpuBlit.AggPainter.Create(tmpMemBmp); #if DEBUG tmpMemBmp._dbugNote = "CreateGlyphImage()"; #endif int j = glyphIndices.Length; for (int i = 0; i < j; ++i) { //build glyph ushort gindex = glyphIndices[i]; builder.BuildFromGlyphIndex(gindex, sizeInPoint); GlyphImage glyphImg = aggTextureGen.CreateGlyphImage(builder, 1); if (applyFilter) { glyphImg = Sharpen(glyphImg, 1); //TODO: //the filter make the image shift x and y 1 px //temp fix with this, glyphImg.TextureOffsetX += 1; glyphImg.TextureOffsetY += 1; } // atlasBuilder.AddGlyph(gindex, glyphImg); } } } }