java pdf 去除文本水印
·
pdf去除文本水印
使用工具包itextpdf-5.5.13.4.jar
优势:此方法是直接对pdf的文件流进行操作,通过itextpdf工具包,扫描到倾斜的文本水印,删除对应流数据,然后重新拼接流,生成新的pdf文件; 而不是通过覆盖,隐藏等方式,虽然不显示,但是水印数据还是在文件里。
代码如下:
package aa;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream;
import com.itextpdf.text.pdf.MemoryLimitsAwareException;
import com.itextpdf.text.pdf.PRStream;
import com.itextpdf.text.pdf.PdfArray;
import com.itextpdf.text.pdf.PdfDictionary;
import com.itextpdf.text.pdf.PdfName;
import com.itextpdf.text.pdf.PdfObject;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.RandomAccessFileOrArray;
/**
* 文本水印消除器
*
* @author liubing1
*
*/
public class TextWaterMarkerRemover {
// 水印命中正则(Tm pdf转置操作符; Tj pdf文本操作符 )
private static Pattern pt = Pattern.compile("[0-9\\.\\s]+Tm[\r\n]+\\(.+\\)Tj");
// pdf页面数据
private Map<Long, DataInfo> pageContent = new TreeMap<Long, DataInfo>();
// 源文件
private String srcPdf;
// 生成目标文件
private String destPdf;
public TextWaterMarkerRemover(String src, String dest) {
this.destPdf = dest;
this.srcPdf = src;
}
public void work() {
InputStream is=null;
OutputStream os=null;
PdfReader reader=null;
try {
is = new FileInputStream(srcPdf);
os = new FileOutputStream(destPdf);
reader = new PdfReader(srcPdf);
int numPages = reader.getNumberOfPages();
RandomAccessFileOrArray rf = reader.getSafeFile();
// 扫描水印内容,并将其替换
for (int i = 1; i <= numPages; i++) {
handlePageContent(i, reader, rf);
}
long index = 0;
for (Long beg : pageContent.keySet()) {
DataInfo info = pageContent.get(beg);
byte[] dd = new byte[(int) (beg - index)];
is.read(dd);
os.write(dd);
is.skip(info.end - info.beg);
index = info.end;
os.write(info.data);
os.flush();
}
byte[] dd = new byte[1024];
int i = 0;
while ((i = is.read(dd)) > -1) {
os.write(dd, 0, i);
}
os.flush();
} catch (Exception e) {
e.printStackTrace();
}finally {
if(is!=null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
reader.close();
try {
if(os!=null) {
os.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void handlePageContent(int pageNum, PdfReader reader, RandomAccessFileOrArray file) throws Exception {
PdfDictionary page = reader.getPageNRelease(pageNum);
if (page == null) {
return;
}
PdfObject contents = PdfReader.getPdfObjectRelease(page.get(PdfName.CONTENTS));
if (contents == null) {
return;
}
if (contents.isStream()) {
getStreamBytes((PRStream) contents, file);
}
if (contents.isArray()) {
PdfArray array = (PdfArray) contents;
for (int k = 0; k < array.size(); ++k) {
PdfObject item = PdfReader.getPdfObjectRelease(array.getPdfObject(k));
if (item == null || !item.isStream())
continue;
getStreamBytes((PRStream) item, file);
if (k == array.size() - 1)
continue;
}
}
}
public void getStreamBytes(PRStream stream, RandomAccessFileOrArray file) throws IOException {
byte[] b;// 原数据
if (stream.getOffset() < 0L) {
b = stream.getBytes();
} else {
b = new byte[stream.getLength()];
file.seek(stream.getOffset());
long beg = file.getFilePointer();
file.readFully(b);
long end = file.getFilePointer();
// 文件内容解压
byte[] b2 = FlateDecode(b, true);
if (b2 == null) {
b2 = FlateDecode(b, false);
}
if (b2 != null && b2.length > 0) {
// 字节数组和字符串转换,必须使用ISO-8859-1,否则会造成数据丢失
String str = new String(b2, "ISO-8859-1");
Matcher mm = pt.matcher(str);
while (mm.find()) {
String a = mm.group();
String[] arr = a.split(" ");
// 获取转置矩阵,倾斜度的属性不为0; 文本倾斜
if (arr.length > 2 && !arr[1].equals("0") && !arr[2].equals("0")) {
str = str.replace(a, "");
}
}
byte[] bb = str.getBytes("ISO-8859-1");
// 文件内容再次压缩
bb = FlateEncode(bb);
pageContent.put(beg, new DataInfo(beg, end, bb));
}
}
}
// 压缩
private static byte[] FlateEncode(byte[] in) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
DeflaterOutputStream os = new DeflaterOutputStream(out);
try {
for (byte bb : in) {
os.write(bb);
}
out.close();
os.close();
byte[] arrby = out.toByteArray();
return arrby;
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException iOException) {
}
}
return null;
}
// 解压
private static byte[] FlateDecode(byte[] in, boolean strict) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream stream = new ByteArrayInputStream(in);
InflaterInputStream zip = new InflaterInputStream(stream);
byte[] b = new byte[strict ? 4092 : 1];
try {
int n;
while ((n = zip.read(b)) >= 0) {
out.write(b, 0, n);
}
zip.close();
out.close();
byte[] arrby = out.toByteArray();
return arrby;
} catch (MemoryLimitsAwareException e) {
throw e;
} catch (Exception e) {
if (strict) {
byte[] arrby = null;
return arrby;
}
byte[] arrby = out.toByteArray();
return arrby;
} finally {
try {
zip.close();
} catch (IOException iOException) {
}
try {
out.close();
} catch (IOException iOException) {
}
}
}
private static class DataInfo {
private long beg;
private long end;
private byte[] data;
public DataInfo(long beg, long end, byte[] data) {
this.beg = beg;
this.end = end;
this.data = data;
}
}
public static void main(String[] args) throws Exception {
long beg = System.currentTimeMillis();
new TextWaterMarkerRemover("1.pdf","11.pdf").work();
System.out.println(System.currentTimeMillis() - beg);
}
}
更多推荐
所有评论(0)