Thanks, @Ryan .
I’ve realized that PDFTron is using the wkhtmltopdf dll, and have found that this is an issue that has gone unaddressed for a long time: radio buttons not rendered as input fields in pdf · Issue #1583 · wkhtmltopdf/wkhtmltopdf · GitHub.
I have found a workaround, for anyone who’s curious. You can render radio buttons in the HTML as checkboxes with radio button styling, and the PDF will have the appropriate display:
<div>
<label>
<input type="checkbox" name="Radio_Buttons_" value="" style="-webkit-appearance: radio;-moz-appearance: radio;appearance: radio">
<span></span>
</label>
</div>
<div>
<label>
<input type="checkbox" name="Radio_Buttons_Dr" value="Dr" style="-webkit-appearance: radio;-moz-appearance: radio;appearance: radio">
<span>Dr</span>
</label>
</div>
<div>
<label>
<input type="checkbox" name="Radio_Buttons_Miss" value="Miss" style="-webkit-appearance: radio;-moz-appearance: radio;appearance: radio">
<span>Miss</span>
</label>
</div>
Use this approach with caution, as the resulting fields will not behave like radio buttons, but could, I’m certain, be converted by those a little more PDFTron savvy than myself. In our case however (generating PDF templates that we then fill out programmatically based on controlled input), this is not a problem.
The one thing you could help me with, @Ryan , is getting the appearance of this pseudo-radio button to be correct (that is, to populate with a filled circle).
I have the following code for setting the value and state of these pseudo-radio buttons based on a list of string values:
foreach (string val in strVals) {
if (!string.IsNullOrWhiteSpace(val)) {
Field valField = srcPdfDoc.GetField($"{strName}_{val}");
if (valField != null) {
valField.SetValue(GetOnState(valField));
var widget = CheckBoxWidget.Create(srcPdfDoc, valField.GetUpdateRect());
widget.SetAppearance(CreateCheckmarkAppearance(srcPdfDoc, valField.GetUpdateRect()));
widget.SetChecked(true);
srcPdfDoc.GetPage(1).AnnotPushBack(widget);
}
}
}
And I have modified the CreateCheckmarkAppearance() function as such:
Obj CreateCheckmarkAppearance(PDFDoc doc, Rect updateRectangle) {
// Create a checkmark appearance stream
ElementBuilder build = new ElementBuilder();
ElementWriter writer = new ElementWriter();
writer.Begin(doc);
// Draw background
Element e = build.CreateRect(updateRectangle.x1, updateRectangle.y1, updateRectangle.Width(), updateRectangle.Height());
e.SetPathFill(true); // this path is should be filled
// Set the path color space and color
GState gstate = e.GetGState();
gstate.SetFillColorSpace(ColorSpace.CreateDeviceRGB());
gstate.SetFillColor(new ColorPt(0, 0, 1)); // blue
writer.WritePlacedElement(e);
// Draw checkmark
writer.WriteElement(build.CreateTextBegin());
// other options are circle ("l"), diamond ("H"), cross ("\x35")
// See section D.4 "ZapfDingbats Set and Encoding" in PDF Reference
//Manual for
// the complete graphical map for ZapfDingbats font.
e = build.CreateTextRun("1", Font.Create(doc,
Font.StandardType1Font.e_zapf_dingbats), 1);
writer.WriteElement(e);
writer.WriteElement(build.CreateTextEnd());
Obj stm = writer.End();
// Set the bounding box
stm.PutRect("BBox", updateRectangle.x1, updateRectangle.y1, updateRectangle.x2, updateRectangle.y2);
stm.PutName("Subtype", "Form");
return stm;
}
However, I still get the default checked appearance. What am I doing wrong here?