PDFDocument Text Aligment

Hello guys,

I am trying to do a document, where i need to create an Invoice,

Some parts are on the left side some on the right side, I don’t seem to find anywhere the text alignment, ,so how do you achieve that ? as so far it is a nightmare

I cannot get the Text Length in order to calculate a position, i can get only the page.Width and page.Height based on the g but that’s about it.

How in the world you manage to align the text to one side and the other ?

If you base all to the left then this would me a nightmare to create an invoice and doing all from code without a visual aid into adding the fields and the rest of the data.

Thanks

Use PDFDocument’s PDFGraphics object to draw text, shapes, etc. into the PDF. It has a TextWidth function that you can use for this purpose.

This method in a module will be very handy:

Public Sub DrawTextLine(extends g As Graphics, value As String, x As Double, y As Double, width As Double, alignment As TextAlignments = TextAlignments.Default, truncate As Boolean = False)
  
  
  Select case alignment
    
  Case TextAlignments.Default
    
    g.DrawText(value, x, y, width, truncate)
    
  Case TextAlignments.Left
    
    g.DrawText(value, x, y, width, truncate)
    
  Case TextAlignments.Center
    
    Dim txtWidth As Double = g.TextWidth(value)
    
    g.DrawText(value, x + (Width-txtWidth)/2, y, if(truncate, width, 0), truncate)
    
  Case TextAlignments.Right
    
    Dim txtWidth As Double = g.TextWidth(value)
    
    g.DrawText(value, x+(Width-txtWidth), y, width, truncate)
    
  End Select
End Sub

Use it like this:


g.DrawTextLine("left aligned", 0, 10, g.Width, TextAlignments.Left)

g.DrawTextLine("Centered", 0, 30, g.Width, TextAlignments.Center)

g.DrawTextLine("Right aligned", 0, 50, g.Width, TextAlignments.Right)
1 Like

Cool, thanks Jeremie,

I did this on my side and i was testing it

Public Sub DrawAlignedText(extends g As Graphics, txt As String, Optional x As Integer, y As Integer, width As Integer, horizontalAlign As String, fontSize As Integer, leftMargin As Integer, rightMargin As Integer, topMargin As Integer, bottomMargin As Integer)
  // Estimate text dimensions based on font size
  Dim avgCharWidth As Integer = fontSize * 0.6 // Approximate width of one character
  Dim txtWidth As Integer = avgCharWidth * txt.Len // Estimated width of the text
  Dim txtHeight As Integer = fontSize // Estimated height of the text
  
  // Adjust the width for margins
  Dim effectiveWidth As Integer = width - leftMargin - rightMargin
  
  // Calculate x-coordinate based on horizontal alignment
  Dim startX As Integer
  Select Case horizontalAlign
  Case "left"
    startX = leftMargin + x
  Case "center"
    startX = leftMargin + (effectiveWidth - txtWidth) / 2
  Case "right"
    startX = leftMargin + effectiveWidth - txtWidth
  Else
    startX = leftMargin // Default to left if unrecognized alignment
  End Select
  
  // Calculate y-coordinate based on vertical alignment
  Dim startY As Integer = y + topMargin + txtHeight // Adjust for text baseline and top margin
  
  // Draw the text at the calculated position
  g.DrawText(txt, startX, startY)
End Sub

As we still need to do the basic formatting of the page to know where to put that text in the first place, i guess if you have a better idea or i don’t see the page formatting part that would help.

I guess XOJO should start with that first considering that you create a document.

In my case i need to setup the left; top; bottom; right limits in order to be able to process the document

Well for some reason my code writes as expected, i guess

g.TextWidth(value)
does not take in consideration the Font Size and charWidth in this case , so maybe that should be adapted. so far with my code it generates properly, with your code the text gets cut

And this one apparently fixed the issue

Public Sub DrawTextLine(extends g As Graphics, value As String, x As Double, y As Double, width As Double, alignment As TextAlignments = TextAlignments.Default, leftMargin As Double, rightMargin As Double, topMargin As Double, bottomMargin As Double, fontSize As Integer, truncate As Boolean = False)
  // Adjust the width for margins
  Dim effectiveWidth As Double = width - leftMargin - rightMargin
  Dim avgCharWidth As Integer = fontSize * 0.6 // Approximate width of one character
  Dim txtWidth As Integer = avgCharWidth * value.Length // Estimated width of the text
  Dim txtHeight As Integer = fontSize // Estimated height of the text
  
  // Adjust the x-coordinate based on margins
  Dim effectiveX As Double
  Select Case alignment
  Case TextAlignments.Default, TextAlignments.Left
    effectiveX = x + leftMargin
  Case TextAlignments.Center
    'Dim txtWidth As Double = g.TextWidth(value)
    effectiveX = x + leftMargin + (effectiveWidth - txtWidth) / 2
  Case TextAlignments.Right
    'Dim txtWidth As Double = g.TextWidth(value)
    effectiveX = x + leftMargin + (effectiveWidth - txtWidth)
  End Select
  
  // Adjust the y-coordinate based on the top margin
  Dim effectiveY As Double = y + topMargin + txtHeight
  'Dim startY As Integer = y + topMargin + txtHeight // Adjust for text baseline and top margin
  
  // Draw the text at the calculated position
  g.DrawText(value, effectiveX, effectiveY, If(truncate, effectiveWidth, 0), truncate)
