Question

Je génère un reçu et j'utilise l'objet Graphics pour appeler la méthode DrawString afin d'imprimer le texte requis.

graphics.DrawString(string, font, brush, widthOfPage / 2F, yPoint, stringformat);

Cela fonctionne bien pour ce que j’avais besoin de faire. J'ai toujours su ce que j'imprimais afin de pouvoir couper manuellement les chaînes pour qu'elles tiennent correctement sur du papier de reçu de 80 mm. Ensuite, j'ai dû ajouter un peu plus de fonctionnalités pour rendre cela plus flexible. L'utilisateur peut passer des chaînes qui seraient ajoutées au bas.

Comme je ne savais pas ce qu'ils allaient mettre, je viens de créer ma propre fonction de retour à la ligne qui englobe un certain nombre de caractères et la chaîne elle-même. Afin de connaître le nombre de caractères, je faisais quelque chose comme ceci:

float width = document.DefaultPageSettings.PrintableArea.Width;
int max = (int)(width / graphics.MeasureString("a", font).Width);

Maintenant, la largeur me renvoie 283, ce qui en mm est environ 72, ce qui est logique lorsque vous prenez en compte les marges sur du papier 80 mm.

Mais la méthode MeasureString renvoie 10.5 sur une police Courier New 8pt. Donc, au lieu d’éviter ce que j’espérais être entre 36 et 40, j’en ai 26, ce qui donne deux lignes de texte transformées en 3-4.

Les unités pour PrintableArea.Width sont égales à 1 / 100ème de pouce et le PageUnit pour l’objet graphique est Display (ce qui est généralement 1 / 100ème de pouce pour les imprimantes). Alors, pourquoi n’en ai-je que 26?

Était-ce utile?

La solution

À partir de WindowsClient.net:

  

