Як робити водяні знаки PDF файлів, використовуючи текст або зображення?

Будь ласка, подивіться приклад TransparentWatermark2 . Він додає прозорий текст на кожну непарну сторінку і прозоре зображення на кожній парній сторінці існуючого документа PDF.

Ось як це робиться:

public void manipulatePdf (String src, String dest) throws IOException, DocumentException {PdfReader reader = new PdfReader (src); int n = reader.getNumberOfPages (); PdfStamper stamper = new PdfStamper (reader, new FileOutputStream (dest)); // text watermark Font f = new Font (FontFamily.HELVETICA, 30); Phrase p = new Phrase ( "My watermark (text)", f); // image watermark Image img = Image.getInstance (IMG); float w = img.getScaledWidth (); float h = img.getScaledHeight (); // transparency PdfGState gs1 = new PdfGState (); gs1.setFillOpacity (0.5f); // properties PdfContentByte over; Rectangle pagesize; float x, y; // loop over every page for (int i = 1; i <= n; i ++) {pagesize = reader.getPageSizeWithRotation (i); x = (pagesize.getLeft () + pagesize.getRight ()) / 2; y = (pagesize.getTop () + pagesize.getBottom ()) / 2; over = stamper.getOverContent (i); over.saveState (); over.setGState (gs1); if (i% 2 == 1) ColumnText.showTextAligned (over, Element.ALIGN_CENTER, p, x, y, 0); else over.addImage (img, w, 0, 0, h, x - (w / 2), y - (h / 2)); over.restoreState (); } Stamper.close (); reader.close (); }

Як ви можете бачити, ми створюємо об'єкт Phrase для тексту і об'єкт Image для зображення. Ми також створюємо об'єкт PdfGState для прозорості. У нашому випадку ми йдемо на 50% непрозорість (змініть 0.5f на щось ще, щоб експериментувати).

Як тільки у нас є ці об'єкти, ми перебираємо кожну сторінку. Ми використовуємо об'єкт PdfReader, щоб отримати інформацію про існуючий документі, наприклад розміри кожної сторінки. Ми використовуємо об'єкт PdfStamper, коли хочемо штампувати додатковий контент в існуючому документі, наприклад, додавши водяний знак поверх кожної окремої сторінки.

При зміні стану графіки завжди безпечно виконувати saveState () перед початком роботи і restoreState () після завершення. Ви, ймовірно, будете працювати, якщо ви цього не зробите, але повірте мені: він може заощадити вам багато часу налагодження, якщо ви приймете дисципліну для цього, так як ви можете отримати дійсно дивні ефекти, якщо стан графіки не збалансовано.

Ми застосовуємо прозорість за допомогою методу setGState (), і в залежності від того, чи є сторінка непарній або парній сторінкою, ми додаємо текст (використовуючи ColumnText і координату (x, y), розраховану так, щоб текст був доданий в середині кожної сторінки) або зображення (використовуючи метод addImage () і відповідні параметри для матриці перетворення).

Як тільки ви зробили це для кожної сторінки документа, ви повинні close () stamper і reader.

протест:

Ви помітите, що сторінки 3 і 4 знаходяться в пейзажі, але є різниця між цими двома сторінками, які не видно неозброєним оком. Сторінка 3 - це насправді сторінка, розмір якої визначається так, як якщо б це була сторінка в портреті, але вона поверталася на 90 градусів. Сторінка 4 - це сторінка, розмір якої визначається таким чином, що шірінa> висота.

Це може вплинути на спосіб додавання водяного знака, але якщо ви використовуєте getPageSizeWithRotation (), iText буде адаптуватися. Можливо, це не те, що ви хочете: можливо, ви хочете додати водяний знак по-іншому.

Погляньте на TransparentWatermark3 :

public void manipulatePdf (String src, String dest) throws IOException, DocumentException {PdfReader reader = new PdfReader (src); int n = reader.getNumberOfPages (); PdfStamper stamper = new PdfStamper (reader, new FileOutputStream (dest)); stamper.setRotateContents (false); // text watermark Font f = new Font (FontFamily.HELVETICA, 30); Phrase p = new Phrase ( "My watermark (text)", f); // image watermark Image img = Image.getInstance (IMG); float w = img.getScaledWidth (); float h = img.getScaledHeight (); // transparency PdfGState gs1 = new PdfGState (); gs1.setFillOpacity (0.5f); // properties PdfContentByte over; Rectangle pagesize; float x, y; // loop over every page for (int i = 1; i <= n; i ++) {pagesize = reader.getPageSize (i); x = (pagesize.getLeft () + pagesize.getRight ()) / 2; y = (pagesize.getTop () + pagesize.getBottom ()) / 2; over = stamper.getOverContent (i); over.saveState (); over.setGState (gs1); if (i% 2 == 1) ColumnText.showTextAligned (over, Element.ALIGN_CENTER, p, x, y, 0); else over.addImage (img, w, 0, 0, h, x - (w / 2), y - (h / 2)); over.restoreState (); } Stamper.close (); reader.close (); }

В цьому випадку ми не використовуємо getPageSizeWithRotation (), а просто getPageSize (). Ми також повідомляємо stamper не компенсоване існуюче обертання сторінки: stamper.setRotateContents (false);

Погляньте на різницю в отриманих PDF файлах:

У першому скріншоті (див. Стор. 3 і 4 результуючого PDF файлу TransparentWatermark2), сторінка зліва фактично являє собою сторінку в портреті, повернену на 90 градусів. iText, однак, відноситься до нього так, як якщо б він був сторінкою в ландшафті, як сторінка справа.

У другому скріншоті (див. Стор. 3 і 4 результуючого PDF файлу TransparentWatermark3) сторінка зліва є сторінкою з портретом, повернену на 90 градусів, і ми додаємо водяний знак, як якщо б сторінку в портреті, В результаті водяний знак також повертається на 90 градусів. Це не відбувається зі сторінкою справа, тому що ця сторінка має поворот на 0 градусів.

Це тонка різниця, але я думав, що ви хочете знати.

Якщо ви хочете прочитати цю відповідь на французькій мові, прочитайте Коментар créer un filigrane transparent en PDF?