PDFsharp & MigraDoc Foundation

PDFsharp - A .NET library for processing PDF & MigraDoc Foundation - Creating documents on the fly
It is currently Thu Sep 26, 2024 11:12 pm

All times are UTC


Forum rules


Please read this before posting on this forum: Forum Rules



Post new topic Reply to topic  [ 14 posts ] 
Author Message
 Post subject: Question: Text Height
PostPosted: Wed Sep 10, 2008 3:43 pm 
Offline

Joined: Tue Sep 09, 2008 12:34 pm
Posts: 3
Hello,

I'm using the XTextFormatter to draw text onto my PDF, but I need to measure the height of my resulting text when it is on multiple lines.

On a single line I'm fine, I have estimated 150% of the font size. But when adding a Paragraph(s) of text I can not be sure how many lines come out as a result.

Is there any way to find this out?

Code:
 XTextFormatter.DrawString("Paragraph of text", font, brush , rectangle, XStringFormats.TopLeft); 


Top
 Profile  
Reply with quote  
 Post subject: Bump
PostPosted: Thu Jan 29, 2009 5:44 am 
Offline

Joined: Thu Jan 29, 2009 1:31 am
Posts: 2
To bump an old question, is there a solution for this yet? I need to do the same thing and I've been running into trouble.


Top
 Profile  
Reply with quote  
PostPosted: Thu Aug 27, 2009 2:21 pm 
Offline

Joined: Thu Aug 27, 2009 1:23 pm
Posts: 8
I got the same trouble out here.

Code:
new PdfSharp.Drawing.Layout.XTextFormatter(_gfx).DrawString(text
    , new PdfSharp.Drawing.XFont(fontName, fontSize, (PdfSharp.Drawing.XFontStyle)fontStyle)
    , new PdfSharp.Drawing.XSolidBrush(PdfSharp.Drawing.XColor.FromArgb(foreColour))
    , new PdfSharp.Drawing.XRect(new PdfSharp.Drawing.XPoint(xPos, yPos), new PdfSharp.Drawing.XPoint(xLimit, yLimit))
    , PdfSharp.Drawing.XStringFormats.Default);


fontStyle is of type System.Drawing.FontStyle
foreColour is of type System.Drawing.Color
I have already predefined _gfx from a PdfPage with Orientation = Landscape, Size = Letter
xPos and yPos are parameters of type double, the same with xLimit and yLimit.

I get the runtime error that the LayoutRectangle must have a height of zero (0)...

As for the rectangle, per definition a rectangle is meant to have a height, I don't get it!... :-)

I tried with the XGraphics.DrawString() method directly, and I get the same error. It seems that I can't use the LayoutRectangle but have to manage that the text fit within the desired area manually.

Code:
var textFont = new PdfSharp.Drawing.XFont(fontName, fontSize, (PdfSharp.Drawing.XFontStyle)fontStyle);

while (xPos + _gfx.MeasureString(text, textFont).Width > xLimit)
    textFont = new PdfSharp.Drawing.XFont(fontName, --fontSize, (PdfSharp.Drawing.XFontStyle)fontStyle);

while (yPos + _gfx.MeasureString(text, textFont).Height > yLimit && fontSize > 0)
    textFont = new PdfSharp.Drawing.XFont(fontName, --fontSize, (PdfSharp.Drawing.XFontStyle)fontStyle);
       
_gfx.DrawString(text
    , textFont
    , new PdfSharp.Drawing.XSolidBrush(PdfSharp.Drawing.XColor.FromArgb(foreColour))
    , new PdfSharp.Drawing.XPoint(xPos, yPos));


But then, when I try to write two different sentences at a different X position, at the same Y position, it prints about like this.

.......................................Hello World! <- This is bad (Instead of points before the text, imagine spaces)
Hello World! <- This is okay

Though the yPos variable value is the exact same value!

yPos = Page.Height * .4093, either 40,93% of the page's height.

I tried reading a lot about the subject within the forum, but I don't seem to find any convenient answer nor right solutions for this issue.

