admin管理员组

文章数量:1391008

I'm working on a PDF form where I need to restrict a multiline text field from being overfilled. The idea is to prevent users from entering more text than the field can visually accommodate. However, I'm running into an issue with text measurement.

For example, when measuring a string like "T.", "Te", "V.", etc. the library I'm using calculates the dot/letter as if it starts directly under the horizontal bar of the "T" (and right next to its vertical stroke). In the actual rendered PDF, though, the dot appears to start after the horizontal line of the "T". This discrepancy means that my measurement logic—which relies on calculating the total width of the text—ends up misjudging when the text has reached the maximum allowable width.

The issue is that the measurement (using context.measureText()) doesn’t reflect the actual rendered spacing in the PDF—especially for cases like "T." where parts of glyphs overlap or have unusual kerning. I’ve tried per-character measurements and other tweaks, but I still face problems because some letters seem to overlap or “stick” together in the measurement while, in the final PDF rendering, they have natural spacing.

Has anyone encountered this problem before? Is there a library or a more reliable approach to measure and restrict text that takes into account the nuances of glyph positioning and kerning as rendered in PDFs?

This would work, if the measurement was using the same font as the rendered PDF.

I've tried various approaches:

  • Measuring each character individually and summing their widths.
  • Using canvas metrics and even adjusting for kerning.

but I have no clue what the kerning is etc. it is always out by a lot and not really a good method.

const textField = document.getElementById('text');
const statusMessage = document.getElementById('statusMessage');
const maxTextWidth = 600; // Maximum width per line in pixels
const allowedLines = 12;

// Create an offscreen canvas for text measurement
const measurementCanvas = document.createElement('canvas');
const measurementContext = measurementCanvas.getContext('2d');
measurementContext.font = '10pt Arial';

// Function to count how many wrapped lines the text occupies
function getWrappedLineCount(text, maxWidth, context) {
    let lines = 0;
    const paragraphs = text.split('\n');
    paragraphs.forEach(para => {
        if (para === "") {
            lines++;
        } else {
            const words = para.split(' ');
            let line = '';
            words.forEach(word => {
                const testLine = line ? line + ' ' + word : word;
                if (context.measureText(testLine).width > maxWidth && line !== '') {
                    lines++;
                    line = word;
                } else {
                    line = testLine;
                }
            });
            if (line !== '') {
                lines++;
            }
        }
    });
    return lines;
}

// Listen for input on the multiline text field and restrict further input if needed
textField.addEventListener('input', function() {
    let text = textField.value;
    let lines = getWrappedLineCount(text, maxTextWidth, measurementContext);
    if (lines <= allowedLines) {
        statusMessage.textContent = "Platz vorhanden";
        statusMessage.style.color = "green";
    } else {
        // Trim the text until it fits within the allowed lines.
        while (getWrappedLineCount(text, maxTextWidth, measurementContext) > allowedLines && text.length > 0) {
            text = text.slice(0, -1);
        }
        textField.value = text;
        statusMessage.textContent = "Keine Zeicheneingabe mehr möglich";
        statusMessage.style.color = "red";
    }
});

本文标签: javascriptPDFlibjs unable to measure and fill text in a multiline text field correctlyStack Overflow