GDI + ajoute une petite quantité (1/6 em) à chaque extrémité de chaque chaîne affichée. Ce 1/6 em tient compte des glyphes aux extrémités débordantes (comme l'italique ' f '), et donne également à GDI + une petite marge de manœuvre pour aider à l'expansion de l'ajustement de la grille.

     

L'action par défaut de DrawString fonctionnera contre vous pour l'affichage des exécutions adjacentes:

     
      
  • Tout d'abord, le format par défaut StringFormat ajoute un 1/6 supplémentaire à chaque extrémité de chaque sortie;
  •   
  • Deuxièmement, lorsque les largeurs ajustées de la grille sont inférieures à celles prévues, la chaîne est autorisée à se contracter jusqu'à un em.
  •   
     

Pour éviter ces problèmes:

     
      
  • Passez toujours MeasureString et DrawString à un StringFormat basé sur le typographique StringFormat ( GenericTypographic ).
      Définissez TextRenderingHint sur TextRenderingHintAntiAlias ??. Cette méthode de rendu utilise un anti-crénelage et un positionnement des glyphes de sous-pixels pour éviter la nécessité d'une adaptation de la grille. Elle est donc intrinsèquement indépendante de la résolution.
  •   

Il existe deux manières de dessiner du texte dans .NET:

  • GDI + ( graphics.MeasureString et graphics.DrawString )
  • GDI ( TextRenderer.MeasureText et TextRenderer.DrawText )

Tiré de l'excellent blog de Michael Kaplan (rip) Tout trier , dans .NET 1.1, tout ce qui était utilisé GDI + pour le rendu du texte. Mais il y avait quelques problèmes:

  
      
  • Certains problèmes de performances sont dus à la nature un peu sans état de GDI +: les contextes de périphérique sont définis, puis l'original est restauré après chaque appel.
  •   
  • Les moteurs de mise en forme du texte international ont été mis à jour plusieurs fois pour Windows / Uniscribe et Avalon (Windows Presentation Foundation), mais pas pour GDI +, ce qui empêche la prise en charge du rendu international des nouvelles langues qualité.
  •   

Ils savaient donc qu'ils souhaitaient modifier le cadre .NET afin de cesser d'utiliser le système de rendu de texte de GDI + et d'utiliser GDI . Au début, ils espéraient pouvoir changer simplement:

graphics.DrawString

pour appeler l'ancienne API DrawText au lieu de GDI +. Mais ils ne pouvaient pas faire en sorte que le retour à la ligne et l'espacement du texte correspondent exactement à ce que GDI + faisait. Ils ont donc été obligés de garder graphics.DrawString pour appeler GDI + (raisons de compatibilité; les personnes qui appelaient graphics.DrawString s'apercevraient soudainement que leur texte ne fermait pas la manière dont il était écrit. habitué).

Une nouvelle classe statique TextRenderer a été créée pour envelopper le rendu de texte GDI. Il existe deux méthodes:

TextRenderer.MeasureText
TextRenderer.DrawText
  

Remarque: TextRenderer est un wrapper autour de GDI, alors que graphics.DrawString est toujours un wrapper autour de GDI +.

Il y avait ensuite la question de savoir quoi faire avec tous les contrôles .NET existants, par exemple:

.
  • Étiquette
  • Bouton
  • TextBox

Ils voulaient les changer pour utiliser TextRenderer (c'est-à-dire GDI), mais ils devaient faire attention. Il se peut que certaines personnes dépendent de leurs contrôles comme elles le faisaient dans .NET 1.1. Et ainsi est né le rendu de texte compatible ".

Par défaut, les contrôles de l'application se comportent comme ils le faisaient dans .NET 1.1 (ils sont " compatibles ").

Vous désactivez le mode de compatibilité en appelant:

Application.SetCompatibleTextRenderingDefault(false);

Cela rend votre application meilleure, plus rapide, avec un meilleur support international. Pour résumer:

SetCompatibleTextRenderingDefault(true)  SetCompatibleTextRenderingDefault(false)
=======================================  ========================================
 default                                  opt-in
 bad                                      good
 the one we don't want to use             the one we want to use
 uses GDI+ for text rendering             uses GDI for text rendering
 graphics.MeasureString                   TextRenderer.MeasureText
 graphics.DrawString                      TextRenderer.DrawText
 Behaves same as 1.1                      Behaves *similar* to 1.1
                                          Looks better
                                          Localizes better
                                          Faster

Il est également utile de noter le mappage entre GDI + TextRenderingHint et le LOGFONT Qualité utilisée pour le dessin de police GDI:

TextRenderingHint           mapped by TextRenderer to LOGFONT quality
========================    =========================================================
ClearTypeGridFit            CLEARTYPE_QUALITY (5) (Windows XP: CLEARTYPE_NATURAL (6))
AntiAliasGridFit            ANTIALIASED_QUALITY (4)
AntiAlias                   ANTIALIASED_QUALITY (4)
SingleBitPerPixelGridFit    PROOF_QUALITY (2)
SingleBitPerPixel           DRAFT_QUALITY (1)
else (e.g.SystemDefault)    DEFAULT_QUALITY (0)

Échantillons

Voici quelques comparaisons entre le rendu de texte GDI + (graphics.DrawString) et le rendu de texte GDI (TextRenderer.DrawText):

GDI + : TextRenderingHintClearTypeGridFit , GDI : CLEARTYPE_QUALITY :

entrer la description de l'image ici

GDI + : TextRenderingHintAntiAlias ??, GDI : ANTIALIASED_QUALITY :

entrer la description de l'image ici

GDI + : TextRenderingHintAntiAliasGridFit , GDI : non pris en charge, utilise ANTIALIASED_QUALITY :

:

entrer la description de l'image ici

GDI + : TextRenderingHintSingleBitPerPixelGridFit , GDI : PROOF_QUALITY :

entrer la description de l'image ici

GDI + : TextRenderingHintSingleBitPerPixel , GDI : DRAFT_QUALITY :

entrer la description de l'image ici

Je trouve étrange que DRAFT_QUALITY soit identique à PROOF_QUALITY , qui est identique à CLEARTYPE_QUALITY .

Voir aussi

Autres conseils

Nouveau coursier 11

Lorsque vous créez une police 'Courier New' avec Size = 11, vous obtenez une sortie similaire à celle de l'image ci-dessus. Vous voyez que la hauteur est de 14 pixels sans compter le soulignement. La largeur est exactement de 14 pixels (7 pixels pour chaque caractère).

Ainsi, cette police affiche 14 x 14 pixels.

Mais TextRenderer.MeasureText () renvoie plutôt une largeur de 21 pixels. Si vous avez besoin de valeurs exactes, cela ne sert à rien.

La solution est le code suivant:

Font i_Courier = new Font("Courier New", 11, GraphicsUnit.Pixel);

Win32.SIZE k_Size;
using (Bitmap i_Bmp = new Bitmap(200, 200, PixelFormat.Format24bppRgb))
{
    using (Graphics i_Graph = Graphics.FromImage(i_Bmp))
    {
        IntPtr h_DC = i_Graph.GetHdc();
        IntPtr h_OldFont = Win32.SelectObject(h_DC, i_Courier.ToHfont());

        Win32.GetTextExtentPoint32(h_DC, "Áp", 2, out k_Size);

        Win32.SelectObject(h_DC, h_OldFont);
        i_Graph.ReleaseHdc();
    }
}

k_Size contiendra la taille correcte: 14x14

IMPORTANT: Ce code mesure correctement une police standard. Si vous avez besoin des valeurs exactes également pour les polices italiques (qui ont toujours un surplomb à droite), vous devez lire les liens mentionnés dans cet article: http://www.codeproject.com/Articles/14915/Width-of-text-in-italic-font

APPENDICE: Pour ceux qui n'ont jamais utilisé d'appels d'API en C #, voici un indice sur la création de la classe Win32. Ce n'est pas complet. Pour plus de détails, consultez http://www.pinvoke.net

using System.Runtime.InteropServices;

public class Win32
{       
    [StructLayout(LayoutKind.Sequential)]
    public struct SIZE
    {
        public int cx;
        public int cy;
    }

    [DllImport("Gdi32.dll")]
    public static extern bool GetTextExtentPoint32(IntPtr hdc, string lpString, int cbString, out SIZE lpSize);

    [DllImport("Gdi32.dll")]
    public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
}

Voici une explication qui peut vous aider à comprendre comment cela fonctionne. et ce qui cause les espaces de plus ou moins avant et après chaque caractère.

application de configuration GDI DrawString

Capture d'écran

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top