PDF-Checkbox - check one and uncheck another without JavaScript - java

in my project I need 3 checkboxes which should work like radiobuttons. But radiobuttons have some drawbacks with appearance in Adobe Reader. For this reason I have to use checkboxes. There is a very interesting answer, but I don't understand how this can be done with iText:
Java iText and custom Radiobutton behaviour
Can anybody -- especially Lonzak, the author of this posting -- help me in this case. Thanks and Kind regards, Dirk

I think the solution is to fix your current code. The following example creates 3 radiobuttons and all contain a cross. It was based on itext 5 and you may have to adapt it a bit for itext 7.
Document document = new Document(PageSize.A4, 50, 50, 50, 50);
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("output.pdf"));
document.open();
RadioCheckField bt = new RadioCheckField(writer, new Rectangle(261, 576, 279, 594), "radio", "value1");
bt.setCheckType(RadioCheckField.TYPE_CROSS);
bt.setBackgroundColor(BaseColor.WHITE);
//bt.setBorderStyle(PdfBorderDictionary.STYLE_SOLID);
bt.setBorderColor(BaseColor.BLACK);
bt.setTextColor(BaseColor.BLACK);
bt.setBorderWidth(BaseField.BORDER_WIDTH_THIN);
bt.setChecked(false);
PdfFormField f1 = bt.getRadioField();
bt.setOnValue("value2");
bt.setChecked(true);
bt.setBox(new Rectangle(287, 577, 305, 595));
PdfFormField f2 = bt.getRadioField();
bt.setChecked(false);
PdfFormField top = bt.getRadioGroup(true, false);
bt.setOnValue("value3");
bt.setBox(new Rectangle(314, 578, 332, 596));
PdfFormField f3 = bt.getRadioField();
top.addKid(f1);
top.addKid(f2);
top.addKid(f3);
writer.addAnnotation(top);
document.close();
Update: Here is your code with iText7 however there seems to be a bug so that the check style is not changed for radiobuttons. Maybe the itext guys can say more...
PdfDocument pdfDoc = new PdfDocument(new PdfWriter("output7.pdf"));
Document doc = new Document(pdfDoc);
PdfButtonFormField radioGroup = PdfFormField.createRadioGroup(pdfDoc, "ExampleGroup", "");
radioGroup.setPage(1);
pdfDoc.addNewPage();
PdfFormField field1 = PdfFormField.createRadioButton(pdfDoc, new Rectangle(261, 576, 18, 18), radioGroup, "value1");
field1.setCheckType(PdfFormField.TYPE_CROSS);
field1.setValue("value1");
field1.regenerateField();
PdfFormField field2 = PdfFormField.createRadioButton(pdfDoc, new Rectangle(287, 577, 18, 18), radioGroup, "value2");
field2.setCheckType(PdfFormField.TYPE_CROSS);
field2.regenerateField();
PdfFormField field3 = PdfFormField.createRadioButton(pdfDoc, new Rectangle(314, 578, 18, 18), radioGroup, "value3");
field3.setCheckType(PdfFormField.TYPE_CROSS);
field3.regenerateField();
PdfAcroForm.getAcroForm(pdfDoc, true).addField(radioGroup);
doc.close();

