如何使用iText使用嵌入字体添加水印

时间:2011-02-03 11:40:50

标签: java fonts itext

我有几个带有一些嵌入字体的pdf / a文档,现在我要使用iText对这些文档进行后期处理以添加水印。

我知道可以使用iText嵌入字体:

BaseFont bf = BaseFont.createFont(BaseFont.HELVETICA, BaseFont.WINANSI, BaseFont.EMBEDDED);

但我想使用已经嵌入文档中的字体来添加文本水印(类似“SAMPLE COPY”)。

我该怎么做?

3 个答案:

答案 0 :(得分:2)

你想要的是DocumentFont。你不能直接创建它们,构造函数是包私有的,但BaseFont.createFont(PRIndirectReference)可以解决这个问题。

所以你只需要PRIndirectReference得到你想要的字体。 “PR”来自PdfReader。有两种方法可以找到您正在寻找的字体并获得对它的引用:

1)枚举PdfReader中的每个对象,过滤掉所有不是PRStream的对象,从那里删除所有不是/Type /Font的对象,并查找具有正确名称的字体。

public PRIndirectReference findNamedFont( PdfReader myReader, String desiredFontName) {
  int objNum = 0;
  PdfObject curObj;
  do {
    //The "Release" version doesn't keep a reference 
    //to the object so it can be GC'd later.  Quite Handy 
    //when dealing with Really Big PDFs.
    curObj = myReader.getPdfObjectRelease( objNum++ );
    if (curObj instanceof PRStream) {
      PRStream stream = (PRStream)curObj;
      PdfName type = stream.getAsName(PdfName.TYPE);
      if (PdfName.FONT.equals(type)) {
        PdfString fontName = stream.getAsString(PdfName.BASEFONT);
        if (desiredFontName.equals(fontName.toString())) {
          return curObj.getIndRef();
        }
      }
    }
  } while (curObj != null);
return null;
}  

2)检查您网页的资源词典/Font <<>>,查找具有正确名称的字体。请记住,XObject Form资源拥有自己需要检查的资源:

public PRIndirectReference findFontInPage(PdfReader reader, String desiredName, int i) {

  PdfDictionary page = reader.getPageN(i); 
  return findFontInResources(page.getAsDict(PdfName.RESOURCES), desiredName);
}   

public PRIndirectReference findFontInResources(PdfDictionary resources, String desiredName) {
  if (resources != null) {
    PdfDictionary fonts = resources.getAsDict(PdfName.FONTS);
    if (fonts != null) {
      for (PdfName curFontName : fonts.keySet()) {
        PRStream curFont (PRStream)= fonts.getAsStream(curFontName);
        if (desiredName.equals(curFont.getAsString(PdfName.BASEFONT).toString()) {
          return (PRIndirectReference) curFont.getIndirectReference();
        }
      }
    }
    PdfDictionary xobjs = resources.getAsDict(PdfName.XOBJECTS);
    if (xobjs != null) {
      for (PdfName curXObjName : xobjs.keySet()) {
        PRStream curXObj = (PRStream)xobjs.getAsStream(curXObjName);
        if (curXObj != null && PdfName.FORM.equals(curXObj.getAsName(PdfName.SUBTYPE)) {
          PdfDictionary resources = curXObj.getAsDict(PdfName.RESOURCES);
          PRIndirectReference ref = findFontInResources(resources, desiredName);
          if (ref != null) {
            return ref;
          }
        }
      }
    }
  }
  return null;
}

其中任何一个都会让你获得PRIndirectReference。然后,您拨打BaseFont.createFont(myPRRef),即可获得所需的DocumentFont。第一种方法将在PDF中找到任何字体,而第二种方法只能找到实际使用的字体。

此外,子集化字体应该在字体名称前加上“6-random-letters-plus-sign”标签。不要使用字体子集。您正在使用的字符可能不在子集中,导致我称之为“arry ole”的问题。这听起来不错又脏,但它实际上只是我们的销售人员的名字:“Harry Vole”错过了大写字母,因为我将一些字体分类,我不应该拥有许多月之前。

PS:永远不会嵌入您打算在表单字段中使用的字体子集。没有布埃诺。

通常的“我在这里的答案框中写了所有代码”免责声明适用,但我写了很多这样的代码,所以它可能开箱即用。交叉你的手指。 ;)

答案 1 :(得分:1)

完全不同的方法:使用Line Art而不是Text。

如果您从页面的overContent创建“仅限艺术线条”的PdfGraphics2D对象,则可以使用AWT字体,而无需担心嵌入。使用相对较短的字符串,您不必担心PDF的大小会爆炸。

PdfContentByte overcontent = stamper.getOverContent(1);
Graphics2D g2d = overcontent.createGraphicsShapes(pageWid, pageHei);

drawStuffToTheGraphic(g2d);

g2d.dispose();

这将导致“文本”实际上是艺术线条。它无法被选中,搜索等。这可能是好的或坏的,取决于你所追求的。

答案 2 :(得分:0)

使用普通的jPod(BSD,SourceForge),您可以基于“水印”示例。与

PDFontTools.getFonts(doc)

你可以枚举字体,然后在“createForm”方法中使用其中一种......