Выделите слова в файле PDF, используя itextsharp, не отображая выделенное слово в браузере

Выделенные слова не отображаются в браузере с помощью itextsharp.

саман

введите описание изображения здесь

браузер

введите описание изображения здесь

КОД

 List<iTextSharp.text.Rectangle> MatchesFound = strategy.GetTextLocations(splitText[i].Trim(), StringComparison.CurrentCultureIgnoreCase);
                    foreach (Rectangle rect in MatchesFound)
                    {
                        float[] quad = { rect.Left - 3.0f, rect.Bottom, rect.Right, rect.Bottom, rect.Left - 3.0f, rect.Top + 1.0f, rect.Right, rect.Top + 1.0f };
                        //Create our hightlight
                        PdfAnnotation highlight = PdfAnnotation.CreateMarkup(stamper.Writer, rect, null, PdfAnnotation.MARKUP_HIGHLIGHT, quad);
                        //Set the color
                        highlight.Color = BaseColor.YELLOW;
                       
                        //Add the annotation
                        stamper.AddAnnotation(highlight, pageno);
                        
                    }

Пожалуйста, помогите мне решить эту проблему.

Код Updaetd

  private void highlightPDF()
{
    //Create a simple test file
    string outputFile = Server.MapPath("~/pdf/16193037V_Dhana-FI_NK-QA_Completed.pdf");
    string filename = "HL" + Convert.ToString(Session["Filename"]) + ".pdf";
    Session["Filename"] = "HL" + Convert.ToString(Session["Filename"]);
    //Create a new file from our test file with highlighting
    string highLightFile = Server.MapPath("~/pdf/" + filename);

    //Bind a reader and stamper to our test PDF

    PdfReader reader = new PdfReader(outputFile);
    iTextSharp.text.pdf.PdfContentByte canvas;
    int pageno = Convert.ToInt16(txtPageno.Text);
    using (FileStream fs = new FileStream(highLightFile, FileMode.Create, FileAccess.Write, FileShare.None))
    {
        using (PdfStamper stamper = new PdfStamper(reader, fs))
        {
            canvas = stamper.GetUnderContent(pageno);
            myLocationTextExtractionStrategy strategy = new myLocationTextExtractionStrategy();
            strategy.UndercontentCharacterSpacing = canvas.CharacterSpacing;
            strategy.UndercontentHorizontalScaling = canvas.HorizontalScaling;

            string currentText = PdfTextExtractor.GetTextFromPage(reader, pageno, strategy);
            string text = txtHighlight.Text.Replace("\r\n", "").Replace("\\n", "\n").Replace("  ", " ");
            string[] splitText = text.Split(new string[] { "\n" }, StringSplitOptions.RemoveEmptyEntries);
            for (int i = 0; i < splitText.Length; i++)
            {
                List<iTextSharp.text.Rectangle> MatchesFound = strategy.GetTextLocations(splitText[i].Trim(), StringComparison.CurrentCultureIgnoreCase);
                foreach (Rectangle rect in MatchesFound)
                {
                    canvas.SaveState();
                    canvas.SetColorFill(BaseColor.YELLOW);
                    canvas.Rectangle(rect);
                    canvas.Fill();
                    canvas.RestoreState();                      
                }
            }

        }
    }
    reader.Close();      


}

Это не выделение текста. Я пропустил текст и страницу нет, чтобы выделить текст.

2 ответа

Решение

Прежде всего...

Почему (обновленный) код OP не работает

На самом деле есть два фактора.

Прежде всего, есть проблема в коде OP, чтобы добавить прямоугольник к пути, который он использует

canvas.Rectangle(rect);

К сожалению, это не то, что он ожидает: Rectangle У класса есть несколько свойств, кроме простых координат прямоугольника, прежде всего информации о выбранных границах, цветах границ и цвете интерьера, и PdfContentByte.Rectangle(Rectangle) рисует прямоугольник в соответствии с этими свойствами.