Final solution with iText 7:
public static void main(String[] args) throws Exception {
// RadioButton with cross instead of bullet.
final String filename = "SampleRadioButton.pdf";
final float boxLength = 20;
final float crossWidth = 1;
final String[] languages = { "Dutch", "English", "French" };
try (PdfWriter writer = new PdfWriter(filename); PdfDocument pdfDoc = new PdfDocument(writer); Document doc = new Document(pdfDoc)) {
pdfDoc.addNewPage();
final PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDoc, true);
final PdfButtonFormField radioGroup = PdfFormField.createRadioGroup(pdfDoc, "Language", languages[1]);
int count = 0;
for (final String language : languages) {
count++;
// button
final Rectangle rect = new Rectangle(40, 800 - (count * 30), boxLength, boxLength);
final PdfFormField radioButton = PdfFormField.createRadioButton(pdfDoc, rect, radioGroup, language);
final PdfDictionary radioDict = radioButton.getPdfObject();
final PdfDictionary mk = new PdfDictionary();
mk.put(PdfName.CA, new PdfString("8")); // check=4, circle=1, cross=8, diamond=u, square=n, star=H
radioDict.put(PdfName.MK, mk);
radioButton.setVisibility(PdfFormField.VISIBLE);
editAppearance(pdfDoc, radioButton, language, boxLength, crossWidth);
// text
final Paragraph para = new Paragraph(language).setFontSize(18);
doc.showTextAligned(para, 70, 800 - (count * 30), TextAlignment.LEFT);
}
form.addField(radioGroup);
}
Desktop.getDesktop().open(new File(filename));
}
private static void editAppearance(PdfDocument pdfDoc, PdfFormField radioButton, String value, float length, float crossWidth) {
final PdfStream streamOn = (PdfStream) new PdfStream().makeIndirect(pdfDoc);
final PdfCanvas canvasOn = new PdfCanvas(streamOn, new PdfResources(), pdfDoc);
final Rectangle rect = new Rectangle(0, 0, length, length);
final PdfFormXObject xObjectOn = new PdfFormXObject(rect);
canvasOn.saveState();
canvasOn.setStrokeColor(ColorConstants.BLACK).setLineWidth(crossWidth);
// bottom left to top right
canvasOn.moveTo(0, 0).lineTo(length, length).stroke();
// Top left to bottom right
canvasOn.moveTo(0, length).lineTo(length, 0).stroke();
canvasOn.restoreState();
xObjectOn.getPdfObject().getOutputStream().writeBytes(streamOn.getBytes());
final PdfWidgetAnnotation widget = radioButton.getWidgets().get(0);
widget.setNormalAppearance(new PdfDictionary());
widget.getNormalAppearanceObject().put(new PdfName(value), xObjectOn.getPdfObject());
}
}

Related

Empty PDF using XChart ChartPie as SVG ressource with PDFBoxGraphics2D and Salamander