Thanks for any help!


Top
 Profile  
Reply with quote  
PostPosted: Thu Aug 27, 2009 7:11 pm 
Offline

Joined: Thu Aug 27, 2009 6:59 pm
Posts: 3
Ok so I bumbed against the same problem and fixed it by writing a much better TextFormatter :)

I've called my class PdfWordWrapper (see attachment below). You can add textparts with different fonts/color, at the end you can measure the height and Draw it on a XGraphics with the specified alignment.

Download the class:
Attachment:
File comment: The PdfWordWrapper class
PdfWordWrapper.zip [1.93 KiB]
Downloaded 1126 times


Usage example:
Code:
                    PdfWordWrapper wrapper = new PdfWordWrapper(g, XUnit.FromMillimeter(50)); // 137
                    wrapper.Add("Dit isnuweleenseenheellangwoorddienietopeenvolledigelijnzalkunnen een test om test te testen een test om test te testen een test om test te testen een test om test te testen een test om test te testen een test om test te testen een test om test te testen een test om test te testen een test om test te testen een test om test te testen", regularFont, XBrushes.Black);
                    wrapper.Add("\n\nNog een test", boldFont, XBrushes.Red);
                    wrapper.Add("Nog een test", boldFont, XBrushes.Green);
                    wrapper.Process();
                    g.DrawRectangle(XPens.Blue, XUnit.FromMillimeter(10), XUnit.FromMillimeter(10), wrapper.Size.Width, wrapper.Size.Height);
                    wrapper.Draw(g, XUnit.FromMillimeter(10), XUnit.FromMillimeter(10), PdfWordWrapper.Alignment.Left);


Greetz,
Wouter Huysentruit


Last edited by housy2002 on Thu Aug 27, 2009 7:56 pm, edited 3 times in total.

Top
 Profile  
Reply with quote  
PostPosted: Thu Aug 27, 2009 7:41 pm 
Offline

Joined: Thu Aug 27, 2009 1:23 pm
Posts: 8
Thanks for your hand!

I shall take an eye out this. I will let you know my progress so that it may help others too. :-)


Top
 Profile  
Reply with quote  
PostPosted: Thu Aug 27, 2009 7:46 pm 
Offline

Joined: Thu Aug 27, 2009 6:59 pm
Posts: 3
Hi Will,

I see you've downloaded the file already, I just fixed the line spacing in the class. So I suggest you download the class again.

Thank you.


Top
 Profile  
Reply with quote  
PostPosted: Thu Aug 27, 2009 7:51 pm 
Offline

Joined: Thu Aug 27, 2009 1:23 pm
Posts: 8
You bet I did! lol

Thanks for your support! If this works for me, you can be sure I'll let the world know! ;-)

I've been working around this issue for about two days in a row now, with no advancement.

I'll study it tonight.

Thanks!


Top
 Profile  
Reply with quote  
PostPosted: Fri Aug 28, 2009 2:11 pm 
Offline

Joined: Thu Aug 27, 2009 1:23 pm
Posts: 8
Hi Wouter,

I tried your PdfWordWrapper class, and it doesn't seem to do what I need unless I misunderstood its functionning.

Here is the code I am writing:

