2009-05-23 29 views

Respuesta

10

En .NET puede llamar Graphics.MeasureString para averiguar cómo grande el texto dibujado va a ser.

Correcto, pero cuando usa PDFsharp llama a XGraphics.MeasureString.

+1

Esto no parece ser la respuesta. MeasureString no toma rect/width y por lo tanto no puede saber la altura dibujada, ¿o me he perdido algo? – noelicus

+1

Utilice XGraphics.MeasureString para buscar las dimensiones de una sola línea de texto. Consulte la clase XTextFormatter para ver el código que divide líneas automáticamente (usando MeasureString()). Debería ser fácil agregar un nuevo método XTextFormatter.MeasureString que devuelve la altura. Normalmente utilizamos MigraDoc en nuestra aplicación, por lo que solo agregamos texto al documento y MigraDoc se preocupa por los saltos de línea y saltos de página. –

20

El objeto PdfSharp.Drawing.XGraphics tiene un método MeasureString que devuelve lo que necesita.

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

Esto debería ayudarlo. Tenga en cuenta que no probé este código porque lo escribí sobre la marcha para ayudar. Puede contener algunos errores en tiempo de compilación, pero puede que se haga una idea.

+0

¿con qué clase "PdfSharp"? –

+0

@ Chanipoz: Esto no es realmente una clase, esta es una aplicación PDF de nivel n para ayudar a la producción de archivos PDF sobre la marcha en el lado del código. –

0

El OP preguntó cómo calcular la altura del texto según ancho disponible y fuente. Windows .NET proporciona una llamada de API para esto que toma un argumento de ancho; la versión de PDFsharp que estoy usando (0.9.653, .NET 1.1) no.

Mi solución: utilice la llamada API .NET con un objeto Graphics asignado para un objeto Bitmap personalizado para obtener la respuesta.

Lo que funcionó para mí fue utilizar un mapa de bits que tenía una resolución de 100 DPI (crítico) y resultó ser del tamaño de una página de retrato (probablemente menos crítica).

Luego le pregunté a .NET cuál sería el tamaño de píxel para pintar en ese mapa de bits.

Probablemente querrás convertir las unidades de 1/100 de pulgada a Puntos (para 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

Eso suena como un hack ya que los resultados pueden diferir de XGraphics.MeasureString utilizado por PDFsharp/MigraDoc internamente debido a errores de redondeo, kerning, diferente tratamiento de negrita y cursiva. –

5

que tenía un problema similar por lo que he implementado este método de extensión:

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

Esto funcionó bien para mí como una solución rápida y simple. Sin embargo, me di cuenta de que al hacer el tamaño. Height * Math.Floor (size.Width/width), a veces subestimará el ancho (o tal vez el TextFormatter sobrestima el ancho al envolver el texto). Así que tuve que aumentar el valor del ancho en aproximadamente un 15% para hacerlo más preciso. No estoy seguro de por qué, si alguien pudiera explicar eso sería útil. –

0

Por si alguien aún quiere encontrar una respuesta, he implementado un razonablemente fácil de entender método para encontrar a la altura del texto resultante.

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 

Al explicar el código:

En primer lugar, se imprime el texto. Incluí un XTextFormatter opcional llamado tf porque uso XGraphics o XTextFormatters indistintamente en mi aplicación.

Luego, calcule cuánto tiempo estuvo el texto por MeasureString(). Ancho.

Luego, calcule cuántas líneas de texto hay.Esto se hace dividiendo la longitud total del texto encontrado anteriormente por el ancho del rectángulo provisto (recuadro) donde se imprime el impuesto. Lo hice con un ciclo while aquí.

Multiplique la altura del texto (usando graph.MeasureString(). Height) por el número de líneas que haya. Esta es la altura final de su texto.

Devuelve el valor de la altura. Ahora, al llamar a la función PrintString(), se imprimirá el texto provisto y al mismo tiempo se devolverá el alto del texto impreso.

+0

El código no tiene en cuenta que XTextFormatter agrega saltos de línea entre palabras solamente. El resultado de PrintString puede estar desactivado en una o más líneas. El código fuente de la clase XTextFormatter se incluye con PDFsharp. Esta clase está destinada a hacer que la gente comience y puede agregar saltos de página o un parámetro de salida que devuelve la altura. El ciclo While puede ser reemplazado por una división (pero esto no mejorará los resultados). –

+0

@PDFsharpTeam Me gustaría saber cómo hacerlo. Siempre me he preguntado por qué la clase XTextFormatter no devuelve automáticamente la altura del texto resultante. ¿Cómo se edita la clase? – Wakka02

+0

@ Wakka02 Creé una clase XTextFormatterEx basada en XTextFormatter. Fue fácil editar la clase, pero tuve algunos problemas técnicos para compilarla. El código fuente completo se puede encontrar en el foro PDFsharp. Vea mi respuesta a esta pregunta. –

0

PDFsharp incluye una clase XTextFormatter que se puede utilizar para dibujar texto con saltos de línea.

Sin embargo, no puede determinar la altura necesaria para el texto. Inspirado por un comentario de @ Wakka02, mejoré esta clase, generando la clase XTextFormatterEx.
En mi opinión, también responde la pregunta original, por lo tanto, publico una respuesta.
Sé que esta es una pregunta antigua y la respuesta puede no ayudar al OP, pero es una pregunta frecuente y la respuesta puede ayudar a otros.

La nueva clase tiene 500 líneas de código, y creo que esto sería demasiado para esta publicación.

El código fuente se puede encontrar en el foro PDFsharp:
http://forum.pdfsharp.net/viewtopic.php?p=9213#p9213

También se puede encontrar en mi humilde blog:
http://developer.th-soft.com/developer/pdfsharp-improving-the-xtextformatter-class-measuring-the-height-of-the-text/

Al utilizar la nueva clase, primero se puede llamar PrepareDrawString para averiguar cuánto del texto cabe y qué altura tiene el texto apropiado. Entonces su decodificador puede dibujar el texto preparado o preparar otro texto o preparar el mismo texto con un rectángulo diferente.

Mi nueva clase en el trabajo: 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 preparación del texto invoca MeasureString muchas veces. Más tarde, el texto preparado se puede dibujar sin invocar MeasureString nuevamente.

A partir de hoy (17 de julio de 2015), la clase XTextFormatterEx (como el original XTextFormatter) utiliza campos internos de la clase XFont. Esto requiere un tratamiento especial al compilar la clase. Decidí copiar mi clase XTextFormatterEx en la carpeta PDFsharp después de descargar el paquete fuente completo para PDFsharp 1.32.
Cualquiera que intente modificar la clase XTextFormatter o XTextFormatterEx tendrá el mismo problema.
Espero que este problema se resuelva con versiones futuras de PDFsharp, lo que permite incluir versiones modificadas de estas clases en el proyecto de la aplicación.

Cuestiones relacionadas