В данном случае, однако, rect используется только для переноса координат прямоугольника, поэтому все эти дополнительные свойства false или же null, Таким образом, canvas.Rectangle(rect) ничего не делает!

Вместо этого ОП должен использовать

canvas.Rectangle(rect.Left, rect.Bottom, rect.Width, rect.Height);

Вот.

Кроме того, @Bruno упомянул в своем ответе

Обратите внимание, что вы не увидите желтый прямоугольник, если добавите его под непрозрачную форму (например, под изображение).

К сожалению, это именно тот случай: документ на самом деле является отсканированным документом, каждая страница была изображением, заполняющим страницу, под которым рисуется эквивалентный текст (вероятно, после распознавания текста), чтобы разрешить текстовое копирование и вставку.

Таким образом, какой бы код ОП не использовался на UnderContentЭто будет скрыто этим самым образом.

Итак, давайте попробуем что-то другое...

Как заставить это работать

@Bruno в своем ответе также указал решение для такого случая:

В этом случае вы можете добавить прозрачный прямоугольник поверх существующего содержимого.

Следуя этому совету, мы заменим

canvas = stamper.GetUnderContent(pageno);

от

canvas = stamper.GetOverContent(pageno);

PdfGState state = new PdfGState();
state.FillOpacity = .3f;
canvas.SetGState(state);

Выбрав слово "поддержка" на третьей странице документа, мы получим:

используя непрозрачность.3

Желтый здесь довольно бледный.

Используя Opacity ценность .6 вместо этого мы получаем

используя непрозрачность 0,6

Теперь желтый становится более интенсивным, но текст начинает выцветать.

Для подобных задач я предпочитаю использовать режим смешивания Darken. Это можно сделать с помощью

state.BlendMode = new PdfName("Darken");

вместо state.FillOpacity = .3f, Это приводит к

используя режим наложения Darken

Это ИМО выглядит лучше.

Как клиент сделал это

ОП прокомментировал

Клиент дал PDF. При этом они подсвечивают текст, подсвеченный текст отображается в браузере

PDF-файл клиента на самом деле использует аннотации, точно так же, как OP в его исходном коде, но, напротив, каждая из аннотаций клиента содержит поток внешнего вида, которого нет в выделенных аннотациях, генерируемых iText.

Предоставление внешнего вида является необязательным, и средства просмотра PDF действительно должны генерировать внешний вид, если ничего не указано. Тем не менее, очевидно, что существует множество программ для просмотра PDF, которые полагаются на внешний вид, который приносит PDF.

Кстати, в клиентских PDF-файлах фактически используется режим смешивания Multiply. Для базового белого и черного цветов Darken и Multiply имеют одинаковый результат.

Заставить это работать с аннотациями

В комментарии ОП задается вопросом

Пожалуйста, еще одно сомнение, если пользователь неправильно выделил, то как убрать желтый цвет (или изменить желтый на белый)? Я изменил желтый на белый, но он не работает. canvas.SetColorFill(BaseColor.WHITE);

Отмена изменения содержимого страницы, как правило, сложнее, чем отмена добавления аннотации. Таким образом, давайте сделаем так, чтобы исходный код OP также работал, т.е. добавил поток появления к аннотациям выделения.

Как ОП сообщил в другом комментарии, его первая попытка добавить поток появления не удалась:

PdfAppearance appearance = PdfAppearance.CreateAppearance(stamper.Writer, rect.Width, rect.Height);
appearance.Rectangle(rect.Left, rect.Bottom, rect.Width, rect.Height);
appearance.SetColorFill(BaseColor.WHITE);
appearance.Fill();
highlight.SetAppearance( PdfAnnotation.APPEARANCE_NORMAL, appearance );
stamper.AddAnnotation(highlight, pageno);

но это не работает

