2009-05-23 10 views

risposta

10

In .NET è possibile chiamare Graphics.MeasureString per scoprire come grande testo elaborato sta per essere.

Giusto, ma quando si utilizza PDFsharp si chiama XGraphics.MeasureString.

+1

Questa non sembra la risposta. MeasureString non prende il rect/width e quindi non può conoscere l'altezza disegnata - o ho perso qualcosa? – noelicus

+1

Usa XGraphics.MeasureString per trovare le dimensioni di una singola riga di testo. Vedi la classe XTextFormatter per il codice che interrompe le linee automaticamente (usando MeasureString()). Dovrebbe essere facile aggiungere un nuovo metodo XTextFormatter.MeasureString che restituisce l'altezza. Normalmente utilizziamo MigraDoc nella nostra applicazione in modo da aggiungere solo del testo al documento e MigraDoc si prende cura dei linebreak e delle interruzioni di pagina. –

20

L'oggetto PdfSharp.Drawing.XGraphics ha un metodo MeasureString che restituisce ciò che è necessario.

var pdfDoc = new PdfSharp.Pdf.PdfDocument(); 
var pdfPage = pdfDoc.AddPage(); 
var pdfGfx = PdfSharp.Drawing.XGraphics.FromPdfPage(pdfPage); 
var pdfFont = new PdfSharp.Drawing.XFont("Helvetica", 20); 

while (pdfGfx.MeasureString("Hello World!").Width > pdfPage.Width) 
     --pdfFont.Size; 

pdfGfx.DrawString("Hello World!", pdfFont 
     , PdfSharp.Drawing.XBrushes.Black 
     , new PdfSharp.Drawing.XPoint(100, 100)); 

Questo dovrebbe aiutarti. Si prega di considerare che non ho testato questo codice come l'ho scritto al volo per aiutare. Potrebbe contenere alcuni errori in fase di compilazione, ma potresti avere l'idea.

+0

qual è la classe "PdfSharp"? –

+0

@Chanipoz: questa non è una classe, questa è un'applicazione PDF a più livelli per aiutare la produzione di file PDF al volo sul lato codice. –

0

L'OP ha chiesto come calcolare l'altezza del testo in base alla larghezza disponibile e al tipo di carattere. Windows .NET fornisce una chiamata API per questo che accetta un argomento di larghezza; la versione di PDFsharp che sto usando (0.9.653, .NET 1.1) non lo è.

La mia soluzione: utilizzare la chiamata API .NET con un oggetto Graphics allocato per un oggetto Bitmap creato dall'utente per ottenere la risposta.

Ciò che ha funzionato per me era utilizzare una bitmap con una risoluzione di 100 DPI (critica) e la dimensione di una pagina di ritratto (probabilmente meno critica).

Quindi ho chiesto a .NET quali sarebbero le dimensioni dei pixel per la pittura su tale bitmap.

Probabilmente vorrete convertire le unità da 1/100 di pollice in Punti (per PDFsharp).

 
''' Adapted Code - this not tested or even compiled - Caveat Emptor! 
''' Target: Visual Basic, .NET 1.1 (VS2003) [adapt as necessary] 

' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' 
' GraphicsAlt.MeasureString() does substantially what System.Drawing MeasureString(...,Integer) does. 
' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' 
Public Module GraphicsAlt 

    ' 
    ' Static data used Only to compute MeasureString() below. 
    ' 
    '  Cache a single copy of these two objects, to address an otherwise unexplained intermittent exception. 
    ' 
    Private Shared myImage As Bitmap = Nothing 
    Private Shared myGraphics As Graphics = Nothing 

    Public Shared Function GetMeasureGraphics() As Graphics 
     If myImage Is Nothing Then 
      myImage = New Bitmap(1700, 2200) '' ... Specify 8.5x11 
      myImage.SetResolution(100, 100) '' ... and 100 DPI (if you want different units, you might change this) 
      myGraphics = Graphics.FromImage(myImage) 
     End If 
     Return myGraphics 
    End Function 

    'Given 1/100TH inch max width, return Rect to hold with units 1/100TH inch 
    ' 
    Public Function MeasureString(ByVal text As String, ByVal aFont As System.Drawing.Font, ByVal width As Integer) As System.Drawing.SizeF 
     Return (GraphicsAlt.GetMeasureGraphics()).MeasureString(text, aFont, width) 
    End Function 

End Module 
+0

Sembra un trucco perché i risultati potrebbero differire da XGraphics.MeasureString utilizzato internamente da PDFsharp/MigraDoc a causa di errori di arrotondamento, crenatura, trattamento diverso di grassetto e corsivo. –

5

ho avuto un problema simile quindi ho implementato questo metodo di estensione:

public static double MeasureHeight(this PdfSharp.Drawing.XGraphics gfx, string text, PdfSharp.Drawing.XFont font, int width) 
{ 
    var lines = text.Split('\n'); 

    double totalHeight = 0; 

    foreach (string line in lines) 
    { 
     var size = gfx.MeasureString(line, font); 
     double height = size.Height + (size.Height * Math.Floor(size.Width/width)); 

     totalHeight += height; 
    } 

    return totalHeight; 
} 
+0

Questo ha funzionato bene per me come soluzione rapida e semplice. Tuttavia ho notato che quando si eseguono le dimensioni. Altezza * Math.Floor (size.Width/width), a volte sottovaluta la larghezza (o forse il TextFormatter sovrastima la larghezza durante il wrapping del testo). Quindi ho dovuto aumentare il valore della larghezza di circa il 15% per renderlo più preciso. Non so perché, se qualcuno potesse spiegare che sarebbe utile. –

0

