-
Notifications
You must be signed in to change notification settings - Fork 675
Description
When placing text with ColumnText in a rectangular area, it is hard to precisely control the baseline Y of the first rendered line inside the column. Today, the first line’s baseline is derived from yLine and the effective leading (yLine − leading). In practice, this becomes non‑intuitive and error‑prone when:
setSimpleColumn resets yLine to the top (ury), forcing extra calculations.
- Effective leading can be a mix of fixed and multiplied leading.
- Flags like setUseAscender and setAdjustFirstLine can affect first-line placement.
- Switching between addText(...) and addElement(Paragraph/…) changes how first-line spacing behaves.
The result is that aligning the first line to an exact baseline Y (for forms, labels, receipts, or precise grid layouts) requires trial‑and‑error and knowledge of several interacting flags, rather than a simple, explicit API.
Note:
ColumnText does expose setYLine(float) and documents that “The line will be written to yLine − leading”
ColumnText.java . However, this still requires callers to precompute the correct yLine from a desired baseline and the effective leading, and to account for ascender/first‑line adjustments and composite vs. simple text flows.
Suggested Solution:
Introduce an explicit and ergonomic way to set the first line’s baseline Y inside the column, independent from internal leading/ascender logic. For example:
- Compute the firstLine without currentLeading
- A direct setter:
- setFirstLineBaselineY(float baselineY)
- Guarantees the first line’s baseline equals baselineY, regardless of setUseAscender, setAdjustFirstLine,
fixed/multiplied leading, or whether the content was added via addText or addElement. - A relative alternative:
- setFirstLineOffsetFromTop(float offset)
- Starts the first line’s baseline at (ury − offset) inside the current simple column. - an overload to setSimpleColumn:
- setSimpleColumn(llx, lly, urx, ury, float firstLineBaselineY)
- setSimpleColumn(llx, lly, urx, ury, float offsetFromTop, boolean offsetIsFromTop)
Additional notes:
- This API should only control the first line; subsequent lines continue with normal leading and pagination.
- Document clear precedence rules vs. setYLine, setUseAscender, setAdjustFirstLine, and leading.
- Provide examples for both addText(...) and addElement(...) usage.
Current feature example
`PdfContentByte cb = writer.getDirectContent();
ColumnText ct = new ColumnText(cb);
float llx = 50f, lly = 500f, urx = 300f, ury = 700f;
ct.setSimpleColumn(llx, lly, urx, ury);
ct.setUseAscender(false);
float dAscent =font.getBaseFont.getAscentPoint("d", font.getSize);
float baseline = ury-dAscent
// We want firstYLine == baseline but ColumnText writes firstYLine = yLine - leading
ct.setYLine(baseline); //Note: must be yLine < ury && yLine > lly
Chunk chunk = new Chunk("Hello, world\nWelcome to OpenPdf", font);
chunk.setCharacterSpacing(0.4f);
chunk.setHorizontalScaling(1f);
Paragraph paragraph = new Paragraph(chunk)
paragraph.setLeading(14f)
ct.addText(paragraph);
ct.go();`
To be short:
Actual:
yLine = ury - dAscent
firstYLine = (ury - dAscent) - currentLeading = 694.68 - 14 = 680.68
Expected:
dAscent = 5.32f
baseline(yLine) = ury - dAscent
firstYline = yLine = 694.68
Your real name
Balaji