Code:
        IPromotion newPromotion = new Promotion(0, 0, 2009, "B", "0005", 0, 0, DateTime.Today, DateTime.Today.AddDays(7)
            , "Product Name", "Product Description", true, 3, string.Empty, null, 25.49, 28.49, DateTime.Now, DateTime.Now);
        newPromotion.PromoType = (int)PromoTypes.Manager;
        // Both my IPromotion interface and Promotion object class function just fine. There's no code into them, only data through properties.

        PdfPage pdfPage = new PdfPage();
        pdfPage.Size = PageSize.Letter;
        pdfPage.Orientation = PageOrientation.Landscape;
        double pageHeight = pdfPage.Height.Millimeter;
        double pageWidth = pdfPage.Width.Millimeter;
        PdfDocument pdfDoc = new PdfDocument();
        pdfDoc.AddPage(pdfPage);
        XPdfFontOptions pdfFontOptions = new XPdfFontOptions(PdfFontEncoding.Unicode, PdfFontEmbedding.Always);
        XFont prodNamefont = new XFont("Helvetica", 10, XFontStyle.Bold, pdfFontOptions);
        XFont prodDescFont = new XFont("Helvetica", 10, XFontStyle.Regular, pdfFontOptions);
        XFont priceDollarsFont = new XFont("Helvetica", 90, XFontStyle.Bold, pdfFontOptions);
        string priceDollars = newPromotion.PromoPrice.ToString().Split(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.CurrencyDecimalSeparator[0])[0]; // Contains "25"

        double yPos = pageHeight * .4093;

        XGraphics gfx = XGraphics.FromPdfPage(pdfPage, XGraphicsPdfPageOptions.Replace, XGraphicsUnit.Millimeter);

        PdfWordWrapper pdfWrapper = new PdfWordWrapper(gfx, pageWidth);
        pdfWrapper.Draw(gfx, 0, yPos, PdfWordWrapper.Alignment.Left);
        pdfWrapper.Add(newPromotion.ProductName, prodNamefont, XBrushes.Black);
        pdfWrapper.Draw(gfx, pageWidth * .3978, yPos, PdfWordWrapper.Alignment.Left);
        pdfWrapper.Add(priceDollars, priceDollarsFont, XBrushes.Black);

        MemoryStream ms = new MemoryStream();
        pdfDoc.Save(ms);
        string tempFilepath = GetTempFilename().Replace("tmp", "pdf");
        FileStream fs = new FileStream(tempFilepath, FileMode.Create, FileAccess.Write);
        fs.Write(ms.ToArray(), 0, ms.ToArray().Length);
        fs.Flush();
        fs.Close();
        Process.Start(tempFilepath);


Notice that yPos is used for both the strings which I intend to draw onto the PDF file.
The output for the first string is located to the right Y position.
The ouput for the second string is like half way on the Y axis than it should be. I don't get it!

Let's consider the page's height to about 279mm.
Lets consider the page's width to about 215mm.
Quote:
yPos = 279 * .4093 = 114.1947

So, I expect both strings to print at approx. 114mm from the top of the page. Though, one prints at the right Y pos, and the second prints like at 57mm from the top.

The one and only difference between these two strings is the font size. That is why I initializes two instances of the PdfSharp.Drawing.XFont class, one for each string.

Am I missing something here?
Shall I consider working with tables? If so, any help with tables would be gratefuly appreciated.

Thanks!


Top
 Profile  
Reply with quote  
PostPosted: Fri Aug 28, 2009 5:21 pm 
Offline

Joined: Thu Aug 27, 2009 1:23 pm
Posts: 8
I've begun to study MigraDoc combined with PdfSharp, and the results are better. Not exactly what I expected yet, since it becomes very unfunctional to create two different instance of a PDF document in order to be able to create one. One for creating pages, saving, etc. and another for rendering. Not quite friendly, if I am allowed to say so.

What I expect and tend to bring to my programmers are ways to get more and more functional. Functional programming is according to me the best way to get more productive. For instance:

Code:
public static class FacadePdfHelper {
    private static readonly PdfHelperFactory _pdfHelperFactory = new PdfHelperFactory();

    public static PdfDocument WorkingDocument {
        get {
            return _pdfHelperFactory.WorkingDocument;
        }
    }

    public static PdfPage AddPage() {
        return AddPage(PageSize.Letter, PageOrientation.Portrait);
    }
    public static PdfPage AddPage(PageSize size, PageOrientation orientation) {
        return AppPage(WorkingDocument, size, orientation);
    }
    public static PdfPage AddPage(PdfDocument pdfDoc, PageSize size, PageOrientation orientation) {
        return _pdfHelperFactory.AddPage(pdfDoc, size, orientation);
    }
    public static void Write(string text) {
        Write(text, 0, 0);
    }
    public static void Write(string text, double xPos, double yPos) {
        Write(text, xPos, yPos, new XFont("Helvetica", 12));
    }
    public static void Write(string text, double xPos, double yPos, XFont font) {
        Write(text, xPos, yPos, font, XFontStyle.Regular);
    }
    public static void Write(string text, double xPos, double yPos, XFont font, XFontStyle fontStyle, params int[] pages) {
        _pdfHelperFactory.Write(text, xPos, yPos, font, fontStyle, pages);
    }
} // End of class FacadePdfHelper.

