Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
92 commits
Select commit Hold shift + click to select a range
c272c28
GH-338 basic signature button setup.
pcorless Mar 19, 2024
f561ba3
GH-238 save point, won't compile but getting close to a proper test.
pcorless Apr 6, 2024
2f12cdf
GH-238 more setup and api definitions.
pcorless Apr 8, 2024
3d6ffc0
GH-238 more setup and api definitions.
pcorless Apr 11, 2024
d33eca6
GH-238 at the crux, calculate offset and contents.
pcorless Apr 15, 2024
68688a8
GH-238 brute force but inserting signature content. Format seems to …
pcorless Apr 17, 2024
2e48ca0
GH-238 save point, singing is working, lots of clean up to do and fea…
pcorless Apr 18, 2024
d44dea4
GH-238 fix missing import.
pcorless Apr 18, 2024
983d317
GH-238 correct issue with /content hex string possibly having an odd …
pcorless Apr 18, 2024
2339fb1
GH-238 save point, further api refinement.
pcorless Apr 22, 2024
db95f43
GH-238 further definitions for Pkcs#11 and Pkcs#11 keystore handling.
pcorless Apr 23, 2024
ff1cd10
GH-238 cleanup
pcorless Apr 24, 2024
3f0ef5b
GH-238 fix bug in pkcs provider configuration and installation. Added…
pcorless Apr 25, 2024
4af9508
GH-238 cleanup
pcorless Apr 25, 2024
a9b46ab
GH-238 fix parsing issues when converting a hex string to an integer.
pcorless Apr 26, 2024
1e1b04d
GH-238 fix parsing issues when converting a hex string to an integer.
pcorless Apr 26, 2024
ecb4d42
Merge remote-tracking branch 'origin/master' into GH-238.document.sig…
pcorless May 9, 2024
93bdbf2
GH-238 callback api for appearance stream generation.
pcorless May 15, 2024
5382a9f
GH-238 touch up some offset issues when writing the signature values …
pcorless May 23, 2024
1e12ffc
GH-356 save point
pcorless May 25, 2024
0bbbf47
GH-356 save point, signature layout
pcorless May 29, 2024
5808f36
GH-238 signature formatting save point
pcorless Jun 6, 2024
b44a65e
GH-238 build out annotation content generation utility class.
pcorless Jun 7, 2024
3782cd7
GH-238 save point, working on getting signature image to render.
pcorless Jun 20, 2024
8ba073d
GH-238 save point, something rendering, colour space/decode is still…
pcorless Jun 21, 2024
eafdf5a
GH-238 get an embedded test images rendering.
pcorless Jun 25, 2024
feebb4f
GH-238 save point, added transparency and starting to build out appea…
pcorless Jun 26, 2024
01cdc43
GH-238 basic layout for SignatureAppearanceModel, next step is buildi…
pcorless Jun 27, 2024
4fea864
GH-238 working out api kinks
pcorless Jun 28, 2024
f1beeac
GH-238 add plumbing for specifying PKCS configurations.
pcorless Jul 3, 2024
9e81486
GH-238 save point
pcorless Jul 5, 2024
accf508
GH-238 save point
pcorless Jul 9, 2024
35c9d04
GH-238 save point
pcorless Jul 11, 2024
c98f0d1
GH-238 save point
pcorless Jul 18, 2024
f221e7e
GH-238 doc updates
pcorless Jul 19, 2024
ffa12d7
Merge remote-tracking branch 'origin/main' into GH-238.document.signing
pcorless Jul 19, 2024
80202d0
GH-238 touch up module info declarations.
pcorless Jul 19, 2024
ae90a49
GH-238 fix merge issue and i18n keystore password dialog.
pcorless Jul 21, 2024
8d6f512
GH-238 save point, start on appearance settings
pcorless Jul 22, 2024
440b9a2
GH-238 save point
pcorless Jul 24, 2024
728bd4f
GH-238 save point
pcorless Jul 31, 2024
64fdf64
GH-238 save point
pcorless Aug 2, 2024
4bc6253
GH-238 save point, basic signature image loading, still lots of lose…
pcorless Aug 8, 2024
3ec1f5d
Merge remote-tracking branch 'origin/main' into GH-238.document.signing
pcorless Aug 30, 2024
daeea46
GH-238 debugging appearance stream regression
pcorless Aug 30, 2024
78a7d1b
GH-238 debugging appearance stream regression
pcorless Aug 30, 2024
053c9b3
GH-238 found font size issue.
pcorless Aug 31, 2024
4ddc505
GH-238 finally figured out preview paint issue. Can get back to impr…
pcorless Sep 4, 2024
adfc6cc
GH-238 creation dialog tweaks for live preview of what signature will…
pcorless Sep 5, 2024
d1d62fa
GH-238 implement more of the signature dialog ui controls
pcorless Sep 6, 2024
2b9e818
GH-238 further cleanup of signature resources on deletion and cancell…
pcorless Sep 6, 2024
6d1774b
GH-238 add a basic signature scaling slider.
pcorless Sep 10, 2024
2959cbe
GH-238 add browse buttons for pkcs cert and image selection
pcorless Sep 10, 2024
0e34928
GH-238 start of code clean up and refinements for signature creation.
pcorless Sep 11, 2024
b8df621
GH-238 code clean up.
pcorless Sep 12, 2024
2774d81
GH-238 code clean up.
pcorless Sep 12, 2024
34be1aa
GH-238 add centering of text and image inside the signatures bounding…
pcorless Sep 13, 2024
23928c5
GH-238 fix duplicate stream generations issues.
pcorless Sep 18, 2024
18bdbc8
GH-238 fix signer hashed data length and tighten up certificate error…
pcorless Sep 18, 2024
f1483b6
GH-238 fix offset issue when writing new ByteRange
pcorless Sep 18, 2024
3d21f05
GH-238 fix acroform dictionary not being populated
pcorless Sep 19, 2024
79bda7e
GH-238 further refinement around deletion cleanup and lots of small b…
pcorless Sep 19, 2024
6306300
GH-238 fix immutable list bug.
pcorless Sep 19, 2024
5ed9e19
GH-238 limit signature creation via the viewer ri to one instance.
pcorless Sep 20, 2024
bb3698d
GH-238 update signatures examples to latest api.
pcorless Sep 21, 2024
77dc1c8
GH-238 signer test formating.
pcorless Sep 21, 2024
2d3cca7
GH-238 cleaned up signature icon and various states.
pcorless Sep 23, 2024
55ba631
Merge remote-tracking branch 'origin/main' into GH-238.document.signing
pcorless Sep 23, 2024
ecaa79c
Merge remote-tracking branch 'origin/main' into GH-238.document.signing
pcorless Sep 23, 2024
70004dc
GH-238 support multiple signature annotation from one signature dicti…
pcorless Sep 24, 2024
7299ebd
GH-238 fix save pkcs path keys.
pcorless Sep 25, 2024
b9b6a97
GH-238 make class name a little more descriptive.
pcorless Oct 4, 2024
177b4d1
GH-379 update authentication logging to show exception.
pcorless Nov 29, 2024
0acad0e
GH-238 add keystore authentication failed dialog
pcorless Nov 29, 2024
04a27ba
GH-238 fix refresh issue with signature type radio toggle.
pcorless Nov 29, 2024
586a241
Merge remote-tracking branch 'origin/main' into GH-238.document.signing
pcorless Nov 29, 2024
7f49091
Merge remote-tracking branch 'origin/main' into GH-238.document.signing
pcorless Feb 20, 2025
abe7805
GH-238 fix merge issue.
pcorless Feb 20, 2025
202dcb4
GH-238 improve text centering.
pcorless Feb 21, 2025
8bbf238
GH-238 fix finally copy issue if there is no signature.
pcorless Feb 22, 2025
1cb30fd
GH-238 touch up label as PKCS12 isn't a keystore.
pcorless Feb 25, 2025
989326a
Merge remote-tracking branch 'origin/main' into GH-238.document.signing
pcorless Apr 15, 2025
868d659
GH-238 fix post merge method signature change.
pcorless Apr 15, 2025
c2521b0
Merge remote-tracking branch 'origin/main' into GH-238.document.signing
pcorless Apr 17, 2025
dbdebef
GH-236 post merge touch up.
pcorless Apr 17, 2025
d116de2
GH-238 improve image centering
pcorless Apr 23, 2025
2638bf2
GH-238 re-enable annotation content stream encoding
pcorless Apr 23, 2025
8f79322
Merge remote-tracking branch 'origin/main' into GH-238.document.signing
pcorless May 2, 2025
7c42526
Merge remote-tracking branch 'origin/main' into GH-238.document.signing
pcorless May 2, 2025
fc3e426
GH-238 clean up.
pcorless May 5, 2025
be795cf
GH-238 error message improvements when working with fresh config.
pcorless May 7, 2025
60aa267
GH-238 add default properties states for new annotations toolbar butt…
pcorless May 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions core/core-awt/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,14 @@
exports org.icepdf.core.pobjects;
exports org.icepdf.core.pobjects.acroform;
exports org.icepdf.core.pobjects.acroform.signature;
exports org.icepdf.core.pobjects.acroform.signature.appearance;
exports org.icepdf.core.pobjects.acroform.signature.certificates;
exports org.icepdf.core.pobjects.acroform.signature.exceptions;
exports org.icepdf.core.pobjects.acroform.signature.handlers;
exports org.icepdf.core.pobjects.acroform.signature.utils;
exports org.icepdf.core.pobjects.actions;
exports org.icepdf.core.pobjects.annotations;
exports org.icepdf.core.pobjects.annotations.utils;
exports org.icepdf.core.pobjects.fonts;
exports org.icepdf.core.pobjects.graphics;
exports org.icepdf.core.pobjects.graphics.commands;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
* class for convenience, but can also be accessed via the {@link PTrailer} class.
* Useful information about the document can be extracted from the Catalog
* Dictionary, such as PDF version information and Viewer Preferences. All
* Catalog dictionary properties can be accesed via the getEntries method.
* Catalog dictionary properties can be accessed via the getEntries method.
* See section 3.6.1 of the PDF Reference version 1.6 for more information on
* the properties available in the Catalog Object. </p>
*
Expand Down Expand Up @@ -415,6 +415,23 @@ public InteractiveForm getInteractiveForm() {
return interactiveForm;
}

