FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Support of embedded images in SVGs, linked images are supported but s… · classicist/processing@0eb5ba5 · GitHub

Repository navigation

Commit 0eb5ba5

Browse files
Jeremy Laviole
committed
Support of embedded images in SVGs, linked images are supported but should not be avoided if possible.
Support of Text in SVGs (partial). Multiline text are also displayed. Text limitations : Inline styles are not supported. Not all fonts are supported (depending on your OS). Tested only on Inkscape SVGs.
1 parent f775d44 commit 0eb5ba5

2 files changed

Lines changed: 291 additions & 19 deletions

File tree

‎core/src/processing/core/PShape.java‎

Lines changed: 94 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,23 @@
2222

2323
package processing.core;
2424

25+
import java.awt.Image;
26+
import java.awt.color.ColorSpace;
27+
import java.awt.image.BufferedImage;
28+
import java.io.IOException;
29+
import java.nio.charset.Charset;
30+
import java.nio.file.Files;
31+
import java.nio.file.Paths;
2532
import java.util.HashMap;
2633
import java.util.Map;
34+
import java.util.Base64.Decoder;
35+
import java.util.logging.Level;
36+
import java.util.logging.Logger;
37+
import java.nio.charset.StandardCharsets;
38+
import javax.swing.ImageIcon;
39+
import javax.xml.bind.DatatypeConverter;
40+
41+
2742

2843
import processing.core.PApplet;
2944