internal class PdfHelperFactory {
    internal PdfHelperFactory() {
        WorkingDocument = new PdfDocument();
    }

    internal PdfDocument WokringDocument { get; private set; }

    internal PdfPage AddPage(PdfDocument pdfDoc, PageSize size, PageOrientation orientation) {
        if(pdfDoc == null)
            pdfDoc = new PdfDocument();

        var newPdfPage = new PdfPage();
        newPdfPage.Size = size;
        newPdfPage.Orientation = orientation;

        pdfDoc.Pages.Add(newPdfPage);
        return newPdfPage;
    }
    internal void Write(PdfDocument pdfDoc, string text, double xPos, double yPos, XFont font, XBrush brush, params int[] pages) {
        if (pdfDoc == null)
            pdfDoc = new PdfDocument();

        if(pdfDoc.Pages.Count < 1) {
            pdfPage = FacadePdfHelper.AddPage();
            pdfDoc.Pages.Add(pdfPage);
        }

        if (pages == null)
            pages = new int[1] { 0 };

        pages.ToList().ForEach((p) =>
            using(var pdfGfx = XGraphics.FromPdfPage(p))
                pdfGfx.DrawString(text, font, brush, xPos, yPos, XStringFormats.Default);
        );
       
    }
}

So when it comes to begin writing to a PDF file, one can fully concentrate on the positions, font and font style of the text to print to the PDF without having to care about PDF complexity as shown below.

Ithink the code below becomes rather interesting and functional, synonyms of productivity. :-)
Code:
FacadePdfHelper.Write("Hello World!", 200, 200);
string tempFilepath = Path.GetTempFileName();
FileStream fs = new FileStream(tempFilepath, FileMode.Create, FileAccess.Write);
FacadePdfHelper.WorkingDocument.Save(fs);
fs.Close();
Process.Start(tempFilepath);

Anyway, after all this typing, all I wish is to share my perception about functional programming after all. Perhaps it could get interesting to have someday a FPDFSharp for Functional PDF Sharp library! ;-)

All I have to say humbly is that the work performed into any PDF library such as PDF Sharp is real hard labour. And after all, perhaps just a little more summary comments could help other programmers get acquainted faster with the library, since we always have to ask for questions and wait for answers. At least, with summary, we could get some more faster explanations.

I do hope I did not offend anyone with my comments.

But I still do have my positionning problem! lol ;-)


Top
 Profile  
Reply with quote  
PostPosted: Fri Aug 28, 2009 6:05 pm 
Offline

Joined: Thu Aug 27, 2009 6:59 pm
Posts: 3
You should have used it like this:

Code:
PdfWordWrapper pdfWrapper = new PdfWordWrapper(gfx, pageWidth);
pdfWrapper.Add(newPromotion.ProductName, prodNamefont, XBrushes.Black);
pdfWrapper.Process();
pdfWrapper.Draw(gfx, 0, yPos, PdfWordWrapper.Alignment.Left);

pdfWrapper.Clear();
pdfWrapper.Add(priceDollars, priceDollarsFont, XBrushes.Black);
pdfWrapper.Process();
pdfWrapper.Draw(gfx, pageWidth * .3978, yPos, PdfWordWrapper.Alignment.Left);


But my class was intended to do line wrapping with the addition that you could get the height of the wrapped text (after Process()) before drawing the whole thing on the graphics.

It seems not quit that what you are looking for...

Greetz,
Wouter


Top
 Profile  
