Add JavaScript Actions to PDF in Java
First of all, you need to add needed dependencies for including Spire.PDF for Java into your Java project. If you use maven, you can install the library’s jar from Maven repository by adding the following code to your project’s pom.xml file.
repositories> repository> id>com.e-iceblueid> name>e-icebluename> url>https://repo.e-iceblue.com/nexus/content/groups/public/ repository> repositories> dependencies> dependency> groupId>e-icebluegroupId> artifactId>spire.pdfartifactId> version>5.2.3version> dependency> dependencies>
For non-maven project, you can download Spire.PDF for Java from this link, extract the package and then import the jar under the lib folder into your project as a dependency.
Add Document Level JavaScript Action to PDF in Java
The document level JavaScript action is applied to an entire document when certain document event occurs. For example, you can add a document level JavaScript action which is performed when a PDF document is opened in a JavaScript-compatible viewer (such as Adobe or Foxit).
The following are the steps to do so:
- Initialize an object of PdfDocument class.
- Add a page using PdfDocument.getPages().add() method.
- Initialize an object of PdfJavaScriptAction class to create a JavaScript action. To the constructor of this class, pass the required JavaScript in the form of String.
- Assign PdfJavaScriptAction object to the document open action using PdfDocument.setAfterOpenAction() method.
- Save the result file using PdfDocument.saveToFile() method.
import com.spire.pdf.PdfDocument; import com.spire.pdf.PdfPageBase; import com.spire.pdf.actions.PdfJavaScriptAction; public class AddJavaScriptToDocument public static void main(String[] args) //Create a PdfDocument instance PdfDocument pdf = new PdfDocument(); //Add a page PdfPageBase page = pdf.getPages().add(); //String javaScript = "app.alert(\"This is a document-level JavaScript example\")"; //Create a JavaScript action String javaScript = "app.alert( );"; PdfJavaScriptAction javaScriptAction = new PdfJavaScriptAction(javaScript); //Set the action to be performed when the document is opened pdf.setAfterOpenAction(javaScriptAction); //Save the result file pdf.saveToFile("AddJavaScriptToDocument.pdf"); > >
Add Form Level JavaScript Action to PDF in Java
The form level JavaScript is associated with a specific form field or fields, such as a button. This type of script is executed when an event occurs, such as a Mouse Down action.
The following example shows how to add a JavaScript action to a button field:
import com.spire.pdf.PdfDocument; import com.spire.pdf.PdfPageBase; import com.spire.pdf.actions.PdfJavaScriptAction; import com.spire.pdf.fields.PdfBorderStyle; import com.spire.pdf.fields.PdfButtonField; import com.spire.pdf.fields.PdfTextBoxField; import com.spire.pdf.graphics.*; import java.awt.geom.Rectangle2D; import java.util.EnumSet; public class AddJavaScriptToFormField public static void main(String[] args) throws Exception //Create a new PDFDocument instance PdfDocument doc = new PdfDocument(); //Add a page PdfPageBase page = doc.getPages().add(); //Create a PdfFont instance PdfFont font = new PdfFont(PdfFontFamily.Times_Roman, 12f, EnumSet.of(PdfFontStyle.Regular)); //Create a PdfBrush instance PdfBrush brush = PdfBrushes.getBlack(); float x = 80; float y = 100; float tempX = 0; //Draw text into page String text1 = "Name: "; //Draw text into page page.getCanvas().drawString(text1, font, brush, x, y); tempX = (float) font.measureString(text1).getWidth() + x + 15; //Create a PdfTextBoxField instance PdfTextBoxField textbox = new PdfTextBoxField(page, "NameBox"); textbox.setBounds(new Rectangle2D.Float(tempX, y, 100, 15)); textbox.setBorderWidth(0.75f); textbox.setBorderStyle(PdfBorderStyle.Solid); //Add the textbox field to the field collection doc.getForm().getFields().add(textbox); //Create a PdfButtonField instance PdfButtonField resetButton = new PdfButtonField(page, "resetButton"); resetButton.setBounds(new Rectangle2D.Float(150, 150, 50, 15)); resetButton.setText("Reset"); resetButton.setBackColor(new PdfRGBColor(181, 191, 203)); //Create a PdfJavaScriptAction instance PdfJavaScriptAction scriptAction = new PdfJavaScriptAction("this.resetForm([\"NameBox\"])"); //Assign the PdfJavaScriptAction instance to the MouseDown action of the button resetButton.getActions().setMouseDown(scriptAction); //Add the button to the field collection doc.getForm().getFields().add(resetButton); //Save the result file doc.saveToFile("AddJavaScriptActionToFormField.pdf"); > >
Javascript в PDF
Недалек тот час, когда PDF документы можно будет полноценно отображать средствами Javascript. При этом обратная возможность, а именно использование Javascript в PDF документах, существует уже очень давно. Об этом и пойдет речь в данной статье.
Любое ПО содержит некоторый активно используемый функционал и значительную долю редко используемого функционала. Можно прикинуть, все ли возможности операционной системы (или Microsoft Word, или своей IDE) мы используем в повседневной работе или вообще использовали хоть раз в жизни. Как правило, далеко не все.
Формат PDF не является исключением. Все мы привыкли к тексту и изображениям в PDF документах, однако это лишь малая часть того, что можно использовать. В частности, формат PDF включает в себя разнообразные возможности для создания документов с динамическим контентом, зависящим от читателя и его действий. Одной из таких возможностей является использование Javascript.
- Для изменения содержимого документа в зависимости от некоторых событий. Например, скрыть часть документа при отправке на печать. Или при открытии документа автоматически заполнить часть полей формы.
- Для ограничения действий читателя. Например, для валидации вводимых значений при заполнении форм.
Рассмотрим ряд практических примеров использования Javascript в PDF документах.
Hello World
Начнем рассмотрение темы с традиционного Hello World примера. В данном и последующих примерах используется язык C# и библиотека Docotic.Pdf для работы с PDF документами. Ссылка на исходники с кодом всех примеров приводится в конце статьи.
using BitMiracle.Docotic.Pdf; namespace JavascriptInPdf < public static class Demo < public static void Main(string[] args) < PdfDocument pdf = new PdfDocument(); pdf.OnOpenDocument = pdf.CreateJavaScriptAction("app.alert(\"Привет, Хабр!\", 3);"); pdf.Save("Hello world.pdf"); >> >
Если открыть созданный этим кодом документ в Adobe Reader, то увидим примерно следующее:
Что же происходит в примере? Суть заключена в строке
pdf.OnOpenDocument = pdf.CreateJavaScriptAction("app.alert(\"Привет, Хабр!\", 3);");
Формат PDF включает поддержку actions – это действия, происходящие по тому или иному событию. Например, когда в оглавлении в некотором PDF документе кликаем на ссылку с номером страницы – срабатывает определенный action для перехода на соответствующую страницу:
Для Javascript также есть соответствующий action. Мы создаем его с помощью метода PdfDocument.CreateJavaScriptAction, которому передаем в качестве параметра JS код. Созданный action мы привязываем к событию OnOpenDocument, происходящему при открытии документа просмотрщиком.
Непосредственно Javascript код выглядит так:
Статический класс app является частью Javascript API и предоставляет набор методов для взаимодействия с приложением-просмотрщиком. В частности, он содержит несколько перегрузок метода alert для показа модального диалога с сообщением. В данном примере используется перегрузка со вторым необязательным параметром – индексом иконки диалога, значение 3 соответствует Status Icon.
От простого – к сложному
Рассмотрим более реалистичный пример.
Многие PDF документы описывают некоторые формы для заполнения – это может быть договор открытия банковского вклада, анкета на получение визы или загран. паспорта, заявление на отпуск и т.п. Довольно удобно, поскольку такую форму можно заполнить прямо в просмотрщике и сохранить или распечатать. Авторы PDF документов, содержащих формы, могут облегчить пользователю их заполнение с помощью Javascript.
Реальные документы часто содержат поля для ввода даты заполнения. Например, это может выглядеть так:
В принципе, создавая документ, можно на этом и остановиться. Однако, можно пойти чуть дальше и немного упростить задачу заполняющему – например, устанавливать дату по умолчанию в текущую – в 99% случаев именно это и необходимо.
Устанавливаем дату по умолчанию
C# код по созданию полей для даты, как на скриншоте, в данном случае не так интересен. Рассмотрим лишь часть, касающуюся Javascript. Необходимо при открытии документа устанавливать в полях текущую дату, делается это так:
function setDay(date) < var dayField = this.getField("day"); if (dayField.value.length == 0) < dayField.value = util.printd("dd", date); >> function setMonth(date) < var monthField = this.getField("month"); if (monthField.value.length == 0) < monthField.value = util.printd("date(ru)", date, true); > > function setYear(date) < var yearField = this.getField("year"); if (yearField.value.length == 0) < yearField.value = util.printd("yyyy", date); >> function setCurrentDate() < var now = new Date(); setDay(now); setMonth(now); setYear(now); >setCurrentDate();
По сравнению с предыдущим примером JS код увеличился в объемах, поэтому использовать его напрямую в C# строке стало неудобно из-за необходимости экранировать кавычки и вставлять переносы строк. Поэтому поместим данный код в ресурсы, тогда использоваться скрипт будет так:
pdf.OnOpenDocument = pdf.CreateJavaScriptAction(Resources.SetCurrentDate);
В результате при открытии документа увидим примерно следующую картину:
Обратите внимание на код для установки месяца – мы используем специфическую перегрузку метода util.printd для вывода локализованного месяца.
monthField.value = util.printd("date(ru)", date, true);
Это дает отличные результаты в Adobe Reader, но, к сожалению, не гарантируется, что другие просмотрщики будут корректно поддерживать столь специфические конструкции. При проектировании документа это нужно учитывать. Возможно, стоит заменить этот код на более многословный (самостоятельное получение названия месяца в нужном падеже), но зато поддерживаемый большим количеством просмотрщиков.
В данном примере также важно то, что значения устанавливаются только в пустые поля. Без этих проверок может возникнуть ситуация, когда пользователь сохранит заполненную форму, а при открытии такой сохраненной формы дата будет изменена на текущую.
Валидация вводимых значений
Если при заполнении формы все-таки необходимо поменять дату, то имеет смысл разрешать ввод только цифр в поля для дня и года. Используем для этого следующий Javascript код:
function validateNumeric(event) < var validCharacters = "0123456789"; for (var i = 0; i < event.change.length; i++) < if (validCharacters.indexOf(event.change.charAt(i)) == -1) < app.beep(0); event.rc = false; break; >> > validateNumeric(event);
В C# коде используем событие OnKeyPress у контролов для проверки вводимого символа:
PdfJavaScriptAction validateNumericAction = m_document.CreateJavaScriptAction(Resources.ValidateNumeric); dayTextBox.OnKeyPress = validateNumericAction; yearTextBox.OnKeyPress = validateNumericAction;
После этого в поля для дня и года будет невозможно ввести любой символ, отличный от цифры. Вставить строку из буфера обмена, содержащую некорректный символ, также не удастся.
Синхронизация значений полей
Часто бывает, что одну и ту же информацию в документе нужно указывать несколько раз. И в случае PDF документов с помощью Javascript можно избавить пользователя от повторения одних и тех же действий.
Предположим, имеется документ следующего вида:
Модифицируем его так, чтобы при изменении одного из полей с ФИО обновлялось и другое.
Используем простую Javascript функцию:
function synchronizeFields(sourceFieldName, destinationFieldName) < var source = this.getField(sourceFieldName); var destination = this.getField(destinationFieldName); if (source != null && destination != null) < destination.value = source.value; >>
PdfDocument pdf = new PdfDocument(“Names.pdf”); pdf.SharedScripts.Add( pdf.CreateJavaScriptAction(Resources.SynchronizeFields) ); pdf.GetControl("name0").OnLostFocus = pdf.CreateJavaScriptAction("synchronizeFields(\"name0\", \"name1\");"); pdf.GetControl("name1").OnLostFocus = pdf.CreateJavaScriptAction("synchronizeFields(\"name1\", \"name0\");"); pdf.Save("NamesModified.pdf");
Теперь при потере фокуса любым из текстбоксов будет обновлено значение другого. Обратите внимание на прием, не встречавшийся ранее, — общий Javascript код помещается в коллекцию PdfDocument.SharedScripts, и далее мы получаем возможность из конкретных action’ов вызывать функцию, определенную в общем коде.
Подытожим
Использовать Javascript можно не только в web-разработке, но и в такой области, как оформление PDF документов. Немного дополнительных усилий, и создаваемые PDF документы порадуют читателя не меньше, чем программа с удобным и продуманным интерфейсом – искушенного пользователя.
- Сложнее писать Javascript код, чем в случае обычной web-разработки. Нужно создать и открыть документ, чтобы проверить корректность написанного кода.
- Javascript полноценно поддерживается лишь просмотрщиками от Adobe. В альтернативных просмотрщиках поддержка существенно ограничена либо отсутствует вообще.
- Javascript может быть отключен в просмотрщике PDF.
- Теоретически исполнение Javascript скриптов в документе небезопасно, и периодически обнаруживаются различные уязвимости.
Скачать код примеров из статьи можно здесь.