Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

png 24 and png 32 support added to addimage #195

Merged
merged 7 commits into from Mar 12, 2014
Merged

Conversation

jamesbrobb
Copy link
Contributor

Hi,

i've added png support to addimage. 24 and 32 bit at this point and i'm looking into 8. I've also added the ability to pass ArrayBuffer and ArrayBufferView/TypedArray to addimage, although i'm not sure if this is actually desirable?

I need to get together a list of my additions and the thinking behind them and also an example file. And it also needs a bit of refactoring/optimization. But i just thought i'd send this over now and get the ball rolling.

If there's anything that makes you think 'WTF is this guy on', i'm fairly new to JS, so bare with me...

png 32 and png 24 support added to addImage
partial png 8, but needs looking at as there are issues with
transparency… and colour
ArrayBuffer and ArrayBufferView/TypedArray support added to addImage
@MrRio
Copy link
Member

MrRio commented Feb 15, 2014

That's brilliant! Thanks for that. I'll have a look through it.

Added example file
added transparent parameter for greater control of canvas output when
adding a DOM element
@jamesbrobb
Copy link
Contributor Author

Nice one, no problem. I've now added an example html.

I've also added a new parameter to addImage - transparency. This is really just for use with DOM elements, as i'd set it to canvas.toDataURL(), instead of canvas.toDataURL('image/jpeg'), so that transparency was maintained for any element that had it, but there's a big difference in file size. As 'image/jpeg' it's coming out at 17kb, but with transparency ('image/png') it's 238kb. Unless there's an easy way to tell if a DOM element has transparency?

This is due to the way that transparency is dealt with in the pdf. You have to take the raw, uncompressed pixel bytes and separate them out into two TypedArray's of colour and alpha. These then get added as two separate images to the pdf, with the alpha also getting applied as a mask (or smask, as it's called).

I think it's also possible to re-compress those bytes using zlib or LZW compression, but i need to take a look at that. As otherwise it'll be quite a jump in file size if you have a lot of images.

@diegocr
Copy link
Collaborator

diegocr commented Feb 17, 2014

Awesome work without a doubt, congrats and thanks! :-)

However, if i could request something... is that such PNG support is made optional, I.e having to ship all these dependencies with our dist files will apparently turn them too bloated, IMHO.

@jamesbrobb
Copy link
Contributor Author

Yeah definitely. I'm going to look at refactoring/optimization over the next few nights and will look at separating it out.

heavy refactoring - separated png functionality into separate plugin
added compression to transparent pngs
added png filter method 0
fixed indexed png colour issues, but still no transparency
made addImage method scaleable for new formats
@jamesbrobb
Copy link
Contributor Author

I've refactored addImage and separated out the png support. To add support for any new image format, all you need to do is add it's type to the 'supported_image_types' array at the top of the addImage plugin and then create a new plugin that implements a method with this signature,

jsPDFAPI.process[IMAGE TYPE] = function(data, index, alias, compress, dataAsBinaryString)

So to implement tiff support you'd have,

supported_image_types = ['jpeg', 'jpg', 'png', 'tiff'];

and a plugin with,

jsPDFAPI.processTIFF = function(data, index, alias, compress, dataAsBinaryString)

You can see this in action in jspdf.plugin.png_support.js

@jamesbrobb
Copy link
Contributor Author

I've added zlib compression, but it's using zpipe at the moment as i've struggled to get it working with Deflate. I've also noticed an issue when adding multiple compressed images, as it doesn't look like zpipe is cleaning itself up properly... or it might just me.

Also indexed png's have moved a step closer, as the image is now displaying correctly, but i still need to sort out the transparency.

@jamesbrobb
Copy link
Contributor Author

One last thing. At the moment if you pass in a jpeg as an ArrayBuffer, there's a dependency on jpg.js. This is overkill (was just there to get it working), as it parses the entire jpeg. I need to just look at abstracting out the part that gets the width and height from the buffer, as that's all we need.

Oh. And i've got rid of the 'transparency' param that i added and just use the format that's passed instead. It was only being used for DOM elements, so now if 'png' is specified as the format when a DOM element is passed to addImage as the imageData, it knows to keep the transparency.

8 bit colour types supported and 16 bit for type 1, 2, 4 and 6
Recompression added using Deflator - now recompresses images and masks
Colour type 3 key masks and smack support added for multi pixel alpha
example updated
@jamesbrobb
Copy link
Contributor Author

Support's now added for all 5 png colour types. Recompression (using Deflate.js) and png filters have also been implemented and can be set at varying levels. And i've updated the example file so that the output of all different types can be tested.

MrRio added a commit that referenced this pull request Mar 12, 2014
@MrRio MrRio merged commit e8a92c1 into parallax:master Mar 12, 2014
@MrRio
Copy link
Member

MrRio commented Mar 12, 2014

This is brilliant thanks. I will make separate issues to bring the dependencies down a bit

@jamesbrobb
Copy link
Contributor Author

No problem, glad to help out.

A couple of things i forgot to mention. There's a small modification to png.js on line 142 - it's commented to explain why - so that specific version is needed to convert indexed png's. I've opened an issue on the authors repos, but looking at his response rate, i don't think it'll be updated any time soon.

The other thing is the dependency on ArrayBuffer and TypedArray to add a png. I briefly looked for a shim/polyfill, but nothing i found was suitable as they all have size restrictions on the the array that can be produced and due to language capabilities, aren't very efficient.

So currently on line 351 of jspdf.plugin.png_support.js there's an empty block where this should be handled. I was going to have a look at rewriting a version of png.js that handles binary strings instead, but due to a new work commitment, don't have time at the moment.

@sebastianperrone
Copy link

I'm was testing png ecoding with phonegap in android and result in a corrupt pdf. The text shown ok, but the images are corrupt. I test using directly the data string of each example image of this issue. In all cases (jpg too) the image was shown corrupted. The code I use was the following:

function createOrder() {
    console.log("create pdf object");
    pdf = new jsPDF("p", "mm", "a4")
    var imgData = "data:image/png;base64,iVBORw0..."; 
    //var imgData = "data:image/png;base64,iVBORw0KG...";
    //var imgData = "data:image/jpeg;base64,/9j/4AAQ...";
    //var imgData = "data:image/jpeg;base64,/9j/4AAQ...";
    pdf.addImage(imgData, "JPG", 14, 28, 44, 18); // or PNG for .png images
    printText(rows); // function which add text (this works fine)
    return pdf;
}

I try each one of the commented image data.
am I doing something wrong ? is there any solution for this problem ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants