I'm trying to create a PDF that's PAC3 approved for accessibility but I'm having an issue when it comes to the links I'm writing. This is the code I have one function that draws the text and tags it given the structType (this function is from https://github.com/chris271/UAPDFBox/blob/a8b280bcbc838722ba872d6b382b8fd45bd35303/src/com/wi/test/util/PDFormBuilder.java)
public PDStructureElement drawElement(Cell textCell, float x, float y, float height,PDStructureElement parent,
String structType, int pageIndex) throws IOException {
//Set up the next marked content element with an MCID and create the containing H1 structure element.
PDPageContentStream contents = new PDPageContentStream(pdf, pages.get(pageIndex),
PDPageContentStream.AppendMode.APPEND, false);
currentElem = addContentToParent(null, structType, parent);
setNextMarkedContentDictionary();
contents.beginMarkedContent(COSName.ARTIFACT, PDPropertyList.create(currentMarkedContentDictionary));
//Draws the cell itself with the given colors and location.
drawDataCell(textCell, x, y + height, height * 2, contents);
contents.endMarkedContent();
addContentToParent(COSName.ARTIFACT, null, currentElem);
contents.close();
//Set up the next marked content element with an MCID and create the containing P structure element.
contents = new PDPageContentStream(pdf, pages.get(pageIndex), PDPageContentStream.AppendMode.APPEND, false);
setNextMarkedContentDictionary();
contents.beginMarkedContent(COSName.P, PDPropertyList.create(currentMarkedContentDictionary));
//Draws the given text centered within the current table cell.
drawCellText(textCell, x, y + height + textCell.getFontSize(), contents, pages.get(pageIndex).getResources());
//End the marked content and append it's P structure element to the containing P structure element.
contents.endMarkedContent();
addContentToParent(COSName.P, null, currentElem);
contents.close();
return currentElem;
}
After it's written to the page I call a separate function to add the underline for hyperlinks
public void drawLink(float firstX,float firstY,float lastX,float width, float height,int pageNum, float lastCharWidth) throws IOException {
PDAnnotationTextMarkup markup = new PDAnnotationTextMarkup(PDAnnotationTextMarkup.SUB_TYPE_UNDERLINE);
PDRectangle position = new PDRectangle();
position.setLowerLeftX(firstX);
position.setLowerLeftY(firstY);
position.setUpperRightX(firstX + width);
position.setUpperRightY(firstY + height);
markup.setRectangle(position);
//need to modify quadpoints lastX so it's inline with link
float quadPoints[] = {firstX, firstY + height + 2,
lastX + lastCharWidth, firstY + height + 2,
firstX, firstY - 5,
lastX + lastCharWidth, firstY - 5};
markup.setQuadPoints(quadPoints);
PDColor color = new PDColor(new float[]{ 1, 15/ 255F, 1 }, PDDeviceRGB.INSTANCE);
markup.setColor(color);
pdf.getPage(pageNum).getAnnotations().add(markup);
}
The result of calling these 2 functions are below, it draws the link properly but I'm missing information for the annotation. My question is how do I utilize the PDAnnotation object to create a PAC3 approved annotation?
Image of PAC3 detailed results
Related
I am developing an application using kotlin and opencv. The application has an image segmentation step in which the user marks a region of interest which I need to fill in the entire outside of that region with black. I'm taking the coordinates of the marked region and using floodFill to fill the image. However, with the code below it ends up filling the whole image, and not just the external region of the mark.
Code:
private fun extractBackground(coordinates: Coordinates, currentPhotoPath: String): String {
// TODO: Provide complex object that has both path and extension
val width: Int
val height: Int
width = bitmap.getWidth()
height = bitmap.getHeight()
val rect = Rect(coordinates.first, coordinates.second)
val rgba = Mat()
val gray_mat = Mat()
val threeChannel = Mat()
Utils.bitmapToMat(bitmap, gray_mat)
Imgproc.cvtColor(gray_mat, rgba, Imgproc.COLOR_RGBA2RGB)
Imgproc.cvtColor(rgba, threeChannel, Imgproc.COLOR_RGB2GRAY)
val mask = Mat.zeros(rgba.rows() + 2, rgba.cols() + 2, CvType.CV_8UC1)
Imgproc.floodFill(rgba, mask, Point(0.0, 0.0), Scalar(255.0), rect, Scalar(0.0), Scalar(0.0), 4 + (255 shl 8) + Imgproc.FLOODFILL_MASK_ONLY)
Core.subtract(mask, Scalar.all(0.0), mask)
val roi = Rect(1, 1, rgba.cols() - 2, rgba.rows() - 2)
val temp = Mat()
mask.submat(roi).copyTo(temp)
Imgcodecs.imwrite(currentPhotoPath + "_tmp.png", temp)
return currentPhotoPath
}
Input:
Output:
Expected output:
can someone help me fix this?
I need to create PDF using some java API which has the capabilities like HTML. Basically, I want to create a form which can take input from users, perform some basic client side validations and also generate this PDF programmatically using Java. I am also looking for rich HTML like features like expand, collapse, hyperlinks, add a section on a button click etc. So basically I am trying to create an HTML like page but within PDF.
I have tried using itext but able to only to do only handful of things and not able to add dynamism into PDF. Is there any tool/API which supports this?
PDF itself allows you to embed (a subset of) javascript.
This embedded code can be linked to document events (e.g. opening the document) or specific form elements (e.g. clicking a button, changing the text in a text-input field).
This is a page from their website entitled 'Making a PDF interactive' which focusses on adding form elements.
The book (iText in Action) by Bruno Lowagie (original founder of iText) also goes in great detail. It even shows how to program a calculator in a PDF document, page 232.
I'm just going to copy-paste the relevant section here.
Listing 7.29 Calculator
public void addTextField(PdfWriter writer, Rectangle rect, String name) {
PdfFormField field = PdfFormField.createTextField(writer, false, false, 0);
field.setFieldName(name);
field.setWidget(rect, PdfAnnotation.HIGHLIGHT_NONE);
field.setQuadding(PdfFormField.Q_RIGHT);
field.setFieldFlags(PdfFormField.FF_READ_ONLY);
writer.addAnnotation(field);
}
public void addPushButton(PdfWriter writer, Rectangle rect, String btn, String script) {
float w = rect.getWidth();
float h = rect.getHeight();
PdfFormField pushbutton = PdfFormField.createPushButton(writer);
pushbutton.setFieldName("btn_" + btn);
pushbutton.setWidget(rect, PdfAnnotation.HIGHLIGHT_PUSH);
PdfContentByte cb = writer.getDirectContent();
pushbutton.setAppearance(PdfAnnotation.APPEARANCE_NORMAL, createAppearance(cb, btn, BaseColor.GRAY, w, h));
pushbutton.setAppearance(PdfAnnotation.APPEARANCE_ROLLOVER, createAppearance(cb, btn, BaseColor.RED, w, h));
pushbutton.setAppearance(PdfAnnotation.APPEARANCE_DOWN, createAppearance(cb, btn, BaseColor.BLUE, w, h));
pushbutton.setAdditionalActions(PdfName.U, PdfAction.javaScript(script, writer));
pushbutton.setAdditionalActions(PdfName.E, PdfAction.javaScript( "this.showMove('" + btn + "');", writer));
pushbutton.setAdditionalActions(PdfName.X, PdfAction.javaScript( "this.showMove(' ');", writer));
writer.addAnnotation(pushbutton);
}
public PdfAppearance createAppearance(PdfContentByte cb, String btn, BaseColor color, float w, float h) {
PdfAppearance app = cb.createAppearance(w, h);
app.setColorFill(color);
app.rectangle(2, 2, w - 4, h - 4);
app.fill();
app.beginText();
app.setColorFill(BaseColor.BLACK);
app.setFontAndSize(bf, h / 2);
app.showTextAligned(Element.ALIGN_CENTER, btn, w / 2, h / 4, 0);
app.endText();
return app;
}
I have a PDF viewer that doesn't show highlights if they do not have an appearance stream. I'm trying out iText 7 core in java to try and add highlight annotations to PDFs but these annotations do not have appearance streams, and thus I'm looking to try and add them myself when writing the annotations to the PDF file.
I've come across this old answer, but it's for C# and iText 5, and I can't seem to figure out how to replicate it in iText 7 with a successful result.
So my question is thus: how do you set appearance streams on the highlighting annotations in iText 7 core that are working?
The furthest I've gotten with the code is shown below. I'm using the RegexBasedLocationExtrationStrategy class to find the locations of all search words in the pdf.
RegexBasedLocationExtractionStrategy evntlstnr = new RegexBasedLocationExtractionStrategy(pattern);
for (int pIdx = 0; pIdx < pdfDoc.getNumberOfPages(); ++pIdx) {
final PdfPage page = pdfDoc.getPage(pIdx + 1);
new PdfCanvasProcessor(evntlstnr).processPageContent(page);
Collection<IPdfTextLocation> locations = evntlstnr.getResultantLocations();
for (IPdfTextLocation location : locations) {
Rectangle rect = location.getRectangle();
// Specify quad points in Z-like order
// [0,1] x1,y1 [2,3] x2,y2
// [4,5] x3,y3 [6,7] x4,y4
float[] quads = new float[8];
quads[0] = rect.getX();
quads[1] = rect.getY() + rect.getHeight();
quads[2] = rect.getX() + rect.getWidth();
quads[3] = quads[1];
quads[4] = quads[0];
quads[5] = rect.getY();
quads[6] = quads[2];
quads[7] = quads[5];
Color highlightColor = new DeviceRgb(0f, 0f, 1f);
PdfTextMarkupAnnotation highlight = PdfTextMarkupAnnotation.createHighLight(rect, quads);
highlight.setColor(highlightColor);
Rectangle appearRect = new Rectangle(0f, 0f, rect.getWidth(), rect.getHeight());
PdfFormXObject appearObj = new PdfFormXObject(appearRect);
final PdfResources appearRes = appearObj.getResources();
PdfExtGState extGState = new PdfExtGState();
extGState.setBlendMode(PdfExtGState.BM_MULTIPLY);
appearRes.addExtGState(extGState);
appearObj.setBBox(new PdfArray(new float[] {0f, 0f, rect.getWidth(), rect.getHeight()}));
PdfShading appearShading = new PdfShading.Axial(highlightColor.getColorSpace(), 0f, 0f, highlightColor.getColorValue(), 1f, 1f, highlightColor.getColorValue());
appearRes.addShading(appearShading);
appearRes.addColorSpace(highlightColor.getColorSpace());
PdfAnnotationAppearance appearance = new PdfAnnotationAppearance(appearObj.getPdfObject());
highlight.setNormalAppearance(appearance);
highlight.setFlag(PdfAnnotation.PRINT);
page.addAnnotation(highlight);
}
}
Using Samuel's answer I stumbled my way to a working answer.
I'm no expect in the PDF standard and this framework (iText), but my hypothesis, based on my working example below, is that the rectangle I was trying to write for the highlight is a crude fall-back method for "faking" the highlight rectangle when the viewer cannot render the annotations (since they have no appearance stream). Realizing this that the two operations are not linked, I came to the working example shown below. Hope this helps others in the future.
RegexBasedLocationExtractionStrategy evntlstnr = new RegexBasedLocationExtractionStrategy(pattern);
for (int pIdx = 0; pIdx < pdfDoc.getNumberOfPages(); ++pIdx) {
final PdfPage page = pdfDoc.getPage(pIdx + 1);
new PdfCanvasProcessor(evntlstnr).processPageContent(page);
Collection<IPdfTextLocation> locations = evntlstnr.getResultantLocations();
for (IPdfTextLocation location : locations) {
Rectangle rect = location.getRectangle();
// Specify quad points in Z-like order
// [0,1] x1,y1 [2,3] x2,y2
// [4,5] x3,y3 [6,7] x4,y4
float[] quads = new float[8];
quads[0] = rect.getX();
quads[1] = rect.getY() + rect.getHeight();
quads[2] = rect.getX() + rect.getWidth();
quads[3] = quads[1];
quads[4] = quads[0];
quads[5] = rect.getY();
quads[6] = quads[2];
quads[7] = quads[5];
Color highlightColor = new DeviceRgb(1f, 1f, 0f);
PdfTextMarkupAnnotation highlight = PdfTextMarkupAnnotation.createHighLight(rect, quads);
highlight.setColor(highlightColor);
highlight.setFlag(PdfAnnotation.PRINT);
page.addAnnotation(highlight);
PdfCanvas canvas = new PdfCanvas(page);
PdfExtGState extGState = new PdfExtGState();
extGState.setBlendMode(PdfExtGState.BM_MULTIPLY);
canvas.setExtGState(extGState);
canvas.rectangle(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
canvas.setFillColor(highlightColor);
canvas.fill();
canvas.release();
}
}
i have to insert image with drawImage(page, docu, x, y, ximage, fRatioImage), until now I can insert the image with this function, but the problem is that the image is shifted relative to the x and y coordinates.
does anyone knows the unit of measurement used by this function to the point (x, y)?
this is the code that i use :
PDDocument docu=docu = PDDocument.load(filedoc);
inputStream in = ImageSignature.is;
biimage=ImageIO.read(in);
PDPage page = (PDPage)docu.getDocumentCatalog().getAllPages().get( 0 );
PDXObjectImage ximage = new PDJpeg(docu, biimage );
PdfBoxImageUtil.drawImage(page, docu, x, y, ximage, fRatioImage);
I have SWT wizard page as my parent shell , for creating another shell on click of button i am writing following code
Shell permissionSetShell = new Shell(Display.getCurrent().getActiveShell(), SWT.CENTER|SWT.DIALOG_TRIM|SWT.APPLICATION_MODAL);
permissionSetShell.setText(PropertyClass.getPropertyLabel(QTLConstants.PERMISSION_SET_COLUMN_LABEL));
// Add shell to the center of parent wizard
permissionSetShell.setLayout(componentsRenderer.createGridLayout(1, false, 0, 5, 0, 0));
Monitor primary = Display.getCurrent().getPrimaryMonitor ();
Rectangle bounds = primary.getBounds ();
Rectangle rect = Display.getCurrent().getActiveShell().getBounds ();
int x = bounds.x + (bounds.width - rect.width) / 2;
int y = bounds.y + (bounds.height - rect.height)/2;
permissionSetShell.setLocation (x, y);
but as the child shell means this shell is not placed at the center of SWT wizard that is parent shell why?
Rectangle screenSize = display.getPrimaryMonitor().getBounds();
shell.setLocation((screenSize.width - shell.getBounds().width) / 2, (screenSize.height - shell.getBounds().height) / 2);
If you are writing a dialog or a child component you may want to use getParent instead of asking the display for the primary monitor so that the window is centered on the current screen for multiple monitor setups.
Rectangle parentSize = getParent().getBounds();
Rectangle shellSize = shell.getBounds();
int locationX = (parentSize.width - shellSize.width)/2+parentSize.x;
int locationY = (parentSize.height - shellSize.height)/2+parentSize.y;
shell.setLocation(new Point(locationX, locationY));
I think the best would be to use style SWT.SHEET for such dialog.
I just ran into this same problem. The solution I got is a little different. This might help others with the same issue. The context is a shell (hoverShell) that hovers over the parent (shell) for a couple of seconds displaying a message.
private void displayMessage(Shell shell, String message) {
Shell hoverShell = new Shell(shell, SWT.ON_TOP);
hoverShell.setLayout(new FillLayout());
Label messageLabel = new Label(hoverShell, SWT.NONE);
messageLabel.setText(message);
Point shellLocation = shell.getLocation();
hoverShell.pack();
hoverShell.setLocation(shellLocation.x + (shell.getSize().x / 2) - (hoverShell.getSize().x / 2), shellLocation.y + 40);
hoverShell.open();
Display.getDefault().timerExec(2000, new Runnable() {
#Override
public void run() {
hoverShell.dispose();
}
});
}
In a nutshell this is the following formula:
child_location.x = parent_location.x + .5*(parent_width.x) - .5*(child_width.x)
If you want y then it's the exact same I believe. May depend if the top border of the window is calculated.
tried, tested and working code:
int width = display.getClientArea().width;
int height = display.getClientArea().height;
shell.setLocation(((width - shell.getSize().x) / 2) + display.getClientArea().x, ((height - shell.getSize().y) / 2) + display.getClientArea().y);