Я барахтаюсь и хожу по кругу с этой проблемой уже пару дней. Я надеюсь, что кто-то здесь может помочь.
У меня есть PDF-документ в файловом потоке, который я хотел бы использовать iText7 8.0.3 из C#, чтобы найти все экземпляры ключевого слова «и» и выделить их красным фоном, а затем сохранить документ обратно в поток памяти, а затем в копию pdf.
Вот мой код, который почти работает, он отображает красный фон, но только в неправильных относительных местах: -
using iText.Kernel.Colors;
using iText.Kernel.Pdf;
using iText.Kernel.Pdf.Canvas;
using iText.Kernel.Pdf.Canvas.Parser;
using iText.Kernel.Pdf.Canvas.Parser.Listener;
using System.IO;
FileStream src = new FileStream("C:\\Temp\\34207180.pdf", FileMode.Open);
MemoryStream ms = new MemoryStream();
string keyword = "and";
PdfDocument pdfDoc = new PdfDocument(new PdfReader(src), new PdfWriter(ms));
int pdfPages = pdfDoc.GetNumberOfPages();
for (int page = 1; page <= pdfPages; page++)
{
Regex regex = new Regex(keyword, RegexOptions.IgnoreCase);
RegexBasedLocationExtractionStrategy extractionStrategy = new RegexBasedLocationExtractionStrategy(regex);
PdfCanvasProcessor parser = new PdfCanvasProcessor(extractionStrategy);
parser.ProcessPageContent(pdfDoc.GetPage(page));
List<IPdfTextLocation> locs = extractionStrategy.GetResultantLocations().ToList();
PdfCanvas pdfCanvas = new PdfCanvas(pdfDoc.GetPage(page).NewContentStreamAfter(), pdfDoc.GetPage(page).GetResources(), pdfDoc);
foreach (var l in locs)
{
pdfCanvas
.SaveState()
.SetFillColor(ColorConstants.RED)
.Rectangle(l.GetRectangle().GetX(), l.GetRectangle().GetY(), l.GetRectangle().GetWidth(), l.GetRectangle().GetHeight())
.Fill()
.RestoreState();
}
}
pdfDoc.Close();
byte[] img = ms.ToArray();
File.WriteAllBytes("C:\\Temp\\34207180-dest.pdf", img);
А вот примеры входных и выходных PDF-файлов: ИсточникПункт назначения
Кто-нибудь может объяснить, что происходит? Это похоже на то, что GetResultantLocations возвращает значения в масштабе, отличном от того, который требуется для PdfCanvas Rectangle Fill.
Я прочитал много статей на этом сайте и в других местах, но безрезультатно.
На создаваемый вами рисунок влияет матрица преобразования, установленная в исходном содержимом.
Чтобы на вас не повлияла какая-либо активная матрица преобразования, вы можете использовать конструктор Canvas PdfCanvas(PdfPage page, bool wrapOldContent)
. Этот WrapOldContent обернет существующий контент в состояние сохранения и восстановления, что приведет к нетронутому состоянию.
Нарисованные прямоугольники заблокируют текст. Это можно исправить, установив режим наложения на умножение. Canvas.SetExtGState(new PdfExtGState().SetBlendMode(PdfExtGState.BM_MULTIPLY))
Я обновил часть вашего кода, чтобы отразить эти и некоторые другие изменения:
PdfCanvas pdfCanvas = new PdfCanvas(pdfDoc.GetPage(page), true);
pdfCanvas.SaveState();
pdfCanvas.SetFillColor(ColorConstants.RED);
pdfCanvas.SetExtGState(new PdfExtGState().SetBlendMode(PdfExtGState.BM_MULTIPLY));
foreach (var l in locs)
{
pdfCanvas
.Rectangle(l.GetRectangle().GetX(), l.GetRectangle().GetY(), l.GetRectangle().GetWidth(),
l.GetRectangle().GetHeight())
.Fill();
}
pdfCanvas.RestoreState();
Одно предупреждение: этот код изменяет статическое содержимое страницы. В целом это нормально, но если вы хотите выделить слова в документах с цифровой подписью, вам не следует изменять содержимое страницы. Вместо этого вам придется добавить аннотации для основных моментов.
Это работает отлично, поэтому я отметил это как ответ. Большое спасибо. Я пытался проголосовать за вас, но я не отвечаю минимальным требованиям для этого. Желаем вам фантастических выходных!