Closed mhjy closed 1 month ago
FWIW, that's quite common - you need to learn more about graphics in general. Space has zero width and zero row, which describes the size of the drawn pixels. There is no pixels drawn. Spaces have a non-zero "advance width" or "advance". That's the shift in positioning for the next non-space character.
The positioning and width/row are separate - it is possible for a character to partly overlap its previous or the next character, or have gaps. So the (pixel) width can be large than the advance (width) in these cases.
You can read two examples in freetype-py - python binding of freetype, which is similar since SharpFont is really just c# binding of freetype:
They do the same thing. Cairo does not let you draw zero width pixel chunks, but numpy does, hence there is an extra "if ..." in one. But other than that, both do x += advance ...
below to reposition for the next character.
Disclaimer: I wrote the cairo version, and is co-maintainer of freetype-py.
the code "Bitmap cBmp = face.Glyph.Bitmap.ToGdipBitmap(Color.Firebrick);" has mistake?
namespace SharpFont.HarfBuzz.Example { class Program { static void Main(string[] args) { Console.WriteLine("Version string: " + HB.VersionString); Version v = HB.Version; Console.WriteLine("Version: " + v.Major + "." + v.Minor + "." + v.Build); Console.WriteLine("VersionCheck: " + HB.VersionAtLeast(v));
var lib = new Library();
var face = new SharpFont.Face(lib, @"C:\Windows\Fonts\汉仪雪峰体简.ttf");
//var face = new SharpFont.Face(lib, @"C:\Windows\Fonts\tahoma.ttf");
//var face = new SharpFont.Face(lib, @"C:\Windows\Fonts\GLTHawangTig.ttf");
face.SetCharSize(0, 50, 72, 72);
var font = HarfBuzz.Font.FromFTFace(face);
var buf = new HarfBuzz.Buffer();
//buf.Direction = Direction.TopToBottom;
//buf.Direction= Direction.RightToLeft;
buf.Direction = Direction.LeftToRight;
//buf.Script = Script.Arabic;
buf.Script = Script.Mongolian;
buf.AddText("ᠥᠩᠬᠡᠵᠠᠶᠠᠭ ᠠ");//ᠥᠩᠬᠡᠵᠠᠶᠠᠭ ᠠ1234 计算机");
font.Shape(buf);
var glyphInfos = buf.GlyphInfo();
var glyphPositions = buf.GlyphPositions();
int height = (face.MaxAdvanceHeight - face.Descender) >>6;
int width = 0;
for (int i = 0; i < glyphInfos.Length; ++i)
{
width += glyphPositions[i].xAdvance>> 6;
}
Bitmap bmp = new Bitmap(width, height);
Graphics g = Graphics.FromImage(bmp);
g.Clear(Color.Gray);
int penX = 0, penY = face.MaxAdvanceHeight >> 6;
//draw the string
for (int i = 0; i < glyphInfos.Length; ++i)
{
face.LoadGlyph(glyphInfos[i].codepoint, LoadFlags.Default, LoadTarget.Normal);
face.Glyph.RenderGlyph(RenderMode.Normal);
Bitmap cBmp = face.Glyph.Bitmap.ToGdipBitmap(Color.Firebrick);
g.DrawImageUnscaled(cBmp,
penX + (glyphPositions[i].xOffset >> 6) + face.Glyph.BitmapLeft,
penY - (glyphPositions[i].yOffset >> 6) - face.Glyph.BitmapTop);
penX += glyphPositions[i].xAdvance >> 6;
penY -= glyphPositions[i].yAdvance >> 6;
}
g.Dispose();
bmp.Save("output.bmp");
}
}
}
Not looking at your code in detail - it is your own job to figure out what's wrong with it. I already gave you a clue telling you cairo's drawing routine has a similar issue. I.e. most likely you need to insert a if (pixel_width > 0)
before ...Bitmap cBmp...
. Already told you that some drawing libraries (numpy/pillow) let you draw zero pixels, some (cairo) don't let you draw zero pixels.
In the the latter case, you simply skip the draw as there is nothing to draw, but keep doing the re-positioning of the pen. Ie. You mostly likely need to modify your code to looks a bit like this (not debugged , and please do not complain about cut-and-paste into yours don't work):
...
face.LoadGlyph(glyphInfos[i].codepoint, LoadFlags.Default, LoadTarget.Normal);
face.Glyph.RenderGlyph(RenderMode.Normal);
If (pixel_width > 0) {
Bitmap cBmp = face.Glyph.Bitmap.ToGdipBitmap(Color.Firebrick);
g.DrawImageUnscaled(cBmp,
penX + (glyphPositions[i].xOffset >> 6) + face.Glyph.BitmapLeft,
penY - (glyphPositions[i].yOffset >> 6) - face.Glyph.BitmapTop);
}
penX += glyphPositions[i].xAdvance >> 6;
penY -= glyphPositions[i].yAdvance >> 6;
}
...
Thank you very much! ..................... if (face.Glyph.Bitmap.Width>0) { Bitmap cBmp = face.Glyph.Bitmap.ToGdipBitmap(Color.Firebrick); g.DrawImageUnscaled(cBmp, penX + (glyphPositions[i].xOffset >> 6) + face.Glyph.BitmapLeft, penY - (glyphPositions[i].yOffset >> 6) - face.Glyph.BitmapTop); } penX += glyphPositions[i].xAdvance >> 6; penY -= glyphPositions[i].yAdvance >> 6; ................................
I want to draw a text include space. But the program throw the exception: if (b.Width == 0 || b.Rows == 0) throw new InvalidOperationException("Invalid image size - one or both dimensions are 0.");