Пример #1
0
  /**
   * create a new TrueTypeFont object based on a description of the font from the PDF file. If the
   * description happens to contain an in-line true-type font file (under key "FontFile2"), use the
   * true type font. Otherwise, parse the description for key information and use that to generate
   * an appropriate font.
   */
  public TTFFont(String baseFont, PDFObject fontObj, PDFFontDescriptor descriptor)
      throws IOException {
    super(baseFont, fontObj, descriptor);

    String fontName = descriptor.getFontName();
    PDFObject ttfObj = descriptor.getFontFile2();

    // try {
    //    byte[] fontData = ttfObj.getStream();
    //    java.io.FileOutputStream fis = new java.io.FileOutputStream("/tmp/" + fontName + ".ttf");
    //    fis.write(fontData);
    //    fis.flush();
    //    fis.close();
    // } catch (Exception ex) {
    //    ex.printStackTrace();
    // }
    if (ttfObj != null) {
      this.font = TrueTypeFont.parseFont(ttfObj.getStreamBuffer());
      // read the units per em from the head table
      HeadTable head = (HeadTable) this.font.getTable("head");
      this.unitsPerEm = head.getUnitsPerEm();
    } else {
      this.font = null;
    }
    //        System.out.println ("TTFFont: ttfObj: " + ttfObj + ", fontName: " + fontName);

  }
Пример #2
0
  /**
   * Fix a broken font name table for a TrueType font. Some fonts do not have Microsoft-specific
   * name information, but Java won't work without it (grrr.). This method takes a font and adds the
   * Microsoft data into it.
   *
   * @param ttf the font
   * @param name the font's name table
   * @return true if the table was fixed, or false if it was left as is
   */
  private boolean fixNameTable(TrueTypeFont ttf, NameTable name) {
    // if we didn't find the table, or there was an exception,
    // just create a new one
    if (name == null) {
      name = (NameTable) TrueTypeTable.createTable(ttf, "name");
      ttf.addTable("name", name);
    }

    // first, figure out some info about the font
    String fName = this.getBaseFont();
    String style = "Regular";

    if (fName.indexOf("Italic") > -1 || fName.indexOf("italic") > -1) {
      style = "Italic";
    } else if (fName.indexOf("Bold") > -1 || fName.indexOf("bold") > -1) {
      style = "Bold";
    }

    if (fName.indexOf('-') > -1) {
      fName = fName.substring(0, fName.indexOf('-'));
    }

    short platID = NameTable.PLATFORMID_MICROSOFT;
    short encID = 1;
    short langID = 1033;

    short[] nameIDs = {
      NameTable.NAMEID_COPYRIGHT,
      NameTable.NAMEID_FAMILY,
      NameTable.NAMEID_SUBFAMILY,
      NameTable.NAMEID_SUBFAMILY_UNIQUE,
      NameTable.NAMEID_FULL_NAME,
      NameTable.NAMEID_VERSION,
      NameTable.NAMEID_POSTSCRIPT_NAME,
      NameTable.NAMEID_TRADEMARK
    };

    String[] defaultValues = {
      "No copyright",
      fName,
      style,
      fName + " " + style,
      fName + " " + style,
      "1.0 (Fake)",
      fName,
      "No Trademark"
    };

    boolean changed = false;

    for (int i = 0; i < nameIDs.length; i++) {
      if (name.getRecord(platID, encID, langID, nameIDs[i]) == null) {
        name.addRecord(platID, encID, langID, nameIDs[i], defaultValues[i]);
        changed = true;
      }
    }

    return changed;
  }
