2010-07-14 29 views
6

Tôi có một ứng dụng Silverlight mà tôi cần để nhúng một số phông chữ ít phổ biến hơn. Nó đủ đơn giản để tôi chỉ sao chép qua TTF/OTF và biên dịch với ứng dụng của tôi. Tuy nhiên, trong nhiều trường hợp, chỉ có khoảng 5-10 ký tự thực sự được sử dụng. Trong các trường hợp khác, một số tệp phông chữ cực kỳ lớn (Arial Unicode MS Thường xuyên là 22,1 MB, làm ví dụ). Thời gian tải xuống nhanh của ứng dụng của tôi thực sự quan trọng, vì vậy việc tối ưu hóa phông chữ được sử dụng là tối quan trọng.Làm thế nào để tạo phông chữ tập hợp con trong .NET?

Vì vậy, những gì tôi đã suy nghĩ là tôi đã thấy trong các ứng dụng như Expression Blend, nơi <Glyph/>is used to create a read-only font và bạn cũng có thể chỉ chọn nhúng các ký tự nhất định. Trong các trường hợp khác, tôi đã thấy mọi người sử dụng phông chữ chỉ chứa các ký tự nhất định dưới dạng tập hợp con của phông chữ đầy đủ (và không sử dụng <Glyph/> trong Silverlight, mà chỉ sử dụng tập con .TTF là <FontFamily/>.) về những gì tôi theo sau, ngoại trừ tôi không sử dụng Biểu thức.

Tôi không tìm cách giải quyết lén lút, như xuất sang tệp XPS và lấy tệp .odtff.

Có cách lập trình (.NET/GDI +) để tạo một tập con của một phông chữ chỉ với một số ký tự nhất định và biên dịch nó thành .TTF/.OTF? Ngoài ra, điều này cũng cần phải làm việc cho các tệp .TTC.

Trả lời

3

Thay đổi câu trả lời được chấp nhận cho câu trả lời này là thuần túy. NET không có tham chiếu bên ngoài. Sử dụng .NET 4.0:

Imports System.Windows.Media 
Imports System.Text.Encoding 
Imports System.Collections 

Public Sub CreateSubSet(sourceText As String, fontURI As Uri) 
    Dim gt As FontEmbeddingManager = New FontEmbeddingManager 

    Dim glyphTypeface As GlyphTypeface = New GlyphTypeface(fontURI) 
    Dim Index As Generic.ICollection(Of UShort) 
    Index = New Generic.List(Of UShort) 
    Dim sourceTextBytes As Byte() = Unicode.GetBytes(sourceText) 
    Dim sourceTextChars As Char() = Unicode.GetChars(sourceTextBytes) 
    Dim sourceTextCharVal As Integer 
    Dim glyphIndex As Integer 
    For sourceTextCharPos = 0 To UBound(sourceTextChars) 
     sourceTextCharVal = AscW(sourceTextChars(sourceTextCharPos)) 
     glyphIndex = glyphTypeface.CharacterToGlyphMap(sourceTextCharVal) 
     Index.Add(glyphIndex) 
    Next 
    Dim filebytes() As Byte = glyphTypeface.ComputeSubset(Index) 
    Using fileStream As New System.IO.FileStream("C:\Users\Me\new-subset.ttf", System.IO.FileMode.Create) 
     fileStream.Write(filebytes, 0, filebytes.Length) 
    End Using 
End Sub 
+0

Tôi tự hỏi mục đích của tuyên bố gt là gì? Nó không được sử dụng sau khi nó được khai báo ... –

+0

@ BrianTHOMAS, vâng, xin lỗi về điều đó, nó là một tạo phẩm từ nhiều mã hơn. nó không được sử dụng trong ví dụ này. vui lòng chỉnh sửa mã. –

5

API gốc CreateFontPackage có thể là những gì bạn đang tìm kiếm. Bạn có thể vượt qua TTF và danh sách các ký tự cần lưu giữ. Nếu bạn vượt qua TTFCFP_SUBSET cho usSubsetFormat, thì bạn sẽ lấy lại TTF đang hoạt động chỉ với những ký tự đó.

