Thank Gary and Tilman, digesting the code right now.

I am about 20+ hours in decomposing the differences of my output vs acrobat.

If I have anything re-usable, will make a pull request for examples.

-JAson

> -----Original Message-----
> From: Gary Grosso <gary.gro...@oberontech.com>
> Sent: Thursday, November 7, 2019 12:24 PM
> To: users@pdfbox.apache.org
> Subject: RE: Unable to find documentation on using PDRadioButton.setValue 
> with regards to
> PDDocument.saveIncremental (selected appearance not show in PDF viewer)
> 
> I haven't looked at this code in a few years, so I am not in a position to 
> expound on it. I offer it
> in the possibility it suggests something. Caveat: I seem to recall they 
> wanted their radio buttons
> optionally to do some things that did not seem radio-button-like to me.
> 
> 
> private static void addRadiobuttonAtRect(PDDocument document, PDPage page, 
> PDAcroForm acroForm, String
> name,
> Map<String, String> optionMap, PDRectangle rect, GroupInfo groupInfo, String 
> dflt) {
> PDAnnotationWidget radioButton = new PDAnnotationWidget();
> 
>         String grp = Utils.unescapeChar(optionMap.get("grp"));
>         System.out.println("grp=" + grp + "; name=" + name + "; num=" + 
> optionMap.get("num"));
> 
>         radioButton.setRectangle(rect);
>         radioButton.setPrinted(true);
> 
>         int wd = Utils.getInt(optionMap.get("wd"));
>         if (wd == -1) {
>         System.out.println("Zero or invalid wd of radio button '" + 
> optionMap.get("wd") + "'");
>         wd = 8;
>         }
> rect.setUpperRightX(rect.getLowerLeftX() + wd);
> rect.setUpperRightY(rect.getLowerLeftY() + wd); // assume buttons are never 
> oblong/oval
> 
> boolean squareButtons = true;
>         String type = optionMap.get("btnshape");
>         if ((type != null) && type.equals("round")) {
>         squareButtons = false;
>         }
> 
>         PDFormFieldAdditionalActions fieldActions = new 
> PDFormFieldAdditionalActions();
>         PDAnnotationAdditionalActions annotationActions = new 
> PDAnnotationAdditionalActions();
>         setWidgetActions(optionMap, fieldActions, annotationActions);
>         radioButton.setActions(annotationActions);
> 
>         PDAppearanceCharacteristicsDictionary fieldAppearance
>                 = new PDAppearanceCharacteristicsDictionary(new 
> COSDictionary());
>         if (Utils.getInt(optionMap.get("brdwt")) != 0) {
>         /*
>          * For borderWeight of zero to work reliably (and not exhibit a thin 
> rule),
>          * it is important not so set any border color.
>          */
>         
> fieldAppearance.setBorderColour(Utils.hexToPDColor(optionMap.get("brdclr")));
>         }
> fieldAppearance.setBackground(Utils.hexToPDColor(optionMap.get("bclr")));
> 
> radioButton.setAnnotationFlags(4);
>         radioButton.setPage(page);
>         PDRadioButton radioGroupWidget = (PDRadioButton) 
> groupInfo.getGroupButton();
> radioButton.setParent(radioGroupWidget);
> 
> 
> COSDictionary apNDict = new COSDictionary();
> COSDictionary apDDict = new COSDictionary();
> 
>         PDAppearanceDictionary appearance = new PDAppearanceDictionary();
>         PDAppearanceEntry appearanceNEntry;
> PDAppearanceEntry appearanceDEntry;
> 
> COSStream offNStream = new COSStream();
> offNStream.setItem(COSName.BBOX, rect);
> offNStream.setItem(COSName.FORMTYPE, COSInteger.ONE);
> offNStream.setItem(COSName.TYPE, COSName.XOBJECT);
> offNStream.setItem(COSName.SUBTYPE, COSName.FORM);
> apNDict.setItem(COSName.Off, offNStream);
> 
> COSStream onNStream = new COSStream();
> onNStream.setItem(COSName.BBOX, rect);
> onNStream.setItem(COSName.FORMTYPE, COSInteger.ONE);
> onNStream.setItem(COSName.TYPE, COSName.XOBJECT);
> onNStream.setItem(COSName.SUBTYPE, COSName.FORM);
> 
> apNDict.setItem(name, onNStream);
> 
> COSStream offDStream = new COSStream();
> offDStream.setItem(COSName.BBOX, rect);
> offDStream.setItem(COSName.FORMTYPE, COSInteger.ONE);
> offDStream.setItem(COSName.TYPE, COSName.XOBJECT);
> offDStream.setItem(COSName.SUBTYPE, COSName.FORM);
> apDDict.setItem(COSName.Off, offDStream);
> 
> COSStream onDStream = new COSStream();
> onDStream.setItem(COSName.BBOX, rect);
> onDStream.setItem(COSName.FORMTYPE, COSInteger.ONE);
> onDStream.setItem(COSName.TYPE, COSName.XOBJECT);
> onDStream.setItem(COSName.SUBTYPE, COSName.FORM);
> 
> apDDict.setItem(name, onDStream);
> 
> if ((dflt != null) && dflt.equals("Yes")) {
> //radioButton.setAppearanceState(name);
> } else {
> radioButton.setAppearanceState("Off");
> }
> 
>         radioButton.setAppearance(appearance);
>         radioButton.setAppearanceCharacteristics(fieldAppearance);
> 
>         appearanceNEntry = new PDAppearanceEntry(apNDict);
> appearanceDEntry = new PDAppearanceEntry(apDDict);
>         appearance.setNormalAppearance(appearanceNEntry);
> appearance.setDownAppearance(appearanceDEntry);
> 
> if (squareButtons) {
> /* The following controls what appears within a selected square.
>  * If applied to round buttons, they become square. */
> // 8 = cross; 4 = checkmark; H = star; u = diamond; n = square, l = dot
> fieldAppearance.setNormalCaption("4");
> 
> try {
> apNDict.setItem(COSName.Off, createRadioButtonAppearanceStream(document, 
> radioButton, false));
> apNDict.setItem(COSName.YES, createRadioButtonAppearanceStream(document, 
> radioButton, true));
> } catch (IOException exc) {
> System.out.println("IOException calling createRadioButtonAppearanceStream: " 
> + exc.getMessage());
> }
> }
> 
> // Add the annotation to the group.
> groupInfo.addItem(radioButton);
> 
> try {
> page.getAnnotations().add(radioButton);
> } catch (IOException exc) {
> System.out.println("IOException adding readioButton to page: " + 
> exc.getMessage());
> }
> 
> }
> 
> private static PDAppearanceStream createRadioButtonAppearanceStream (final 
> PDDocument document,
> PDAnnotationWidget widget, boolean on) throws IOException {
>         PDRectangle rect = widget.getRectangle();
>         PDAppearanceCharacteristicsDictionary appearanceCharacteristics;
>         PDAppearanceStream yesAP = new PDAppearanceStream(document);
>         yesAP.setBBox(new PDRectangle(rect.getWidth(), rect.getHeight()));
>         yesAP.setResources(new PDResources());
>         try (PDAppearanceContentStream yesAPCS = new 
> PDAppearanceContentStream(yesAP)) {
>             appearanceCharacteristics = widget.getAppearanceCharacteristics();
>             PDColor backgroundColor = 
> appearanceCharacteristics.getBackground();
>             PDColor borderColor = appearanceCharacteristics.getBorderColour();
>             float lineWidth = 1.0F;
>             yesAPCS.setBorderLine(lineWidth, widget.getBorderStyle(), 
> widget.getBorder());
>             yesAPCS.setNonStrokingColor(backgroundColor);
>             yesAPCS.addRect(0, 0, rect.getWidth(), rect.getHeight());
>             yesAPCS.fill();
>             if (borderColor != null) {
>             yesAPCS.setStrokingColor(borderColor);
>             }
>             yesAPCS.addRect(lineWidth / 2, lineWidth / 2, rect.getWidth() - 
> lineWidth,
> rect.getHeight() - lineWidth);
>             yesAPCS.stroke();
>             if (!on) {
>                 return yesAP;
>             }
> 
>             yesAPCS.addRect(lineWidth, lineWidth, rect.getWidth() - lineWidth 
> * 2, rect.getHeight() -
> lineWidth * 2);
>             yesAPCS.clip();
> 
>             String normalCaption = 
> appearanceCharacteristics.getNormalCaption();
>             if (normalCaption == null) {
>                 normalCaption = "4"; // Adobe behaviour
>             }
>             if ("8".equals(normalCaption)) {
>                 // Adobe paints a cross instead of using the Zapf Dingbats 
> cross symbol
>                 yesAPCS.setStrokingColor(0f);
>                 yesAPCS.moveTo(lineWidth * 2, rect.getHeight() - lineWidth * 
> 2);
>                 yesAPCS.lineTo(rect.getWidth() - lineWidth * 2, lineWidth * 
> 2);
>                 yesAPCS.moveTo(rect.getWidth() - lineWidth * 2, 
> rect.getHeight() - lineWidth * 2);
>                 yesAPCS.lineTo(lineWidth * 2, lineWidth * 2);
>                 yesAPCS.stroke();
>             } else {
>                 // The caption is not unicode, but the Zapf Dingbats code in 
> the PDF
>                 // Thus convert it back to unicode
>                 // Assume that only the first character is used.
>                 String name = 
> PDType1Font.ZAPF_DINGBATS.codeToName(normalCaption.codePointAt(0));
>                 String unicode = 
> PDType1Font.ZAPF_DINGBATS.getGlyphList().toUnicode(name);
>                 Rectangle2D bounds = 
> PDType1Font.ZAPF_DINGBATS.getPath(name).getBounds2D();
>                 float size = (float) Math.min(bounds.getWidth(), 
> bounds.getHeight()) / 1000;
>                 // assume that checkmark has square size
>                 // the calculations approximate what Adobe is doing, i.e. put 
> the glyph in the middle
>                 float fontSize = (rect.getWidth() - lineWidth * 2) / size * 
> 0.6666f;
>                 float xOffset = (float) (rect.getWidth() - 
> (bounds.getWidth()) / 1000 * fontSize) / 2;
>                 xOffset -= bounds.getX() / 1000 * fontSize;
>                 float yOffset = (float) (rect.getHeight() - 
> (bounds.getHeight()) / 1000 * fontSize) /
> 2;
>                 yOffset -= bounds.getY() / 1000 * fontSize;
>                 yesAPCS.setNonStrokingColor(0);
>                 yesAPCS.beginText();
>                 yesAPCS.setFont(PDType1Font.ZAPF_DINGBATS, fontSize);
>                 yesAPCS.newLineAtOffset(xOffset, yOffset);
>                 yesAPCS.showText(unicode);
>                 yesAPCS.endText();
>             }
>         }
>         return yesAP;
>     }
> 
> 
> 
> 
> -----Original Message-----
> From: Tilman Hausherr <thaush...@t-online.de>
> Sent: Thursday, November 7, 2019 12:13 PM
> To: users@pdfbox.apache.org
> Subject: Re: Unable to find documentation on using PDRadioButton.setValue 
> with regards to
> PDDocument.saveIncremental (selected appearance not show in PDF viewer)
> 
> Am 07.11.2019 um 14:07 schrieb Jason Pyeron:
> > Most of the form is saving and displaying just fine, since we
> > carefully call setNeedToBeUpdated(true) after setting fields.
> >
> >
> >
> > Radio buttons seem to require a bit more. The actual value is there,
> > but the display appearance is blank when going from Off to value, and
> > the old value display is still shown when from going from old value to new 
> > value.
> >
> >
> >
> > Where is this properly documented? I have reviewed the examples,
> > pdfbox website, stackoverflow, google, etc.
> 
> 
> It's not documented, the whole incremental thing is hard to understand even 
> for me... I suspect you
> need to add "setNeedToBeUpdated(true)" on the appearance state / dictionary 
> too. Do a normal save and
> then look at your PDF with PDFDebugger to see what's in the field / the 
> annotation.
> Then do an incrementalSave and look whether something is missing.
> 
> It may also be possible that you can profit from the experimental branch from 
> PDFBOX-45
> (pdfbox/branches/issue45). See the comments around April 2019.
> 
> Tilman
> 
> 
> 
> >
> >
> >
> > v/r,
> >
> >
> >
> > Jason
> >
> >
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscr...@pdfbox.apache.org
> For additional commands, e-mail: users-h...@pdfbox.apache.org
> 
> The content of this email and any attached files are intended for the 
> recipient specified in this
> message only. It may contain information that is confidential, proprietary, 
> privileged, and/or exempt
> from disclosure under applicable law. It is strictly forbidden to share any 
> part of this message with
> any third party or rely on any of its contents, without the written consent 
> of the sender. If you
> received this message by mistake, please reply to this message and follow 
> with deletion of the
> original message, any copies and all attachments, so that Oberon Technologies 
> can ensure such a
> mistake does not occur in the future.
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscr...@pdfbox.apache.org
> For additional commands, e-mail: users-h...@pdfbox.apache.org
> 



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@pdfbox.apache.org
For additional commands, e-mail: users-h...@pdfbox.apache.org

Reply via email to