Проблемы в его попытке:

  • Источник шаблона оформления находится в левом нижнем углу области аннотации, а не на странице. Таким образом, для окрашивания рассматриваемой области прямоугольник должен иметь нижний левый угол в (0, 0).
  • Строго говоря, цвет должен быть установлен до начала построения пути.
  • Для подсветки следует использовать цвет, отличный от белого.
  • Прозрачность или соответствующий режим рендеринга должны использоваться, чтобы позволить оригинальному, маркированному тексту просвечивать.

Таким образом, следующий код показывает, как это сделать.

private void highlightPDFAnnotation(string outputFile, string highLightFile, int pageno, string[] splitText)
{
    PdfReader reader = new PdfReader(outputFile);
    iTextSharp.text.pdf.PdfContentByte canvas;
    using (FileStream fs = new FileStream(highLightFile, FileMode.Create, FileAccess.Write, FileShare.None))
    {
        using (PdfStamper stamper = new PdfStamper(reader, fs))
        {
            myLocationTextExtractionStrategy strategy = new myLocationTextExtractionStrategy();
            strategy.UndercontentHorizontalScaling = 100;

            string currentText = PdfTextExtractor.GetTextFromPage(reader, pageno, strategy);
            for (int i = 0; i < splitText.Length; i++)
            {
                List<iTextSharp.text.Rectangle> MatchesFound = strategy.GetTextLocations(splitText[i].Trim(), StringComparison.CurrentCultureIgnoreCase);
                foreach (Rectangle rect in MatchesFound)
                {
                    float[] quad = { rect.Left - 3.0f, rect.Bottom, rect.Right, rect.Bottom, rect.Left - 3.0f, rect.Top + 1.0f, rect.Right, rect.Top + 1.0f };
                    //Create our hightlight
                    PdfAnnotation highlight = PdfAnnotation.CreateMarkup(stamper.Writer, rect, null, PdfAnnotation.MARKUP_HIGHLIGHT, quad);
                    //Set the color
                    highlight.Color = BaseColor.YELLOW;

                    PdfAppearance appearance = PdfAppearance.CreateAppearance(stamper.Writer, rect.Width, rect.Height);
                    PdfGState state = new PdfGState();
                    state.BlendMode = new PdfName("Multiply");
                    appearance.SetGState(state);
                    appearance.Rectangle(0, 0, rect.Width, rect.Height);
                    appearance.SetColorFill(BaseColor.YELLOW);
                    appearance.Fill();

                    highlight.SetAppearance(PdfAnnotation.APPEARANCE_NORMAL, appearance);

                    //Add the annotation
                    stamper.AddAnnotation(highlight, pageno);
                }
            }
        }
    }
    reader.Close();
}

Эти аннотации также отображаются в Chrome, и как аннотации их можно легко удалить.

Вы используете аннотацию разметки для выделения текста. Замечательно! Там нет ничего плохого ни с вашим кодом, ни с iText. Однако: не все средства просмотра PDF поддерживают эту функцию.

Если вы хотите видеть выделенный текст в каждом средстве просмотра PDF, (субоптимальным) обходным решением может быть добавление желтого прямоугольника в поток содержимого под существующим содержимым (при условии, что существующее содержимое не является непрозрачным).

Это продемонстрировано в примере HighLightByAddingContent:

public void manipulatePdf(String src, String dest) throws IOException, DocumentException {
    PdfReader reader = new PdfReader(src);
    PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
    PdfContentByte canvas = stamper.getUnderContent(1);
    canvas.saveState();
    canvas.setColorFill(BaseColor.YELLOW);
    canvas.rectangle(36, 786, 66, 16);
    canvas.fill();
    canvas.restoreState();
    stamper.close();
    reader.close();
}

В этом примере мы берем файл с именем hello.pdf и добавляем желтый прямоугольник с файлом hello_highlighted.pdf в качестве результата.

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

Обновление: мой пример был написан на Java. Для разработчика не должно быть проблемой перенести это на C#. Это только вопрос изменения некоторых строчных букв в прописные. Например stamper.GetUnderContent(1) вместо stamper.getUnderContent(1), canvas.SaveState() вместо canvas.saveState(), и так далее.

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