Я использую iText в Java, чтобы выбрать несколько страниц из большого PDF-документа и сохранить как новый, меньший PDF-файл. В то же время я хотел бы изменить их цвета.
Например, предположим, что все мои страницы используют оттенки серого, и я хотел бы сделать его зеленым. Все используемые цвета - оттенки серого. Я хотел бы заменить каждый из этих цветов на соответствующий цвет зеленого цвета.
Марк Сторер спрашивает:
Что именно вы пытаетесь достичь?
Преврати это ... в это:
У меня есть некоторых документов , для которых я уже использую iText для выбора меньшего набора страниц из документа на основе пользовательского ввода - сокращая более 100 страниц до примерно 5. В то же время время, когда я хочу выпустить зеленый, синий, желтый, розовый и т. д. их версии. Не каждая страница в оттенках серого, но все те, которые имеют значение, поэтому я могу принудительно настроить их цветовое пространство в случае необходимости.
Обновление:
Следуя совету Марка Сторера о режимах наложения, вот что у меня есть:
val reader = new PdfReader(file.toURL)
val document = new Document
val writer = PdfWriter.getInstance(document, outputStream)
document.open()
/* draw a white background behind the page, so the
blend always has something to transform, otherwise
it just fills. */
val canvas = writer.getDirectContent
canvas.setColorFill(new CMYKColor(0.0f, 0.0f, 0.0f, 0.0f))
canvas.rectangle(10f, 0f, 100f, 100f)
canvas.fill
/* Put the imported page on top of that */
val page = writer.getImportedPage(reader, 1)
canvas.addTemplate(page, 0, 0)
/* Fill a box with colour and a blending mode */
canvas.setColorFill(new CMYKColor(0.6f,0.1f,0.0f,0.5f))
val gstate = new PdfGState
gstate.setBlendMode(PdfGState.BM_SCREEN)
canvas.setGState(gstate)
canvas.rectangle(0f, 0f, 100f, 100f)
canvas.fill
document.close()
(это в Scala, но библиотека iText точно такая же, как в Java)
Проблема в том, что все режимы наложения, которые предлагает iText, являются «разделимыми» режимами: они работают на каждом цветовом канале независимо друг от друга. Это означает, что я могу отдельно настроить значения голубого, пурпурного, желтого или черного, но я не могу превратить серый в зеленый.
Чтобы сделать это, мне нужно использовать режим смешивания цветов, который является «неразделимым», то есть цветовые каналы влияют друг на друга. Насколько я могу судить, iText этого не предлагает - ни один из неразделенных режимов наложения не указан среди констант в PdfGState
. Я использую iText 5.0.5, последнюю версию на момент написания этой статьи.
Есть ли способ получить доступ к этим режимам наложения в iText или даже взломать их? Есть ли другой способ достижения результата?
Обновление:
Даже установка режима наложения на Color не работала. Я сделал это в коде, чтобы заставить его:
val gstate = new PdfGState
gstate.put(PdfName.BM, new PdfName("Color"))
canvas.setGState(gstate)
и я проверил полученный PDF в текстовом редакторе, чтобы убедиться, что он правильно сказал. К сожалению, результат на экране просто не сработал. Я понятия не имею, почему, согласно спецификации PDF, это должен быть правильный режим наложения.
Марк Сторер спрашивает:
"Цвет" не работал? Фанки. Можем ли мы увидеть PDF?
Вот PDF .
Выложив его в Интернете, теперь я вижу, что режим «Цвет» работает правильно в Chrome, но не работает в Acrobat 9 Pro (CS4). Так что техника верна, но Adobe не справляется с рендерингом!
Интересно, не существует ли какого-либо способа "сгладить" эффект режима наложения, поэтому PDF-файл содержит нужный цветовой объект напрямую, а не наложение, предназначенное для получения правильного цвета.
Идея: перевернуть это с ног на голову. Использовать существующую страницу как альфа-канал на странице, заполненной
полностью с желаемым цветом, а не наоборот.
Как? Я не уверен, что GState применяется для добавления шаблона?
Кроме того, импортированная страница должна сначала добавить белый фон, или она просто зальется цветом там, где нет объекта, а не смешивается.
Я пытался сделать это:
val canvas = writer.getDirectContent
canvas.setColorFill(new CMYKColor(0.6f,0.1f,0.0f,0.0f))
canvas.rectangle(10f, 0f, 500f, 500f)
canvas.fill
val template = canvas.createTemplate(500f, 500f)
template.setColorFill(new CMYKColor(0f, 0f, 0f, 0f))
template.rectangle(0f, 0f, 500f, 500f)
template.fill
val page = writer.getImportedPage(reader, 1)
template.addTemplate(page, 0, 0)
val gstate = new PdfGState
gstate.put(PdfName.BM, new PdfName("Color"))
canvas.setGState(gstate)
canvas.addTemplate(template, 0, 0)
И вот PDF, который он создал . Не совсем верно, либо в Chrome, либо в Acrobat:)
Редактировать : Глупый я. Я изменил режим на «Luminosity», производя этот файл . Как и прежде, это выглядит правильно в Chrome, но не в Acrobat.
Я только что проверил, и даже Adobe Reader X не отображает его должным образом. Что, вероятно, означает, что то, о чем я прошу, невозможно. (
Решение
Леонард Розенталь из Adobe вернулся ко мне и прояснил проблему: режим наложения «Цвет» работает только тогда, когда пространство преобразования RGB, а не CMYK. В моем PDF-файле не указывалось пространство, поэтому для продуктов Adobe установлено значение CMYK, а для других - RGB.
Решение в iText состояло в том, чтобы добавить эту строку вверху:
writer.setRgbTransparencyBlending(true)
Конечно, ради точности цвета вам не нужно больше преобразований цветового пространства, чем это абсолютно необходимо, поэтому используйте эту строку, только если вам действительно нужно использовать режимы наложения RGB.
Цветные страницы выглядят немного странно с точки зрения пользователя Photoshop: похоже, светлые оттенки серого были более насыщенными, чем темные. Я исследую способы объединения фильтров для настройки этого вывода.
Вот результат!
Большое спасибо Марку Стореру за помощь в достижении этого решения.