End Sub

So it seems that in this case

g.TextWidth(value)

it’s kind of useless

I don’t see in your code where you are setting the font and size of the PDFGraphics object…?

TextShape is good but it was not supported in PDF in past.

Well something does not work right here , i have random responses on this .

this is the updated method for test

Public Sub DrawTextLine(extends g As Graphics, value As String, x As Double, y As Double, width As Double, alignment As TextAlignments = TextAlignments.Default, leftMargin As Double, rightMargin As Double, topMargin As Double, bottomMargin As Double, fontSize As Integer, truncate As Boolean = False)
  // Adjust the width for margins
  Var effectiveWidth As Double = width - leftMargin - rightMargin
  
  
  Var effectiveY As Double = y + topMargin
  
  // Adjust the x-coordinate based on margins
  Var effectiveX As Double
  Select Case alignment
  Case TextAlignments.Default
    effectiveX = x + leftMargin
    
    g.DrawText(value, effectiveX, y, width, truncate)
    
  Case TextAlignments.Left
    effectiveX = x + leftMargin
    
    g.DrawText(value, effectiveX, y, width, truncate)
    
    
  Case TextAlignments.Center
    Var txtWidth As Double = g.TextWidth(value)
    effectiveX = (effectiveWidth - txtWidth) / 2
    
    g.DrawText(value, x + effectiveX, effectiveY, If(truncate, width, 0), truncate)
    
  Case TextAlignments.Right
    Var txtWidth As Double = g.TextWidth(value)
    effectiveX = x + (effectiveWidth - txtWidth)
    
    g.DrawText(value, effectiveX, effectiveY, width, truncate)
  End Select
  
End Sub

In this case i just keep Jeremie code and added the margins.

I look on the debugger and i get a weird response .

So if you look to the txtWidth you will see that the value is 0 while “value” in my case is INVOICE so text.Width should not be 0, it seems that somehow “g.TextWidth(value)” does not work .

Any other ideas ?

Thanks

can you see if other font result in a txtWidth?
or embed font in pdf.
i would set the break point at .drawtext

You never answered my question. Are you setting the font and size for the PDF graphics object before calling TextWidth?

hi Eric,

I do set the font size :

g.FontName = PDFDocument.StandardFontNames.Arial
'g.FontName = "Tahoma"
g.FontSize = 23
g.PenSize = 1
g.Bold = True
g.DrawingColor = &c7f7f7f
'g.DrawingColor = &c000000

g.DrawTextLine("INVOICE", 0, 100, g.Width, TextAlignments.Right,leftMargin,rightMargin, topMargin,bottomMargin, 23 )

and as you see it was passed via the method as well.

test with Xojo 2021r3.1 there was Arial not available
width is ok, windows 11 destop project

Xojo 2024 1.1

MacOS Sonoma here, it does not seems to work , i tried multiple fonts and custom and the standard ones

which xojo version do you use?

latest one I believe is 2024R2.1

works at my Mac Sonoma 14.5

well you did not followed the chat i guess, the method that Jeremie posted and i updated supposed to be into a module and called in the code, maybe something breaks there, and it’s worth to mention that i am testing on M1 mac mini so maybe it has something related to the cpu or something, i will try later on an intel mac to see if works or breaks.

As well my test is done on a console app, so maybe there does not work, but on XOJO Docs it says that it works on any platform including console and web

1 Like

I remember that console app has some graphics differences with Desktop that makes the results not be consistent with Desktop. Not sure about Issues numbers at this time.

Well honestly i wanted to have it as WebApp, but i find it that web is still not polished enough and i have trouble recreating the Desktop sample app as Web app, i guess @Xojo could help here by creating more examples for Web as well if they say on the docs that works on all the versions of XOJO. So far in PDF > Creating PDF Documents > i see only for IOS And Desktop and nothing for Web ,and seeing that i have issues on replicating that desktop as web then i tried something simple on Console, but it seems tha Console brings a whole set of errors.