Here's a thread có vẻ như mã của ví dụ đang hoạt động (trong C, thật không may).

+0

Điều này thật thú vị, cảm ơn liên kết. Đã hy vọng một cái gì đó sẽ được trong NET, hoặc ít nhất là một ví dụ về cách sử dụng này từ. –

+0

@Otaku: [Bài đăng này] (http://social.msdn.microsoft.com/Forums/en/csharplanguage/thread/1652a9fb-87ab-4725-8a73-7f1015519a71) có mã P/Invoke cần thiết (xem bài đăng thứ hai) để sử dụng API trong .NET. – josh3736

+0

Cảm ơn Josh, tôi sẽ xem xét kỹ điều này. –

5

Trong WPF cho phông chữ có liên kết tĩnh và động. Tất cả có thể được định nghĩa trong Blend. Với liên kết tĩnh của các phông chữ chỉ các ký tự cần thiết được biên dịch và nhúng trong assembly của bạn. Với liên kết động, tất cả các tập hợp phông chữ được nhúng. Vì vậy, hãy thử thiết lập liên kết tĩnh cho các phông chữ được chọn và thử nếu nó hoạt động.

UPD

Cố gắng thêm đoạn mã sau vào bạn .csproj tập tin. Ở đây chúng tôi bao gồm phông chữ Tahoma. Thuộc tính AutoFill được đặt thành true cho biết rằng chúng tôi sẽ nhúng trong các assembly chỉ sử dụng các ký tự của các điều khiển của chúng tôi. Tập hợp các ký tự trong <Charachters/> điểm điền thẻ để bao gồm các ký tự này vào trong assembly. Tất cả các thẻ khác được đặt thành false, bởi vì chúng tôi không cần chúng.

<ItemGroup> 
    <BlendEmbeddedFont Include="Fonts\tahoma.ttf"> 
     <IsSystemFont>True</IsSystemFont> 
     <All>False</All> 
     <AutoFill>True</AutoFill> 
     <Characters>dasf</Characters> 
     <Uppercase>False</Uppercase> 
     <Lowercase>False</Lowercase> 
     <Numbers>False</Numbers> 
     <Punctuation>False</Punctuation> 
    </BlendEmbeddedFont> 
    <BlendEmbeddedFont Include="Fonts\tahomabd.ttf"> 
     <IsSystemFont>True</IsSystemFont> 
     <All>False</All> 
     <AutoFill>True</AutoFill> 
     <Characters>dasf</Characters> 
     <Uppercase>False</Uppercase> 
     <Lowercase>False</Lowercase> 
     <Numbers>False</Numbers> 
     <Punctuation>False</Punctuation> 
    </BlendEmbeddedFont> 
    </ItemGroup> 
    <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> 

    <Import Project="$(MSBuildExtensionsPath)\Microsoft\Expression\Blend\3.0\WPF\Microsoft.Expression.Blend.WPF.targets" /> 
+0

Tôi đã xem http://msdn.microsoft.com/en-us/library/ms753303.aspx và nó nói rõ rằng WPF không có khả năng tạo phông chữ con. Tôi cũng không sử dụng Blend ở tất cả cho điều này, vì vậy tôi đang tìm một cách để làm điều này lập trình trong. –

+0

Xem cập nhật. Nếu bạn không sử dụng Blend, điều này có thể giúp bạn (tôi hy vọng). –

+0

Điều này có vẻ * thực sự * hứa hẹn - trên thực tế, nếu tôi có thể làm cho nó hoạt động, đây sẽ là chính xác những gì tôi cần. Trang này cung cấp một mẫu: http://www.codeproject.com/KB/silverlight/NewIndianRupeeSymbolDemo.aspx. Các mẫu hoạt động, nhưng khi tôi cố gắng làm điều này một mình trong một dự án riêng biệt, nó không thành công. Tôi không nhận được một '' từ IDE, nhưng thậm chí thêm nó bằng tay cũng không hoạt động. Không chắc mình đang làm gì sai. –

0

FontForge (http://fontforge.sourceforge.net/) là trình chỉnh sửa phông chữ nguồn mở cho phép chuyển đổi định dạng tự động. Có vẻ như nó chỉ là Python nhưng nó có thể đáng để kiểm tra.

+0

Điều này có một số API để tạo ra các tập con phông? –

1

Tôi biết đó là một câu hỏi cũ nhưng tôi thấy rất khó để sử dụng CreateFontPackage API từ C# (như đã đề cập bởi câu trả lời @ josh3736 của) vì vậy tôi nghĩ để chia sẻ mã của tôi.

Tôi đang sử dụng API với glyphIndices, bạn có thể sử dụng nó trực tiếp với các ký tự bằng cách xóa cờ TTFCFP_FLAGS_GLYPHLIST.

Đây là mã của tôi:

public byte[] CreateSubset(byte[] inputData, IEnumerable<ushort> glyphIndices) 
{ 
    AllocProc allocProc = Marshal.AllocHGlobal; 
    ReallocProc reallocProc = (p, c) => 
     p == IntPtr.Zero 
      ? Marshal.AllocHGlobal(c) 
      : Marshal.ReAllocHGlobal(p, c); 
    FreeProc freeProc = Marshal.FreeHGlobal; 

    var resultCode = CreateFontPackage(
     inputData, (uint) inputData.Length, 
     out var bufferPtr, 
     out _, 
     out var bytesWritten, 
     TTFCFP_FLAGS_SUBSET | TTFCFP_FLAGS_GLYPHLIST, 
     0, 
     TTFMFP_SUBSET, 
     0, 
     TTFCFP_MS_PLATFORMID, 
     TTFCFP_UNICODE_CHAR_SET, 
     glyphIndices, 
     (ushort)glyphIndices.Length, 
     allocProc, reallocProc, freeProc, (IntPtr)0); 

    if (resultCode != 0 || bufferPtr == IntPtr.Zero) 
    { 
     return null; 
    } 

    try 
    { 
     var buffer = new byte[bytesWritten]; 
     Marshal.Copy(bufferPtr, buffer, 0, buffer.Length); 
     return buffer; 
    } 
    finally 
    { 
     freeProc(bufferPtr); 
    } 
} 

internal const ushort TTFCFP_FLAGS_SUBSET = 0x0001; 
internal const ushort TTFCFP_FLAGS_COMPRESS = 0x0002; 
internal const ushort TTFCFP_FLAGS_TTC = 0x0004; 
internal const ushort TTFCFP_FLAGS_GLYPHLIST = 0x0008; 

internal const ushort TTFMFP_SUBSET = 0x0000; 

internal const ushort TTFCFP_UNICODE_PLATFORMID = 0x0000; 
internal const ushort TTFCFP_MS_PLATFORMID = 0x0003; 

internal const ushort TTFCFP_UNICODE_CHAR_SET = 0x0001; 

[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)] 
private delegate IntPtr AllocProc(Int32 size); 

[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)] 
private delegate IntPtr ReallocProc(IntPtr memBlock, IntPtr size); 

[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)] 
private delegate void FreeProc(IntPtr memBlock); 

[DllImport("FontSub.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)] 
private static extern uint CreateFontPackage(
    [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] 
    byte[] puchSrcBuffer, 
    uint ulSrcBufferSize, 
    out IntPtr puchFontPackageBufferPtr, 
    out uint pulFontPackageBufferSize, 
    out uint pulBytesWritten, 
    ushort usFlags, 
    ushort usTtcIndex, 
    ushort usSubsetFormat, 
    ushort usSubsetLanguage, 
    ushort usSubsetPlatform, 
    ushort usSubsetEncoding, 
    [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 12)] 
    ushort[] pusSubsetKeepList, 
    ushort usSubsetKeepListCount, 
    AllocProc lpfnAllocate, 
    ReallocProc lpfnReAllocate, 
    FreeProc lpfnFree, 
    IntPtr lpvReserved 
); 

tôi đã sử dụng với mã chỉ với các file TTF, cho TTC (bộ sưu tập font chữ), bạn cần phải thay đổi một vài điều nhưng nó phải làm việc dù sao.

Các vấn đề liên quan