/**
* Gets the interactive form object that contains the form widgets for the given PDF. This method should be
* called before adding new widgets.
*
* @return The interactive form object if it exists, if null a new dictionary is inserted into the document.
*/
public InteractiveForm getOrCreateInteractiveForm() {
if (interactiveForm == null) {
interactiveForm = new InteractiveForm(library, new DictionaryEntries());
StateManager stateManager = library.getStateManager();
this.entries.put(ACRO_FORM_KEY, interactiveForm);
stateManager.addChange(new PObject(this, this.getPObjectReference()));
return interactiveForm;
}
return interactiveForm;
}

/**
* Returns a summary of the Catalog dictionary values.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -649,7 +649,7 @@ public long saveToOutputStream(OutputStream out, WriteMode writeMode) throws IOE
* There are two possible entries, SCREEN and PRINT each with configurable
* rendering hints settings.
* @param pageBoundary Constant specifying the page boundary to use when
* painting the page content. Typically use Page.BOUNDARY_CROPBOX.
* painting the page content. Typically, use Page.BOUNDARY_CROPBOX.
* @param userRotation Rotation factor, in degrees, to be applied to the rendered page.
* Arbitrary rotations are not currently supported for this method,
* so only the following values are valid: 0.0f, 90.0f, 180.0f, 270.0f.
Expand Down
65 changes: 64 additions & 1 deletion core/core-awt/src/main/java/org/icepdf/core/pobjects/Form.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.icepdf.core.pobjects.graphics.ExtGState;
import org.icepdf.core.pobjects.graphics.GraphicsState;
import org.icepdf.core.pobjects.graphics.Shapes;
import org.icepdf.core.pobjects.graphics.images.ImageStream;
import org.icepdf.core.util.Library;
import org.icepdf.core.util.parser.content.ContentParser;
import org.icepdf.core.util.updater.callbacks.ContentStreamCallback;
Expand All @@ -28,6 +29,10 @@
import java.util.logging.Level;
import java.util.logging.Logger;

import static org.icepdf.core.pobjects.Resources.FONT_KEY;
import static org.icepdf.core.pobjects.Resources.XOBJECT_KEY;
import static org.icepdf.core.pobjects.annotations.FreeTextAnnotation.EMBEDDED_FONT_NAME;

/**
* Form XObject class. Not currently part of the public api.
* <br>
Expand Down Expand Up @@ -140,7 +145,7 @@ private static AffineTransform getAffineTransform(List v) {

/**
* As of the PDF 1.2 specification, a resource entry is not required for
* a XObject and thus it needs to point to the parent resource to enable
* a XObject, thus it needs to point to the parent resource to enable
* to correctly load the content stream.
*
* @param parentResource parent objects resourse when available.
Expand Down Expand Up @@ -212,6 +217,64 @@ public void setResources(Resources resources) {
entries.put(RESOURCES_KEY, resources.getEntries());
}

/**
* Add a Font resource to this Form's resource dictionary. This is intended for new object only, can't guarantee
* this method will work as expected on an existing object.
*
* @param fontDictionary font dictionary to add as a resource
*/
public void addFontResource(DictionaryEntries fontDictionary) {
StateManager stateManager = library.getStateManager();
org.icepdf.core.pobjects.fonts.Font newFont;
Resources formResources = getResources();
DictionaryEntries fontsDictionary = formResources.getFonts();
if (fontsDictionary == null) {
fontsDictionary = new DictionaryEntries();
formResources.entries.put(FONT_KEY, fontsDictionary);
}
if (formResources.getFont(EMBEDDED_FONT_NAME) == null) {
// set up a new font resource
newFont = new org.icepdf.core.pobjects.fonts.zfont.SimpleFont(library, fontDictionary);
newFont.setPObjectReference(stateManager.getNewReferenceNumber());
// create font entry
fontsDictionary.put(EMBEDDED_FONT_NAME, newFont.getPObjectReference());
// sync font resources with form object.
entries.put(RESOURCES_KEY, formResources.entries);
} else {
// reuse previously defined 'common' annotation font
newFont = formResources.getFont(EMBEDDED_FONT_NAME);
Reference reference = newFont.getPObjectReference();
newFont = new org.icepdf.core.pobjects.fonts.zfont.SimpleFont(library, fontDictionary);
newFont.setPObjectReference(reference);
}

// update hard reference to state manager and weak library reference.
stateManager.addChange(new PObject(newFont, newFont.getPObjectReference()), isNew);
library.addObject(newFont, newFont.getPObjectReference());
// make sure the form changes get picked up as well
stateManager.addChange(new PObject(this, getPObjectReference()), isNew);
}

