0

Coming from itextsharp, where you can use ColumnText to place text at specific coordinates like so:

ColumnText ct = new ColumnText(cb);
            ct.SetSimpleColumn(DrawingSpace.llx, DrawingSpace.lly, DrawingSpace.urx, DrawingSpace.ury);

And then calculate the height of where you are able to draw next:

ct.Go(SimulateOnlyForHeight);

var lowestText = ct.YLine + (float)Math.Floor(ListFont.GetCalculatedBaseFont(false).GetFontDescriptor(BaseFont.DESCENT, ListFont.Size));

return DrawingSpace.y - lowestText;

I thought transitioning to itext7 would be relatively painless. This has not been my experience. I cannot get the things to cooperate and the way that Rectangles are placed and moved around on the Canvas seems to be counter-intuitive -- the rectangles grow upwards from the starting Y value, margin values are added seemingly randomly in places such as ParagraphRenderer.cs from the itext7 source code, and generally the text just seems to bounce around.

Also, to be clear, setting a fixed position on a paragraph and adding that to our page seemed to encounter the same issues with Y values. If I use .SetFixedPosition(llx, lly, width) on the paragraph, it's too far down, if it's written using ury, its too far up.

here is my code, along with the horizontal line drawing function i've been using to test y values

static void Main(string[] args)
{
    float llx = 71.001f;
    float urx = 720.9f;
    float lly = 495f;
    float ury = 561;
    float calcwidth = urx - llx; // this equals 649.9f in our case
    float calcheight = ury - lly; //this equals 66f in our case
    float PageMarginSize = 35; // Page margins
    float PageTopMarginSize = 38; // Page top margin

    string filePath = "PATH TO FILE EXAMPLE";
    string fontpath = "PATH TO FONT EXAMPLE";
    PdfFont font = PdfFontFactory.CreateFont(fontpath + "Trade Bold.ttf", "CP1252", PdfFontFactory.EmbeddingStrategy.PREFER_EMBEDDED);


    PdfDocument pdfdocument = new PdfDocument(new PdfWriter(filePath));
    Document document = new Document(pdfdocument, PageSize.LETTER.Rotate());
    document.SetMargins(PageTopMarginSize, PageMarginSize, PageMarginSize,       PageMarginSize);
    PdfPage page = pdfdocument.AddNewPage();
    PdfCanvas pdfCanvas = new PdfCanvas(page);


    DrawHorizontalDottedLine(ref pdfdocument, new DeviceRgb(0, 0, 0), llx, 
 lly, 400f);
    DrawHorizontalDottedLine(ref pdfdocument, new DeviceRgb(0, 0, 255), llx, 
 lly, 400f);

Rectangle rectangle = new Rectangle(llx, lly, calcwidth, 52f);
pdfCanvas.SetFillColor(new DeviceRgb(255, 250, 250));
pdfCanvas.Rectangle(rectangle);
pdfCanvas.FillStroke();


Canvas canvas = new Canvas(pdfCanvas, rectangle);
Paragraph paragraph = new Paragraph().Add("Example Text")
.SetFontSize(52f).SetFontColor(new DeviceRgb(204, 0, 0))
.SetFixedLeading(52f)
.SetFont(font);
paragraph.SetProperty(Property.MARGIN_TOP, UnitValue.CreatePointValue(0));

paragraph.SetProperty(Property.MARGIN_BOTTOM, UnitValue.CreatePointValue(0));

canvas.Add(paragraph);


canvas.Close();
pdfdocument.Close();

}
public static void DrawHorizontalDottedLine(
ref PdfDocument pdfDocument, DeviceRgb   lineColor, float x, float y, float width,
float weight = 1f)
{
PdfCanvas canvas = new PdfCanvas(pdfDocument.GetLastPage());
canvas.SetTextRenderingMode(0);

// Set CMYK stroke color
canvas.SetStrokeColor(lineColor);

// Set line dash pattern
canvas.SetLineDash(0);

// Draw horizontal dotted line
canvas.MoveTo(x, y)
      .LineTo(x + width, y);

canvas.SetLineWidth(weight);
canvas.Stroke();
}

I've been under the impression that under Itext7's workflow we would want to use llx and ury to draw a rectangle, create a canvas from it, create a paragraph, and that paragraph will be added to the canvas and flow through.

Generally I am very confused. The rectangle when added seems to start at the ury value and then be built upwards, depending on height or font size instead of being bounded by llx and ury and the text being written inside of that area, downwards. You will also note that I was playing around with .SetProperty, which was another conundrum. When I downloaded the source code, I noticed that within ParagraphRenderer.cs, we apply margins to the rectangle (parentBBox) seemingly arbitrarily?

I would very much appreciate if someone could explain the proper way to add a block of text at a given set of coordinates. Thank you!

1
  • Thank you for the response KJ. The charting system makes sense. Could you explain a bit more about what you mean by your second to last sentence? Not totally understanding it. Generally, is there an approach you would recommend for handling this how we hope? That is, to be able to write downwards from a Y coordinate, and be able to manage that Y value so we know where we can start writing a completely separate line of text? I've tried using the whole .GetOccupiedArea().GetBBox().GetHeight() flow but it's just not helpful if the Y values are messed up to begin with by writing upwards. Commented Mar 6 at 16:47

1 Answer 1

3

In general if you want to use the layout engine, easily set color borders and stuff like that you should be able to do this with the following example: https://github.com/itext/itext-java/blob/aeb7140b9e026cf949e405b1420d639c896f4618/layout/src/test/java/com/itextpdf/layout/CanvasTest.java#L254

    try (PdfDocument pdf = new PdfDocument(new PdfWriter(out))) {
        pdf.addNewPage();
        Canvas canvas = new Canvas(new PdfCanvas(pdf.getFirstPage()),
                new Rectangle(120, 650, 60, 80));

        Div notFittingDiv = new Div().setWidth(100)
                .add(new Paragraph("Paragraph in Div with Not set position"));
        canvas.add(notFittingDiv);

        Div divWithPosition = new Div().setFixedPosition(120, 300, 80);
        divWithPosition.add(new Paragraph("Paragraph in Div with set position"));
        canvas.add(divWithPosition);

        canvas.close();
    }

Results into:enter image description here

Also you can just use fixed position on the paragraph without the div. but it's nice to have a container in an absolute position and then use the layout engine to take care of the inner content in example Please let me know if this helps your usecase.

Sign up to request clarification or add additional context in comments.

3 Comments

I have seen this example before and looked into it. setting a fixed position like so: Div divWithPosition = new Div().SetFixedPosition(llx, lly, 100); and drawing lines to show the position of Y: DrawHorizontalDottedLine(ref pdf, new DeviceRgb(0, 0, 0), llx, lly, 400f); we see both the notFittingDiv and the divWithPosition both are still behaving as mentioned in my original post -- they are positioned at the top of the y value of the fixed position. This makes sense as the parameter for fixed position is for the Bottom, but i want to be able to write downwards to manage Y.
Then you will probably have to use the DIV approach layout it in an virtual plane and get the height from that and then use the calculated height to downshift the fixed position. If you create a followup question and tag me I'll happily provide a sample implementation
Thanks Guust, I should have followed up on this post but that is exactly what I ended up doing earlier. Things are still a bit funky with height placement but that seems like a feasible way foward.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.