@Override
  protected void paintIcon(
      java.awt.Component c,
      java.awt.Graphics2D g2,
      int width,
      int height,
      java.awt.Paint fillPaint,
      java.awt.Paint drawPaint) {
    java.awt.Font prevFont = g2.getFont();
    g2.setFont(font);

    String text = "A";
    java.awt.FontMetrics fm = g2.getFontMetrics();
    int messageWidth = fm.stringWidth(text);
    int ascent = fm.getMaxAscent();
    int descent = fm.getMaxDescent();
    int x = (width / 2) - (messageWidth / 2);
    int y = ((height / 2) + (ascent / 2)) - (descent / 2);

    java.awt.font.GlyphVector glyphVector = font.createGlyphVector(g2.getFontRenderContext(), text);
    java.awt.Shape outline = glyphVector.getOutline(x, y);
    g2.setPaint(drawPaint);
    g2.draw(outline);

    g2.setPaint(fillPaint);
    g2.fill(outline);
    //		g2.drawString( text, x, y );

    g2.setFont(prevFont);
  }
Exemple #2
0
  public static Shape generateShapeFromText(Font font, String string) {
    BufferedImage img = GraphicsUtilities.createCompatibleTranslucentImage(1, 1);
    Graphics2D g2 = img.createGraphics();

    try {
      GlyphVector vect = font.createGlyphVector(g2.getFontRenderContext(), string);
      Shape shape = vect.getOutline(0f, (float) -vect.getVisualBounds().getY());

      return shape;
    } finally {
      g2.dispose();
    }
  }
 /**
  * This deals with a bug/peculiarity for the default Mac font: several pixels of the ascent are
  * actually empty. This screws up certain measurements which assume the font is actually a few
  * pixels taller than it really is.
  */
 private static int getUnusedAscent(FontMetrics fm, Font font) {
   Integer value = ascentTable.get(font);
   if (value == null) {
     int recordedAscent = fm.getAscent();
     FontRenderContext frc = new FontRenderContext(new AffineTransform(), false, false);
     GlyphVector gv = font.createGlyphVector(frc, "XYZ");
     Rectangle2D bounds = ShapeBounds.getBounds(gv.getOutline());
     int observedAscent = (int) (Math.ceil(bounds.getHeight()) + .5);
     value = new Integer(recordedAscent - observedAscent);
     ascentTable.put(font, value);
   }
   return value.intValue();
 }
Exemple #4
0
  private Shape generateShapeFromText() {
    Font font = new Font(fontFamily, Font.PLAIN, fontSize);
    BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
    Graphics2D g2 = img.createGraphics();

    try {
      GlyphVector vect = font.createGlyphVector(g2.getFontRenderContext(), str);
      float dispX = x;
      float dispY = (float) (y - vect.getVisualBounds().getY());
      Shape shape = vect.getOutline(dispX, dispY);

      return shape;
    } finally {
      g2.dispose();
    }
  }
    private static BufferedImage createImage(String s, boolean valid) {
      FontRenderContext frc = new FontRenderContext(null, true, true);
      Font font = new Font("dialog", Font.BOLD, 12);

      GlyphVector glyphs = font.createGlyphVector(frc, s);
      Shape shape = glyphs.getOutline();
      Rectangle bounds = shape.getBounds();

      int imageW = bounds.width;
      int imageH = bounds.height;
      BufferedImage image = new BufferedImage(imageW, imageH, BufferedImage.TYPE_INT_ARGB);
      Graphics2D g = (Graphics2D) image.getGraphics();

      g.setColor(valid ? Color.blue : Color.red);
      g.translate(bounds.x, -bounds.y);
      g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
      g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
      g.fill(shape);

      return image;
    }