I've been trying to compose a pie chart using XChart then vectorising it to SVG format to use it in a PDF built with PDFBox.
To do that, I use:
XChart for the pie chart building and vectorising it ;
SVGSalamender for the Graphics2D building based on previous SVG vectorising ;
PDFBoxGraphics2D for adding previous Graphics2D to my PDF.
Everything runs fine (in compiles and runs without errors) but it does not work. The output PDF stays empty.
This is my code:
#Test
public void test() {
try {
PieChart camembertXChart = camembertXChart();
BufferedImage imageCamembertXChart = BitmapEncoder.getBufferedImage(camembertXChart);
ByteArrayOutputStream output = new ByteArrayOutputStream();
File svg = new File("F:\\Users\\mangin\\Desktop\\Camembert_XChart.svg");
VectorGraphicsEncoder.saveVectorGraphic(camembertXChart, svg.getName(), VectorGraphicsFormat.SVG);
byte[] data = output.toByteArray();
FileInputStream input = new FileInputStream(svg);
BufferedImage imageCamembertXChartVectorise = ImageIO.read(input);
PDDocument document = new PDDocument();
PDPage page = new PDPage();
document.addPage(page);
PDPageContentStream contenu = new PDPageContentStream(document, page, AppendMode.APPEND, false, true);
PdfBoxGraphics2D pdfBoxGraphics2D = new PdfBoxGraphics2D(document, 200, 200);
// SVG Salamander
SVGUniverse universSVG = new SVGUniverse();
SVGDiagram diagramSVG = universSVG.getDiagram(universSVG.loadSVG(svg.toURI().toURL()));
diagramSVG.render(pdfBoxGraphics2D);
pdfBoxGraphics2D.dispose();
var xform = pdfBoxGraphics2D.getXFormObject();
var transform = AffineTransform.getTranslateInstance(200, 200);
xform.setMatrix(transform);
contenu.drawForm(xform);
contenu.close();
document.save("D://tests/archi/PDF_avec_elements_graphique.pdf");
document.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private PieChart camembertXChart() {
PieChart camembert2 = new PieChartBuilder().width(200).height(200).build();
Color[] sliceColors = new Color[] {
new Color(183, 203, 231),
new Color(131, 173, 219),
new Color(84, 143, 197),
new Color(70, 120, 165) };
camembert2.getStyler().setSeriesColors(sliceColors);
camembert2.getStyler().setLegendVisible(false);
camembert2.getStyler().setPlotBorderVisible(false);
camembert2.getStyler().setChartTitleVisible(false);
camembert2.getStyler().setChartTitleBoxVisible(false);
camembert2.getStyler().setChartPadding(0);
camembert2.getStyler().setChartTitlePadding(0);
camembert2.getStyler().setBorderWidth(3);
camembert2.getStyler().setAnnotationsFont(new Font("Arial", Font.BOLD, 10));
camembert2.getStyler().setAnnotationsFontColor(Color.WHITE);
camembert2.addSeries("Item 1", 9);
camembert2.addSeries("Item 2", 10);
camembert2.addSeries("Item 3", 23);
camembert2.addSeries("Item 4", 58);
return camembert2;
}
Does anyone have any experience in an equivalent development ? Or does anybody know why the PDF is empty?
Thanks and regards,
Thomas.

PDFBox Button execute javascript to close document

My use case is to have a button like so on a pdf page (really to add them to existing pages but for now I just want to see it work on anything).
----------
- Back -
----------
And what it does is just closes the current pdf page. The idea is to have multiple tabs opened and each tab is a pdf and then when you hit the "Back" button it closes the current pdf which will then focus back to the previous pdf. This is what I have been trying to use so far.
// Create a new empty document
try {
PDDocument document = new PDDocument();
// Create a new blank page and add it to the document
PDPage blankPage = new PDPage();
document.addPage( blankPage );
PDBorderStyleDictionary borderULine = new PDBorderStyleDictionary();
borderULine.setStyle(PDBorderStyleDictionary.STYLE_UNDERLINE);
PDColor green = new PDColor(new float[] { 0, 1, 0 }, PDDeviceRGB.INSTANCE);
// PDAnnotationTextMarkup txtMark = new PDAnnotationTextMarkup(PDAnnotationTextMarkup.SUB_TYPE_HIGHLIGHT);
// textWidth = (font.getStringWidth("Click Here") / 1000) * 18;
PDAnnotationLink txtLink = new PDAnnotationLink();
txtLink.setBorderStyle(borderULine);
// add an action
// PDActionURI action = new PDActionURI();
// action.setURI("www.google.com");
PDActionJavaScript action = new PDActionJavaScript("this.closeDoc()");
txtLink.setAction(action);
txtLink.setContents("HI");
txtLink.setColor(green);
PDRectangle position = new PDRectangle();
position.setLowerLeftX(10);
position.setLowerLeftY(20);
position.setUpperRightX(100);
position.setUpperRightY(40);
txtLink.setRectangle(position);
txtLink.setInvisible(false);
blankPage.getAnnotations().add(txtLink);
// Save the newly created document
document.save("C:\\Users\\jsmith\\Desktop\\demo\\BlankPage.pdf");
document.close();
} catch (IOException e) {
e.printStackTrace();
}
And I cant seem to see anything on the pdf page (its just all white), I did get the following code at at least be able to go to a new page instead of the javascript but it was still invisible. I just was able to hover over the bottom left and notice i could click on a link.
PDActionURI action = new PDActionURI();
action.setURI("www.google.com");
Improved answer as discussed in the comments of the OPs own answer, and it also includes the answer from the follow-up question.
PDDocument doc = new PDDocument();
PDPage page = new PDPage();
doc.addPage(page);
COSDictionary acroFormDict = new COSDictionary();
PDAcroForm acroForm = new PDAcroForm(doc, acroFormDict);
doc.getDocumentCatalog().setAcroForm(acroForm);
acroForm.setFields(new ArrayList<>());
PDPushButton button = new PDPushButton(acroForm);
button.setPartialName("Btn1");
PDActionJavaScript actionJavaScript = new PDActionJavaScript("this.closeDoc();");
PDAnnotationAdditionalActions additionalActions = new PDAnnotationAdditionalActions();
additionalActions.setU(actionJavaScript);
// widget
PDAnnotationWidget widget = button.getWidgets().get(0);
widget.setActions(additionalActions);
widget.setRectangle(new PDRectangle(100, 700, 100, 50));
PDColor colourBlack = new PDColor(new float[] { 0, 0, 0 }, PDDeviceRGB.INSTANCE);
PDAppearanceCharacteristicsDictionary fieldAppearance
= new PDAppearanceCharacteristicsDictionary(new COSDictionary());
fieldAppearance.setBorderColour(colourBlack);
widget.setAppearanceCharacteristics(fieldAppearance);
// Create appearance
PDAppearanceDictionary appearanceDictionary = new PDAppearanceDictionary();
PDAppearanceStream appearanceStream = new PDAppearanceStream(doc);
appearanceStream.setResources(new PDResources());
try (PDPageContentStream cs = new PDPageContentStream(doc, appearanceStream))
{
PDRectangle bbox = new PDRectangle(widget.getRectangle().getWidth(), widget.getRectangle().getHeight());
appearanceStream.setBBox(bbox);
cs.setNonStrokingColor(0, 0, 0); // black
cs.addRect(bbox.getLowerLeftX() + 0.5f, bbox.getLowerLeftY() + 0.5f, bbox.getWidth() - 1, bbox.getHeight() - 1);
cs.stroke();
// put some useful text
cs.setFont(PDType1Font.HELVETICA, 20);
cs.beginText();
cs.newLineAtOffset(20, 20);
cs.showText("Close");
cs.endText();
}
appearanceDictionary.setNormalAppearance(appearanceStream);
widget.setAppearance(appearanceDictionary);
page.getAnnotations().add(widget);
acroForm.getFields().add(button);
doc.save("..../Button.pdf");
doc.close();

Non removable watermark on PDF file using iText in Java

We have a requirement where we need to add text watermark on magazines which has multiple rich images on each page. I tried com.itextpdf.jar version 5.0.6 to add the watermark but eventually I am able to remove it using Adobe Acrobat Pro.
I tried below option also but that too didn't work.
stamper.setFreeTextFlattening(true);
Is it possible with iText to add a watermark which can not be removed without much effort.
Below is my implementation.
public static void addWaterMark() throws IOException, DocumentException {
PdfReader reader = new PdfReader("C:/Trade-catalog/Catalog2017.pdf");
ByteArrayOutputStream outputPdf = new ByteArrayOutputStream();
PdfStamper stamper = new PdfStamper(reader, outputPdf);
String bodyWatermarkText = "12345 - John Smith";
String bodyWatermarkRotation = "35";
String footerWatermarkText = "Richard Parker";
BaseFont font = BaseFont.createFont("/fonts/micross.ttf", "Cp1250", BaseFont.EMBEDDED);
PdfGState state = new PdfGState();
state.setFillOpacity(0.3f);
for (int i = 1; i <= reader.getNumberOfPages(); i++) {
Rectangle thisPageSize = reader.getPageSize(i);
PdfPatternPainter bodyPainter = stamper.getOverContent(i).createPattern(thisPageSize.getWidth(),
thisPageSize.getHeight());
bodyPainter.setColorFill(new BaseColor(0, 0, 0));
bodyPainter.beginText();
bodyPainter.setTextRenderingMode(PdfPatternPainter.TEXT_RENDER_MODE_FILL);
bodyPainter.setFontAndSize(font, 60);
bodyPainter.showTextAlignedKerned(Element.ALIGN_CENTER, bodyWatermarkText, thisPageSize.getWidth() / 2,
thisPageSize.getHeight() / 2, Integer.valueOf(bodyWatermarkRotation));
bodyPainter.showTextAlignedKerned(Element.ALIGN_RIGHT, footerWatermarkText, thisPageSize.getWidth() * 0.97f,
thisPageSize.getHeight() * 0.015f, 0);
bodyPainter.endText();
PdfContentByte overContent = stamper.getOverContent(i);
overContent.setGState(state);
overContent.setColorFill(new PatternColor(bodyPainter));
overContent.rectangle(thisPageSize.getLeft(), thisPageSize.getBottom(), thisPageSize.getWidth(),
thisPageSize.getHeight());
overContent.fill();
overContent.setFlatness(100);
}
stamper.close();
FileOutputStream outputStream = new FileOutputStream(
"C:/Trade-catalog/output/TradeCatalog2017Watermarked_bodyPainter.pdf");
outputPdf.writeTo(outputStream);
outputPdf.close();
reader.close();
}

iText - PdfActions not working

Good Morning,
I've been following the Merge with TOC examples and not having any luck getting the PdfActions to respond. Here is my snippet:
PdfReader finalReader = new PdfReader(viewableStream.toByteArray());
Document finalDoc = new Document(PageSize.LETTER);
PdfCopy finalPdfCopy = new PdfCopy(finalDoc,stream);
PdfCopy.PageStamp finalPdfStamp;
finalDoc.open();
int finalNumPages = finalReader.getNumberOfPages();
for(int finalPageIndex = 1;finalPageIndex <= finalNumPages;finalPageIndex++) {
PdfImportedPage finalImpPage = finalPdfCopy.getImportedPage(finalReader,finalPageIndex);
finalPdfStamp = finalPdfCopy.createPageStamp(finalImpPage);
if (finalPageIndex == tocPage) {
new TOCCustomizer().generateLinks(finalDoc, finalPdfCopy, finalPdfStamp, finalImpPage, vApp.getBookBuildContext(), book);
}
finalPdfStamp.alterContents();
finalPdfCopy.addPage(finalImpPage);
}
finalDoc.close();
finalPdfCopy.close();
stream.flush();
stream.close();
generateLinks method:
public void generateLinks(Document finalDoc,PdfCopy finalPdfCopy,PdfCopy.PageStamp stamp,PdfImportedPage srcPage,BookBuilderContext context, Book book) throws Exception
{
finalDoc.setMargins(0.75f * 72, 0.75f * 72, 0.75f * 72, 0.75f * 72);
finalDoc.add(new Paragraph(" "));
File fontFile = new File(context.getResourcePath(), "ProximaNova-Reg.otf");
BaseFont bfRegular = BaseFont.createFont(
fontFile.getAbsolutePath(),
BaseFont.CP1252,
BaseFont.EMBEDDED
);
Font font1 = new Font(bfRegular,14, Font.NORMAL, Colors.SLATE_GREY);
// create a table for the content
PdfPTable table = new PdfPTable(3);
table.setTotalWidth(7.5f*72);
table.setWidths(new float[]{32f,458f,50f});
int currentPage = 1;
for (int i = 0; i < book.getNumSections(); i++)
{
v.bookmodel.Section s = book.getSection(i);
String itemNbr = s.getItemNbr();
// don't add excluded sections
if (s.isIncluded() && !TOC_EXCLUDE.contains(itemNbr))
{
PdfPCell sectNumCell = new PdfPCell(new Phrase(i+". ",font1));
sectNumCell.setBorder(0);
sectNumCell.setHorizontalAlignment(PdfPCell.ALIGN_RIGHT);
sectNumCell.setPaddingLeft(5);
sectNumCell.setPaddingBottom(10);
sectNumCell.setPaddingTop(15);
table.addCell(sectNumCell);
Chunk sectChunk = new Chunk(s.getSectionName());
sectChunk.setFont(font1);
// sectChunk.setAction(PdfAction.gotoLocalPage(currentPage, new PdfDestination(PdfDestination.FITH), finalPdfCopy));
sectChunk.setAction(new PdfAction(PdfAction.FIRSTPAGE));
Phrase sectPhrase = new Phrase(sectChunk);
PdfPCell sectDescCell = new PdfPCell(sectPhrase);
sectDescCell.setBorder(0);
sectDescCell.setHorizontalAlignment(PdfPCell.ALIGN_LEFT);
sectDescCell.setPaddingLeft(5);
sectDescCell.setPaddingBottom(10);
sectDescCell.setPaddingTop(15);
table.addCell(sectDescCell);
PdfPCell sectPageCell = new PdfPCell(new Phrase(currentPage+"",font1));
sectPageCell.setBorder(0);
sectPageCell.setHorizontalAlignment(PdfPCell.ALIGN_RIGHT);
sectPageCell.setPaddingLeft(5);
sectPageCell.setPaddingBottom(10);
sectPageCell.setPaddingTop(15);
table.addCell(sectPageCell);
int sectionPages = s.getSectionTotalPages();
currentPage+=sectionPages;
} else if (s.isIncluded() && TOC_SECTIONS.contains(itemNbr)) {
int sectionPages = s.getSectionTotalPages();
currentPage+=sectionPages;
}
}
The document is getting created, but the TOC links will not go back to the first page. I did convert this to use PdfWriter instead of PdfCopy and this worked for the links, but I can't use PdfWriter due to the different original pdf boxing. I think there's something simple that I'm missing, but struggling to see what it is. Any help would be greatly appreciated. I'm currently using version 2.0.7 on this project.
Thanks In Advance,
-Jeff

How to make a footer in generating a pdf file using an itextpdf

I have been searching the net on how to make or set a footer using itextpdf in java. and up until now i havent found anything on how to do it. I have seen some articles on how to use and set a header. but not footers. here's a sample code
Document document = new Document(PageSize.LETTER);
Paragraph here = new Paragraph();
Paragraph there = new Paragraph();
Font Font1 = new Font(Font.FontFamily.HELVETICA, 9, Font.BOLD);
here.add(new Paragraph("sample here", Font1));
there.add(new Paragraph("sample there", Font1));
//footer here
document.add(here);
document.add(there);
document.add(footer);
For implementing Header and footer you need to implement a HeaderFooter class that extends
PdfPageEventHelper class of iText API. Then override the onEndPage() to set header and footer. In this example I am settingname in header and 'page mumber` in footer.
In pdf creation side code you need to use HeaderAndFooter class like this:
Document document = new Document(PageSize.LETTER);
PdfWriter writer = PdfWriter.getInstance(document, "C:\sample.pdf");
//set page event to PdfWriter instance that you use to prepare pdf
writer.setPageEvent(new HeaderAndFooter(name));
.... //Add your content to documne here and close the document at last
/*
* HeaderAndFooter class
*/
public class HeaderAndFooter extends PdfPageEventHelper {
private String name = "";
protected Phrase footer;
protected Phrase header;
/*
* Font for header and footer part.
*/
private static Font headerFont = new Font(Font.COURIER, 9,
Font.NORMAL,Color.blue);
private static Font footerFont = new Font(Font.TIMES_ROMAN, 9,
Font.BOLD,Color.blue);
/*
* constructor
*/
public HeaderAndFooter(String name) {
super();
this.name = name;
header = new Phrase("***** Header *****");
footer = new Phrase("**** Footer ****");
}
#Override
public void onEndPage(PdfWriter writer, Document document) {
PdfContentByte cb = writer.getDirectContent();
//header content
String headerContent = "Name: " +name;
//header content
String footerContent = headerContent;
/*
* Header
*/
ColumnText.showTextAligned(cb, Element.ALIGN_LEFT, new Phrase(headerContent,headerFont),
document.leftMargin() - 1, document.top() + 30, 0);
/*
* Foooter
*/
ColumnText.showTextAligned(cb, Element.ALIGN_RIGHT, new Phrase(String.format(" %d ",
writer.getPageNumber()),footerFont),
document.right() - 2 , document.bottom() - 20, 0);
}
}
Hope it helps. I had used this in one of the allication.
small demo with itextpdf 5
final ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
final Document document = new Document();
final PdfContentByte cb = PdfWriter.getInstance(document, byteStream).getDirectContent();
final Paragraph footerTitleParagraph = new Paragraph();
footerTitleParagraph.add("footer title with no style");
ColumnText.showTextAligned(cb, Element.ALIGN_CENTER, footerTitleParagraph, document.right()/2, document.bottom()-15, 0);
final Paragraph footerSubTitleParagraph = new Paragraph("footer sub-title with style", FOOTER_FONT_SUB));
ColumnText.showTextAligned(cb, Element.ALIGN_CENTER, footerSubTitleParagraph, document.right()/2, document.bottom()-25, 0);

Categories