Question

I'm creating a PDF document in a web app with jsPDF, sending that document to Perl, and having Perl email it, and it works fine. However, when I add an image to the PDF document, it no longer works, as the Adobe Reader says the file is corrupt. The app is huge, so here is a stub with similar pertinent code that acts in the same way:

html:

<!DOCTYPE html>
<html>
    <head>
        <script src="https://<myserver>/js/jquery.js"></script>
        <script src="https://<myserver>/js/jspdf.js"></script>
        <script src="https://<myserver>/js/jspdf.plugin.addimage.js"></script>      
        <script src="https://<myserver>/test/pdf.js"></script>
    </head>
    <body>
        <input type="submit" id="go">
    </body>
</html>

js:

$(document).ready(function() {
    $('#go').on('click',function() {
        //create PDF
        var imgData = 'data:image/jpeg;base64,<dataurlencoded image string>';
        var doc = new jsPDF('p','pt','a4');
        doc.addImage(imgData, 'JPEG', 22, 22, 138, 28);     
        doc.text(30, 120, 'Lorem Ipsum!');
        var perl_pdf = doc.output();

        //send PDF to perl and have perl email it
        $.ajax({
            type: "POST",
            url: "https://<myserver>/cgi-bin/pdf.pl", 
            contentType: "application/x-www-form-urlencoded; charset=UTF-8",
            dataType: "json",
            data: "perl_pdf="+encodeURIComponent(perl_pdf),
            error: function(XMLHttpRequest, textStatus, errorThrown) { 
                alert("error:  "+ XMLHttpRequest.responseText + ", textStatus: " + textStatus + ", errorThrown: " + errorThrown);
            }, 
            success: function(data){
                alert("Success: "+data.success);
            } 
       });
    });     
});

perl:

#!d:/perl/bin/perl.exe -w
use strict;
use warnings;
use CGI qw(:all);
use MIME::Lite;
use MIME::Base64;

my $q = CGI->new();
my $pdf_doc = $q->param('perl_pdf');

open (OUTFILE, '>pdf.pdf') or die "Could not open file";
binmode(OUTFILE);
print OUTFILE decode_base64($pdf_doc);
close OUTFILE;

my $from_address = '<from_address>';
my $to_address = '<to_address>';
my $mail_host = '<smtp_server>';

my $subject = 'PDF Test';
my $message_body = "The PDF is attached...\n\n";

my $my_file = 'pdf.pdf';
my $out_file = 'test.pdf';

my $msg = MIME::Lite->new (
    From => $from_address,
    To => $to_address,
    Subject => $subject,
    Type => 'multipart/mixed') or die "Cannot create multipart container:  $!\n";

$msg->attach (
    Type => 'TEXT',
    Data => $message_body) or die "Cannot attach text: $!\n";

$msg->attach (
    Type => 'application/pdf',
    Path => $my_file,
    Filename => $out_file,
    Disposition => 'attachment') or die "Cannot attach file: $!\n";

MIME::Lite->send('smtp', $mail_host, Timeout=>60);
$msg->send;

my $json = qq{{"success" : "This worked"}};
print $q->header(-type => "application/json", -charset => "utf-8");
print $json;

If I replace the Ajax call and output creation with...

doc.output('dataurlnewwindow',{});    

...then it correctly displays in a new browser tab, so I know the image is being inserted correctly. From what I've found in my searches, it seems to be some encoding issue, but I have not yet found a solution to the problem. How can I get the PDF document, with the image, sent over to Perl on the server successfully, so that it is not corrupt?

Was it helpful?

Solution 3

I found the problem. Before adding the image to the PDF, sending the file to Perl worked without encoding, apparently because there was no (or no pertinent) binary information lost in the sending of the string. Of course, adding the image added very pertinent binary information to the string which could not be sent in a urlencoded message. Encoding/decoding should have taken care of this, but...

I tried many different Base64 encoding/decoding methods, but my file still ended up corrupt. I finally stumbled on a similar issue where someone mentioned that sending the string as part of the URL will convert + signs to spaces. I removed the decoding on the Perl side to see what the encoded string looked like and there were indeed several spaces throughout the string. Converting these back with

$pdf_doc =~ s/ /+/g;

prior to having Perl write to the file fixed the issue. The file is now able to be pulled up in Adobe on the server side.

OTHER TIPS

This issue is resolved in latest version of JSPDF. If you are sending PDF with images to server as form-data using xmlhttprequest.send or as part of ajax call.

please use jsPDF.output('blob') instead of jsPDF.output().

This will not corrupt the pdf when send to server.

OK, This probably will not help you, because youre using Windows, only demostrating:

My test perl script called as app.pl:

#!/usr/bin/env perl
use strict;
use warnings;
use CGI qw(:all);

my $q = CGI->new();
my $pdf_doc = $q->param('perl_pdf');

open (my $fp, '>', 'pdf.pdf') or die "Could not open file";
print $fp $pdf_doc;
close $fp;
print "OK\n";

Have a pdf file called as x.pdf.

$ ls -l x.pdf
-rw-r--r--@ 1 jm  staff  100838 18 mar 19:20 x.pdf

Running an simple test web-server on port 3000

plackup --port 3000 -MPlack::App::WrapCGI -e 'Plack::App::WrapCGI->new( script => "./app.pl", execute => 1)->to_app'

Says:

HTTP::Server::PSGI: Accepting connections at http://0:3000/

From another terminal sending a base64 encoded file via the curl command

$ curl -i -F perl_pdf="$(base64 < x.pdf)" 0:3000/

response:

HTTP/1.0 200 OK
Date: Tue, 18 Mar 2014 20:15:40 GMT
Server: HTTP::Server::PSGI
Content-Length: 3

OK

the server says:

127.0.0.1 - - [18/Mar/2014:21:06:00 +0100] "POST / HTTP/1.1" 200 3 "-" "curl/7.35.0"

and saved the file pdf.pdf The file has base64 encoded content.

$ ls -la pdf.pdf
-rw-r--r--  1 jm  staff  134452 18 mar 21:06 pdf.pdf

decode it

$ base64 -D < pdf.pdf >decoded.pdf

and compare with original

$ cmp decoded.pdf x.pdf
$ ls -la decoded.pdf 
-rw-r--r--  1 jm  staff  100838 18 mar 21:18 decoded.pdf

no difference - sending the pdf - successsful.

Unfortunately, can't help you more, because:

  • youre using Windows
  • and me don't know Javascript...

Consider to check:

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top