2014-11-19 3 views
0

글리프 위치 문자를 제공하는 Windows의 단순하고 호환되는 GDI 또는 .NET 액세스 가능 하위 시스템이 있습니까? 이 작업은 아라비아어와 같은 결합 기호입니다.이 조합 기호는 때로는 아랍어 Fatha + 아라비아 문자 Superscript Alef + 아랍어 Maddah 위와 같이 서로 결합하여 여러 결합 기호 체인을가집니다. 문제는 X 위치가 GDI GetCharacterPlacement로 정확하게 결정될 수 있지만 OpenType 또는 TrueType 글꼴 테이블과 앵커 및 복잡한 규칙 집합에서 파생 된 Y 위치 계산을 사용할 수 없다는 점입니다. 궁극적으로 올바른 형식의 아랍어로 PDF를 생성하려면 Y 위치가 정확하고 정확하게 필요합니다. Microsoft Word 2013의 PDF 저장 기능을 연구 한 결과, 각 문자가 결합 기호를 포함하여 정확한 위치에 표시된다는 것을 PDF 세부 정보를 조사 할 때이 데이터를 올바르게 수집하는 방법이 있음이 분명합니다.Windows에서 글리프 위치 계산

WPF에는 GlyphRun 클래스 속성 인 GlyphOffsets에서이 작업을 수행 할 수있는 몇 가지 기능이 포함될 수 있습니다. DirectWrite에는 IDWriteTextAnalyzer 인터페이스가 있으며 GetGlyphPlacements 메서드는 DWRITE_GLYPH_OFFSETs 및 기타 여러 가지 복잡한 스크립트 정보를 반환 할 수 있습니다. GDI 디스플레이 및 프린터 드라이브 기능을 살펴보면 STROBJ_bEnumPositionsOnly는이 정보가있는 GLYPHPOS 구조체 집합을 반환하는 것으로 보입니다. GDI는 렌더링 할 전체 텍스트를 보내지 만 글리프로 그리핀을 수행하려는 경우가 아니라면 모든 상황에서이를 올바르게 렌더링합니다.

XPS 개체 모델의 IXpsOMGlyph는이 라이브러리가 거의 적합하지 않지만 XPS_GLYPH_INDEX 집합을 반환하는 GetGlyphIndices 호출에서 horizontalOffset 및 verticalOffset을 제공합니다.

마지막으로 적절한 라이브러리는 Uniscribe로 보이지만 Internet Explorer 5 및 Windows 2000 이후로는 일반적으로 Vista 이상이며 특별한 종속성이 필요한 GDI 이상의 다른 모든 토론과 달리 사용하기가 복잡하지만 지원됩니다. ScriptItemize는 ScriptShace에 전달할 수있는 SCRIPT_STRING_ANALYSIS의 배열을 반환 한 다음 ScriptFlace는 배열을 반환합니다 (GOFFSET). 실제로 Uniscribe는 단어 분리, 발음 구별 부호, 방향 흐름 및 복잡한 스크립트에서 일어나는 일의 많은 다른 측면에 대한 정보를 제공합니다. 나는 Unrecribe가 .NET에서 직접 사용하기가 극히 어려우며 합리적으로 C++ 래퍼가 필요할 것이므로 간단한 메소드가 있는지 또는 Uniscribe가 이러한 작업에 필요한 최소 및 정확한지 여부를 알고 싶었습니다. 구조와 포인터의 거래.

업데이트 및 답변 : GDI 장치 단위에서 정수를 사용하므로 Uniscribe가 PDF 용으로 작동하지 않으므로 정확도가 크게 떨어집니다. 아마 DirectWrite가 의지하는 것 같기 때문에 아마 Microsoft Word 2013이 네이티브 PDF 변환 지원을 지원하는 이유 일 것입니다. 아래에서 언급했듯이 나는 CodeProject에 대한 팁으로 .NET에서 두 가지 코드 솔루션을 모두 게시했습니다. DirectWrite는 사용자 정의 글꼴 모양 및 계산 엔진을 설계하는 것 이상의 유일한 대답 인 것 같습니다. .NET에서

+1

글쎄, 당신의 마지막 단락은 잘 정리해 것으로 보인다. Uniscribe 사용은 어렵지만 어려운 문제이기 때문에 Uniscribe를 사용하는 것이 어렵습니다. 그것 없이는하는 것이 얼마나 힘든지 상상해보십시오. – usr2564301

답변

1

