public Shape getShape(Graphics2D graphics, Expression symbolUrl, Feature feature) throws Exception { String markUrl = symbolUrl.evaluate(feature, String.class); // if it does not start with the right prefix, it's not our business if (!markUrl.startsWith("ttf://")) return null; // if it does not match the expected format, complain before exiting if (!markUrl.matches("ttf://.+#.+")) { throw new IllegalArgumentException( "Mark URL font found, but does not match the required " + "structure font://<fontName>#<charNumber>, e.g., ttf://wingdigs#0x7B. You specified " + markUrl); } String[] fontElements = markUrl.substring(6).split("#"); // get the symbol number String code = fontElements[1]; char character; try { // see if a unicode escape sequence has been used if (code.startsWith("U+") || code.startsWith("\\u")) code = "0x" + code.substring(2); // this will handle most numeric formats like decimal, hex and octal character = (char) Integer.decode(code).intValue(); } catch (NumberFormatException e) { throw new IllegalArgumentException( "Invalid character specification " + fontElements[1], e); } // look up the font String fontFamilyName = fontElements[0]; return getShape(fontFamilyName, character); }
@Override protected void setUp() throws Exception { ttf = new TTFMarkFactory(); ff = CommonFactoryFinder.getFilterFactory(null); }
public void testCreateDynamicMark() throws Exception { PointSymbolizer symb = sf.createPointSymbolizer(); Mark myMark = sf.createMark(); final String ttfUrl = "ttf://Serif#${symb}"; myMark.setWellKnownName(ff.literal(ttfUrl)); symb.getGraphic().addMark(myMark); MarkStyle2D ms = (MarkStyle2D) sld.createStyle(feature, symb, range); assertNotNull(ms.getShape()); // make sure the style has been recognized as dynamic SymbolizerKey key = new SymbolizerKey(symb, range); assertTrue(sld.dynamicSymbolizers.containsKey(key)); Shape expected = new TTFMarkFactory().getShape(null, ff.literal("ttf://Serif#0xF054"), feature); // no general path equality implemented, we have to check manually PathIterator piExpected = expected.getPathIterator(new AffineTransform()); PathIterator pi = ms.getShape().getPathIterator(new AffineTransform()); double[] coordsExpected = new double[6]; double[] coords = new double[6]; assertEquals(piExpected.getWindingRule(), pi.getWindingRule()); while (!piExpected.isDone()) { assertFalse(pi.isDone()); piExpected.currentSegment(coordsExpected); pi.currentSegment(coords); assertEquals(coordsExpected[0], coords[0], 0.00001); assertEquals(coordsExpected[1], coords[1], 0.00001); piExpected.next(); pi.next(); } assertTrue(pi.isDone()); }
/** * Returns a shape from an external mark definition * * @param mark * @return */ public Shape getShape(ExternalMark mark) { if (!"ttf".equals(mark.getFormat())) { return null; } String link = mark.getOnlineResource().getLinkage().toString(); // if it does not start with the right prefix, it's not our business if (!link.startsWith("ttf://")) return null; String family; try { family = URLDecoder.decode(link.substring(6), "UTF-8"); } catch (UnsupportedEncodingException e) { // UTF-8 not supported?? throw new RuntimeException(e); } int markIdx = mark.getMarkIndex(); char character = (char) markIdx; return getShape(family, character); }
/** * Checks valid paths * * @throws Exception */ public void testValidPathSimpleNumber() throws Exception { Shape shape = ttf.getShape(null, ff.literal("ttf://Serif#56"), null); assertNotNull(shape); assertTrue(shape.getBounds2D().getWidth() <= 1); assertTrue(shape.getBounds2D().getHeight() <= 1); }
/** * Checks valid paths * * @throws Exception */ public void testValidPathUnicode() throws Exception { Shape shape = ttf.getShape(null, ff.literal("ttf://Serif#U+0041"), null); assertNotNull(shape); assertTrue(shape.getBounds2D().getWidth() <= 1); assertTrue(shape.getBounds2D().getHeight() <= 1); }
/** * Checks valid paths * * @throws Exception */ public void testValidPathHex() throws Exception { Shape shape = ttf.getShape(null, ff.literal("ttf://Serif#0xF054"), null); assertNotNull(shape); assertTrue(shape.getBounds2D().getWidth() <= 1); assertTrue(shape.getBounds2D().getHeight() <= 1); }
/** * Checks valid paths * * @throws Exception */ public void testLocalFont() throws Exception { String fontPath = TestData.getResource(StreamingRenderer.class, "recreate.ttf").toURI().toString(); Shape shape = ttf.getShape(null, ff.literal("ttf://" + fontPath + "#U+0021"), null); assertNotNull(shape); assertTrue(shape.getBounds2D().getWidth() <= 1); assertTrue(shape.getBounds2D().getHeight() <= 1); } }
Shape shape = TTFMarkFactory.INSTANCE.getShape(mark.getExternalMark()); if (shape != null) { return shape;
/** * Checks various malformed ttf paths, some that should be ignored, some that we should complain * about * * @throws Exception */ public void testInvalidPaths() throws Exception { assertNull(ttf.getShape(null, ff.literal("font://invalid"), null)); try { ttf.getShape(null, ff.literal("ttf://invalid"), null); fail("Should have throw an exception, invalid path"); } catch (IllegalArgumentException e) { } try { ttf.getShape(null, ff.literal("ttf://missingFont#56"), null); fail("Should have throw an exception, invalid font"); } catch (IllegalArgumentException e) { assertTrue(e.getMessage().contains("missingFont")); } try { ttf.getShape(null, ff.literal("ttf://Serif#blah"), null); fail("Should have throw an exception, invalid char number"); } catch (IllegalArgumentException e) { assertTrue(e.getMessage().contains("blah")); } }