示例#1
0
  /**
   * Get a glyph outline by character code
   *
   * <p>Note this method must always return an outline
   *
   * @param src the character code of the desired glyph
   * @return the glyph outline
   */
  @Override
  protected GeneralPath getOutline(char src, float width) {
    // some true type fonts put characters in the undefined
    // region of Unicode instead of as normal characters.
    if (!this.f.canDisplay(src) && this.f.canDisplay((char) (src + 0xf000))) {
      src += 0xf000;
    }

    // filter out control characters
    for (int i = 0; i < controlChars.length; i++) {
      if (controlChars[i] == src) {
        src = (char) (0xf000 | src);
        break;
      }
    }

    char[] glyph = new char[1];
    glyph[0] = src;

    GlyphVector gv = this.f.createGlyphVector(this.basecontext, glyph);
    GeneralPath gp = new GeneralPath(gv.getGlyphOutline(0));

    // this should be gv.getGlyphMetrics(0).getAdvance(), but that is
    // broken on the Mac, so we need to read the advance from the
    // hmtx table in the font
    CMap map = this.cmapTable.getCMap(mapIDs[0], mapIDs[1]);
    int glyphID = map.map(src);
    float advance = (float) this.hmtxTable.getAdvance(glyphID) / (float) this.unitsPerEm;

    float widthfactor = width / advance;
    gp.transform(AffineTransform.getScaleInstance(widthfactor, -1));

    return gp;
  }
示例#2
0
  /**
   * Get a glyph outline by name
   *
   * @param name the name of the desired glyph
   * @return the glyph outline, or null if unavailable
   */
  @Override
  protected GeneralPath getOutline(String name, float width) {
    if (this.postTable != null && this.cmapTable != null) {
      // map this character name to a glyph ID
      short glyphID = this.postTable.getGlyphNameIndex(name);

      if (glyphID == 0) {
        // no glyph -- try by index
        return null;
      }

      // the mapped character
      char mappedChar = 0;

      for (int i = 0; i < mapIDs.length; i += 2) {
        CMap map = this.cmapTable.getCMap(mapIDs[i], mapIDs[i + 1]);
        if (map != null) {
          mappedChar = map.reverseMap(glyphID);

          // we found a character
          if (mappedChar != 0) {
            break;
          }
        }
      }

      return getOutline(mappedChar, width);
    }

    // no maps found, hope the font can deal
    return null;
  }
示例#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
  /**
   * lookup the outline using the CMAPs, as specified in 32000-1:2008, 9.6.6.4, when an Encoding is
   * specified.
   *
   * @param val
   * @param width
   * @return GeneralPath
   */
  protected synchronized GeneralPath getOutlineFromCMaps(char val, float width) {
    // find the cmaps
    CmapTable cmap = (CmapTable) this.font.getTable("cmap");

    if (cmap == null) {
      return null;
    }

    // try maps in required order of (3, 1), (1, 0)
    CMap map = cmap.getCMap((short) 3, (short) 1);
    if (map == null) {
      map = cmap.getCMap((short) 1, (short) 0);
    }
    int idx = map.map(val);
    if (idx != 0) {
      return getOutline(idx, width);
    }

    return null;
  }