private void button2_Click(object sender, EventArgs e) { //test text service if (_textService == null) { _textService = new TextServiceHub(); } Typography.TextServices.TextShapingService shapingService = _textService.ShapingService; shapingService.SetCurrentFont(_basicOptions.Typeface.Name, InstalledFontStyle.Normal, 8); shapingService.SetCurrentScriptLang(Typography.OpenFont.ScriptLangs.Latin); GlyphPlanSequence seq = shapingService.LayoutText("Hello"); //---- // test render the output selectedTextPrinter = _devVxsTextPrinter; selectedTextPrinter.Typeface = _basicOptions.Typeface; selectedTextPrinter.FontSizeInPoints = _basicOptions.FontSizeInPoints; selectedTextPrinter.ScriptLang = _basicOptions.ScriptLang; selectedTextPrinter.PositionTechnique = _basicOptions.PositionTech; selectedTextPrinter.HintTechnique = HintTechnique.None; selectedTextPrinter.EnableLigature = true; _devVxsTextPrinter.UpdateGlyphLayoutSettings(); //------------- //pre-render painter.Clear(PixelFarm.Drawing.Color.White); painter.UseSubPixelRendering = false; painter.FillColor = PixelFarm.Drawing.Color.Black; _devVxsTextPrinter.TargetCanvasPainter = painter; //*** essential *** //render!, float x = 20, y = 200; _devVxsTextPrinter.DrawFromGlyphPlans( GlyphPlanSequence.UnsafeGetInteralGlyphPlanList(seq), seq.startAt, seq.len, x, y); //---------- //use this util to copy image from Agg actual image to System.Drawing.Bitmap PixelFarm.Agg.Imaging.BitmapHelper.CopyToGdiPlusBitmapSameSize(painter.Graphics.DestActualImage, winBmp); //---------------- //copy from Agg's memory buffer to gdi //PixelFarm.Agg.Imaging.BitmapHelper.CopyToGdiPlusBitmapSameSize(destImg, winBmp); g.Clear(Color.White); g.DrawImage(winBmp, new Point(10, 0)); }
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); }
public void PrepareStringForRenderVx(RenderVxFormattedString renderVx, char[] buffer, int startAt, int len) { int j = buffer.Length; //create temp buffer span that describe the part of a whole char buffer TextBufferSpan textBufferSpan = new TextBufferSpan(buffer, startAt, len); //ask text service to parse user input char buffer and create a glyph-plan-sequence (list of glyph-plan) //with specific request font GlyphPlanSequence glyphPlanSeq = _textServices.CreateGlyphPlanSeq(ref textBufferSpan, font); float scale = _fontAtlas.TargetTextureScale; int recommendLineSpacing = _fontAtlas.OriginalRecommendLineSpacing; //-------------------------- //TODO: //if (x,y) is left top //we need to adjust y again float x = 0; float y = 0; y -= ((recommendLineSpacing) * scale); renderVx.RecommmendLineSpacing = (int)(recommendLineSpacing * scale); // float scaleFromTexture = _finalTextureScale; TextureKind textureKind = _fontAtlas.TextureKind; //-------------------------- //TODO: review render steps //NOTE: // -glyphData.TextureXOffset => restore to original pos // -glyphData.TextureYOffset => restore to original pos // ideal_x = (float)(x + (glyph.x * scale - glyphData.TextureXOffset) * scaleFromTexture); // ideal_y = (float)(y + (glyph.y * scale - glyphData.TextureYOffset + srcRect.Height) * scaleFromTexture); //-------------------------- 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); // vboBufferList2.Clear(); indexList2.Clear(); float acc_x = 0; float acc_y = 0; for (int i = glyphPlanSeq.startAt; i < endBefore; ++i) { UnscaledGlyphPlanList glyphPlanList = GlyphPlanSequence.UnsafeGetInteralGlyphPlanList(glyphPlanSeq); UnscaledGlyphPlan glyph = glyphPlanList[i]; Typography.Rendering.TextureFontGlyphData glyphData; if (!_fontAtlas.TryGetGlyphDataByGlyphIndex(glyph.glyphIndex, out glyphData)) { //if no glyph data, we should render a missing glyph *** continue; } //-------------------------------------- //TODO: review precise height in float //-------------------------------------- PixelFarm.Drawing.Rectangle srcRect = ConvToRect(glyphData.Rect); float ngx = acc_x + (float)Math.Round(glyph.OffsetX * scale); float ngy = acc_y + (float)Math.Round(glyph.OffsetY * scale); //NOTE: // -glyphData.TextureXOffset => restore to original pos // -glyphData.TextureYOffset => restore to original pos //-------------------------- g_x = (float)(x + (ngx - glyphData.TextureXOffset) * scaleFromTexture); //ideal x g_y = (float)(y + (ngy - glyphData.TextureYOffset + srcRect.Height) * scaleFromTexture); acc_x += (float)Math.Round(glyph.AdvanceX * scale); //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( vboBufferList2, indexList2, ref srcRect, g_x, g_y, scaleFromTexture); break; } } //--------- DrawingGL.GLRenderVxFormattedString renderVxFormattedString = (DrawingGL.GLRenderVxFormattedString)renderVx; renderVxFormattedString.IndexArray = indexList2.ToArray(); renderVxFormattedString.VertexCoords = vboBufferList2.ToArray(); renderVxFormattedString.VertexCount = indexList2.Count; }
public void DrawString(char[] buffer, int startAt, int len, double x, double y) { _glsx.FontFillColor = painter.FontFillColor; int j = buffer.Length; //create temp buffer span that describe the part of a whole char buffer TextBufferSpan textBufferSpan = new TextBufferSpan(buffer, startAt, len); //ask text service to parse user input char buffer and create a glyph-plan-sequence (list of glyph-plan) //with specific request font GlyphPlanSequence glyphPlanSeq = _textServices.CreateGlyphPlanSeq(ref textBufferSpan, font); float scale = _fontAtlas.TargetTextureScale; int recommendLineSpacing = _fontAtlas.OriginalRecommendLineSpacing; //-------------------------- //TODO: //if (x,y) is left top //we need to adjust y again y -= ((_fontAtlas.OriginalRecommendLineSpacing) * scale); EnsureLoadGLBmp(); // float scaleFromTexture = _finalTextureScale; TextureKind textureKind = _fontAtlas.TextureKind; float g_x = 0; float g_y = 0; int baseY = (int)Math.Round(y); int n = glyphPlanSeq.len; int endBefore = glyphPlanSeq.startAt + n; //------------------------------------- _glsx.LoadTexture1(_glBmp); //------------------------------------- _vboBufferList.Clear(); //clear before use _indexList.Clear(); //clear before use float acc_x = 0; float acc_y = 0; for (int i = glyphPlanSeq.startAt; i < endBefore; ++i) { UnscaledGlyphPlanList glyphPlanList = GlyphPlanSequence.UnsafeGetInteralGlyphPlanList(glyphPlanSeq); UnscaledGlyphPlan glyph = glyphPlanList[i]; Typography.Rendering.TextureFontGlyphData glyphData; if (!_fontAtlas.TryGetGlyphDataByGlyphIndex(glyph.glyphIndex, out glyphData)) { //if no glyph data, we should render a missing glyph *** continue; } //-------------------------------------- //TODO: review precise height in float //-------------------------------------- PixelFarm.Drawing.Rectangle srcRect = ConvToRect(glyphData.Rect); float ngx = acc_x + (float)Math.Round(glyph.OffsetX * scale); float ngy = acc_y + (float)Math.Round(glyph.OffsetY * scale); //NOTE: // -glyphData.TextureXOffset => restore to original pos // -glyphData.TextureYOffset => restore to original pos //-------------------------- g_x = (float)(x + (ngx - glyphData.TextureXOffset) * scaleFromTexture); //ideal x g_y = (float)(y + (ngy - glyphData.TextureYOffset + srcRect.Height) * scaleFromTexture); acc_x += (float)Math.Round(glyph.AdvanceX * scale); //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; } } //------- //we create vbo first //then render _glsx.DrawGlyphImageWithSubPixelRenderingTechnique3(_vboBufferList.ToArray(), _indexList.ToArray()); }
private void button1_Click(object sender, EventArgs e) { selectedTextPrinter = _devVxsTextPrinter; selectedTextPrinter.Typeface = _basicOptions.Typeface; selectedTextPrinter.FontSizeInPoints = _basicOptions.FontSizeInPoints; selectedTextPrinter.ScriptLang = _basicOptions.ScriptLang; selectedTextPrinter.PositionTechnique = _basicOptions.PositionTech; selectedTextPrinter.HintTechnique = HintTechnique.None; selectedTextPrinter.EnableLigature = true; _devVxsTextPrinter.UpdateGlyphLayoutSettings(); //------- var editableTextBlockLayoutEngine = new EditableTextBlockLayoutEngine(); editableTextBlockLayoutEngine.DefaultTypeface = _basicOptions.Typeface; editableTextBlockLayoutEngine.FontSizeInPts = _basicOptions.FontSizeInPoints; editableTextBlockLayoutEngine.LoadText("ABCD\r\n EFGH!"); editableTextBlockLayoutEngine.DoLayout(); //then we render the output to the screen //see UpdateRenderOutput() code //clear previous draw //---------------- //------------- painter.Clear(PixelFarm.Drawing.Color.White); painter.UseSubPixelLcdEffect = false; painter.FillColor = PixelFarm.Drawing.Color.Black; _devVxsTextPrinter.TargetCanvasPainter = painter; List <EditableTextLine> textlines = editableTextBlockLayoutEngine.UnsafeGetEditableTextLine(); //render eachline with painter int lineCount = textlines.Count; float x = 0; int y = 200; int lineSpacing = (int)_devVxsTextPrinter.FontLineSpacingPx; for (int i = 0; i < lineCount; ++i) { EditableTextLine line = textlines[i]; List <IRun> runs = line.UnsageGetTextRunList(); int runCount = runs.Count; for (int r = 0; r < runCount; ++r) { IRun run = runs[r]; TextRun textRun = run as TextRun; if (textRun == null) { continue; } // GlyphPlanSequence seq = textRun.GetGlyphPlanSeq(); _devVxsTextPrinter.DrawFromGlyphPlans( GlyphPlanSequence.UnsafeGetInteralGlyphPlanList(seq), seq.startAt, seq.len, x, y); x += run.Width; y -= lineSpacing; //next line? } x = 0; //reset at newline } //---------- //use this util to copy image from Agg actual image to System.Drawing.Bitmap PixelFarm.Agg.Imaging.BitmapHelper.CopyToGdiPlusBitmapSameSize(painter.RenderSurface.DestActualImage, winBmp); //---------------- //copy from Agg's memory buffer to gdi //PixelFarm.Agg.Imaging.BitmapHelper.CopyToGdiPlusBitmapSameSize(destImg, winBmp); g.Clear(Color.White); g.DrawImage(winBmp, new Point(10, 0)); }
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); UnscaledGlyphPlanList 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; //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.TextureFontGlyphData 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; // } //} ////--------- for (int s = seq_startAt; s < endAt; ++s) { UnscaledGlyphPlan glyphPlan = planList[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); }