Как заменить строку в файле PDF с помощью NodeJS? есть решение для замены текста в PDF. С тем же кодом у меня возникает загадочная проблема: текст заменяется в исходном коде PDF, но не отображается. Соответствующие строки, адаптированные из приведенного выше решения:
console.info(replaceText);
var string = new Buffer(data).toString().replace(findText, replaceText);
console.info(string);
Консоль показывает, что он заменен в исходной строке PDF:
/TT0 1 Tf 65.5689 -24.5097 24.5097 65.5689 363.9941 762.3682 Tm (e)Tj 61.1539 -34.0617 34.0617 61.1539 381.1689 756.6411 Tm (n)Tj 54.8214 -43.5272 43.5272 54.8214 408.6333 741.0947 Tm (d)Tj 48.8331 -50.153 50.153 48.8331 426.3779 726.999 Tm (a)Tj 52 0 0 52 75.8203 226.9756 Tm (abcdefghijklmnopqrstuvwxyz)Tj 33 0 0 33 25.8203 302.9756 Tm (E)Tj (ste cheque-prenda, para:)Tj 1.818 -7.152 Td (www.emocoes.org/abcdefghijklmnopqrstuvwxyz)Tj ET
и PDF выглядит так:
K, X и Y в этом случае отсутствуют. Открытие файла в Adobe Illustrator показывает, что они все еще там за другими буквами:
Мне не удалось найти определенную закономерность: иногда H и J также отсутствуют в других строках замены, а отсутствующие буквы отличаются в других шрифтах (я тестировал Open Sans и Times New Roman).
В чем проблема и как ее исправить?
Мой код:
function customizeVoucher(findText, replaceText) {
var sourceFile = path.join(__dirname, "../private/vouchers/custom-old.pdf");
var link = "/vouchers/cheque-prenda-" + replaceText + ".pdf";
var targetFile = path.join(__dirname, "../private" + link);
var pageNumber = 0;
var writer = hummus.createWriterToModify(sourceFile, {
modifiedFilePath: targetFile,
log: path.join(__dirname, "../hummus.md")
});
var sourceParser = writer.createPDFCopyingContextForModifiedFile().getSourceDocumentParser();
var pageObject = sourceParser.parsePage(pageNumber);
var textObjectId = pageObject.getDictionary().toJSObject().Contents.getObjectID();
var textStream = sourceParser.queryDictionaryObject(pageObject.getDictionary(), 'Contents');
//read the original block of text data
var data = [];
var readStream = sourceParser.startReadingFromStream(textStream);
while(readStream.notEnded()){
Array.prototype.push.apply(data, readStream.read(10000));
}
console.info(replaceText);
var string = new Buffer(data).toString().replace(findText, replaceText);
console.info(string);
// Create and write our new text object.
var objectsContext = writer.getObjectsContext();
objectsContext.startModifiedIndirectObject(textObjectId);
var stream = objectsContext.startUnfilteredPDFStream();
stream.getWriteStream().write(strToByteArray(string));
objectsContext.endPDFStream(stream);
objectsContext.endIndirectObject();
writer.end();
return link;
}
а исходный PDF здесь.
@mkl Да, действительно: файл со всеми скрытыми глифами не имеет этой проблемы. Illustrator может отобразить его, вероятно, потому что у него есть исходный шрифт. Можете ли вы написать ответ и порекомендовать более надежное решение?
Я мог бы написать ответ, но у меня нет более надежного решения для Javascript.
Все в порядке, можете ли вы добавить более надежный метод, отличный от Javascript?
В Java с itext я бы сначала применил извлечение текста с координатами (чтобы найти текст для замены), удалил текст с помощью редактирования в этих координатах и добавил замену как новый текст. Когда я вернусь в офис в следующем году, я смогу написать что-нибудь на этот счет более подробно.
В вашем примере PDF используются два шрифта, MyriadPro-Regular и AmaticSC-Bold, и оба они встроены только как подмножества:
и
Таким образом, когда вы используете свой код для замены строк в тексте, показывающем инструкции, в обычных средствах просмотра PDF видны только глифы из соответствующего подмножества шрифта, выбранного перед этой инструкцией. С другой стороны, Adobe Illustrator для редактирования использует полные шрифты, если они доступны локально.
Если вы сами создали шаблон PDF и можете воссоздать его, сделайте это, но убедитесь, что в него встроены все необходимые глифы. Вы можете убедиться, поместив куда-нибудь невидимую строку со всеми необходимыми символами из соответствующего шрифта; это обычно заставляет создателей PDF вставлять все эти глифы. Вы можете нарисовать невидимую строку, используя невидимый режим рендеринга текста, рисуя белым на белом, закрывая чем-то другим, рисуя за пределами контура клипа или за пределами страницы, ...
Если вы не можете воссоздать шаблон, вы можете сделать так, как предложила gal kahana в выпуске Hummus «Как искать и заменять текст в документе?» , на который ссылается ответ, из которого вы взяли код:
сложная часть состоит в том, чтобы добавить любые новые символы в определение шрифта. Предполагая, что в PDF-файле есть только те символы, которые ему нужны для рендеринга текста, это, вероятно, означает, что вам нужно знать, какой исходный шрифт использовался... реализовать его из PDF-файла не очень просто, но можно сделать. выполнение фактического встраивания ... вам, вероятно, лучше создать новый шрифт с использованием хумуса с тем же именем и написать весь текст с использованием этого шрифта. просто замените команду Tf, поместив старый шрифт на новый, и используйте Tjs для размещения нового текста
В случае вашего примера PDF у вас есть
/TT0 1 Tf
65.5689 -24.5097 24.5097 65.5689 363.9941 762.3682 Tm
(e) Tj
61.1539 -34.0617 34.0617 61.1539 381.1689 756.6411 Tm
(n) Tj
54.8214 -43.5272 43.5272 54.8214 408.6333 741.0947 Tm
(d) Tj
48.8331 -50.153 50.153 48.8331 426.3779 726.999 Tm
(a) Tj
52 0 0 52 75.8203 226.9756 Tm
(nomegenerico) Tj
33 0 0 33 25.8203 302.9756 Tm
(E) Tj
(ste cheque-prenda, para:) Tj
1.818 -7.152 Td
(www.emocoes.org/nomegenerico) Tj
Поэтому, если вы используете Hummus для добавления достаточно полной копии шрифта AmaticSC-Bold в ресурсы страницы с новым именем, например. ASCB, вы бы тогда заменили
(nomegenerico) Tj
к
/ASCB 1 Tf
(REPLACEMENT_TEXT) Tj
/TT0 1 Tf
а также
(www.emocoes.org/nomegenerico) Tj
к
/ASCB 1 Tf
(www.emocoes.org/REPLACEMENT_TEXT) Tj
/TT0 1 Tf
последовать совету Гал Каханы.
Осторожно: хотя описанный выше подход, скорее всего, сработает в случае вашего шаблона, общий случай намного сложнее, см. этот ответ для некоторых фонов.
Меньшее, что вам нужно сделать для более общего решения, - это принять во внимание кодировку шрифта. В вашем PDF-файле оба шрифта используются с WinAnsiEncoding, которая очень похожа на Latin-1, но в целом каждый шрифт может иметь свою собственную кодировку, и эта кодировка не обязательно должна быть стандартной, а может быть полностью пользовательской. Это требует, чтобы вы отслеживали, какой шрифт в настоящее время установлен в потоке содержимого, и искали соответствующую информацию из ресурса шрифта, чтобы правильно интерпретировать следующие текстовые строки.
Галь кахана объяснила, как это сделать с Хумусом, в статье «Извлечение текста из файлов PDF». Для общего метода замены текста вам «просто» нужно расширить код, предоставленный там, чтобы разрешить замену инструкций, рисующих определенные фрагменты текста.
Скорее всего, шрифт встроен только как подмножество, присутствуют только изначально необходимые глифы. Это лишь одна из многих ситуаций, в которых слишком упрощенный метод замены текста, на который вы ссылаетесь, терпит неудачу.