Hopding / pdf-lib

Create and modify PDF documents in any JavaScript environment
https://pdf-lib.js.org
MIT License
6.96k stars 669 forks source link

Drawing a line of thickness Number.MIN_VALUE (slightly) corrupts the pdf file #1217

Open andreaswimmer opened 2 years ago

andreaswimmer commented 2 years ago

What were you trying to do?

Drawing a line as thin as possible.

How did you attempt to do it?

    page.drawLine({
            start: {x: 0, y: 0},
            end: {x: page.getWidth(), y: page.getHeight()},
            thickness: Number.MIN_VALUE,
        }
    )

What actually happened?

Results depend heavily on the PDF viewer. Chrome, Firefox and SumatraPDF have no problem reading the file.

Adobe Acrobat Reader, Adobe Acrobat Pro DC and PDF-Xchange editor have varying degrees of problems parsing the file. Either giving up, or skipping the rest of the current page.

What did you expect to happen?

Interestingly, drawing a line with silly values of thickness like 0 or 0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 does work fine. It is only Number.MIN_VALUE that corrupts the file.

How can we reproduce the issue?

import {PDFDocument} from "pdf-lib";

export async function createCorruptPDF() {
    const jpgUrl = 'https://pdf-lib.js.org/assets/cat_riding_unicorn.jpg'
    const pngUrl = 'https://pdf-lib.js.org/assets/minions_banana_alpha.png'

    const jpgImageBytes = await fetch(jpgUrl).then((res) => res.arrayBuffer())
    const pngImageBytes = await fetch(pngUrl).then((res) => res.arrayBuffer())

    const pdfDoc = await PDFDocument.create()

    const jpgImage = await pdfDoc.embedJpg(jpgImageBytes)
    const pngImage = await pdfDoc.embedPng(pngImageBytes)

    const jpgDims = jpgImage.scale(0.5)
    const pngDims = pngImage.scale(0.5)

    const page = pdfDoc.addPage()

    page.drawImage(jpgImage, {
        x: page.getWidth() / 2 - jpgDims.width / 2,
        y: page.getHeight() / 2 - jpgDims.height / 2 + 250,
        width: jpgDims.width,
        height: jpgDims.height,
    })
    page.drawLine({
            start: {x: 0, y: 0},
            end: {x: page.getWidth(), y: page.getHeight()},
            thickness: Number.MIN_VALUE,
        }
    )
    page.drawImage(pngImage, {
        x: page.getWidth() / 2 - pngDims.width / 2 + 75,
        y: page.getHeight() / 2 - pngDims.height + 250,
        width: pngDims.width,
        height: pngDims.height,
    })

    const pdfBytes = await pdfDoc.save()
    return pdfBytes;
}

Version

1.17.1

What environment are you running pdf-lib in?

Browser

Checklist

Additional Notes

Here is the resulting file from the code above. semi-corrupted.pdf

joewestcott commented 2 years ago

Number.MIN_VALUE is 5-384. Assuming you're using millimeters, this line would become the new smallest observable thing in the universe!?

That said, I would consider this a bug. Looks like numberToString would need to be looked at.