Exemple #6
0
 /**
  * Draws the specified glyph vector at the location {@code (x, y)}.
  *
  * @param g the glyph vector ({@code null} not permitted).
  * @param x the x-coordinate.
  * @param y the y-coordinate.
  */
 @Override
 public void drawGlyphVector(GlyphVector g, float x, float y) {
   fill(g.getOutline(x, y));
 }
  @Override
  public void paint(Graphics g) {
    Graphics2D g2d = (Graphics2D) g;
    int pad = 5;
    Polygon polyLeft =
        new Polygon(
            new int[] {pad, getWidth() / 2, getWidth() / 2, pad},
            new int[] {pad, pad, getHeight() - pad, getHeight() - pad},
            4);
    Polygon polyRight =
        new Polygon(
            new int[] {getWidth() / 2, getWidth() - pad, getWidth() - pad, getWidth() / 2},
            new int[] {pad, pad, getHeight() - pad, getHeight() - pad},
            4);
    g2d.setColor(Color.red.darker());
    if (isSelected()) g2d.setColor(new Color(172, 225, 175));
    else g2d.setColor(Color.gray);
    g2d.fill(polyLeft);
    if (isSelected()) g2d.setColor(Color.gray);
    else g2d.setColor(new Color(172, 225, 175));
    g2d.fill(polyRight);

    Area round1 =
        new Area(new RoundRectangle2D.Double(0, 0, getWidth() - 1, getHeight() - 1, 8, 8));
    Area round2 =
        new Area(new RoundRectangle2D.Double(4, 4, getWidth() - 1 - 8, getHeight() - 1 - 8, 6, 6));
    Area round3 =
        new Area(
            new RoundRectangle2D.Double(6, 6, getWidth() - 1 - 12, getHeight() - 1 - 12, 5, 5));
    Area round4 =
        new Area(
            new Ellipse2D.Float(
                -getWidth() / 2, -getHeight(), getWidth() * 2, getHeight() * 3 / 2));

    round4.intersect(round2);
    round1.exclusiveOr(round2);
    round2.exclusiveOr(round3);
    int width = getWidth();
    int height = getHeight();
    int d1 = 6;
    int d2 = 8;
    Area outBorder =
        new Area(
            new Polygon(
                new int[] {
                  d1,
                  width - 1 - d1,
                  width - 1 - d1,
                  width - 1,
                  width - 1,
                  width - 1 - d1,
                  width - 1 - d1,
                  d1,
                  d1,
                  0,
                  0,
                  d1
                },
                new int[] {
                  0,
                  0,
                  d1,
                  d1,
                  height - 1 - d1,
                  height - 1 - d1,
                  height - 1,
                  height - 1,
                  height - 1 - d1,
                  height - 1 - d1,
                  d1,
                  d1
                },
                12));
    outBorder.subtract(
        new Area(
            new Polygon(
                new int[] {
                  d2,
                  width - 1 - d2,
                  width - 1 - d2,
                  width - 1 - (d2 - d1),
                  width - 1 - (d2 - d1),
                  width - 1 - d2,
                  width - 1 - d2,
                  d2,
                  d2,
                  d2 - d1,
                  d2 - d1,
                  d2
                },
                new int[] {
                  d2 - d1,
                  d2 - d1,
                  d2,
                  d2,
                  height - 1 - d2,
                  height - 1 - d2,
                  height - 1 - (d2 - d1),
                  height - 1 - (d2 - d1),
                  height - 1 - d2,
                  height - 1 - d2,
                  d2,
                  d2
                },
                12)));
    g2d.setColor(new Color(0x993333));
    g2d.fill(outBorder);
    int d3 = 3;
    int d4 = 5;
    Area midBorder =
        new Area(new Rectangle2D.Double(d3, d3, width - 1 - d3 * 2, height - 1 - d3 * 2));
    midBorder.subtract(
        new Area(new Rectangle2D.Double(d4, d4, width - 1 - d4 * 2, height - 1 - d4 * 2)));
    g2d.fill(midBorder);
    GlyphVector glyphVectorLeft =
        new Font("宋体", Font.PLAIN, fontsize)
            .createGlyphVector(new FontRenderContext(null, true, true), onText);
    Shape shapeTextLeft =
        glyphVectorLeft.getOutline(
            -(float)
                (glyphVectorLeft.getVisualBounds().getMinX()
                    - d3
                    - (getWidth() / 2 - glyphVectorLeft.getVisualBounds().getWidth()) / 2
                    + 1),
            -(float)
                    (glyphVectorLeft.getVisualBounds().getMinY()
                        - (getHeight() - glyphVectorLeft.getVisualBounds().getHeight()) / 2)
                - 1);
    GlyphVector glyphVectorRight =
        new Font("宋体", Font.PLAIN, fontsize)
            .createGlyphVector(new FontRenderContext(null, true, true), offText);
    Shape shapeTextRight =
        glyphVectorRight.getOutline(
            -(float)
                (glyphVectorRight.getVisualBounds().getMinX()
                    + d3
                    - (getWidth() * 3 / 2 - glyphVectorRight.getVisualBounds().getWidth()) / 2
                    + 1),
            -(float)
                    (glyphVectorRight.getVisualBounds().getMinY()
                        - (getHeight() - glyphVectorRight.getVisualBounds().getHeight()) / 2)
                - 1);
    g2d.setColor(new Color(23, 54, 93));
    g2d.draw(shapeTextLeft);
    g2d.setColor(new Color(23, 54, 93));
    g2d.draw(shapeTextRight);
  }
