Недалек тот час, когда PDF документы можно будет полноценно отображать средствами Javascript. При этом обратная возможность, а именно использование Javascript в PDF документах, существует уже очень давно. Об этом и пойдет речь в данной статье.
Любое ПО содержит некоторый активно используемый функционал и значительную долю редко используемого функционала. Можно прикинуть, все ли возможности операционной системы (или Microsoft Word, или своей IDE) мы используем в повседневной работе или вообще использовали хоть раз в жизни. Как правило, далеко не все.
Формат PDF не является исключением. Все мы привыкли к тексту и изображениям в PDF документах, однако это лишь малая часть того, что можно использовать. В частности, формат PDF включает в себя разнообразные возможности для создания документов с динамическим контентом, зависящим от читателя и его действий. Одной из таких возможностей является использование Javascript.
Javascript в PDF чаще всего применяется для следующих задач:
Рассмотрим ряд практических примеров использования Javascript в PDF документах.
Начнем рассмотрение темы с традиционного Hello World примера. В данном и последующих примерах используется язык C# и библиотека Docotic.Pdf для работы с PDF документами. Ссылка на исходники с кодом всех примеров приводится в конце статьи.
Если открыть созданный этим кодом документ в Adobe Reader, то увидим примерно следующее:
Что же происходит в примере? Суть заключена в строке
Формат 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. Необходимо при открытии документа устанавливать в полях текущую дату, делается это так:
По сравнению с предыдущим примером JS код увеличился в объемах, поэтому использовать его напрямую в C# строке стало неудобно из-за необходимости экранировать кавычки и вставлять переносы строк. Поэтому поместим данный код в ресурсы, тогда использоваться скрипт будет так:
В результате при открытии документа увидим примерно следующую картину:
Обратите внимание на код для установки месяца – мы используем специфическую перегрузку метода util.printd для вывода локализованного месяца.
Это дает отличные результаты в Adobe Reader, но, к сожалению, не гарантируется, что другие просмотрщики будут корректно поддерживать столь специфические конструкции. При проектировании документа это нужно учитывать. Возможно, стоит заменить этот код на более многословный (самостоятельное получение названия месяца в нужном падеже), но зато поддерживаемый большим количеством просмотрщиков.
В данном примере также важно то, что значения устанавливаются только в пустые поля. Без этих проверок может возникнуть ситуация, когда пользователь сохранит заполненную форму, а при открытии такой сохраненной формы дата будет изменена на текущую.
Если при заполнении формы все-таки необходимо поменять дату, то имеет смысл разрешать ввод только цифр в поля для дня и года. Используем для этого следующий Javascript код:
В C# коде используем событие OnKeyPress у контролов для проверки вводимого символа:
После этого в поля для дня и года будет невозможно ввести любой символ, отличный от цифры. Вставить строку из буфера обмена, содержащую некорректный символ, также не удастся.
Часто бывает, что одну и ту же информацию в документе нужно указывать несколько раз. И в случае PDF документов с помощью Javascript можно избавить пользователя от повторения одних и тех же действий.
Предположим, имеется документ следующего вида:
Модифицируем его так, чтобы при изменении одного из полей с ФИО обновлялось и другое.
Используем простую Javascript функцию:
А также следующий C# код:
Теперь при потере фокуса любым из текстбоксов будет обновлено значение другого. Обратите внимание на прием, не встречавшийся ранее, — общий Javascript код помещается в коллекцию PdfDocument.SharedScripts, и далее мы получаем возможность из конкретных action’ов вызывать функцию, определенную в общем коде.
Использовать Javascript можно не только в web-разработке, но и в такой области, как оформление PDF документов. Немного дополнительных усилий, и создаваемые PDF документы порадуют читателя не меньше, чем программа с удобным и продуманным интерфейсом – искушенного пользователя.
И все же такие возможности второстепенны по сравнению с содержимым документа, поэтому практическая ценность Javascript в PDF не столь высока. Кроме того, с этим связан еще ряд проблем:
Скачать код примеров из статьи можно здесь.
Любое ПО содержит некоторый активно используемый функционал и значительную долю редко используемого функционала. Можно прикинуть, все ли возможности операционной системы (или Microsoft Word, или своей IDE) мы используем в повседневной работе или вообще использовали хоть раз в жизни. Как правило, далеко не все.
Формат PDF не является исключением. Все мы привыкли к тексту и изображениям в PDF документах, однако это лишь малая часть того, что можно использовать. В частности, формат PDF включает в себя разнообразные возможности для создания документов с динамическим контентом, зависящим от читателя и его действий. Одной из таких возможностей является использование Javascript.
Javascript в PDF чаще всего применяется для следующих задач:
- Для изменения содержимого документа в зависимости от некоторых событий. Например, скрыть часть документа при отправке на печать. Или при открытии документа автоматически заполнить часть полей формы.
- Для ограничения действий читателя. Например, для валидации вводимых значений при заполнении форм.
Рассмотрим ряд практических примеров использования 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.alert("Привет, Хабр!", 3);
Статический класс 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){MMMM}", 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){MMMM}", 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;
}
}
А также следующий C# код:
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 в PDF не столь высока. Кроме того, с этим связан еще ряд проблем:
- Сложнее писать Javascript код, чем в случае обычной web-разработки. Нужно создать и открыть документ, чтобы проверить корректность написанного кода.
- Javascript полноценно поддерживается лишь просмотрщиками от Adobe. В альтернативных просмотрщиках поддержка существенно ограничена либо отсутствует вообще.
- Javascript может быть отключен в просмотрщике PDF.
- Теоретически исполнение Javascript скриптов в документе небезопасно, и периодически обнаруживаются различные уязвимости.
Скачать код примеров из статьи можно здесь.