@@ -106,6 +121,7 @@ public class PShape implements PConstants {
106121

107122
/** Texture or image data associated with this shape. */
108123
protected PImage image;
124+
protected String imagePath = null;
109125

110126
public static final String OUTSIDE_BEGIN_END_ERROR =
111127
"%1$s can only be called between beginShape() and endShape()";
@@ -1645,6 +1661,10 @@ protected void drawPrimitive(PGraphics g) {
16451661
params[6], params[7]);
16461662

16471663
} else if (kind == RECT) {
1664+
1665+
if (imagePath != null){
1666+
loadImage(g);
1667+
}
16481668
if (image != null) {
16491669
int oldMode = g.imageMode;
16501670
g.imageMode(CORNER);
@@ -1879,6 +1899,63 @@ protected void drawPath(PGraphics g) {
18791899
g.endShape(close ? CLOSE : OPEN);
18801900
}
18811901

1902+
private void loadImage(PGraphics g){
1903+
1904+
if(this.imagePath.startsWith("data:image")){
1905+
loadBase64Image();
1906+
}
1907+
1908+
if(this.imagePath.startsWith("file://")){
1909+
loadFileSystemImage(g);
1910+
}
1911+
this.imagePath = null;
1912+
}
1913+
1914+
private void loadFileSystemImage(PGraphics g){
1915+
imagePath = imagePath.substring(7);
1916+
PImage loadedImage = g.parent.loadImage(imagePath);
1917+
if(loadedImage == null){
1918+
System.err.println("Error loading image file: " + imagePath);
1919+
}else{
1920+
setTexture(loadedImage);
1921+
}
1922+
}
1923+
1924+
private void loadBase64Image(){
1925+
String[] parts = this.imagePath.split(";base64,");
1926+
String extension = parts[0].substring(11);
1927+
String encodedData = parts[1];
1928+
1929+
byte[] decodedBytes = DatatypeConverter.parseBase64Binary(encodedData);
1930+
1931+
if(decodedBytes == null){
1932+
System.err.println("Decode Error on image: " + imagePath.substring(0, 20));
1933+
return;
1934+
}
1935+
1936+
Image awtImage = new ImageIcon(decodedBytes).getImage();
1937+
1938+
if (awtImage instanceof BufferedImage) {
1939+
BufferedImage buffImage = (BufferedImage) awtImage;
1940+
int space = buffImage.getColorModel().getColorSpace().getType();
1941+
if (space == ColorSpace.TYPE_CMYK) {
1942+
return;
1943+
}
1944+
}
1945+
1946+
PImage loadedImage = new PImage(awtImage);
1947+
if (loadedImage.width == -1) {
1948+
// error...
1949+
}
1950+
1951+
// if it's a .gif image, test to see if it has transparency
1952+
if (extension.equals("gif") || extension.equals("png") ||
1953+
extension.equals("unknown")) {
1954+
loadedImage.checkAlpha();
1955+
}
1956+
1957+
setTexture(loadedImage);
1958+
}
18821959

18831960
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
18841961

@@ -2387,14 +2464,14 @@ public void setFill(boolean fill) {
23872464
/**
23882465
* ( begin auto-generated from PShape_setFill.xml )
23892466
*
2390-
* The <b>setFill()</b> method defines the fill color of a <b>PShape</b>.
2391-
* This method is used after shapes are created or when a shape is defined explicitly
2392-
* (e.g. <b>createShape(RECT, 20, 20, 80, 80)</b>) as shown in the above example.
2393-
* When a shape is created with <b>beginShape()</b> and <b>endShape()</b>, its
2394-
* attributes may be changed with <b>fill()</b> and <b>stroke()</b> within
2395-
* <b>beginShape()</b> and <b>endShape()</b>. However, after the shape is
2396-
* created, only the <b>setFill()</b> method can define a new fill value for
2397-
* the <b>PShape</b>.
2467+
* The <b>setFill()</b> method defines the fill color of a <b>PShape</b>.
2468+
* This method is used after shapes are created or when a shape is defined explicitly
2469+
* (e.g. <b>createShape(RECT, 20, 20, 80, 80)</b>) as shown in the above example.
2470+
* When a shape is created with <b>beginShape()</b> and <b>endShape()</b>, its
2471+
* attributes may be changed with <b>fill()</b> and <b>stroke()</b> within
2472+
* <b>beginShape()</b> and <b>endShape()</b>. However, after the shape is
2473+
* created, only the <b>setFill()</b> method can define a new fill value for
2474+
* the <b>PShape</b>.
23982475
*
23992476
* ( end auto-generated )
24002477
*
@@ -2543,14 +2620,14 @@ public void setStroke(boolean stroke) {
25432620
/**
25442621
* ( begin auto-generated from PShape_setStroke.xml )
25452622
*
2546-
* The <b>setStroke()</b> method defines the outline color of a <b>PShape</b>.
2547-
* This method is used after shapes are created or when a shape is defined
2548-
* explicitly (e.g. <b>createShape(RECT, 20, 20, 80, 80)</b>) as shown in
2549-
* the above example. When a shape is created with <b>beginShape()</b> and
2550-
* <b>endShape()</b>, its attributes may be changed with <b>fill()</b> and
2551-
* <b>stroke()</b> within <b>beginShape()</b> and <b>endShape()</b>.
2552-
* However, after the shape is created, only the <b>setStroke()</b> method
2553-
* can define a new stroke value for the <b>PShape</b>.
2623+
* The <b>setStroke()</b> method defines the outline color of a <b>PShape</b>.
2624+
* This method is used after shapes are created or when a shape is defined
2625+
* explicitly (e.g. <b>createShape(RECT, 20, 20, 80, 80)</b>) as shown in
2626+
* the above example. When a shape is created with <b>beginShape()</b> and
2627+
* <b>endShape()</b>, its attributes may be changed with <b>fill()</b> and
2628+
* <b>stroke()</b> within <b>beginShape()</b> and <b>endShape()</b>.
2629+
* However, after the shape is created, only the <b>setStroke()</b> method
2630+
* can define a new stroke value for the <b>PShape</b>.
25542631
*
25552632
* ( end auto-generated )
25562633
*
@@ -3442,4 +3519,4 @@ protected void colorCalcARGB(int argb, float alpha) {
34423519
calcAlpha = (calcAi != 255);
34433520
}
34443521

3445-
}
3522+
}

‎core/src/processing/core/PShapeSVG.java‎

Lines changed: 197 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424

2525
package processing.core;
2626

27+
import static java.awt.Font.BOLD;
28+
import static java.awt.Font.ITALIC;
29+
import static java.awt.Font.PLAIN;
2730
import processing.data.*;
2831

2932
// TODO replace these with PMatrix2D
@@ -329,6 +332,10 @@ protected PShape parseChild(XML elem) {
329332
} else if (name.equals("rect")) {
330333
shape = createShape(this, elem, true);
331334
shape.parseRect();
335+
336+
} else if (name.equals("image")) {
337+
shape = createShape(this, elem, true);
338+
shape.parseImage();
332339

333340
} else if (name.equals("polygon")) {
334341
shape = createShape(this, elem, true);
@@ -358,8 +365,10 @@ protected PShape parseChild(XML elem) {
358365
// return new FontGlyph(this, elem);
359366

360367
} else if (name.equals("text")) { // || name.equals("font")) {
361-
PGraphics.showWarning("Text and fonts in SVG files are " +
362-
"not currently supported, convert text to outlines instead.");
368+
return new Text(this, elem);
369+
370+
} else if (name.equals("tspan")) {
371+
return new LineOfText(this, elem);
363372

364373
} else if (name.equals("filter")) {
365374
PGraphics.showWarning("Filters are not supported.");
@@ -439,8 +448,23 @@ protected void parseRect() {
439448
getFloatWithUnit(element, "height", svgHeight)
440449
};
441450
}
451+
452+
453+
protected void parseImage() {
454+
kind = RECT;
455+
textureMode = NORMAL;
442456

457+
family = PRIMITIVE;
458+
params = new float[] {
459+
getFloatWithUnit(element, "x", svgWidth),
460+
getFloatWithUnit(element, "y", svgHeight),
461+
getFloatWithUnit(element, "width", svgWidth),
462+
getFloatWithUnit(element, "height", svgHeight)
463+
};
443464

465+
this.imagePath = element.getString("xlink:href");
466+
}
467+
444468
/**
445469
* Parse a polyline or polygon from an SVG file.
446470
* Syntax defined at http://www.w3.org/TR/SVG/shapes.html#PointsBNF
@@ -1557,8 +1581,179 @@ public RadialGradient(PShapeSVG parent, XML properties) {
15571581

15581582

15591583
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1584+
1585+
public static float TEXT_QUALITY = 1;
1586+
protected PFont parseFont(XML properties) {
1587+
1588+
// FontFace fontFace = new FontFace(this, properties);
1589+
String fontFamily = null;
1590+
float size = 10;
1591+
int weight = PLAIN; // 0
1592+
int italic = 0;
1593+
1594+
if (properties.hasAttribute("style")) {
1595+
String styleText = properties.getString("style");
1596+
String[] styleTokens = PApplet.splitTokens(styleText, ";");
1597+
1598+
//PApplet.println(styleTokens);
1599+
for (int i = 0; i < styleTokens.length; i++) {
1600+
1601+
String[] tokens = PApplet.splitTokens(styleTokens[i], ":");
1602+
//PApplet.println(tokens);
1603+
1604+
tokens[0] = PApplet.trim(tokens[0]);
1605+
1606+
if (tokens[0].equals("font-style")) {
1607+
// PApplet.println("font-style: " + tokens[1]);
1608+
if (tokens[1].contains("italic")) {
1609+
italic = ITALIC;
1610+
}
1611+
} else if (tokens[0].equals("font-variant")) {
1612+
// PApplet.println("font-variant: " + tokens[1]);
1613+
// setFillOpacity(tokens[1]);
1614+
1615+
} else if (tokens[0].equals("font-weight")) {
1616+
// PApplet.println("font-weight: " + tokens[1]);
1617+
1618+
if (tokens[1].contains("bold")) {
1619+
weight = BOLD;
1620+
// PApplet.println("Bold weight ! ");
1621+
}
1622+
1623+
1624+
} else if (tokens[0].equals("font-stretch")) {
1625+
// not supported.
1626+
1627+
} else if (tokens[0].equals("font-size")) {
1628+
// PApplet.println("font-size: " + tokens[1]);
1629+
size = Float.parseFloat(tokens[1].split("px")[0]);
1630+
// PApplet.println("font-size-parsed: " + size);
1631+
} else if (tokens[0].equals("line-height")) {
1632+
// not supported
1633+
1634+
} else if (tokens[0].equals("font-family")) {
1635+
// PApplet.println("Font-family: " + tokens[1]);
1636+
fontFamily = tokens[1];
1637+
1638+
} else if (tokens[0].equals("text-align")) {
1639+
// not supported
1640+
1641+
} else if (tokens[0].equals("letter-spacing")) {
1642+
// not supported
1643+
1644+
} else if (tokens[0].equals("word-spacing")) {
1645+
// not supported
1646+
1647+
} else if (tokens[0].equals("writing-mode")) {
1648+
// not supported
1649+
1650+
} else if (tokens[0].equals("text-anchor")) {
1651+
// not supported
1652+
1653+
} else {
1654+
// Other attributes are not yet implemented
1655+
}
1656+
}
1657+
}
1658+
if (fontFamily == null) {
1659+
return null;
1660+
}
1661+
size = size * TEXT_QUALITY;
1662+
1663+
return createFont(fontFamily, weight | italic, size, true);
1664+
}
1665+
1666+
protected PFont createFont(String name, int weight, float size, boolean smooth) {
1667+
1668+
// System.out.println("Try to create a font of " + name + " family, " + weight);
1669+
java.awt.Font baseFont = new java.awt.Font(name, weight, (int) size); // PFont.findFont(name);ç
1670+
1671+
// System.out.println("Resulting family : " + baseFont.getFamily() + " " + baseFont.getStyle());
1672+
PFont outputPFont = new PFont(baseFont.deriveFont(size), smooth, null);
1673+
1674+
// System.out.println("Resulting PFont family : " + outputPFont.getName());
1675+
return outputPFont;
1676+
}
1677+
1678+
public static class Text extends PShapeSVG {
1679+
1680+
protected PFont font;
1681+
1682+
public Text(PShapeSVG parent, XML properties) {
1683+
super(parent, properties, true);
1684+
1685+
// get location
1686+
float x = Float.parseFloat(properties.getString("x"));
1687+
float y = Float.parseFloat(properties.getString("y"));
1688+
1689+
if (matrix == null) {
1690+
matrix = new PMatrix2D();
1691+
}
1692+
matrix.translate(x, y);
1693+
1694+
family = GROUP;
1695+
1696+
font = parseFont(properties);
15601697

1698+
}
1699+
1700+
// @Override
1701+
// public void drawImpl(PGraphics g){
1702+
// }
1703+
}
1704+
1705+
public static class LineOfText extends PShapeSVG {
15611706

1707+
String textToDisplay;
1708+
PFont font;
1709+
1710+
public LineOfText(PShapeSVG parent, XML properties) {
1711+
1712+
// TODO: child should ideally be parsed too...
1713+
// for inline content.
1714+
super(parent, properties, false);
1715+
1716+
// // get location
1717+
float x = Float.parseFloat(properties.getString("x"));
1718+
float y = Float.parseFloat(properties.getString("y"));
1719+
1720+
float parentX = Float.parseFloat(parent.element.getString("x"));
1721+
float parentY = Float.parseFloat(parent.element.getString("y"));
1722+
1723+
if (matrix == null) matrix = new PMatrix2D();
1724+
matrix.translate(x - parentX, (y - parentY) / 2f);
1725+
1726+
// get the first properties
1727+
parseColors(properties);
1728+
font = parseFont(properties);
1729+
1730+
// It is a line..
1731+
boolean isALine = properties.getString("role") == "line";
1732+
// NO inline content yet.
1733+
if (this.childCount > 0) {
1734+
}
1735+
1736+
String text = properties.getContent();
1737+
textToDisplay = text;
1738+
}
1739+
1740+
@Override
1741+
public void drawImpl(PGraphics g) {
1742+
if (font == null) {
1743+
font = ((Text) parent).font;
1744+
if (font == null) {
1745+
return;
1746+
}
1747+
}
1748+
1749+
pre(g);
1750+
g.textFont(font, font.size / TEXT_QUALITY);
1751+
g.text(textToDisplay, 0, 0);
1752+
post(g);
1753+
}
1754+
1755+
}
1756+
15621757
public static class Font extends PShapeSVG {
15631758
public FontFace face;
15641759

0 commit comments

Comments
 (0)

Back | FazBrowse Home | New Git URL