corymickelson / NoPoDoFo

node pdf native bindings
GNU Affero General Public License v3.0
26 stars 6 forks source link

Transparent png support #99

Open MatthewMarkgraaff opened 5 years ago

MatthewMarkgraaff commented 5 years ago

Hey @corymickelson :) Thanks again for this awesome library!

Is there currently a way to embed png images with transparent backgrounds whilst retaining the transparency?

I've had no luck so far after playing around with the Painter class and ExtGState.

For reference sake, here are some examples:

Using ExtGState to try fiddle with transparency:

Screenshot 2019-08-06 at 17 05 14

I realised this affects the painter in it's entirety so the image itself becomes transparent and not only the background

Screenshot 2019-08-06 at 17 05 37

This is a png with transparent background and no ExtGState option being appied.

Your assistance would be hugely appreciated

corymickelson commented 5 years ago

Thank you Matthew for raising this issue. This is a feature/new method I will add to the Image class, I will update you when it's completed.

corymickelson commented 5 years ago

Thank you again Matthew for raising this issue. I have added support for adding image masking/transparency on the Image class as setChromaKeyMask. I've also added to the signer tests an example of using this function to make a signature's background transparent. Please see https://github.com/corymickelson/NoPoDoFo/blob/master/spec/unit/Signer.ts#L128 for more details.

const image = new nopodofo.Image(doc, 'someImg.png')
image.setChromaKeyMask(255, 255, 255, 100)
const painter = new nopodofo.Painter(doc)
painter.setPage(page)
painter.drawImage(image, rect.left, rect.bottom, {width: rect.width, height: rect.height})
MatthewMarkgraaff commented 5 years ago

This is awesome! Thank you! 🥇 I'm on vacation at the moment but as soon as I have a chance I'll implement and give feedback here.

MatthewMarkgraaff commented 5 years ago

Out of interest, is there currently a way to write the image content directly into the signature field content?

From my limited understanding of the PDF spec, an image or other data may be associated directly to a signature. So that when a signature is invalidated or required to be removed for whatever reason, itself and it's content (including the underlying image) can be removed together. Is this something NoPoDoFo currently does or could possibly support?

corymickelson commented 5 years ago

@MatthewMarkgraaff Good question, the signature field does allow you to explicitly set the appearance stream of the field. The appearance stream is an PDF object with some predefined appearance(s) and can be used for multiple states of the target property, for example you can create an appearance stream for a button when the state of the button is rollover(hover), on, and off. Appearance streams are a lower level functionality of PDF, and without some prior knowledge/experience they can be challenging to work with. This is a great use case though. I will keep this in mind for future development. Thank you for mentioning this use case.

MatthewMarkgraaff commented 5 years ago

@corymickelson Thanks for the detailed response 💯

Is the only way to link a stamp or png of a digital signature to a signature object? I understand that an image or stamp is not required to produce a valid digital signature but are a requirement of most if not all signature solutions (including the one i'm building).

I see there is some support for appearance streams in the current version. Is what we've discussed possible with the current NoPoDoFo feature set? If not, I'd be happy to assist where I can to get this done.

MatthewMarkgraaff commented 5 years ago

I closed this by mistake

MatthewMarkgraaff commented 5 years ago

Hey @corymickelson, unfortunately, I can't seem to get this working

Code:

const doc = await loadDocument(docPath);
    const image = new nopodofo.Image(doc, "/Users/matt/Desktop/1x.png");
    image.setChromaKeyMask(255, 255, 255, 100);
    const painter = new nopodofo.Painter(doc);
    const page = doc.getPage(pageIndex);
    painter.setPage(page);
    painter.drawImage(image, positionOpts.left, positionOpts.bottom, {width: positionOpts.width, height: positionOpts.height});
    painter.finishPage();

Here is the result:

Screenshot 2019-08-28 at 22 52 55 Screenshot 2019-08-28 at 22 41 02
corymickelson commented 5 years ago

@MatthewMarkgraaff can you share the image your trying to mask with me. Thanks

MatthewMarkgraaff commented 5 years ago

Sure thing, here's an example:

sig

corymickelson commented 5 years ago

@MatthewMarkgraaff after doing some research I have found some information that I am hoping will help, the root cause however i've yet had time to address. So... the images your are creating are png's with a transparent background. The image chromakey mask operates on rgb colors. When we use something like:

image.setChromaKeyMask(255,255,255,100)

we are saying: hey please find all colors within the rgb colorspace ranging from 155,155,155 to 355,355,355 (remember the last value is the threshold for masking, which is calculated as value + threshold to value - threshold, any colors within that range will be masked)and dont paint any of those colors to the document. When the image we are loading is already transparent we cant (this maybe possible but I haven't figured it out yet) declare the colorspace to mask because that color space is defined in the alpha channel rgba, which is not supported currently. In summary to make this work all you need to do is save your images without a transparent background. To test this you can create an image and save it with and without transparency, here's an easy to use tool to quickly generate some test images and run the signer spec with your transparent and non-transparent png's. You will find that the one saved without transparency will behave as expected.

MatthewMarkgraaff commented 5 years ago

@corymickelson thank you for the detailed explanation. I haven't much experience working with masking and image files so this was a great help. I'll give this a try with images without a transparent background and revert.