あまりなさそうな状況ではありますが、せっかくプログラムを作ったので公開しておきます。
実装言語はJavaです。
必要なライブラリ
- itextpdf-5.5.0.jar、itext-asian.jar
- slf4j-api-1.7.7.jar
- logback-core-1.1.2.jar, logback-classic-1.1.2.jar
※slf4jとlogbackはログ出力に使っているだけなので、なくても良い。
コード
package com.lumiere_couleur.java.pdfwatermark;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PRStream;
import com.itextpdf.text.pdf.PdfDictionary;
import com.itextpdf.text.pdf.PdfName;
import com.itextpdf.text.pdf.PdfNumber;
import com.itextpdf.text.pdf.PdfObject;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.parser.PdfImageObject;
public class ReplaceImages {
private static final Logger log = LoggerFactory
.getLogger(ReplaceImages.class);
public static float FACTOR = 1.0f;
public static void main(String[] args) {
if (args.length < 3) {
System.err
.println("Usage: java ReplaceImages input_pdf output_pdf watermark");
System.exit(1);
}
String input_pdf = args[0];
String output_pdf = args[1];
String watermark = args[2];
if (input_pdf == null || input_pdf.length() == 0
|| !(new File(input_pdf).exists())) {
System.err
.println("Usage: java ReplaceImages input_pdf output_pdf watermark");
System.exit(1);
}
try {
PdfReader reader = new PdfReader(new FileInputStream(input_pdf));
int n = reader.getXrefSize();
PdfObject object;
PRStream stream;
for (int i = 0; i < n; i++) {
object = reader.getPdfObject(i);
if (object == null || !object.isStream()) {
continue;
}
PdfDictionary dic = (PdfDictionary) PdfReader
.getPdfObject(object);
if (dic == null) {
continue;
}
PdfName type = (PdfName) PdfReader.getPdfObject(dic
.get(PdfName.SUBTYPE));
if (!PdfName.IMAGE.equals(type)) {
continue;
}
stream = (PRStream) object;
PdfImageObject image = new PdfImageObject(stream);
BufferedImage bi = null;
try {
bi = image.getBufferedImage();
} catch (javax.imageio.IIOException e) {
// Unsupported Image Type
// CMYK → RGBに変換
// http://stackoverflow.com/questions/2408613/problem-reading-jpeg-image-using-imageio-readfile-file
byte[] imgbytes = image.getImageAsBytes();
if (imgbytes == null) {
continue;
}
// Find a suitable ImageReader
Iterator<ImageReader> readers = ImageIO
.getImageReadersByFormatName("JPEG");
ImageReader imageReader = null;
while (readers.hasNext()) {
imageReader = (ImageReader) readers.next();
if (imageReader.canReadRaster()) {
break;
}
}
// Stream the image file (the original CMYK image)
ImageInputStream input = ImageIO
.createImageInputStream(new ByteArrayInputStream(
imgbytes));
imageReader.setInput(input);
// Read the image raster
Raster raster = imageReader.readRaster(0, null);
// Create a new RGB image
bi = new BufferedImage(raster.getWidth(),
raster.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
// Fill the new image with the old raster
bi.getRaster().setRect(raster);
}
if (bi == null) {
continue;
}
int width = (int) (bi.getWidth() * FACTOR);
int height = (int) (bi.getHeight() * FACTOR);
BufferedImage img = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
AffineTransform at = AffineTransform.getScaleInstance(FACTOR,
FACTOR);
Graphics2D g = img.createGraphics();
g.drawRenderedImage(bi, at);
// 透かしを入れる
g.setPaint(Color.WHITE);
Font font = new Font("メイリオ", Font.PLAIN, 18);
g.setFont(font);
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
String s = watermark;
FontMetrics fm = g.getFontMetrics();
int x = img.getWidth() - fm.stringWidth(s) - 10;
int y = img.getHeight() - 10;
// 文字背景
g.setColor(new Color(1f, 1f, 1f, 0.5f));
int bgx = x - 10;
int bgy = y - 10 - font.getSize() / 2 - 5;
g.fillRect(bgx, bgy, img.getWidth() - bgx, img.getHeight()
- bgy);
// 文字
g.setColor(Color.BLACK);
g.drawString(s, x, y);
ByteArrayOutputStream imgBytes = new ByteArrayOutputStream();
ImageIO.write(img, "JPG", imgBytes);
stream.clear();
stream.setData(imgBytes.toByteArray(), false,
PRStream.NO_COMPRESSION);
stream.put(PdfName.TYPE, PdfName.XOBJECT);
stream.put(PdfName.SUBTYPE, PdfName.IMAGE);
stream.put(PdfName.FILTER, PdfName.DCTDECODE);
stream.put(PdfName.WIDTH, new PdfNumber(width));
stream.put(PdfName.HEIGHT, new PdfNumber(height));
stream.put(PdfName.BITSPERCOMPONENT, new PdfNumber(8));
stream.put(PdfName.COLORSPACE, PdfName.DEVICERGB);
}
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(
output_pdf));
stamper.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (DocumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
log.debug("done");
}
}
あーつかれた。