/**
* Add an ImageStream to this Form's resource dictionary. This is intended for new object only, can't guarantee
* this method will work as expected on an existing object.
*
* @param imageName named image
* @param imageStream corresponding ImageStream data
*/
public void addImageResource(Name imageName, ImageStream imageStream) {
Resources formResources = getResources();
DictionaryEntries xObjectsDictionary = formResources.getXObjects();
if (xObjectsDictionary == null) {
xObjectsDictionary = new DictionaryEntries();
formResources.entries.put(XOBJECT_KEY, xObjectsDictionary);
}
// sync form resources with form object.
entries.put(RESOURCES_KEY, formResources.entries);
xObjectsDictionary.put(imageName, imageStream.getPObjectReference());
StateManager stateManager = library.getStateManager();
stateManager.addChange(new PObject(this, getPObjectReference()), isNew);
}

/**
* Gets the shapes that where parsed from the content stream.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,21 @@ public static HexStringObject createHexString(String literalstring) {
return new HexStringObject(hexString.toString());
}

public static String encodeHexString(byte[] byteArray) {
StringBuffer hexStringBuffer = new StringBuffer();
for (int i = 0; i < byteArray.length; i++) {
hexStringBuffer.append(byteToHex(byteArray[i]));
}
return hexStringBuffer.toString();
}

private static String byteToHex(byte num) {
char[] hexDigits = new char[2];
hexDigits[0] = Character.forDigit((num >> 4) & 0xF, 16);
hexDigits[1] = Character.forDigit((num & 0xF), 16);
return new String(hexDigits);
}

/**
* Encodes the given contents string into a 4 byte hex string. This allows us to easily account for
* mixed encoding of 2-byte and 4 byte string content.
Expand Down Expand Up @@ -281,7 +296,8 @@ private static StringBuilder normalizeHex(StringBuilder hex, int step) {
if (step == 2) {
// pre append 0's to uneven length, be careful as the 0020 isn't the same as 2000
if (length % 2 != 0) {
hex = new StringBuilder("0").append(hex);
// this was done for variable byte font encoding, this seems risky to preappend, pulling
hex = hex.append("0");//new StringBuilder("0").append(hex);
}
}
if (step == 4) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ private static synchronized int getUniqueId() {
private static final Logger logger =
Logger.getLogger(Resources.class.toString());

final DictionaryEntries fonts;
final DictionaryEntries xobjects;
DictionaryEntries fonts;
DictionaryEntries xobjects;
final DictionaryEntries colorspaces;
final DictionaryEntries patterns;
final DictionaryEntries shading;
Expand All @@ -71,6 +71,9 @@ public Resources(Library l, DictionaryEntries h) {
}

public DictionaryEntries getFonts() {
if (fonts == null) {
fonts = library.getDictionary(entries, FONT_KEY);
}
return fonts;
}

Expand Down Expand Up @@ -213,6 +216,9 @@ public Object getXObject(Name s) {
}

public DictionaryEntries getXObjects() {
if (xobjects == null) {
xobjects = library.getDictionary(entries, XOBJECT_KEY);
}
return xobjects;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public class StateManager {
private final CrossReferenceRoot crossReferenceRoot;

private final AtomicInteger nextReferenceNumber;
private final AtomicInteger nextImageNumber;

// snapshot of currently saved changes
private Map<Reference, StateManager.Change> savedChangesSnapshot = new HashMap<>();
Expand All @@ -61,6 +62,8 @@ public StateManager(CrossReferenceRoot crossReferenceRoot) {
// thus the next available number.
nextReferenceNumber = new AtomicInteger();
nextReferenceNumber.set(this.crossReferenceRoot.getNextAvailableReferenceNumber());
// named image reference count
nextImageNumber = new AtomicInteger((int) (Math.random() * 1000));
}

/**
Expand All @@ -75,6 +78,17 @@ public Reference getNewReferenceNumber() {
return new Reference(nextReferenceNumber.getAndIncrement(), 0);
}

/**
* Gets an image number to be used when generating image references. The initial value is randomly
* generated and incremented for each addition image added to the document. There should be very little
* chance that signature would have the same name.
*
* @return unique image number for building images names
*/
public int getNextImageNumber() {
return nextImageNumber.getAndIncrement();
}

