How to Create Subset Fonts in .NET?

后端 未结 5 656
天命终不由人
天命终不由人 2021-01-05 04:35

I have a Silverlight application that I need to embed some less-than-common fonts in. It\'s simple enough for me to just copy over the TTF/OTF and compile that with my app.

5条回答
  •  温柔的废话
    2021-01-05 05:30

    I know it's an old question but I found very difficult to use the CreateFontPackage API from C# (as mentioned by @josh3736's answer) so I thought to share my code.

    I'm using the API with the glyphIndices, you can use it directly with the characters by removing the TTFCFP_FLAGS_GLYPHLIST flag.

    This is my code:

    public byte[] CreateSubset(byte[] inputData, IEnumerable 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
    );
    

    I used with code only with TTF files, for TTC (font collections) you have to change a few things but it should work nonetheless.

提交回复
热议问题