galkahana / HummusJS

Node.js module for high performance creation, modification and parsing of PDF files and streams
http://www.pdfhummus.com
Other
1.15k stars 170 forks source link

Can't modify PDF and add a PNG on the last page of the PDF #140

Open cenjennifer opened 7 years ago

cenjennifer commented 7 years ago

Hi -

I'm trying to modify a pre-existing PDF and add a PNG to the last page of that PDF. I'm just trying to get the image to show up on the PDF, but I can't seem to be able to get it working. I keep getting this error (even though an output pdf is created, but is either damage or just a copy of the original PDF):

TypeError: Unable to modify PDF file, make sure that output file target is available and that it is not protected

Here's the code I'm using to make the PDF modifications:

res.writeHead(200, {'Content-Type': 'application/pdf'});

var pdfWriter = hummus.createWriterToModify(__dirname + '/agreement.pdf', {
        modifiedFilePath: __dirname + '/output.pdf'
    });
var imageXObject = pdfWriter.createFormXObjectFromJPG(__dirname + '/test.jpg');
var page = pdfWriter.createPage(0,0,595,842)
var cxt = pdfWriter.startPageContentContext(page)
    cxt.q()
   .cm(500,0,0,400,0,0)
   .doXObject(imageXObject)
   .Q();

pdfWriter.writePage(page);
pdfWriter.end();

res.end();

Also, if I have an image that is in data uri, how should I tackle in implementing the image onto the pdf?

Many thanks, Jennifer

galkahana commented 7 years ago

Hi. The error that you are getting seems to indicate that the output target is not available for writing. But it does seem a little weird given that a file is being created. so let's ignore the message and consider other possibilities, at this point.

PNG files are not supported as input images in Hummus. At the time #123 turned out to be about a png file, and that person sorted this out by creating a PDF file with PDFKit, and using the result PDF as input for Hummus, which worked because PDF is a supported format.

However, in this example we see a JPG input image (test.jpg), so the problem shouldn't happen, unless the jpg file is not there, or is not actually a jpg.

One other thing is that there's a simpler method to embed images with hummus, with the drawImage command.

You can learn more about it and the supported images types in: https://github.com/galkahana/HummusJS/wiki/Show-images

Also, the res activity there is not gonna really do anything. hope you noted this.

so from the code itself i can't really tell why it's not working. try switching to drawImage. if its still giving you trouble, i might be able to help if you send me the materials that you are trying to use. i'll try to recreate the problem, and if successful, i can debug.

As for data uri images. if i'm not mistaken these are base64 encoded images. if i'm not mistaken they always start with a header specifying their image type. so what you can do is decode the base64 image, save it to a file, and then use it with hummus.

cenjennifer commented 7 years ago

Hi Gal -

Thank you so much for replying back! I took your advice and tried using the drawImage instead. It definitely makes it a lot easier to read/understand.

I realized the problem was actually the pdf that i was using. I tried it with one of your sample generated pdf and I was able to make it work.

Also, you are right about the data uri images being base64 and I found a library that would convert those images into jpg.

I have a couple more questions I want to ask you: 1.) I tried to use a relative path to an image file that isn't in the same directory as my PDF route, so instead of using __dirname, I tried to use require(../../test.jpg). However, with this relative path, the output file wouldn't generate. How would I be able to reference relative paths?

2.) If I want to pass the generated pdf file to an api endpoint that would send the pdf as an attachment in an email after completion, how can I return the pdf? Would I be able to do a res.send() and pass along the pdf file?

I really appreciate your guidance and patience! Thanks for helping out:)

Best, Jennifer

galkahana commented 7 years ago

1.) hi, don't use require, just place the path. i think that it should work, if the path is correct relative to the execution point. but then why not using dirname? this way is the safest. use Path so you can combine dirname with relative path via resolve. 2.) it should be fine. hummus writes in one pass, so provided that you know how to create attachments in email in general, than adding hummus shouldn't be a problem. i do have something similar in my basic example, writing directly to the response object, which is close to what you need - https://github.com/galkahana/HummusJS/wiki/How-to-serve-dynamically-created-pdf

cenjennifer commented 7 years ago

Hi Gal -

Does the PDF need to originally be a PDF? I tried a few files that aren't password encrypted (used the .pdfReader.isEncrypted() and got false), but were exported as an PDF from a previous creator. I saw that the PDF file from your example has no content creator info, but my PDFs do (e.g. Microsoft Word or Preview) and don't work.

The PDF that I'm trying to make work was originally a Word Document that was then converted to a PDF (See attached).

[Hello.pdf](https://github.com/galkahana/HummusJS/files/765279/Hello.pdf)

var pdfWriter = hummus.createWriterToModify(__dirname + '/hello.pdf', {
                modifiedFilePath: __dirname + 'output/output.pdf'
            });

var pageModifier = new hummus.PDFPageModifier(pdfWriter,1);

var cxt = pageModifier.startContext().getContext()
cxt.drawImage(0,0, dataImgFile);

pageModifier.endContext().writePage();
pdfWriter.end();

Any ideas what might be the issue?

Thanks, Jennifer

galkahana commented 7 years ago

first glance - use 0 and not 1, maybe? [b.t.w i did implement encryption handling, to a certain point. then you have to provide the password, but that's on another matter]

cenjennifer commented 7 years ago

You're right! Oh, it must be that I had the wrong page index for that pdf I was testing out with. Thanks so much for your help Gal!

cenjennifer commented 7 years ago

Hi again -

I ran into an issue with writing text in the same pdf. So I used the writeText() function (see below) and it's not throwing me any errors, but the text aren't showing up. Am I doing something wrong?

Also, are all the options for the text mandatory? If I don't include a font, is there a default font that would be used?

const filePDF = __dirname + '/pdf/test.pdf';

let outputPDF = getFilePath('output', 'pdf', accountId, 'self');

let pdfReader = hummus.createReader(filePDF);

let pdfWriter = hummus.createWriterToModify(filePDF, {
modifiedFilePath: outputPDF
});

let pageModifier = new hummus.PDFPageModifier(pdfWriter,14); //place signature on page 14
let cxt = pageModifier.startContext().getContext()

//write ipAddress and timeStamp
var arialFont = pdfWriter.getFontForFile(__dirname + '/pdf/font/Arial.ttf');
console.log(arialFont);

let textOptions = {
    fontSize: 12,
    color: 0xFF45DE,
    colorspace: 'rgb',
    font: arialFont
}
let text = `IP Address: ${req.body.ipAddress} | Signed Timestamp: ${req.body.timeStamp}`;
cxt.writeText('text', 90, 180, [textOptions]);

cxt.drawImage(90,160, dataSelfImgJPGFile, {transformation:[0.6,0,0,0.6,0,0]});

pageModifier.endContext().writePage();
pdfWriter.end();

Thanks again for your help and awesome library!

Best, Jennifer

galkahana commented 7 years ago

dont put textOptions in an array. no defaults.