Exemple #8
0
  // Triangulate glyph with 'unicode' if not already done.
  GeometryArrayRetained triangulateGlyphs(GlyphVector gv, char c) {
    Character ch = new Character(c);
    GeometryArrayRetained geo = geomHash.get(ch);

    if (geo == null) {
      // Font Y-axis is downwards, so send affine transform to flip it.
      Rectangle2D bnd = gv.getVisualBounds();
      AffineTransform aTran = new AffineTransform();
      double tx = bnd.getX() + 0.5 * bnd.getWidth();
      double ty = bnd.getY() + 0.5 * bnd.getHeight();
      aTran.setToTranslation(-tx, -ty);
      aTran.scale(1.0, -1.0);
      aTran.translate(tx, -ty);
      Shape shape = gv.getOutline();
      PathIterator pIt = shape.getPathIterator(aTran, tessellationTolerance);
      int flag = -1, numContours = 0, numPoints = 0, i, j, k, num = 0, vertCnt;
      UnorderList coords = new UnorderList(100, Point3f.class);
      float tmpCoords[] = new float[6];
      float lastX = .0f, lastY = .0f;
      float firstPntx = Float.MAX_VALUE, firstPnty = Float.MAX_VALUE;
      GeometryInfo gi = null;
      NormalGenerator ng = new NormalGenerator();
      FastVector contours = new FastVector(10);
      float maxY = -Float.MAX_VALUE;
      int maxYIndex = 0, beginIdx = 0, endIdx = 0, start = 0;

      boolean setMaxY = false;

      while (!pIt.isDone()) {
        Point3f vertex = new Point3f();
        flag = pIt.currentSegment(tmpCoords);
        if (flag == PathIterator.SEG_CLOSE) {
          if (num > 0) {
            if (setMaxY) {
              // Get Previous point
              beginIdx = start;
              endIdx = numPoints - 1;
            }
            contours.addElement(num);
            num = 0;
            numContours++;
          }
        } else if (flag == PathIterator.SEG_MOVETO) {
          vertex.x = tmpCoords[0];
          vertex.y = tmpCoords[1];
          lastX = vertex.x;
          lastY = vertex.y;

          if ((lastX == firstPntx) && (lastY == firstPnty)) {
            pIt.next();
            continue;
          }
          setMaxY = false;
          coords.add(vertex);
          firstPntx = lastX;
          firstPnty = lastY;
          if (num > 0) {
            contours.addElement(num);
            num = 0;
            numContours++;
          }
          num++;
          numPoints++;
          // skip checking of first point,
          // since the last point will repeat this.
          start = numPoints;
        } else if (flag == PathIterator.SEG_LINETO) {
          vertex.x = tmpCoords[0];
          vertex.y = tmpCoords[1];
          // Check here for duplicate points. Code
          // later in this function can not handle
          // duplicate points.

          if ((vertex.x == lastX) && (vertex.y == lastY)) {
            pIt.next();
            continue;
          }
          if (vertex.y > maxY) {
            maxY = vertex.y;
            maxYIndex = numPoints;
            setMaxY = true;
          }
          lastX = vertex.x;
          lastY = vertex.y;
          coords.add(vertex);
          num++;
          numPoints++;
        }
        pIt.next();
      }

      // No data(e.g space, control characters)
      // Two point can't form a valid contour
      if (numPoints == 0) {
        return null;
      }

      // Determine font winding order use for side triangles
      Point3f p1 = new Point3f(), p2 = new Point3f(), p3 = new Point3f();
      boolean flip_side_orient = true;
      Point3f vertices[] = (Point3f[]) coords.toArray(false);

      if (endIdx - beginIdx > 0) {
        // must be true unless it is a single line
        // define as "MoveTo p1 LineTo p2 Close" which is
        // not a valid font definition.

        if (maxYIndex == beginIdx) {
          p1.set(vertices[endIdx]);
        } else {
          p1.set(vertices[maxYIndex - 1]);
        }
        p2.set(vertices[maxYIndex]);
        if (maxYIndex == endIdx) {
          p3.set(vertices[beginIdx]);
        } else {
          p3.set(vertices[maxYIndex + 1]);
        }

        if (p3.x != p2.x) {
          if (p1.x != p2.x) {
            // Use the one with smallest slope
            if (Math.abs((p2.y - p1.y) / (p2.x - p1.x)) > Math.abs((p3.y - p2.y) / (p3.x - p2.x))) {
              flip_side_orient = (p3.x > p2.x);
            } else {
              flip_side_orient = (p2.x > p1.x);
            }
          } else {
            flip_side_orient = (p3.x > p2.x);
          }
        } else {
          // p1.x != p2.x, otherwise all three
          // point form a straight vertical line with
          // the middle point the highest. This is not a
          // valid font definition.
          flip_side_orient = (p2.x > p1.x);
        }
      }

      // Build a Tree of Islands
      int startIdx = 0;
      IslandsNode islandsTree = new IslandsNode(-1, -1);
      int contourCounts[] = contours.getData();

      for (i = 0; i < contours.getSize(); i++) {
        endIdx = startIdx + contourCounts[i];
        islandsTree.insert(new IslandsNode(startIdx, endIdx), vertices);
        startIdx = endIdx;
      }

      coords = null; // Free memory
      contours = null;
      contourCounts = null;

      // Compute islandCounts[][] and outVerts[][]
      UnorderList islandsList = new UnorderList(10, IslandsNode.class);
      islandsTree.collectOddLevelNode(islandsList, 0);
      IslandsNode nodes[] = (IslandsNode[]) islandsList.toArray(false);
      int islandCounts[][] = new int[islandsList.arraySize()][];
      Point3f outVerts[][] = new Point3f[islandCounts.length][];
      int nchild, sum;
      IslandsNode node;

      for (i = 0; i < islandCounts.length; i++) {
        node = nodes[i];
        nchild = node.numChild();
        islandCounts[i] = new int[nchild + 1];
        islandCounts[i][0] = node.numVertices();
        sum = 0;
        sum += islandCounts[i][0];
        for (j = 0; j < nchild; j++) {
          islandCounts[i][j + 1] = node.getChild(j).numVertices();
          sum += islandCounts[i][j + 1];
        }
        outVerts[i] = new Point3f[sum];
        startIdx = 0;
        for (k = node.startIdx; k < node.endIdx; k++) {
          outVerts[i][startIdx++] = vertices[k];
        }

        for (j = 0; j < nchild; j++) {
          endIdx = node.getChild(j).endIdx;
          for (k = node.getChild(j).startIdx; k < endIdx; k++) {
            outVerts[i][startIdx++] = vertices[k];
          }
        }
      }

      islandsTree = null; // Free memory
      islandsList = null;
      vertices = null;

      contourCounts = new int[1];
      int currCoordIndex = 0, vertOffset = 0;
      ArrayList<GeometryArray> triangData = new ArrayList<GeometryArray>();

      Point3f q1 = new Point3f(), q2 = new Point3f(), q3 = new Point3f();
      Vector3f n1 = new Vector3f(), n2 = new Vector3f();
      numPoints = 0;
      // Now loop thru each island, calling triangulator once per island.
      // Combine triangle data for all islands together in one object.
      for (i = 0; i < islandCounts.length; i++) {
        contourCounts[0] = islandCounts[i].length;
        numPoints += outVerts[i].length;
        gi = new GeometryInfo(GeometryInfo.POLYGON_ARRAY);
        gi.setCoordinates(outVerts[i]);
        gi.setStripCounts(islandCounts[i]);
        gi.setContourCounts(contourCounts);
        ng.generateNormals(gi);

        GeometryArray ga = gi.getGeometryArray(false, false, false);
        vertOffset += ga.getVertexCount();

        triangData.add(ga);
      }
      // Multiply by 2 since we create 2 faces of the font
      // Second term is for side-faces along depth of the font
      if (fontExtrusion == null) vertCnt = vertOffset;
      else {
        if (fontExtrusion.shape == null) vertCnt = vertOffset * 2 + numPoints * 6;
        else {
          vertCnt = vertOffset * 2 + numPoints * 6 * (fontExtrusion.pnts.length - 1);
        }
      }

      // XXXX: Should use IndexedTriangleArray to avoid
      // duplication of vertices. To create triangles for
      // side faces, every vertex is duplicated currently.
      TriangleArray triAry =
          new TriangleArray(vertCnt, GeometryArray.COORDINATES | GeometryArray.NORMALS);

      boolean flip_orient[] = new boolean[islandCounts.length];
      boolean findOrient;
      // last known non-degenerate normal
      Vector3f goodNormal = new Vector3f();

      for (j = 0; j < islandCounts.length; j++) {
        GeometryArray ga = triangData.get(j);
        vertOffset = ga.getVertexCount();

        findOrient = false;

        // Create the triangle array
        for (i = 0; i < vertOffset; i += 3, currCoordIndex += 3) {
          // Get 3 points. Since triangle is known to be flat, normal
          // must be same for all 3 points.
          ga.getCoordinate(i, p1);
          ga.getNormal(i, n1);
          ga.getCoordinate(i + 1, p2);
          ga.getCoordinate(i + 2, p3);

          if (!findOrient) {
            // Check here if triangles are wound incorrectly and need
            // to be flipped.
            if (!getNormal(p1, p2, p3, n2)) {
              continue;
            }

            if (n2.z >= EPS) {
              flip_orient[j] = false;
            } else if (n2.z <= -EPS) {
              flip_orient[j] = true;
            } else {
              continue;
            }
            findOrient = true;
          }
          if (flip_orient[j]) {
            // New Triangulator preserves contour orientation. If contour
            // input is wound incorrectly, swap 2nd and 3rd points to
            // sure all triangles are wound correctly for j3d.
            q1.x = p2.x;
            q1.y = p2.y;
            q1.z = p2.z;
            p2.x = p3.x;
            p2.y = p3.y;
            p2.z = p3.z;
            p3.x = q1.x;
            p3.y = q1.y;
            p3.z = q1.z;
            n1.x = -n1.x;
            n1.y = -n1.y;
            n1.z = -n1.z;
          }

          if (fontExtrusion != null) {
            n2.x = -n1.x;
            n2.y = -n1.y;
            n2.z = -n1.z;

            triAry.setCoordinate(currCoordIndex, p1);
            triAry.setNormal(currCoordIndex, n2);
            triAry.setCoordinate(currCoordIndex + 1, p3);
            triAry.setNormal(currCoordIndex + 1, n2);
            triAry.setCoordinate(currCoordIndex + 2, p2);
            triAry.setNormal(currCoordIndex + 2, n2);

            q1.x = p1.x;
            q1.y = p1.y;
            q1.z = p1.z + fontExtrusion.length;
            q2.x = p2.x;
            q2.y = p2.y;
            q2.z = p2.z + fontExtrusion.length;
            q3.x = p3.x;
            q3.y = p3.y;
            q3.z = p3.z + fontExtrusion.length;

            triAry.setCoordinate(currCoordIndex + vertOffset, q1);
            triAry.setNormal(currCoordIndex + vertOffset, n1);
            triAry.setCoordinate(currCoordIndex + 1 + vertOffset, q2);
            triAry.setNormal(currCoordIndex + 1 + vertOffset, n1);
            triAry.setCoordinate(currCoordIndex + 2 + vertOffset, q3);
            triAry.setNormal(currCoordIndex + 2 + vertOffset, n1);
          } else {
            triAry.setCoordinate(currCoordIndex, p1);
            triAry.setNormal(currCoordIndex, n1);
            triAry.setCoordinate(currCoordIndex + 1, p2);
            triAry.setNormal(currCoordIndex + 1, n1);
            triAry.setCoordinate(currCoordIndex + 2, p3);
            triAry.setNormal(currCoordIndex + 2, n1);
          }
        }
        if (fontExtrusion != null) {
          currCoordIndex += vertOffset;
        }
      }

      // Now add side triangles in both cases.

      // Since we duplicated triangles with different Z, make sure
      // currCoordIndex points to correct location.
      if (fontExtrusion != null) {
        if (fontExtrusion.shape == null) {
          boolean smooth;
          // we'll put a crease if the angle between the normals is
          // greater than 44 degrees
          float threshold = (float) Math.cos(44.0 * Math.PI / 180.0);
          float cosine;
          // need the previous normals to check for smoothing
          Vector3f pn1 = null, pn2 = null;
          // need the next normals to check for smoothing
          Vector3f n3 = new Vector3f(), n4 = new Vector3f();
          //  store the normals for each point because they are
          // the same for both triangles
          Vector3f p1Normal = new Vector3f();
          Vector3f p2Normal = new Vector3f();
          Vector3f p3Normal = new Vector3f();
          Vector3f q1Normal = new Vector3f();
          Vector3f q2Normal = new Vector3f();
          Vector3f q3Normal = new Vector3f();

          for (i = 0; i < islandCounts.length; i++) {
            for (j = 0, k = 0, num = 0; j < islandCounts[i].length; j++) {
              num += islandCounts[i][j];
              p1.x = outVerts[i][num - 1].x;
              p1.y = outVerts[i][num - 1].y;
              p1.z = 0.0f;
              q1.x = p1.x;
              q1.y = p1.y;
              q1.z = p1.z + fontExtrusion.length;
              p2.z = 0.0f;
              q2.z = p2.z + fontExtrusion.length;
              for (int m = 0; m < num; m++) {
                p2.x = outVerts[i][m].x;
                p2.y = outVerts[i][m].y;
                q2.x = p2.x;
                q2.y = p2.y;
                if (getNormal(p1, q1, p2, n1)) {

                  if (!flip_side_orient) {
                    n1.negate();
                  }
                  goodNormal.set(n1);
                  break;
                }
              }

              for (; k < num; k++) {
                p2.x = outVerts[i][k].x;
                p2.y = outVerts[i][k].y;
                p2.z = 0.0f;
                q2.x = p2.x;
                q2.y = p2.y;
                q2.z = p2.z + fontExtrusion.length;

                if (!getNormal(p1, q1, p2, n1)) {
                  n1.set(goodNormal);
                } else {
                  if (!flip_side_orient) {
                    n1.negate();
                  }
                  goodNormal.set(n1);
                }

                if (!getNormal(p2, q1, q2, n2)) {
                  n2.set(goodNormal);
                } else {
                  if (!flip_side_orient) {
                    n2.negate();
                  }
                  goodNormal.set(n2);
                }
                // if there is a previous normal, see if we need to smooth
                // this normal or make a crease

                if (pn1 != null) {
                  cosine = n1.dot(pn2);
                  smooth = cosine > threshold;
                  if (smooth) {
                    p1Normal.x = (pn1.x + pn2.x + n1.x);
                    p1Normal.y = (pn1.y + pn2.y + n1.y);
                    p1Normal.z = (pn1.z + pn2.z + n1.z);
                    normalize(p1Normal);

                    q1Normal.x = (pn2.x + n1.x + n2.x);
                    q1Normal.y = (pn2.y + n1.y + n2.y);
                    q1Normal.z = (pn2.z + n1.z + n2.z);
                    normalize(q1Normal);
                  } // if smooth
                  else {
                    p1Normal.x = n1.x;
                    p1Normal.y = n1.y;
                    p1Normal.z = n1.z;
                    q1Normal.x = n1.x + n2.x;
                    q1Normal.y = n1.y + n2.y;
                    q1Normal.z = n1.z + n2.z;
                    normalize(q1Normal);
                  } // else
                } // if pn1 != null
                else {
                  pn1 = new Vector3f();
                  pn2 = new Vector3f();
                  p1Normal.x = n1.x;
                  p1Normal.y = n1.y;
                  p1Normal.z = n1.z;

                  q1Normal.x = (n1.x + n2.x);
                  q1Normal.y = (n1.y + n2.y);
                  q1Normal.z = (n1.z + n2.z);
                  normalize(q1Normal);
                } // else

                // if there is a next, check if we should smooth normal

                if (k + 1 < num) {
                  p3.x = outVerts[i][k + 1].x;
                  p3.y = outVerts[i][k + 1].y;
                  p3.z = 0.0f;
                  q3.x = p3.x;
                  q3.y = p3.y;
                  q3.z = p3.z + fontExtrusion.length;

                  if (!getNormal(p2, q2, p3, n3)) {
                    n3.set(goodNormal);
                  } else {
                    if (!flip_side_orient) {
                      n3.negate();
                    }
                    goodNormal.set(n3);
                  }

                  if (!getNormal(p3, q2, q3, n4)) {
                    n4.set(goodNormal);
                  } else {
                    if (!flip_side_orient) {
                      n4.negate();
                    }
                    goodNormal.set(n4);
                  }

                  cosine = n2.dot(n3);
                  smooth = cosine > threshold;

                  if (smooth) {
                    p2Normal.x = (n1.x + n2.x + n3.x);
                    p2Normal.y = (n1.y + n2.y + n3.y);
                    p2Normal.z = (n1.z + n2.z + n3.z);
                    normalize(p2Normal);

                    q2Normal.x = (n2.x + n3.x + n4.x);
                    q2Normal.y = (n2.y + n3.y + n4.y);
                    q2Normal.z = (n2.z + n3.z + n4.z);
                    normalize(q2Normal);
                  } else { // if smooth
                    p2Normal.x = n1.x + n2.x;
                    p2Normal.y = n1.y + n2.y;
                    p2Normal.z = n1.z + n2.z;
                    normalize(p2Normal);
                    q2Normal.x = n2.x;
                    q2Normal.y = n2.y;
                    q2Normal.z = n2.z;
                  } // else
                } else { // if k+1 < num
                  p2Normal.x = (n1.x + n2.x);
                  p2Normal.y = (n1.y + n2.y);
                  p2Normal.z = (n1.z + n2.z);
                  normalize(p2Normal);

                  q2Normal.x = n2.x;
                  q2Normal.y = n2.y;
                  q2Normal.z = n2.z;
                } // else

                // add pts for the 2 tris
                // p1, q1, p2 and p2, q1, q2

                if (flip_side_orient) {
                  triAry.setCoordinate(currCoordIndex, p1);
                  triAry.setNormal(currCoordIndex, p1Normal);
                  currCoordIndex++;

                  triAry.setCoordinate(currCoordIndex, q1);
                  triAry.setNormal(currCoordIndex, q1Normal);
                  currCoordIndex++;

                  triAry.setCoordinate(currCoordIndex, p2);
                  triAry.setNormal(currCoordIndex, p2Normal);
                  currCoordIndex++;

                  triAry.setCoordinate(currCoordIndex, p2);
                  triAry.setNormal(currCoordIndex, p2Normal);
                  currCoordIndex++;

                  triAry.setCoordinate(currCoordIndex, q1);
                  triAry.setNormal(currCoordIndex, q1Normal);
                  currCoordIndex++;
                } else {
                  triAry.setCoordinate(currCoordIndex, q1);
                  triAry.setNormal(currCoordIndex, q1Normal);
                  currCoordIndex++;

                  triAry.setCoordinate(currCoordIndex, p1);
                  triAry.setNormal(currCoordIndex, p1Normal);
                  currCoordIndex++;

                  triAry.setCoordinate(currCoordIndex, p2);
                  triAry.setNormal(currCoordIndex, p2Normal);
                  currCoordIndex++;

                  triAry.setCoordinate(currCoordIndex, q1);
                  triAry.setNormal(currCoordIndex, q1Normal);
                  currCoordIndex++;

                  triAry.setCoordinate(currCoordIndex, p2);
                  triAry.setNormal(currCoordIndex, p2Normal);
                  currCoordIndex++;
                }
                triAry.setCoordinate(currCoordIndex, q2);
                triAry.setNormal(currCoordIndex, q2Normal);
                currCoordIndex++;
                pn1.x = n1.x;
                pn1.y = n1.y;
                pn1.z = n1.z;
                pn2.x = n2.x;
                pn2.y = n2.y;
                pn2.z = n2.z;
                p1.x = p2.x;
                p1.y = p2.y;
                p1.z = p2.z;
                q1.x = q2.x;
                q1.y = q2.y;
                q1.z = q2.z;
              } // for k

              // set the previous normals to null when we are done
              pn1 = null;
              pn2 = null;
            } // for j
          } // for i
        } else { // if shape
          int m, offset = 0;
          Point3f P2 = new Point3f(), Q2 = new Point3f(), P1 = new Point3f();
          Vector3f nn = new Vector3f(),
              nn1 = new Vector3f(),
              nn2 = new Vector3f(),
              nn3 = new Vector3f();
          Vector3f nna = new Vector3f(), nnb = new Vector3f();
          float length;
          boolean validNormal = false;

          // fontExtrusion.shape is specified, and is NOT straight line
          for (i = 0; i < islandCounts.length; i++) {
            for (j = 0, k = 0, offset = num = 0; j < islandCounts[i].length; j++) {
              num += islandCounts[i][j];

              p1.x = outVerts[i][num - 1].x;
              p1.y = outVerts[i][num - 1].y;
              p1.z = 0.0f;
              q1.x = p1.x;
              q1.y = p1.y;
              q1.z = p1.z + fontExtrusion.length;
              p3.z = 0.0f;
              for (m = num - 2; m >= 0; m--) {
                p3.x = outVerts[i][m].x;
                p3.y = outVerts[i][m].y;

                if (getNormal(p3, q1, p1, nn1)) {
                  if (!flip_side_orient) {
                    nn1.negate();
                  }
                  goodNormal.set(nn1);
                  break;
                }
              }
              for (; k < num; k++) {
                p2.x = outVerts[i][k].x;
                p2.y = outVerts[i][k].y;
                p2.z = 0.0f;
                q2.x = p2.x;
                q2.y = p2.y;
                q2.z = p2.z + fontExtrusion.length;
                getNormal(p1, q1, p2, nn2);

                p3.x = outVerts[i][(k + 1) == num ? offset : (k + 1)].x;
                p3.y = outVerts[i][(k + 1) == num ? offset : (k + 1)].y;
                p3.z = 0.0f;
                if (!getNormal(p3, p2, q2, nn3)) {
                  nn3.set(goodNormal);
                } else {
                  if (!flip_side_orient) {
                    nn3.negate();
                  }
                  goodNormal.set(nn3);
                }

                // Calculate normals at the point by averaging normals
                // of two faces on each side of the point.
                nna.x = (nn1.x + nn2.x);
                nna.y = (nn1.y + nn2.y);
                nna.z = (nn1.z + nn2.z);
                normalize(nna);

                nnb.x = (nn3.x + nn2.x);
                nnb.y = (nn3.y + nn2.y);
                nnb.z = (nn3.z + nn2.z);
                normalize(nnb);

                P1.x = p1.x;
                P1.y = p1.y;
                P1.z = p1.z;
                P2.x = p2.x;
                P2.y = p2.y;
                P2.z = p2.z;
                Q2.x = q2.x;
                Q2.y = q2.y;
                Q2.z = q2.z;
                for (m = 1; m < fontExtrusion.pnts.length; m++) {
                  q1.z = q2.z = fontExtrusion.pnts[m].x;
                  q1.x = P1.x + nna.x * fontExtrusion.pnts[m].y;
                  q1.y = P1.y + nna.y * fontExtrusion.pnts[m].y;
                  q2.x = P2.x + nnb.x * fontExtrusion.pnts[m].y;
                  q2.y = P2.y + nnb.y * fontExtrusion.pnts[m].y;

                  if (!getNormal(p1, q1, p2, n1)) {
                    n1.set(goodNormal);
                  } else {
                    if (!flip_side_orient) {
                      n1.negate();
                    }
                    goodNormal.set(n1);
                  }

                  if (flip_side_orient) {
                    triAry.setCoordinate(currCoordIndex, p1);
                    triAry.setNormal(currCoordIndex, n1);
                    currCoordIndex++;

                    triAry.setCoordinate(currCoordIndex, q1);
                    triAry.setNormal(currCoordIndex, n1);
                    currCoordIndex++;
                  } else {
                    triAry.setCoordinate(currCoordIndex, q1);
                    triAry.setNormal(currCoordIndex, n1);
                    currCoordIndex++;

                    triAry.setCoordinate(currCoordIndex, p1);
                    triAry.setNormal(currCoordIndex, n1);
                    currCoordIndex++;
                  }
                  triAry.setCoordinate(currCoordIndex, p2);
                  triAry.setNormal(currCoordIndex, n1);
                  currCoordIndex++;

                  if (!getNormal(p2, q1, q2, n1)) {
                    n1.set(goodNormal);
                  } else {
                    if (!flip_side_orient) {
                      n1.negate();
                    }
                    goodNormal.set(n1);
                  }

                  if (flip_side_orient) {
                    triAry.setCoordinate(currCoordIndex, p2);
                    triAry.setNormal(currCoordIndex, n1);
                    currCoordIndex++;

                    triAry.setCoordinate(currCoordIndex, q1);
                    triAry.setNormal(currCoordIndex, n1);
                    currCoordIndex++;
                  } else {
                    triAry.setCoordinate(currCoordIndex, q1);
                    triAry.setNormal(currCoordIndex, n1);
                    currCoordIndex++;

                    triAry.setCoordinate(currCoordIndex, p2);
                    triAry.setNormal(currCoordIndex, n1);
                    currCoordIndex++;
                  }
                  triAry.setCoordinate(currCoordIndex, q2);
                  triAry.setNormal(currCoordIndex, n1);
                  currCoordIndex++;

                  p1.x = q1.x;
                  p1.y = q1.y;
                  p1.z = q1.z;
                  p2.x = q2.x;
                  p2.y = q2.y;
                  p2.z = q2.z;
                } // for m
                p1.x = P2.x;
                p1.y = P2.y;
                p1.z = P2.z;
                q1.x = Q2.x;
                q1.y = Q2.y;
                q1.z = Q2.z;
                nn1.x = nn2.x;
                nn1.y = nn2.y;
                nn1.z = nn2.z;
              } // for k
              offset = num;
            } // for j
          } // for i
        } // if shape
      } // if fontExtrusion
      geo = (GeometryArrayRetained) triAry.retained;
      geomHash.put(ch, geo);
    }

    return geo;
  }
 /** @see Graphics2D#drawGlyphVector(GlyphVector, float, float) */
 public void drawGlyphVector(GlyphVector g, float x, float y) {
   Shape s = g.getOutline(x, y);
   fill(s);
 }
