public static extern uint GetGlyphOutline( IntPtr hdc, uint ch, GGOFormat fmt, out GLYPHMETRICS gm, uint bufferSize, IntPtr buffer, ref MAT2 matrix);
public static extern uint GetGlyphOutlineW( [In] SafeHandle hDC, uint uChar, uint fuFormat, [Out] out GLYPHMETRICS lpgm, uint cjBuffer, IntPtr pvBuffer, [In] ref MAT2 lpmat2);
public static extern int GetGlyphOutlineW( IntPtr hdc, int c, int format, ref GLYPHMETRICS metrics, int bufferSize, IntPtr pBuffer, ref MAT2 mat2 );
public static uint hGetGlyphOutlineW(IntPtr hdc, uint uChar, uint uFormat, out GLYPHMETRICS lpgm, uint cbBuffer, IntPtr lpvBuffer, ref MAT2 lpmat2) { uChar = (uint)ParsePtr(ProcessReal(new IntPtr((int)uChar))); #if DEBUG if (Debugging) { Log("OutlineW Hooked, {0:X4}", true, uChar); } #endif if (OutlineW.ImportHook) { return(GetGlyphOutlineW(hdc, uChar, uFormat, out lpgm, cbBuffer, lpvBuffer, ref lpmat2)); } OutlineW.Uninstall(); uint Ret = GetGlyphOutlineW(hdc, uChar, uFormat, out lpgm, cbBuffer, lpvBuffer, ref lpmat2); OutlineW.Install(); return(Ret); }
// Parse a glyph outline in native format public int GetGlyphWidth(Font pIncFont, int charIndex) { GLYPHMETRICS metrics = new GLYPHMETRICS(); MAT2 matrix = new MAT2(); matrix.eM11.value = 1; matrix.eM12.value = 0; matrix.eM21.value = 0; matrix.eM22.value = 1; using (MyDeviceContext dc = new MyDeviceContext()) { Font newFont = new Font(pIncFont.FontFamily, pIncFont.FontFamily.GetEmHeight(pIncFont.Style), pIncFont.Style, GraphicsUnit.Pixel); dc.SelectedFont = newFont; if (GetGlyphOutline(dc.GetHdc(), (uint)charIndex, (uint)GGO_GLYPH_METRICS, out metrics, 0, IntPtr.Zero, ref matrix) != GDI_ERROR) { return((int)((float)metrics.gmCellIncX * 1000.0f / (float)pIncFont.FontFamily.GetEmHeight(pIncFont.Style))); //return metrics.gmBlackBoxX; } } return(0); }
private uint GetGlyphOutline(void *hdc, uint uChar, uint uFormat, out GLYPHMETRICS lpgm, uint cbBuffer, byte *lpvBuffer, ref MAT2 lpmat2) { uChar = (uint)EntryPoint.Process((void *)uChar); return(Bypass(hdc, uChar, uFormat, out lpgm, cbBuffer, lpvBuffer, ref lpmat2)); }
internal static extern uint GetGlyphOutlineW(IntPtr hdc, uint uChar, uint uFormat, out GLYPHMETRICS lpgm, uint cbBuffer, IntPtr lpvBuffer, ref MAT2 lpmat2);
public FontOutline?GetOutline(string text, OutlineMode outlineMode) { if (SharedFont.OutlineTextMetric is null) { return(null); } // 参考文献 // http://marupeke296.com/TIPS_Main.html // http://marupeke296.com/WINT_GetGlyphOutline.html // http://marupeke296.com/DXG_No67_NewFont.html // https://msdn.microsoft.com/ja-jp/library/cc410385.aspx // https://msdn.microsoft.com/ja-jp/library/cc428640.aspx // https://www11.atwiki.jp/slice/pages/78.html // http://dendrocopos.jp/tips/win32.html // http://www.geocities.co.jp/Playtown-Dice/9391/program/win04.html // http://misohena.jp/article/ggo_trap/index.html // https://oshiete.goo.ne.jp/qa/4743793.html // http://eternalwindows.jp/graphics/bitmap/bitmap12.html // https://social.msdn.microsoft.com/Forums/ja-JP/3442d813-823a-449a-993e-7fc073aea949/opentype?forum=vcgeneralja // http://phys.cool.coocan.jp/physjpn/htextmetric.htm // https://docs.microsoft.com/ja-jp/windows/desktop/api/wingdi/ns-wingdi-_outlinetextmetricw // // 参考資料 // https://support.microsoft.com/en-us/help/87115/how-to-getglyphoutline-native-buffer-format // http://kone.vis.ne.jp/diary/diaryb08.html // https://msdn.microsoft.com/ja-jp/library/windows/desktop/dd144891(v=vs.85).aspx // try { GLYPHMETRICS metrics = new GLYPHMETRICS(); MAT2 matrix = new MAT2(); matrix.eM11.value = 1; matrix.eM12.value = 0; matrix.eM21.value = 0; matrix.eM22.value = 1; using (var hdc = DeviceContextSafeHandle.CreateMesurementDeviceContext()) { // アウトライン取得用のフォントを生成。この時フォントサイズは制御店のメッシュサイズと一致させる。 // 一致しない場合は取得されるアウトラインの精度が著しく低下する場合がある。 var outlineAccessFont = Gdi32FontPool.GetPoolingFont(Key.FaceName, FontSizeUnit.Pixel, SharedFont.OutlineTextMetric.Value.otmEMSquare, Key.Weight, Key.Italic, Key.Underline, Key.StrikeOut, Key.CharSet, Key.FontQuality); if (outlineAccessFont.SharedFont.OutlineTextMetric is null) { return(null); } var selectResult = NativeApi.SelectObject(hdc, outlineAccessFont.Handle); if (selectResult == IntPtr.Zero) { throw new Win32Exception(); } NativeApi.GetCharacterPlacement(hdc, text, GCPFlags.GCP_GLYPHSHAPE, out var characterPlacement); if (characterPlacement.Glyphs is null || characterPlacement.Glyphs.Length == 0) { return(null); } var size = NativeApi.GetTextExtentPoint(hdc, text); uint glyphIndex = (uint)characterPlacement.Glyphs[0]; uint format = GGO_GLYPH_INDEX | (outlineMode == OutlineMode.Bezier ? GGO_BEZIER : GGO_NATIVE); int bufferSize = (int)NativeApi.GetGlyphOutline(hdc, glyphIndex, format, out metrics, 0, IntPtr.Zero, ref matrix); if (bufferSize <= 0) { return(null); } IntPtr buffer = Marshal.AllocHGlobal(bufferSize); List <TtPolygon> ttPolygons = new List <TtPolygon>(); try { uint ret = NativeApi.GetGlyphOutline(hdc, glyphIndex, format, out metrics, (uint)bufferSize, buffer, ref matrix); if (ret == GDI_ERROR) { throw new Win32Exception(Marshal.GetLastWin32Error()); } int polygonHeaderSize = Marshal.SizeOf(typeof(TTPOLYGONHEADER)); int curveHeaderSize = Marshal.SizeOf(typeof(TTPOLYCURVEHEADER)); int pointFxSize = Marshal.SizeOf(typeof(POINTFX)); int index = 0; while (index < bufferSize) { TTPOLYGONHEADER header = (TTPOLYGONHEADER)Marshal.PtrToStructure(new IntPtr(buffer.ToInt64() + index), typeof(TTPOLYGONHEADER)); POINTFX startPoint = header.pfxStart; // サイズをfontEmSquareで指定して内部メッシュと一致させているので、正しくできている限り端数は生じない。 Debug.Assert(startPoint.x.fract == 0); Debug.Assert(startPoint.y.fract == 0); int endCurvesIndex = index + header.cb; index += polygonHeaderSize; List <TtPolygonCurve> ttPolygonCurves = new List <TtPolygonCurve>(); while (index < endCurvesIndex) { TTPOLYCURVEHEADER curveHeader = (TTPOLYCURVEHEADER)Marshal.PtrToStructure(new IntPtr(buffer.ToInt64() + index), typeof(TTPOLYCURVEHEADER)); index += curveHeaderSize; TtPolygonPoint[] curvePoints = new TtPolygonPoint[curveHeader.cpfx]; for (int i = 0; i < curveHeader.cpfx; i++) { var curvePoint = (POINTFX)Marshal.PtrToStructure(new IntPtr(buffer.ToInt64() + index), typeof(POINTFX)); // サイズをfontEmSquareで指定して内部メッシュと一致させているので、正しくできている限り端数は生じない。 // ただし、ベジェ曲線に変換している場合は制御店の創出により端数が生じる。 Debug.Assert(outlineMode != OutlineMode.Native || curvePoint.x.fract == 0); Debug.Assert(outlineMode != OutlineMode.Native || curvePoint.y.fract == 0); curvePoints[i] = curvePoint.ToTtPolygonPoint(outlineAccessFont.SharedFont.OutlineTextMetric.Value, metrics); index += pointFxSize; } TtPrimitiveTypes type; switch (curveHeader.wType) { case TT_PRIM_LINE: type = TtPrimitiveTypes.Line; break; case TT_PRIM_QSPLINE: Debug.Assert(outlineMode == OutlineMode.Native); type = TtPrimitiveTypes.QuadraticBezierSpline; break; case TT_PRIM_CSPLINE: Debug.Assert(outlineMode == OutlineMode.Bezier); type = TtPrimitiveTypes.CubicBezierSpline; break; default: throw new FormatException(); } ttPolygonCurves.Add(new TtPolygonCurve(type, curvePoints.ToImmutableArray())); } ttPolygons.Add(new TtPolygon(startPoint.ToTtPolygonPoint(outlineAccessFont.SharedFont.OutlineTextMetric.Value, metrics), ttPolygonCurves.ToImmutableArray())); } } finally { Marshal.FreeHGlobal(buffer); } Debug.Assert(metrics.gmCellIncX >= 0); Debug.Assert(metrics.gmCellIncY >= 0); var glyphMetrics = new GlyphMetrics(metrics.gmBlackBoxX, metrics.gmBlackBoxY, metrics.gmptGlyphOrigin.x, metrics.gmptGlyphOrigin.y, metrics.gmCellIncX, metrics.gmCellIncY); return(new FontOutline( outlineAccessFont.SharedFont.OutlineTextMetric.Value.otmEMSquare, outlineAccessFont.SharedFont.OutlineTextMetric.Value.otmMacAscent, glyphMetrics, ttPolygons.ToImmutableArray() )); } } catch (Win32Exception ex) { Debug.WriteLine(ex); return(null); } }
public static extern int GetGlyphOutline(IntPtr hdc, uint uChar, uint uFormat, ref GLYPHMETRICS lpgm, uint cbBuffer, byte[] lpvBuffer, [In] ref MAT2 lpmat2);
static extern uint GetGlyphOutline(IntPtr hdc, uint uChar, uint uFormat, out GLYPHMETRICS lpgm, uint cbBuffer, IntPtr lpvBuffer, ref MAT2 lpmat2);
// Parse a glyph outline in native format public int GetGlyphWidth(Font pIncFont, int charIndex) { GLYPHMETRICS metrics = new GLYPHMETRICS(); MAT2 matrix = new MAT2(); matrix.eM11.value = 1; matrix.eM12.value = 0; matrix.eM21.value = 0; matrix.eM22.value = 1; using (MyDeviceContext dc = new MyDeviceContext()) { Font newFont = new Font(pIncFont.FontFamily, pIncFont.FontFamily.GetEmHeight(pIncFont.Style), pIncFont.Style, GraphicsUnit.Pixel); dc.SelectedFont = newFont; if (GetGlyphOutline(dc.GetHdc(), (uint)charIndex, (uint)GGO_GLYPH_METRICS, out metrics, 0, IntPtr.Zero, ref matrix) != GDI_ERROR) { return (int)((float)metrics.gmCellIncX * 1000.0f / (float)pIncFont.FontFamily.GetEmHeight(pIncFont.Style)); //return metrics.gmBlackBoxX; } } return 0; }
public static extern uint GetGlyphOutline(DeviceContextSafeHandle hdc, uint uChar, uint uFormat, out GLYPHMETRICS lpgm, uint cbBuffer, IntPtr lpvBuffer, ref MAT2 lpmat2);