Nel caso qualcuno ha ancora voglia di trovare una risposta, ho implementato un ragionevolmente facile da capire metodo per trovare fuori l'altezza del testo risultante.

Public Function PrintString(text As String, ft As XFont, rect As XRect, graph As XGraphics, b As SolidBrush, Optional tf As XTextFormatter = Nothing) As Integer 
    If Not IsNothing(tf) Then 
     tf.DrawString(text, ft, b, rect) 
    Else 
     Dim drawLeft As New XStringFormat 
     drawLeft.Alignment = XStringAlignment.Near 

     graph.DrawString(text, ft, b, rect, drawLeft) 
    End If 

    Dim width As Double = graph.MeasureString(text, ft).Width 
    Dim multiplier As Integer = 0 

    While width > 0 
     multiplier += 1 

     width -= rect.Width 
    End While 

    Dim height As Double = (graph.MeasureString(text, ft).Height) * multiplier 
    Return height 
End Function 

Spiegando il codice:

In primo luogo, stampare il testo. Ho incluso un XTextFormatter opzionale chiamato tf perché uso XGraphics o XTextFormatters in modo intercambiabile nella mia applicazione.

Quindi, calcolare per quanto tempo il testo era di MeasureString(). Larghezza.

Quindi, calcolare quante righe di testo c'erano.Questo viene fatto dividendo la lunghezza totale del testo trovato in precedenza dalla larghezza del rettangolo (riquadro) fornito dove viene stampata la tassa. L'ho fatto con un ciclo temporale qui.

Moltiplicare l'altezza del testo (utilizzando graph.MeasureString(). Height) per il numero di righe che c'erano. Questa è l'altezza finale del tuo testo.

Restituisce il valore di altezza. Ora, chiamando la funzione PrintString() stamperà il testo fornito restituendo successivamente l'altezza del testo stampato.

+0

Il codice non tiene conto del fatto che XTextFormatter aggiunge interruzioni di riga tra solo parole. Il risultato di PrintString potrebbe essere disattivato da una o più righe. Il codice sorgente per la classe XTextFormatter è incluso in PDFsharp. Questa classe è pensata per far iniziare le persone e puoi aggiungere interruzioni di pagina o un parametro out che restituisce l'altezza. Il ciclo While può essere sostituito da una divisione (ma ciò non migliorerà i risultati). –

+0

@PDFsharpTeam Mi piacerebbe molto sapere come farlo. Mi sono sempre chiesto perché la classe XTextFormatter non restituisca automaticamente l'altezza del testo risultante. Come si modifica la classe? – Wakka02

+0

@ Wakka02 Ho creato una classe XTextFormatterEx basata su XTextFormatter. È stato facile modificare la classe, ma ho avuto alcuni problemi tecnici per farlo compilare. Il codice sorgente completo può essere trovato nel forum PDFsharp. Vedi la mia risposta a questa domanda. –

0

PDFsharp include una classe XTextFormatter che può essere utilizzata per disegnare il testo con interruzioni di riga.

Tuttavia non è possibile determinare l'altezza necessaria per il testo. Ispirato da un commento di @ Wakka02 ho migliorato questa classe, generando la classe XTextFormatterEx.
A mio parere risponde anche alla domanda originale, quindi invio una risposta.
So che questa è una vecchia domanda e la risposta potrebbe non aiutare l'OP, ma è una domanda frequente e la risposta può aiutare gli altri.

La nuova classe ha 500 righe di codice - e penso che questo sarebbe troppo per questo post.

Il codice sorgente può essere trovato sul forum PDFsharp:
http://forum.pdfsharp.net/viewtopic.php?p=9213#p9213

Può anche essere trovato a mio modesto blog:
http://developer.th-soft.com/developer/pdfsharp-improving-the-xtextformatter-class-measuring-the-height-of-the-text/

Quando si utilizza la nuova classe, è possibile chiamare prima PrepareDrawString per scoprire quanta parte del testo si adatta e quale altezza ha il testo di adattamento. Quindi il decodificatore può disegnare il testo preparato o preparare un altro testo o preparare lo stesso testo con un rettangolo diverso.

La mia nuova classe al lavoro: XTextFormatterEx tf = new XTextFormatterEx (gfx); int lastCharIndex; double neededHeight;

// Draw the text in a box with the optimal height 
// (magic: we know that one page is enough). 
XRect rect = new XRect(40, 100, 250, double.MaxValue); 
//tf.Alignment = ParagraphAlignment.Left; 
tf.PrepareDrawString(text, font, rect, 
        out lastCharIndex, out neededHeight); 
rect = new XRect(40, 100, 250, neededHeight); 
gfx.DrawRectangle(XBrushes.SeaShell, rect); 
// Both variants should look the same. 

// Optimized version: draw the prepared string. 
tf.DrawString(XBrushes.Black, XStringFormats.TopLeft); 

La preparazione del testo richiama MeasureString molte volte. Successivamente il testo preparato può essere disegnato senza richiamare MeasureString di nuovo.

A partire da oggi (17 luglio 2015) la classe XTextFormatterEx (come l'originale XTextFormatter) utilizza i campi interni della classe XFont. Ciò richiede un trattamento speciale durante la compilazione della classe. Ho deciso di copiare la mia classe XTextFormatterEx nella cartella PDFsharp dopo aver scaricato il pacchetto sorgente completo per PDFsharp 1.32.
Chiunque tenti di modificare la classe XTextFormatter o XTextFormatterEx dovrà affrontare lo stesso problema.
Spero che questo problema venga risolto con le versioni future di PDFsharp, consentendo l'inclusione di versioni modificate di queste classi nel progetto dell'applicazione.

Problemi correlati