Exemple #10
0
  private TessOutput tesselateString(String s) {
    GlyphVector gv = _font.createGlyphVector(_frc, s);

    Shape shape = gv.getOutline();
    //
    AffineTransform at = new AffineTransform();
    at.scale(1, -1);
    PathIterator pIt = shape.getPathIterator(at, _font.getSize() / 200.0);

    // Create a GLU tesselator
    GLUtessellator tess = GLU.gluNewTess();
    CharTesselator tessAdapt = new CharTesselator();

    GLU.gluTessCallback(tess, GLU.GLU_TESS_VERTEX, tessAdapt);
    GLU.gluTessCallback(tess, GLU.GLU_TESS_BEGIN, tessAdapt);
    GLU.gluTessCallback(tess, GLU.GLU_TESS_END, tessAdapt);
    GLU.gluTessCallback(tess, GLU.GLU_TESS_COMBINE, tessAdapt);
    GLU.gluTessCallback(tess, GLU.GLU_TESS_ERROR, tessAdapt);

    int winding = pIt.getWindingRule();

    if (winding == PathIterator.WIND_EVEN_ODD)
      GLU.gluTessProperty(tess, GLU.GLU_TESS_WINDING_RULE, GLU.GLU_TESS_WINDING_ODD);
    else if (winding == PathIterator.WIND_NON_ZERO)
      GLU.gluTessProperty(tess, GLU.GLU_TESS_WINDING_RULE, GLU.GLU_TESS_WINDING_NONZERO);
    else assert (false); // PathIterator should only return these two winding rules

    GLU.gluBeginPolygon(tess);
    GLU.gluTessNormal(tess, 0, 0, 1);
    double[] first = null;
    double[] v;
    while (!pIt.isDone()) {
      v = new double[3];
      int type = pIt.currentSegment(v);
      v[2] = 0.0;
      if (type == PathIterator.SEG_MOVETO) {
        first = v;
        GLU.gluNextContour(tess, GLU.GLU_UNKNOWN);
        GLU.gluTessVertex(tess, v, 0, v);
      } else if (type == PathIterator.SEG_LINETO) {
        GLU.gluTessVertex(tess, v, 0, v);
      } else if (type == PathIterator.SEG_CLOSE) {
        assert (first != null); // If this is true, there is an error in the AWT path iterator
        GLU.gluTessVertex(tess, first, 0, first);
        first = null;
      } else {
        assert (false); // The path itertor should not return other path types here
      }
      pIt.next();
    }
    GLU.gluEndPolygon(tess);

    int numVerts = tessAdapt.getVerts().size();
    double[] verts = new double[numVerts];
    int count = 0;
    for (double d : tessAdapt.getVerts()) {
      verts[count++] = d;
    }

    TessOutput ret = new TessOutput();
    ret.verts = verts;
    ret.bounds = gv.getVisualBounds();

    ret.advances = new double[s.length()];
    for (int i = 0; i < s.length(); ++i) {
      ret.advances[i] = gv.getGlyphMetrics(i).getAdvance();
    }
    return ret;
  }
  static void renderTextWithJavaFonts(
      GraphicsState gs,
      DynamicVectorRenderer current,
      int streamType,
      ParserOptions parserOptions,
      PdfFont currentFontData,
      GlyphData glyphData,
      final int Tmode,
      final float currentWidth,
      final boolean isTextShifted,
      final PdfJavaGlyphs glyphs,
      final float[][] Trm) {

    final float actualWidth = glyphData.getActualWidth();

    /** set values used if rendering as well */
    Object transformedGlyph2;
    AffineTransform glyphAt = null;

    final int rawInt = glyphData.getRawInt();

    //
    { // render now
      final boolean isSTD =
          actualWidth > 0
              || DecoderOptions.isRunningOnMac
              || streamType == ValueTypes.FORM
              || StandardFonts.isStandardFont(currentFontData.getBaseFontName(), false)
              || currentFontData.isBrokenFont();

      /** flush cache if needed */
      // if(!DynamicVectorRenderer.newCode2){
      if (glyphs.lastTrm[0][0] != Trm[0][0]
          || glyphs.lastTrm[1][0] != Trm[1][0]
          || glyphs.lastTrm[0][1] != Trm[0][1]
          || glyphs.lastTrm[1][1] != Trm[1][1]) {
        glyphs.lastTrm = Trm;
        glyphs.flush();
      }
      // }

      // either calculate the glyph to draw or reuse if already drawn
      Area glyph = glyphs.getCachedShape(rawInt);
      glyphAt = glyphs.getCachedTransform(rawInt);

      if (glyph == null) {

        double dY = -1, dX = 1, x3 = 0, y3 = 0;

        // allow for text running up the page
        if ((Trm[1][0] < 0 && Trm[0][1] >= 0) || (Trm[0][1] < 0 && Trm[1][0] >= 0)) {
          dX = 1f;
          dY = -1f;
        }

        if (isSTD) {

          glyph = glyphs.getGlyph(rawInt, glyphData.getDisplayValue(), currentWidth);

          // hack to fix problem with Java Arial font
          if (glyph != null && rawInt == 146 && glyphs.isArialInstalledLocally) {
            y3 = -(glyph.getBounds().height - glyph.getBounds().y);
          }
        } else {

          // remap font if needed
          String xx = glyphData.getDisplayValue();

          GlyphVector gv1 = null;

          // do not show CID fonts as Lucida unless match
          if (!glyphs.isCIDFont || glyphs.isCorrupted() || glyphs.isFontInstalled) {
            gv1 = glyphs.getUnscaledFont().createGlyphVector(PdfJavaGlyphs.frc, xx);
          }

          if (gv1 != null) {

            glyph = new Area(gv1.getOutline());

            // put glyph into display position
            double glyphX = gv1.getOutline().getBounds2D().getX();

            // ensure inside box
            x3 = 0;

            if (glyphX < 0) {
              glyphX = -glyphX;

              x3 = glyphX * 2;

              // System.out.println(x3+" "+displayTrm[0][0]+" "+displayTrm[0][0]);

              if (Trm[0][0] > Trm[0][1]) {
                x3 *= Trm[0][0];
              } else {
                x3 *= Trm[0][1];
              }

              // glyphAt =AffineTransform.getTranslateInstance(x3,0);

            }

            final double glyphWidth = gv1.getVisualBounds().getWidth() + (glyphX * 2);
            final double scaleFactor = currentWidth / glyphWidth;
            if (scaleFactor < 1) {
              dX *= scaleFactor;
            }

            if (x3 > 0) {
              x3 *= dX;
            }
          }
        }

        glyphAt =
            new AffineTransform(
                dX * Trm[0][0], dX * Trm[0][1], dY * Trm[1][0], dY * Trm[1][1], x3, y3);
        // create shape for text using transformation to make correct size
        // glyphAt =new AffineTransform(dX* displayTrm[0][0],dX* displayTrm[0][1],dY*
        // displayTrm[1][0],dY* displayTrm[1][1] ,x3, y3);

        // save so we can reuse if it occurs again in this TJ command
        glyphs.setCachedShape(rawInt, glyph, glyphAt);
      }

      if (glyph != null && Tmode == GraphicsState.CLIPTEXT && glyph.getBounds().width > 0) {
          /** support for TR7 */

        final Area glyphShape = (Area) glyph.clone();

        // we need to apply to make it all work
        glyphShape.transform(glyphAt);

        // if its already generated we just need to move it
        if (parserOptions.renderDirectly()) {
          final AffineTransform at2 = AffineTransform.getTranslateInstance(Trm[2][0], (Trm[2][1]));
          glyphShape.transform(at2);
        }

        gs.addClip(glyphShape);

        // current.drawClip(gs,null,false);

        // if(parserOptions.renderDirectly()) {
        glyph = null;
        // }

      }

      transformedGlyph2 = glyph;
    }

    if (transformedGlyph2 != null) {

      final double[] textTrans = new double[6];
      glyphAt.getMatrix(textTrans);

      final int fontSize = glyphData.getFontSize();

      if (parserOptions.useJavaFX()) {
        current.drawEmbeddedText(
            Trm,
            fontSize,
            null,
            null,
            DynamicVectorRenderer.TEXT,
            gs,
            textTrans,
            glyphData.getUnicodeValue(),
            currentFontData,
            -100);
      } else

      // add to renderer
      if (parserOptions.renderDirectly()) {
        current.drawEmbeddedText(
            Trm,
            fontSize,
            null,
            transformedGlyph2,
            DynamicVectorRenderer.TEXT,
            gs,
            textTrans,
            glyphData.getUnicodeValue(),
            currentFontData,
            -100);
      } else {

        if (isTextShifted) {
          current.drawEmbeddedText(
              Trm,
              -fontSize,
              null,
              transformedGlyph2,
              DynamicVectorRenderer.TEXT,
              gs,
              null,
              glyphData.getUnicodeValue(),
              currentFontData,
              -100);
        } else {
          current.drawEmbeddedText(
              Trm,
              fontSize,
              null,
              transformedGlyph2,
              DynamicVectorRenderer.TEXT,
              gs,
              null,
              glyphData.getUnicodeValue(),
              currentFontData,
              -100);
        }
      }
    }
  }
  @Override
  protected void createChars(final BufferedImage theCharImage, final Graphics2D theGraphics) {
    _myTesselator = new CCVectorFontTesselator();

    // six element array received from the Java2D path iterator
    float textPoints[] = new float[6];

    // array passed to createGylphVector
    char textArray[] = new char[1];

    final Graphics2D myGraphics = theGraphics;
    final FontRenderContext frc = myGraphics.getFontRenderContext();

    int index = 0;

    for (int i = 0; i < _myCharCount; i++) {
      char c = _myCharSet.chars()[i];

      if (!_myFont.canDisplay(c) || _myFontMetrics.charWidth(c) <= 0) {
        continue;
      }

      if (c < 128) {
        _myAsciiLookUpTable[c] = index;
      }

      _myCharCodes[index] = c;

      textArray[0] = c;
      final GlyphVector myGlyphVector = _myFont.createGlyphVector(frc, textArray);
      final Shape myShape = myGlyphVector.getOutline();
      final PathIterator myPathIterator = myShape.getPathIterator(null, 0.05);

      final CC3DChar my3DChar =
          new CC3DChar(c, myGlyphVector.getGlyphCode(0), charWidth(c), height(), _mySize, _myDepth);
      _myTesselator.beginPolygon(my3DChar);

      float lastX = 0;
      float lastY = 0;

      while (!myPathIterator.isDone()) {
        int type = myPathIterator.currentSegment(textPoints);
        switch (type) {
          case PathIterator.SEG_MOVETO: // 1 point (2 vars) in textPoints
            _myTesselator.beginContour();
            my3DChar.beginPath();
          case PathIterator.SEG_LINETO: // 1 point
            _myTesselator.vertex(textPoints[0], textPoints[1] + _myFontMetrics.getAscent(), 0);
            my3DChar.addOutlineVertex(textPoints[0], textPoints[1] + _myFontMetrics.getAscent());
            lastX = textPoints[0];
            lastY = textPoints[1];
            break;

          case PathIterator.SEG_QUADTO: // 2 points
            for (int j = 1; j < _myBezierDetail; j++) {
              float t = (float) j / _myBezierDetail;
              _myTesselator.vertex(
                  CCMath.bezierPoint(lastX, textPoints[0], textPoints[2], textPoints[2], t),
                  CCMath.bezierPoint(lastY, textPoints[1], textPoints[3], textPoints[3], t)
                      + _myFontMetrics.getAscent(),
                  0);
              my3DChar.addOutlineVertex(
                  CCMath.bezierPoint(lastX, textPoints[0], textPoints[2], textPoints[2], t),
                  CCMath.bezierPoint(lastY, textPoints[1], textPoints[3], textPoints[3], t)
                      + _myFontMetrics.getAscent());
            }

            lastX = textPoints[2];
            lastY = textPoints[3];
            break;

          case PathIterator.SEG_CUBICTO: // 3 points
            for (int j = 1; j < _myBezierDetail; j++) {
              float t = (float) j / _myBezierDetail;
              _myTesselator.vertex(
                  CCMath.bezierPoint(lastX, textPoints[0], textPoints[2], textPoints[4], t),
                  CCMath.bezierPoint(lastY, textPoints[1], textPoints[3], textPoints[5], t)
                      + _myFontMetrics.getAscent(),
                  0);
              my3DChar.addOutlineVertex(
                  CCMath.bezierPoint(lastX, textPoints[0], textPoints[2], textPoints[4], t),
                  CCMath.bezierPoint(lastY, textPoints[1], textPoints[3], textPoints[5], t)
                      + _myFontMetrics.getAscent());
            }

            lastX = textPoints[4];
            lastY = textPoints[5];
            break;

          case PathIterator.SEG_CLOSE:
            _myTesselator.endContour();
            my3DChar.endPath();
            break;
        }

        myPathIterator.next();
      }
      _myTesselator.endPolygon();
      _myChars[index] = my3DChar;

      index++;
    }
  }