Reply with quote  
PostPosted: Fri Aug 28, 2009 6:34 pm 
Offline

Joined: Thu Aug 27, 2009 1:23 pm
Posts: 8
I'll give it a try the way you show me. I'll let you know whether it works for what I'm required to perform.

Thanks in either case Wouter! I'm grateful for your help. :)


Top
 Profile  
Reply with quote  
PostPosted: Mon Aug 31, 2009 4:42 pm 
Offline

Joined: Thu Aug 27, 2009 1:23 pm
Posts: 8
While trying to figure out how text positioning works with PdfSharp, I noticed that the DrawString() method writes on top of the Y coordinate that we specify.

If I wish to write at (0, 100)(x, y), this points to the lower-left corner while I thought this was the top-left corner coordinates. As a result, the text string Y coordinate that I should have specified is
Quote:
100 + string.Height * .6.


Code:
PdfDocument pdfDoc = new PdfDocument();
PdfPage pdfPage = new pdfPage();
pdfPage.Size = PageSize.Letter;
pdfPage.Orientation = Orientation.Landscape;
pdfDoc.Pages.Add(pdfPage);

double posX = 0;
double posY = pdfPage.Height * .4093;
string helloString = "Hello";
string worldString = "World!";
XFont helloFont = new XFont("Helvetica", 25, XFontStyle.Regular);
XFont worldFont = new XFont("Helvetica", 270, XFontStyle.Bold);

using(var pdfGfx = XGraphics.FromPdfPage(pdfPage)) { // assuming the default Point UOM   
    XSize helloStringSize = pdfGfx.MeasureString(helloString, helloFont);   
    XSize worldStringSize = pdfGfx.MeasureString(worldString, worldFont);

    pdfGfx.DrawString(helloString   
        , helloFont   
        , XBrushes.Black   
        , posX   
        , posY + helloStringSize.Height * .6   
        , XStringFormats.Default);
    pdfGfx.DrawString(worldString   
        , worldFont   
        , XBrushes.Black   
        , pdfPage.Width * .3978   
        , posY + (worldStringSize.Height + helloStringSize.Height) * .6   
        , XStringFormats.Default);
}

You'll perhaps wonder why I only add 60% of the string size when I want to get my string written below my Y coordinate? That is because the full height of the font includes somekind of leap on top. So, the computing result will not be what is expected. On the other hand, you don't have to care about a leap if you need one. In my particular case, I don't require leap, so I must take it off the string's height.

If you feel like my explanation needs more accurate details, please feel free to either add them as comments or keep me informed so that I may include them.

Thanks!


Top
 Profile  
Reply with quote  
PostPosted: Tue Sep 01, 2009 7:27 am 
Offline
PDFsharp Guru
User avatar

Joined: Mon Oct 16, 2006 8:16 am
Posts: 3110
Location: Cologne, Germany
Hi!
Will wrote:
You'll perhaps wonder why I only add 60% of the string size when I want to get my string written below my Y coordinate? That is because the full height of the font includes somekind of leap on top. So, the computing result will not be what is expected.

You call DrawString with "XStringFormats.Default" (which actually means "XLineAlignment.BaseLine"). Therefore the y coordinate specifies the bottom of "normal" characters (i. e. characters without descent) - the baseline.

To specify the TopLeft position, use
Code:
XStringFormat format = new XStringFormat();
format.Alignment = XStringAlignment.Near;
format.LineAlignment = XLineAlignment.Near;

_________________
Regards
Thomas Hoevel
PDFsharp Team


Top
 Profile  
Reply with quote  
PostPosted: Tue Sep 01, 2009 11:37 am 
Offline

Joined: Thu Aug 27, 2009 1:23 pm
Posts: 8
Oh that's it!?

I'll try that for sure! Thanks for the tip! This is really appreciated!

Thanks Thomas! =)


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 14 posts ] 

All times are UTC


Who is online

Users browsing this forum: Google [Bot] and 74 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Privacy Policy, Data Protection Declaration, Impressum
Powered by phpBB® Forum Software © phpBB Group