Ошибка замены текста в PDF на NodeJS и хумус

Как заменить строку в файле 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 23.12.2020 23:35

@mkl Да, действительно: файл со всеми скрытыми глифами не имеет этой проблемы. Illustrator может отобразить его, вероятно, потому что у него есть исходный шрифт. Можете ли вы написать ответ и порекомендовать более надежное решение?

miguelmorin 24.12.2020 16:02

Я мог бы написать ответ, но у меня нет более надежного решения для Javascript.

mkl 24.12.2020 19:38

Все в порядке, можете ли вы добавить более надежный метод, отличный от Javascript?

miguelmorin 26.12.2020 10:46

В Java с itext я бы сначала применил извлечение текста с координатами (чтобы найти текст для замены), удалил текст с помощью редактирования в этих координатах и ​​добавил замену как новый текст. Когда я вернусь в офис в следующем году, я смогу написать что-нибудь на этот счет более подробно.

mkl 26.12.2020 12:05
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
5
874
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В вашем примере 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». Для общего метода замены текста вам «просто» нужно расширить код, предоставленный там, чтобы разрешить замену инструкций, рисующих определенные фрагменты текста.

Другие вопросы по теме