/**
* Add a new PObject containing changed data to the cache.
*
Expand Down Expand Up @@ -206,6 +220,12 @@ public CrossReferenceRoot getCrossReferenceRoot() {
return crossReferenceRoot;
}

/**
* Checks to see if any redaction annotations are present in the changes. This is used to determine if
* the document has redactions that need to be burned in.
*
* @return true if redactions are present, false otherwise.
*/
public boolean hasRedactions() {
if (changes.isEmpty()) return false;
Collection<Change> changesValues = changes.values();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ public int getPermissions() {
* @return always returns 1.2 as a name.
*/
public Name getVersion() {
return DocMDPTransferParam.getDocMDPVersion();
}

public static Name getDocMDPVersion() {
return new Name("1.2");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@
package org.icepdf.core.pobjects.acroform;

import org.icepdf.core.pobjects.*;
import org.icepdf.core.pobjects.annotations.AbstractWidgetAnnotation;
import org.icepdf.core.pobjects.annotations.SignatureWidgetAnnotation;
import org.icepdf.core.util.Library;
import org.icepdf.core.util.Utils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Logger;

Expand Down Expand Up @@ -206,6 +208,36 @@ public synchronized void init() {
}
}

public void addField(Object field) {
if (!(field instanceof AbstractWidgetAnnotation)) {
throw new IllegalStateException("Field must be an AbstractWidgetAnnotation");
}
if (fields == null) {
fields = new ArrayList<>();
fields.add(field);
entries.put(FIELDS_KEY,
new ArrayList<>(Arrays.asList(((AbstractWidgetAnnotation) field).getPObjectReference())));
} else {
fields.add(field);
List<Reference> fieldReferences = (List<Reference>) library.getObject(entries, FIELDS_KEY);
fieldReferences.add(((AbstractWidgetAnnotation) field).getPObjectReference());
}
// mark the catalog as changed, this object is always contained in the catalog as a dictionary, it
// should never be an indirect reference.
Catalog catalog = library.getCatalog();
StateManager stateManager = library.getStateManager();
stateManager.addChange(new PObject(catalog, catalog.getPObjectReference()));
}

public void removeField(AbstractWidgetAnnotation field) {
if (fields != null) {
fields.remove(field);
List<Reference> fieldReferences = (List<Reference>) library.getObject(entries, FIELDS_KEY);
fieldReferences.remove((field).getPObjectReference());
}
}


/**
* Gets the fields associated with this form.
*
Expand All @@ -216,7 +248,8 @@ public ArrayList<Object> getFields() {
}

/**
* Gets the signature fields associated with this form. A new array that references the forms signature annotations.
* Gets the signature fields associated with this form. A new array that references the forms signature
* annotations.
* If no fields are found an empty list is returned.
*
* @return a list of form signature objects.
Expand Down Expand Up @@ -351,7 +384,8 @@ public String getDefaultVariableTextDAField() {
/**
* Ges the default variable text quadding rule.
*
* @return integer represented by VariableTextFieldDictionary.QUADDING_LEFT_JUSTIFIED, VariableTextFieldDictionary.QUADDING_CENTERED or
* @return integer represented by VariableTextFieldDictionary.QUADDING_LEFT_JUSTIFIED,
* VariableTextFieldDictionary.QUADDING_CENTERED or
* VariableTextFieldDictionary.QUADDING_RIGHT_JUSTIFIED.
*/
public int getDefaultVariableTextQField() {
Expand Down
Loading