8
votes

Comment créer des polices de sous-ensemble dans .NET?

J'ai une application Silverlight que j'ai besoin d'intégrer certaines polices moins que communes. C'est assez simple pour que je puisse simplement copier sur le TTF / OTF et compiler avec mon application. Cependant, dans de nombreux cas, seuls 5-10 des caractères sont réellement utilisés. Dans d'autres cas, certains fichiers de polices sont incroyablement volumineux ( Arial Unicode MS System est de 22,1 Mo, à titre d'exemple). Les heures de téléchargement rapide de mon application sont vraiment importantes, afin d'optimiser les polices utilisées est primordiale.

Alors, ce que je pensais, c'est que j'ai vu dans des applications telles que l'expression mélangeur où un est utilisé pour créer une police en lecture seule et vous pouvez également choisir d'incorporer certains caractères. Dans d'autres circonstances, j'ai vu que les gens utilisent des polices qui contiennent certains caractères sous forme de sous-ensemble de la police complète (et non d'utiliser un dans Silverlight, mais utilisent simplement le sous-sol -Setf comme .) C'est un peu ce que je suis après, sauf que je n'utilise pas les expressions.

Je ne cherche pas de solution de contournement sournoise, comme l'exportation vers un fichier XPS et saisir le fichier .odtff.

Y a-t-il une manière programmatique (.NET / GDI +) pour créer un sous-ensemble d'une police avec seulement certains caractères et le compiler à un .ttf / .otf? En outre, cela aurait également besoin de fonctionner pour des fichiers .TTC.


0 commentaires

5 Réponses :


5
votes

L'API Native Createefontpackage peut être quoi vous cherchez. Vous pouvez transmettre une TTF et une liste de caractères à conserver. Si vous passez ttfcfp_subset pour USSubsetFormat , vous récupérerez ensuite un TTF de travail avec uniquement ces caractères.

Voici un thread avec ce qui semble être le code d'un exemple de travail (en C , malheureusement).


2 commentaires

C'est intéressant, merci pour le lien. Espérait que quelque chose serait dans .NET, ou au moins un exemple d'utilisation de cela de .NET.


@Otaku: Ce message A le code P / invoke nécessaire (voir Second Post) pour utiliser l'API dans .NET.



5
votes

dans WPF pour les polices Il existe une liaison statique et dynamique. Tout peut être défini dans le mélange. Avec une liaison statique des polices, seuls les caractères nécessaires sont compilés et intégrés dans votre assemblée. Avec une liaison dynamique, tout le jeu de polices est intégré. Ainsi, essayez de définir une liaison statique pour les polices sélectionnées et essayez si cela fonctionne si cela fonctionne.

upd fort> p>

Essayez d'ajouter le code suivant dans votre .csproj code> déposer. Ici, nous incluons les polices de Tahoma. La propriété Autofill définie sur True dit que nous allons intégrer à l'assemblage uniquement des caractères de nos commandes. L'ensemble des caractères dans Code> Point de remplissage des balises Pour inclure ces caractères en montage. Toutes les autres balises définies sur FALSE, car nous n'avons pas besoin d'eux. P>

<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" />


11 commentaires

J'ai regardé msdn.microsoft.com/en-us/library/ms753303.aspx et cela indique spécifiquement que WPF n'a pas la possibilité de créer des polices de sous-ensemble. Je n'utilise pas non plus de mélange du tout pour cela, alors je cherche un moyen de le faire de manière programmatique .NET.


Voir la mise à jour. Si vous n'utilisez pas Mélange, cela peut vous aider (j'espère).


Cela semble vraiment prometteur - en fait, si je pouvais le faire fonctionner, ce serait exactement ce dont j'ai besoin. Cette page donne un échantillon: codeProject.com/kb/silverlight/newindianduppesyMBoldemo.aspx. L'échantillon fonctionne, mais quand j'essaie de le faire seul dans un projet séparé, il échoue. Je ne reçois pas un de l'IDE, mais même l'ajout manuellement cela ne fonctionne pas. Je ne sais pas ce que je fais mal.


Essayez d'installer MS Expression Blend au moins une version d'essai afin que cette extension apparaisse.


Ouais, j'ai essayé ça. Pas de chance. Avez-vous BlendembeddedFont dans la construction de l'action lors de l'ajout d'une police?


Non, je n'ai pas sur ma machine à domicile, seulement au travail (j'ai installé Blend 3.0). Vous devriez regarder vers ce genre des tags. Expérimentez avec eux et jetez un coup d'œil à des versions de votre logiciel, je veux dire si vous avez SL 4.0 puis utilisez approprié. Obtenez l'exemple de CP et essayez de déterminer ce qui est nécessaire pour utiliser cette extension.


Oui, je vais me jouer avec elle pour voir si je peux le faire travailler.


Quel environnement avez-vous sur votre machine, je veux dire versions de VS, SL et Mélange?


Gagnez XP, VS2008 W / SP1, SL3, SL 3 SDK, Expressions Mélange 3 (essai)


Enfin, ça va travailler - belle! Remarque: Les expressions Blend ne sont pas nécessaires - juste le mélange 3.0 ou 4.0 SDK (gratuit) fonctionnera.


Super! Je suis content pour toi! Merci de note.



0
votes

Fontforge ( http://fontforge.sourceforge.net/ ) est un éditeur de polices open source qui Permet des conversions de format automatisées. On dirait que c'est seulement python mais cela peut valoir la peine de vérifier.


1 commentaires

Cela a une API pour la création de sous-ensembles de polices?



4
votes

Modification de la réponse acceptée à celle-ci, car elle est pure .Net sans références externes. Utilise .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


2 commentaires

Je me demandais à quel point la Déclaration de GT sert-t-elle? Il n'est pas utilisé après que cela a été déclaré ...


@Brianthomas, ouais, désolé pour ça, c'était un artefact de plus de code. Ce n'est pas utilisé dans cet exemple. N'hésitez pas à éditer le code.



1
votes

Je sais que c'est une vieille question, mais j'ai trouvé très difficile d'utiliser le Createefontpackage Code> API de C # (comme indiqué par la réponse de @ Josh3736), donc je pensais partager mon code.

Je suis Utilisation de l'API avec les glyphindices, vous pouvez l'utiliser directement avec les caractères en supprimant le drapeau ttfcfp_flags_glyphlist code>. p>

Ceci est mon code: P>

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
);


0 commentaires