Пример #3
0
  /**
   * Fix the CMap table. This can be necessary if characters are mapped to control characters (0x9,
   * 0xa, 0xd) Java will not render them, even though they are valid.
   *
   * <p>Also, Java tends to not like it when there is only a Format 0 CMap, which happens frequently
   * when included Format 4 CMaps are broken. Since PDF prefers the Format 0 map, while Java prefers
   * the Format 4 map, it is generally necessary to re-write the Format 0 map as a Format 4 map to
   * make most PDFs work.
   *
   * @param ttf the font
   * @param cmap the CMap table
   * @return true if the font was changed, or false if it was left as-is
   */
  private boolean fixCMapTable(TrueTypeFont ttf, CmapTable cmap) {
    CMapFormat4 fourMap = null;
    CMapFormat0 zeroMap = null;

    for (int i = 0; i < mapIDs.length; i += 2) {
      CMap map = this.cmapTable.getCMap(mapIDs[i], mapIDs[i + 1]);
      if (map != null) {
        if (fourMap == null && map instanceof CMapFormat4) {
          fourMap = (CMapFormat4) map;
        } else if (zeroMap == null && map instanceof CMapFormat0) {
          zeroMap = (CMapFormat0) map;
        }
      }
    }

    // if there were no maps, we could have problems.  Just try creating
    // an identity map
    if (zeroMap == null && fourMap == null) {
      fourMap = (CMapFormat4) CMap.createMap((short) 4, (short) 0);
      fourMap.addSegment((short) getFirstChar(), (short) getLastChar(), (short) 0);
    }

    // create our map based on the type 0 map, since PDF seems
    // to prefer a type 0 map (Java prefers a unicode map)
    if (zeroMap != null) {
      fourMap = (CMapFormat4) CMap.createMap((short) 4, (short) 0);

      // add the mappings from 0 to null and 1 to notdef
      fourMap.addSegment((short) 0, (short) 1, (short) 0);

      for (int i = getFirstChar(); i <= getLastChar(); i++) {
        short value = (short) (zeroMap.map((byte) i) & 0xff);
        if (value != 0) {
          fourMap.addSegment((short) i, (short) i, (short) (value - i));
        }
      }
    }

    // now that we have a type four map, remap control characters
    for (int i = 0; i < controlChars.length; i++) {
      short idx = (short) (0xf000 | controlChars[i]);
      short value = (short) fourMap.map(controlChars[i]);

      fourMap.addSegment(idx, idx, (short) (value - idx));
    }

    // create a whole new table with just our map
    cmap = (CmapTable) TrueTypeTable.createTable(ttf, "cmap");
    cmap.addCMap((short) 3, (short) 1, fourMap);

    // replace the table in the font
    ttf.addTable("cmap", cmap);

    // change the stored table
    this.cmapTable = cmap;

    return true;
  }
Пример #4
0
  /**
   * Set the font
   *
   * @param f the font to use
   */
  protected void setFont(Font f) {
    this.f = f;

    // if it's an OpenType font, parse the relevant tables to get
    // glyph name to code mappings
    if (f instanceof OpenType) {
      OpenType ot = (OpenType) f;

      byte[] cmapData = ot.getFontTable(OpenType.TAG_CMAP);
      byte[] postData = ot.getFontTable(OpenType.TAG_POST);

      TrueTypeFont ttf = new TrueTypeFont(0x10000);

      this.cmapTable =
          (CmapTable) TrueTypeTable.createTable(ttf, "cmap", ByteBuffer.wrap(cmapData));
      ttf.addTable("cmap", this.cmapTable);

      this.postTable =
          (PostTable) TrueTypeTable.createTable(ttf, "post", ByteBuffer.wrap(postData));
      ttf.addTable("post", this.postTable);
    }
  }
Пример #5
0
  /**
   * Set the font
   *
   * @param fontdata the font data as a byte array
   */
  protected void setFont(byte[] fontdata) throws FontFormatException, IOException {

    // System.out.println("Loading " + getBaseFont());
    // FileOutputStream fos = new FileOutputStream("/tmp/" + getBaseFont() + ".ttf");
    // fos.write(fontdata);
    // fos.close();

    try {
      // read the true type information
      TrueTypeFont ttf = TrueTypeFont.parseFont(fontdata);

      // System.out.println(ttf.toString());

      // get the cmap, post, and hmtx tables for later use
      this.cmapTable = (CmapTable) ttf.getTable("cmap");
      this.postTable = (PostTable) ttf.getTable("post");
      this.hmtxTable = (HmtxTable) ttf.getTable("hmtx");

      // read the units per em from the head table
      HeadTable headTable = (HeadTable) ttf.getTable("head");
      this.unitsPerEm = headTable.getUnitsPerEm();

      /* Find out if we have the right info in our name table.
       * This is a hack because Java can only deal with fonts that
       * have a Microsoft encoded name in their name table (PlatformID 3).
       * We'll 'adjust' the font to add it if not, and take our chances
       * with our parsing, since it wasn't going to work anyway.
       */
      NameTable nameTable = null;

      try {
        nameTable = (NameTable) ttf.getTable("name");
      } catch (Exception ex) {
        System.out.println("Error reading name table for font " + getBaseFont() + ".  Repairing!");
      }

      boolean nameFixed = fixNameTable(ttf, nameTable);

      /* Figure out if we need to hack the CMap table.  This might
       * be the case if we use characters that Java considers control
       * characters (0x9, 0xa and 0xd), that have to be re-mapped
       */
      boolean cmapFixed = fixCMapTable(ttf, this.cmapTable);

      // use the parsed font instead of the original
      if (nameFixed || cmapFixed) {
        // System.out.println("Using fixed font!");
        // System.out.println(ttf.toString());
        fontdata = ttf.writeFont();

        // FileOutputStream fos2 = new FileOutputStream("/tmp/" + getBaseFont() + ".fix");
        // fos2.write(fontdata);
        // fos2.close();
      }
    } catch (Exception ex) {
      System.out.println("Error parsing font : " + getBaseFont());
      ex.printStackTrace();
    }

    ByteArrayInputStream bais = new ByteArrayInputStream(fontdata);
    this.f = Font.createFont(Font.TRUETYPE_FONT, bais);
    bais.close();
  }