Getting a PShape from an emoji...?

The following version of the getShape() function will run in Processing with the default window without using java components. It’s important to use the P2D renderer to get the desired output. A few additions to the original function were made to get the vectors and translate the points into the window.

import java.awt.Font;
import java.awt.Shape;
import java.awt.Toolkit;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.awt.geom.PathIterator;

PShape myShape;
PFont processingFont;

// Array added to temporarily hold coordinates
double[] coords = new double[2];

public PShape getShape(char ch, float detail) {
  Font font = (Font) processingFont.getNative();
  if (font == null) {
    throw new IllegalArgumentException("getShape() only works on fonts loaded with createFont()");
  }

  // PShape s = new PShape(PShape.PATH);
  // This was added
  PShape s = createShape();
  // six element array received from the Java2D path iterator
  float[] iterPoints = new float[6];
  // array passed to createGlyphVector
  char[] textArray = new char[] { ch };

  //Graphics2D graphics = (Graphics2D) this.getGraphics();
  //FontRenderContext frc = graphics.getFontRenderContext();
  @SuppressWarnings("deprecation")
    FontRenderContext frc =
    Toolkit.getDefaultToolkit().getFontMetrics(font).getFontRenderContext();
  GlyphVector gv = font.createGlyphVector(frc, textArray);
  Shape shp = gv.getOutline();
  // make everything into moveto and lineto
  PathIterator iter = (detail == 0) ?
    shp.getPathIterator(null) :  // maintain curves
    shp.getPathIterator(null, detail);  // convert to line segments

// This was added to translate path down into window
  AffineTransform translate = new AffineTransform();
  translate.setToTranslation(250, 150);
  PathIterator path = shp.getPathIterator(translate, 0.5);
  while (!path.isDone()) {
    path.currentSegment(coords);
    circle((int)coords[0], (int)coords[1], 4);
    path.next();
  }

  int contours = 0;
  while (!iter.isDone()) {
    int type = iter.currentSegment(iterPoints);
    switch (type) {
    case PathIterator.SEG_MOVETO:   // 1 point (2 vars) in textPoints
      if (contours == 0) {
        s.beginShape();
      } else {
        s.beginContour();
      }
      contours++;
      s.vertex(iterPoints[0], iterPoints[1]);
      break;

    case PathIterator.SEG_LINETO:   // 1 point
      s.vertex(iterPoints[0], iterPoints[1]);
      break;

    case PathIterator.SEG_QUADTO:   // 2 points
      s.quadraticVertex(iterPoints[0], iterPoints[1],
        iterPoints[2], iterPoints[3]);
      break;

    case PathIterator.SEG_CUBICTO:  // 3 points
      s.bezierVertex(iterPoints[0], iterPoints[1],
        iterPoints[2], iterPoints[3],
        iterPoints[4], iterPoints[5]);
      break;

    case PathIterator.SEG_CLOSE:
      if (contours > 1) {
        s.endContour();
      }
      break;
    }
    iter.next();
  }
  s.endShape(CLOSE);
  return s;
}

void setup() {
  size(400, 400, P2D);  // Note use of P2D renderer; IMPORTANT!
  processingFont = createFont("Webdings", 106);  // Should work for other fonts, esp Wingdings
  fill(12, 135, 155);  // teal; use whatever color you want
  //range 33 - 255  use char(int) or char('a..z' or 'A..Z' or '!@#$') keys from keyboard
  myShape = getShape(char('!'), 0.5);
  println(myShape);
}

void draw() {
  scale(2.0);
  shape(myShape, 50, 150);
}

1 Like