3

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?

mike
  • 55
  • 11
  • Without trying to analyze the scripts, you should first to try sending one 100% ok pdf (e.g. what is verified) with the perl script. If it will send OK the problem is in JS - if not - time to checking the perl script ;) – clt60 Mar 18 '14 at 17:10
  • and.. consider: MIME::Lite is not recommended by its current maintainer. ... https://metacpan.org/pod/MIME::Lite – clt60 Mar 18 '14 at 17:13
  • @jm666, please read my original post again - the app works correctly if there is no image in the PDF; the document is created, sent to the server, Perl emails it, the recipient opens it successfully. When the image is added, the PDF is generated correctly and opens correctly if it is sent to the browser. It does not work, however, when there is an image and I send it to the server. Again, all indications that I've found point to encoding issues with the image - base64 vs UTF-8, but I have not found a solution in how to deal with this. – mike Mar 18 '14 at 17:19
  • read my comment again. Are you sure than the saved file pdf.pdf realy contains the right data? I'm not. You should: 1.) base64 encode the whole pdf on the JS side, 2.) send the base64 encoded string to the server as POST 3.) in the perl script decode the base64 to get the original content. Because the base64 containing only ascii you shouldn't care about the encoding. – clt60 Mar 18 '14 at 18:36
  • Okay, I've edited the scripts - I'm using the encodeURIComponent() method on the data in the Ajax call, then decoding it once Perl receives it. The resulting PDF file is still corrupt. I cannot tell if the encoding is corrupting it or the decoding. – mike Mar 18 '14 at 19:44

3 Answers3

1

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.

Jérémie Bertrand
  • 3,025
  • 3
  • 44
  • 53
0

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:

Community
  • 1
  • 1
clt60
  • 62,119
  • 17
  • 107
  • 194
0

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.

mike
  • 55
  • 11