샘플 유니 스크라이브 (Uniscribe) 코드는 현재 웹에 없습니다 이후 :

 
    _ 
    Public Structure GCP_RESULTS 
     Public StructSize As UInteger 
     _ 
     Public OutString As String 
     Public Order As IntPtr 
     Public Dx As IntPtr 
     Public CaretPos As IntPtr 
     Public [Class] As IntPtr 
     Public Glyphs As IntPtr 
     Public GlyphCount As UInteger 
     Public MaxFit As Integer 
    End Structure 
    _ 
    Public Structure SCRIPT_CONTROL 
     Public ScriptControlFlags As UInteger 
    End Structure 
    _ 
    Public Structure SCRIPT_STATE 
     Public ScriptStateFlags As UShort 
    End Structure 
    _ 
    Public Structure SCRIPT_ANALYSIS 
     Public ScriptAnalysisFlags As UShort 
     Public s As SCRIPT_STATE 
    End Structure 
    _ 
    Public Structure SCRIPT_VISATTR 
     Public ScriptVisAttrFlags As UShort 
    End Structure 
    _ 
    Public Structure SCRIPT_ITEM 
     Public iCharPos As Integer 
     Public a As SCRIPT_ANALYSIS 
    End Structure 
    _ 
    Public Structure GOFFSET 
     Public du As Integer 
     Public dv As Integer 
    End Structure 
    _ 
    Public Structure ABC 
     Public abcA As Integer 
     Public abcB As UInteger 
     Public abcC As Integer 
    End Structure 
    Public Const E_OUTOFMEMORY As Integer = &H8007000E 
    Public Const E_PENDING As Integer = &H8000000A 
    Public Const USP_E_SCRIPT_NOT_IN_FONT As Integer = &H80040200 
    _ 
    Public Shared Function GetCharacterPlacement(hdc As IntPtr, lpString As String, nCount As Integer, nMaxExtent As Integer, ByRef lpResults As GCP_RESULTS, dwFlags As UInteger) As UInteger 
    End Function 
    _ 
    Public Shared Function ScriptItemize(wcInChars As String, cInChars As Integer, cMaxItems As Integer, psControl As SCRIPT_CONTROL, psState As SCRIPT_STATE, pItems() As SCRIPT_ITEM, ByRef pcItems As Integer) As Integer 
    End Function 
    _ 
    Public Shared Function ScriptShape(hdc As IntPtr, ByRef psc As IntPtr, wcChars As String, cChars As Integer, cMaxGlyphs As Integer, ByRef psa As SCRIPT_ANALYSIS, wOutGlyphs() As UShort, wLogClust() As UShort, psva() As SCRIPT_VISATTR, ByRef cGlyphs As Integer) As Integer 
    End Function 
    _ 
    Public Shared Function ScriptPlace(hdc As IntPtr, ByRef psc As IntPtr, wGlyphs() As UShort, cGlyphs As Integer, psva() As SCRIPT_VISATTR, ByRef psa As SCRIPT_ANALYSIS, iAdvance() As Integer, pGoffset() As GOFFSET, ByRef pABC As ABC) As Integer 
    End Function 
    _ 
    Public Shared Function ScriptFreeCache(ByRef psc As IntPtr) As Integer 
    End Function 
    _ 
    Public Shared Function GetDC(hWnd As IntPtr) As IntPtr 
    End Function 
    _ 
    Public Shared Function ReleaseDC(hWnd As IntPtr, hdc As IntPtr) As Integer 
    End Function 
    _ 
    Private Shared Function SelectObject(ByVal hdc As IntPtr, ByVal hObject As IntPtr) As IntPtr 
    End Function 
    Structure CharPosInfo 
     Public Index As Integer 
     Public Width As Integer 
     Public PriorWidth As Integer 
     Public X As Integer 
     Public Y As Integer 
    End Structure 
    Public Shared Function GetWordDiacriticPositions(Str As String, useFont As Font) As CharPosInfo() 
     Dim hdc As IntPtr 
     Dim CharPosInfos As New List(Of CharPosInfo) 
     hdc = GetDC(IntPtr.Zero) 'desktop device context 
     Dim oldFont As IntPtr = SelectObject(hdc, useFont.ToHfont()) 
     Dim MaxItems As Integer = 16 
     Dim Control As New SCRIPT_CONTROL With {.ScriptControlFlags = 0} 
     Dim State As New SCRIPT_STATE With {.ScriptStateFlags = 1} '0 LTR, 1 RTL 
     Dim Items() As SCRIPT_ITEM = Nothing 
     Dim ItemCount As Integer 
     Dim Result As Integer 
     Do 
      ReDim Items(MaxItems - 1) 
      Result = ScriptItemize(Str, Str.Length, MaxItems, Control, State, Items, ItemCount) 
      If Result = 0 Then 
       ReDim Preserve Items(ItemCount) 'there is a dummy last item so adding one here 
       Exit Do 
      ElseIf Result = E_OUTOFMEMORY Then 
      End If 
      MaxItems *= 2 
     Loop While True 
     If Result = 0 Then 
      'last item is dummy item pointing to end of string 
      Dim Cache As IntPtr = IntPtr.Zero 
      For Count = 0 To ItemCount - 2 
       Dim Logs() As UShort = Nothing 
       Dim Glyphs() As UShort = Nothing 
       Dim VisAttrs() As SCRIPT_VISATTR = Nothing 
       ReDim Glyphs((Items(Count + 1).iCharPos - Items(Count).iCharPos) * 3 \ 2 + 16 - 1) 
       ReDim VisAttrs((Items(Count + 1).iCharPos - Items(Count).iCharPos) * 3 \ 2 + 16 - 1) 
       ReDim Logs(Items(Count + 1).iCharPos - Items(Count).iCharPos - 1) 
       Dim dc As IntPtr = IntPtr.Zero 
       Do 
        Dim GlyphsUsed As Integer 
        Result = ScriptShape(dc, Cache, Str.Substring(Items(Count).iCharPos), Items(Count + 1).iCharPos - Items(Count).iCharPos, Glyphs.Length, Items(Count).a, Glyphs, Logs, VisAttrs, GlyphsUsed) 
        If Result = 0 Then 
         ReDim Preserve Glyphs(GlyphsUsed - 1) 
         ReDim Preserve VisAttrs(GlyphsUsed - 1) 
         Exit Do 
        ElseIf Result = E_PENDING Then 
         dc = hdc 
        ElseIf Result = E_OUTOFMEMORY Then 
         ReDim Glyphs(Glyphs.Length * 2 - 1) 
         ReDim VisAttrs(VisAttrs.Length * 2 - 1) 
        ElseIf Result = USP_E_SCRIPT_NOT_IN_FONT Then 
        Else 
        End If 
       Loop While True 
       If Result = 0 Then 
        Dim Advances(Glyphs.Length - 1) As Integer 
        Dim Offsets(Glyphs.Length - 1) As GOFFSET 
        Dim abc As New ABC With {.abcA = 0, .abcB = 0, .abcC = 0} 
        dc = IntPtr.Zero 
        Do 
         Result = ScriptPlace(dc, Cache, Glyphs, Glyphs.Length, VisAttrs, Items(Count).a, Advances, Offsets, abc) 
         If Result E_PENDING Then Exit Do 
         dc = hdc 
        Loop While True 
        If Result = 0 Then 
         Dim LastPriorWidth As Integer = 0 
         Dim RunStart As Integer = 0 
         For CharCount = 0 To Logs.Length - 1 
          Dim PriorWidth As Integer = 0 
          Dim RunCount As Integer = 0 
          For ResCount As Integer = Logs(CharCount) To If(CharCount = Logs.Length - 1, 0, Logs(CharCount + 1)) Step -1 
           'fDiacritic or fZeroWidth 
           If (VisAttrs(ResCount).ScriptVisAttrFlags And (32 Or 64)) 0 Then 
            CharPosInfos.Add(New CharPosInfo With {.Index = RunStart + RunCount, .PriorWidth = LastPriorWidth, .Width = Advances(ResCount), .X = Offsets(ResCount).du, .Y = Offsets(ResCount).dv}) 
           End If 
           If CharCount = Logs.Length - 1 OrElse Logs(CharCount) Logs(CharCount + 1) Then 
            PriorWidth += Advances(ResCount) 
            RunCount += 1 
           End If 
          Next 
          LastPriorWidth += PriorWidth 
          If CharCount = Logs.Length - 1 OrElse Logs(CharCount) Logs(CharCount + 1) Then 
           RunStart = CharCount + 1 
          End If 
         Next 
        End If 
       End If 
      Next 
      ScriptFreeCache(Cache) 
     End If 
     SelectObject(hdc, oldFont) 
     ReleaseDC(IntPtr.Zero, hdc) 
     Return CharPosInfos.ToArray() 
    End Function 
+0

.. 이제는! http://www.codeproject.com/Tips/844745/Analyzing-Text-With-DirectWrite-in-NET-Using-Sharp – usr2564301