Giter Club home page Giter Club logo

svgsalamander's Introduction

SVG Salamander

SVG Salamander is an SVG engine for Java that's designed to be small, fast, and allow programmers to use it with a minimum of fuss. It's in particular targeted for making it easy to integrate SVG into Java games and making it much easier for artists to design 2D game content - from rich interactive menus to charts and graphics to complex animations.

Features

  • Ant task to allow easy conversion from SVG to images from within Ant scripts
  • SVGIcon class greatly simplifies loading and drawing images to screen
  • A much smaller code foot print than Batik, and only one JAR file to include
  • Direct access to the scene graph tree. You can use Java commands to manipulate it directly.
  • An index of all named shapes in the SVG graph is easily accessible.
  • Picking shapes given (x, y) coordinates is possible, and can be used to implement graphical buttons selected by the mouse
  • Clip region sensitivity makes for fast rendering when only updating part of the image. This makes panning the camera quite efficient.
  • Easy rendering to any Graphics2D or BufferedImage. Unlike Batik, the SVG Salamander engine does not own the graphics context, so you can pass it whatever graphics context you like.
  • Internal and external links are implemented as URIs, which allows the engine to automatically import linked documents - even if they're stored on a remote server.
  • SVG can be read from an InputStream, so you can create documents dynamically from an in-program XSLT transformation.

Documentation

An overview of how to use SVG Salamader in your project.

Current status

SVG Salamander is part of the Salamander project hosted on http://www.kitfox.com

Projects using SVG Salamander

  • Apache Pivot - An alternate crossplatform GUI for Java.
  • VisiCut - A tool for laser precision cutting.
  • Xoetrope - An alternate crossplatform GUI for Java.
  • Power Line - A slide editor for SVG.
  • Tygron - Serious games illustrating urban planning and climate change.
  • NeoLogica - Medical imaging.
  • JOSM - Java OpenStreetMap Editor.
  • Freeplane - Java program for working with Mind Maps

License

SVG Salamander is available under two licenses. You may choose to use either the LGPL license or the BSD license - whichever is more appropriate for your project.

svgsalamander's People

Contributors

arlith avatar basix86 avatar blackears avatar dependabot[bot] avatar don-vip avatar dpolivaev avatar fnatter avatar fra-orolo avatar jformdesigner avatar jimmymic avatar matthiasblaesing avatar maxwalls avatar mkuehne-git avatar nidi3 avatar philippecade avatar simon04 avatar tsmock avatar weisj avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

svgsalamander's Issues

Use Java 8 as minimum requirement?

Currently svgSalamander is compiled for Java 6. See:

<maven.compiler.source>1.6</maven.compiler.source>
<maven.compiler.target>1.6</maven.compiler.target>

But it already uses Java 8 API java.util.List.sort(Comparator) in class Gradient. See:

stopList.sort(new Comparator<Stop>(){

So svgSalamander maybe runs on Java 6 but probably fails as soon as gradients are used?

Would it be OK to change the minimum required Java version to 8
and benefit from "new" features like lambdas, try-with-resources, etc.?

If yes, I could create a PR.

Java 6 reached "end of public updates" in 2013.

Wrong text align

If you set the X/Y coordinates dynamically, the rendered images still have the old (initial) values from the SVG and not the set ones

use the SVG for example:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg"
     id="video_format"
     width="160"
     height="97"
     viewBox="-12 -5 164 97"
     version="1.1">

    <text id="text"
          y="39"
          style="font-size: 42px;
                 text-anchor: middle;
                 font-weight: bold;
                 font-style: italic;
                 display:inline;
                 stroke-width:2.85;"/>
</svg>

If you dynamically set the text (and coordinates), the text is always centered at 0/39:

protected void setText(String text, int x) {
  SVGDiagram diagram = getSvgUniverse().getDiagram(getSvgURI());
  Text textElement = (Text) diagram.getElement("text");
  if (textElement != null) {
    textElement.addAttribute("x", AnimationElement.AT_XML, String.valueOf(x));
    textElement.appendText(text);
    setFill(getHexString(UIManager.getColor("Label.foreground")), diagram.getRoot());
    textElement.rebuild();
  }
}

I've spotted the issue at https://github.com/blackears/svgSalamander/blob/master/svg-core/src/main/java/com/kitfox/svg/Text.java#L133 where you get the initial X value (from SVG) and afterwards read the values from the attributes, but the method alignSegmentsAtAnchor is called with the initial X value (0 in out case)

mouse click listener on SVGElement?

Hi,

We have been using SVG Salamander for a while and it works great, thanks a lot!
However, I have been requested to upgrade our SVG Panel to respond to mouse click on some elements.
Would that be possible with SVG Salamander?

This is probably not the proper channel to be asking this kind of support, sorry about that.. if there is such a channel, could you please redirect me?

SVG to Image Using SVGSalamander not rendering SVG correctly

I have worked for SVG image rendering for iText PDF document. to do this i used SVGSalamander for convert SVG to image format. it works fine but it has a strange behavior that some of the SVG images are not rendering correctly while some are doing. those wrongly rendered svg are not aligned with the real image. I tried but i couldn't figure out why its happening only for some images.

Really appreciate if someone help me to resolve this.

Java Code:


private static Image createSVGImage(PdfWriter pdfWriter, String imageEntry) throws BadElementException {
        Image image = null;

        Graphics2D g2dgraphics =null;
        PdfTemplate template = null;
        try{
            SVGDiagram diagram = SVGCache.getSVGUniverse().getDiagram( new java.io.File( imageEntry ).toURI() );
            template = pdfWriter.getDirectContent().createTemplate( diagram.getWidth(), diagram.getHeight());
            diagram.setIgnoringClipHeuristic(true);
             g2dgraphics= new PdfGraphics2D(template, diagram.getWidth(), diagram.getHeight());
        diagram.render(g2dgraphics);
    }catch( Exception e ){
        e.printStackTrace();
    } finally {
        if( g2dgraphics != null ){
            g2dgraphics.dispose();
          image = Image.getInstance(template);

        }
        g2dgraphics.dispose();
    }

    return image;
}

SVG xml code that its not align

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
  <path d="M19,16a46,46 0,1,0 62,0l-8,8a34,34 0,1,1-46,0z" fill="#069"/>
  <path d="M46,43v35a28,28 0,0,1-14-49zM54,43v35a28,28 0,0,0 14-49z" fill="#396"/>
  <circle r="15" cx="50" cy="18" fill="#900"/>
</svg>

more details are available in question in stackoverflow ( images )
https://stackoverflow.com/questions/58373840/svg-to-image-using-svgsalamander-not-rendering-svg-correctly

Embedded SVG fonts don't seem to register correctly

Font.loaderEndElement calls Universe.registerFont. Universe keeps a map of font face names that map to Font instances. However, at the time Font.loader.EndElement is called, FontFace.build has not been called, which means that FontFace.fontFamily will be null. This means that any <font> tags in the SVG will get registered in the Universe with a key value of null.

As far as I can tell, this makes it so no <font> tags will ever get used properly.

Maven Update

Can you please upload the latest release 1.1.1 to Maven?

NPE at Tspan.appendToShape for generic font "sans-serif"

Environment:

  • svgSalamander version: 1.1.2
  • Java version: 8u181
  • OS: Windows 10
  • Locale: French

The fix for #13 introduced a regression, we face this exception for the 7 attached files:
svg_bug.zip

java.lang.NullPointerException
	at com.kitfox.svg.Tspan.appendToShape(Tspan.java:269)
	at com.kitfox.svg.Text.buildText(Text.java:350)
	at com.kitfox.svg.Text.build(Text.java:264)
	at com.kitfox.svg.Text.updateTime(Text.java:598)
	at com.kitfox.svg.Group.updateTime(Group.java:313)
	at com.kitfox.svg.Group.updateTime(Group.java:313)
	at com.kitfox.svg.SVGRoot.updateTime(SVGRoot.java:403)
	at com.kitfox.svg.Group.updateTime(Group.java:313)
	at com.kitfox.svg.SVGRoot.updateTime(SVGRoot.java:403)
	at com.kitfox.svg.SVGDiagram.updateTime(SVGDiagram.java:243)
	at com.kitfox.svg.SVGUniverse.loadSVG(SVGUniverse.java:616)
	at com.kitfox.svg.SVGUniverse.loadSVG(SVGUniverse.java:468)
	at com.kitfox.svg.SVGUniverse.loadSVG(SVGUniverse.java:445)

Problem 1:
The system font "sans-serif" is not found. Indeed the Java font family name is called "SansSerif".

The W3C defines 5 generic font families:

  1. serif
  2. sans-serif
  3. cursive
  4. fantasy
  5. monospace

Java defines some of them as follows:

  1. Serif
  2. SansSerif
  3. N/A
  4. N/A
  5. Monospaced

So we should add a mapping for serif, sans-serif and monospace to actual Java names.

Problem 2:
Same crash if family name is defined with quotes, such as 'Arial Black' or 'Bookman Old Style'

Problem 3:
Same crash for unknown family names such as 'Sans' or 'Bitstream Vera Sans'

Problem 4:
The default font is wrongly spelled "Sans Serif" instead of "SansSerif" (correct java name)

NPE: "href" is null in Use

I am not sure what exactly is the cause for this problem.
But debugging shows that the "href" in the class "Use" is null.

Searching in the SVG (which I may not share) shows this:

<use
   href="#Flags"
   id="MyId"
   x="0"
   y="0"
   width="100%"
   height="100%"
   transform="translate(-284.35164,225.73852)" />

This is a file created by inkscape which seems to reference that part:

<defs
    id="defs1908">
<symbol
       id="Flags"><g [...]
java.lang.NullPointerException
	at com.kitfox.svg.SVGUniverse.getElement(SVGUniverse.java:336)
	at com.kitfox.svg.SVGUniverse.getElement(SVGUniverse.java:308)
	at com.kitfox.svg.Use.getBoundingBox(Use.java:157)
	at com.kitfox.svg.Group.calcBoundingBox(Group.java:271)
	at com.kitfox.svg.Group.getBoundingBox(Group.java:252)
	at com.kitfox.svg.Group.calcBoundingBox(Group.java:271)
	at com.kitfox.svg.Group.getBoundingBox(Group.java:252)
	at com.kitfox.svg.Group.calcBoundingBox(Group.java:271)
	at com.kitfox.svg.Group.getBoundingBox(Group.java:252)
	at com.kitfox.svg.SVGRoot.getBoundingBox(SVGRoot.java:380)
	at com.kitfox.svg.SVGRoot.prepareViewport(SVGRoot.java:180)
	at com.kitfox.svg.SVGRoot.build(SVGRoot.java:159)
	at com.kitfox.svg.SVGRoot.updateTime(SVGRoot.java:467)
	at com.kitfox.svg.SVGDiagram.updateTime(SVGDiagram.java:243)
	at com.kitfox.svg.SVGUniverse.loadSVG(SVGUniverse.java:610)
	at com.kitfox.svg.SVGUniverse.loadSVG(SVGUniverse.java:466)
	at com.kitfox.svg.SVGUniverse.getDiagram(SVGUniverse.java:401)
	at com.kitfox.svg.SVGUniverse.getDiagram(SVGUniverse.java:365)

On Windows the clip region messes up render but not Linux

I'm rendering to a JPanel and on Linux it behaves as expected but on Windows the rendering is offset to the location of the clip region. So if you do repaint() on the JPanel it works just fine but if you do repaint(50,60,200,200) it will be translated by (50,60) pixels. You also need to specify a transform as is shown in the code below. It's also intermittent.

I'm using this version on Gradle:
compile group: 'com.metsci.ext.com.kitfox.svg', name: 'svg-salamander', version: '0.1.19'

The code looks something like:

In Constructor

svg = new SVGUniverse();
uri = svg.loadSVG(classloader.getResource( "image.svg"));
diagram = svg.getDiagram(uri);

In paintComponent()

transform.setTransform(0.1,0,0, 0.1,20,10);
g2.setTransform(transform);
diagram .render(g2);

Unclear License

Hi,
Your project's Readme states "SVG Salamander is available both under the LGPL and BSD licenses." From legal perspective, it means users MUST follow both licenses - lgpl AND bsd. I'm sure you wanted to give them a choice of using either one. If that is the case, please change logical operator AND to OR.

Compliance?

Hello!

I am very interested in using svgSalamnder for https://github.com/UprootLabs/gngr.

Have you performed any tests to see how many features are covered? I did a quick search on the web. In the answers here there are some hints about running the SVG tests from W3C. The reference images were apparently generated by Batik. So it should be possible to write a script that compares the output from SVGSalamaner and Batik and gives a pass/fail report.

Intermittent Nullpointer exception

Hi. Our users sometimes report nullpointer exceptions in svgsalamander. It seems intermittent and I cannot reproduce it myself. Here's the stack trace:

java.lang.NullPointerException
at com.kitfox.svg.SVGDiagram.render(SVGDiagram.java:105)
at com.kitfox.svg.app.beans.SVGIcon.paintIcon(SVGIcon.java:280)
at com.kitfox.svg.app.beans.SVGIcon.paintIcon(SVGIcon.java:171)
at se.datadosen.component.DeferredSVGIcon.paintIcon(DeferredSVGIcon.java:84)
at com.kitfox.svg.app.beans.SVGIcon.getImage(SVGIcon.java:113)
at se.datadosen.component.JPlainButton.brighten(JPlainButton.java:157)
at se.datadosen.component.JPlainButton.setIcon(JPlainButton.java:137)
at javax.swing.AbstractButton.init(AbstractButton.java:2172)
at javax.swing.JButton.(JButton.java:137)
at javax.swing.JButton.(JButton.java:100)
at se.datadosen.component.JPlainButton.(JPlainButton.java:73)
at se.datadosen.component.JNotification.(JNotification.java:82)
at se.datadosen.jalbum.TipOfTheDay.showInBackground(TipOfTheDay.java:63)
at se.datadosen.jalbum.JPublishWizard$PublishStep.doAfterUploadAlbum(JPublishWizard.java:2077)
at se.datadosen.jalbum.JPublishWizard$PublishStep.access$1400(JPublishWizard.java:747)
at se.datadosen.jalbum.JPublishWizard$PublishStep$20.run(JPublishWizard.java:1928)

Ruby icon failed to render

Hello. I catch this problem.

Original icon from wiki (https://upload.wikimedia.org/wikipedia/commons/7/73/Ruby_logo.svg)

Render throw exception:

Caused by: com.kitfox.svg.SVGException: java.lang.IllegalArgumentException: Keyframe fractions must be increasing: 0.0
	at com.kitfox.svg.ShapeElement.renderShape(ShapeElement.java:169)

I reexport this icon in Illustrator with plain options(svg1., no css, etc). And got this exception:

(svg code https://gist.github.com/VISTALL/3ba9af463cfce543e918a82f55855691)

Exception in thread "main" java.awt.geom.IllegalPathStateException: missing initial moveto in path definition
	at java.awt.geom.Path2D$Float.needRoom(Path2D.java:323)
	at java.awt.geom.Path2D.closePath(Path2D.java:1876)
	at com.kitfox.svg.pathcmd.Terminal.appendPath(Terminal.java:65)

All icons rendered in Illustrator/Chrome correctly

Thanks

Parsing style elements

Hi,
it seems that its not possible to parse style elemenst like:
<style type="text/css"> .st0{fill:#005CA9;} </style>

will it be implemented in the near future ?

best regards.

Parsing a single transform with capitalized e notation is not working

Hello,

Would it be possible to allow parsing a single transform when using the capitalized e notation?

private static final Pattern WORD_PATTERN = Pattern.compile("([a-zA-Z]+|-?\\d+(\\.\\d+)?(e-?\\d+)?|-?\\.\\d+(e-?\\d+)?)");

With this example:

<svg xmlns="http://www.w3.org/2000/svg">  
   <g transform="matrix(2.64845E-014 -1 1 2.64845E-014 127.203 1119.35)">
    <text x="800" y="500">Hello world!</text>
   </g>
</svg>

The results are as follows:

function = "matrix"
termList = [2.64845, E, -014, -1, 1, 2.64845, E, -014, 127.203, 1119.35]

And the corresponding text is not rendered.

Thank you.

StyleAttributes resolves URI incorrectly when running on module path

Note that this happens when running on the module path due to a somewhat different code path when calling Class#getResource. The issue in particular is the following:
Assuming that we are packaged in a jar (haven't testes it for non packaged content yet but I assume the same issue occurs)

 URI base = SomeClass.class.getResource("someResource.svg").toURI();
 System.out.println(base);
// This prints: jar:file///[path to jar]![package path of SomeClass]/someResource.svg
// On the classpath it is: jar:file/[path to jar]![package path of SomeClass]/someResource.svg
// => The amount of slashes is differen.

// The following code is abridged from StyleAttribute#getURIValue(URI)
String fragment = "#fragment";

//[scheme:]scheme-specific-part[#fragment]
URI uriFrag = new URI(fragment);
if (uriFrag.isAbsolute()) { // ... Unrelevant branch }

URI relBase = new URI(null, base.getSchemeSpecificPart(), null);
System.out.println("RelBase: " + relBase);
URI relUri;
if (relBase.isOpaque()) {
   // ... Unrelevant branch
} else {
    relUri = relBase.resolve(uriFrag);
}
System.out.println("relUri " + relUri);
// Here relUri = jar:file/[path to jar]![package path of SomeClass]/someResource.svg#fragment
// Now with one slash!
return new URI(base.getScheme() + ":" + relUri)

This causes the SVGDiagram for all files to be loaded twice if the svg uses url() attributes.
Once when loading the svg i.e. SVGUniverse#load and then a second time in SVGUniverse#getElement called with
the now modified xml base from the code above.
In SVGUniverse#getElement only xmlBase.getSchemeSpecificPart() is relevant which now is different that when loading the first time.
Besides the increased memory usage this is painful in particular when modifying the xml graph at runtime. Any modifications won't be mirrored when painting as the duplicated diagram is used there.

Note that the problematic call is relBase.resolve(uriFrag), which looses the slashes in URI::resolvePath.
Actually I'm not quite certain this is the problematic line. Moreover I am somewhat unsure why the two branches in if (relbase.isQpaque()) are different. The line in the true branch does preserve the uri structure correctly.

relUri = new URI(null, base.getSchemeSpecificPart(), uriFrag.getFragment());

I'm really not experienced with the whole URI situation. Is there a scenario, where relBase can actually be opaque the way it is defined?

Y offset of nested SVG not taken into account

When loading the attached SVG file svg_bug_30.zip we face the following display error (after I fixed #29):

svg_bug

The expected display is:
expected

The SVG is defined as follows:

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="300" height="480" viewBox="0 0 300 480">
	<rect x="140" y="0" width="20" style="fill:#f5f5f5;stroke:#000000;" id="pole" height="480"/>
	<svg version="1.1" id="Nederlands_verkeersbord_C3" height="300" width="300" viewBox="0 0 300 300" y="10" preserveAspectRatio="xMidYMid meet">
		<g>
                    <!-- -->
		</g>
	</svg>
	<svg version="1.1" id="Nederlands_verkeersbord_OB54" height="150" width="300" viewBox="0 0 300 150" y="310" preserveAspectRatio="xMidYMid meet">
		<g>
                    <!-- -->
		</g>
	</svg>
</svg>

It seems the y=10 and y=310 attributes of nested svg elements are not taken into account.

SVGUniverse: 'loadedImages' may contain URL objects

IntelliJ warning:

Reports objects which are a subtype of java.util.Set or java.util.Map and which may contain java.net.URL objects. Adding java.net.URL objects to such collections can cause performance problems because of calls to the equals() and hashCode() methods of java.net.URL. java.net.URL's equals() and hashCode() method use a DNS lookup, which depending on the availability of the network and the speed of the DNS server can cause significant delays.

Fixed height, but variable width to keep aspect ratio

Dear svgSalamander maintainer,

I am a developer of the Mind Mapping solution Freeplane
(http://freeplane.org), which will use svgSalamander starting from version
1.6. Many thanks for the excellent library!

AUTOSIZE_STRETCH mostly works for Freeplane, but our artist says that not
all icons are squared, and we would like to specify a squared size using
setPreferredSize() (e.g. setPreferredSize(new Dimension(48,48))), and then
have the width above ignored and calculated so that the aspect ratio of
the SVG is preserved.

So I picked an SVG Icon that has a non-squared aspect ratio ("button_ok.svg"),
and tried with AUTOSIZE_STRETCH, AUTOSIZE_HORIZ and AUTOSIZE_VERT:
https://github.com/fnatter/svgtest/blob/master/screenshot.png

The minimal source code is at:
https://github.com/fnatter/svgtest/blob/master/src/main/java/org/freeplane/svgtest/TestAutostretch.java

I would expect that with AUTOSIZE_HORIZ, the width is taken from
setPreferredSize(), and the height is calculated to preserve the aspect
ratio, and vice versa for AUTOSIZE_VERT (or the other way around). But why
is the resulting image cropped (HORIZ) or there is extra space (VERT)?
What am I doing wrong? (please see the minimal source code above)

All files are at:
https://github.com/fnatter/svgtest

BTW: Could you add Freeplane to README.md?

  • Freeplane - Program for working with Mind Maps.

Many Thanks and Best Regards,
Felix

Font rendering issues

When using the text-anchor-attribute the text is not placed correctly when used with certain values and fonts (e.g. Arial and '1'). I found that using cursorX - x instead of textPath.getBounds().getWidth() in Line 377 and Line 384 gives much better results.

Performance problem on OpenJDK11 when generating XMLReader

Why the XMLReader reader is always generated in the SVGUniverse.java?

if we call SVGUniverse.loadSVG multiple times in an array, the block getXMLReader takes 1-2 ms in oracle jdk but 2000-3000ms on openjdk (Adopt 11.0.6.10) both on windows and linux environments (with openwebstart and with console invoke with java --)

I modified the code and generated a static common XMLReader and used that for all operations (no multithreading, provided that you do not use that instance by more than 1 threads), then it has the same performnce as oracle jdk.

new release?

It looks like it's been a couple of years since the last release of SVG Salamander. It would be nice to have a new release when possible, especially since some useful new methods were added recently (i.e. in a679f7c and d856eb2).

logic error in SVGElement.getStyle()

There is a logic error in SVGElement.getStyle() that has no impact in the current code base, where style sheets are unimplemented, but fails if style sheets are implemented. The problem is that if the code finds a style sheet, it unconditionally returns the attribute value from the style sheet, without checking to see if the attribute is undefined in the style sheet.

build problems

It has been a while since I have tried to build svgSalamander.
I do not see any instructions on how to do that, so I ran ant in the svg-core directory.
It failed here:

-do-test-run:
[junit] WARNING: multiple versions of ant detected in path for junit
[junit] jar:file:/usr/local/ant/lib/ant.jar!/org/apache/tools/ant/Project.class
[junit] and jar:file:/Volumes/L/Java/svgSalamander/repo/libraries/ant.jar!/org/apache/tools/ant/Project.class
[junit] Exception in thread "main" java.lang.NoSuchMethodError: org.apache.tools.ant.util.FileUtils.close(Ljava/io/Writer;)V
[junit] at org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.registerTestCase(JUnitTestRunner.java:1212)
[junit] at org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.main(JUnitTestRunner.java:934)
[junit] Testsuite: com.kitfox.salamander.javascript.JSTest
[junit] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0 sec
[junit]
[junit] Testcase: com.kitfox.salamander.javascript.JSTest:BeforeFirstTest: Caused an ERROR
[junit] Forked Java VM exited abnormally. Please note the time in the report does not reflect the time until the VM exit.
[junit] junit.framework.AssertionFailedError: Forked Java VM exited abnormally. Please note the time in the report does not reflect the time until the VM exit.
[junit]
[junit]
[junit] Test com.kitfox.salamander.javascript.JSTest FAILED (crashed)

Image with base64 data not rendered

Hello.

Example svg

https://raw.githubusercontent.com/JetBrains/intellij-plugins/master/protobuf/resources/META-INF/pluginIcon.svg

Actual result, exception:

java.io.FileNotFoundException: https://raw.githubusercontent.com/JetBrains/intellij-plugins/master/protobuf/resources/META-INF/null
	at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1872)
	at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1474)
	at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
	at java.net.URL.openStream(URL.java:1045)

Expected result - render image from base64.

Thanks.

memory footprint

It think it would be good to use String.intern() at those places where strings are read from *.svg files.
e.g. in XMLParseUtil.parseStyle(). Sorry, I am not familar with git, so I don't know how to create a pull request.
In the JOSM project this saves quite a lot of memory because it keeps several instances of SVGDiagram.
I've attached a small patch there:
https://josm.openstreetmap.de/attachment/ticket/17040/kitfox.patch

Can't get a proper antialiased SVG rendering

I can't get a proper antialiased rendering of our SVG logo:
https://josm.openstreetmap.de/export/15290/josm/trunk/images/logo.svg

This is what I get compared to IE rendering at a similar size:
damned

I think I use all possible rendering hints to ensure smooth rendering, so is it an issue coming from svgSalamander?

    public static BufferedImage createImageFromSvg(SVGDiagram svg, Dimension dim) {
        final float sourceWidth = svg.getWidth();
        final float sourceHeight = svg.getHeight();
        final float realWidth;
        final float realHeight;
        if (dim.width >= 0) {
            realWidth = dim.width;
            if (dim.height >= 0) {
                realHeight = dim.height;
            } else {
                realHeight = sourceHeight * realWidth / sourceWidth;
            }
        } else if (dim.height >= 0) {
            realHeight = dim.height;
            realWidth = sourceWidth * realHeight / sourceHeight;
        } else {
            realWidth = GuiSizesHelper.getSizeDpiAdjusted(sourceWidth);
            realHeight = GuiSizesHelper.getSizeDpiAdjusted(sourceHeight);
        }

        int roundedWidth = Math.round(realWidth);
        int roundedHeight = Math.round(realHeight);
        BufferedImage img = new BufferedImage(roundedWidth, roundedHeight, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = img.createGraphics();
        g.setClip(0, 0, img.getWidth(), img.getHeight());
        g.scale(realWidth / sourceWidth, realHeight / sourceHeight);
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        g.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
        g.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
        g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        try {
            synchronized (getSvgUniverse()) {
                svg.render(g);
            }
        } catch (SVGException ex) {
            Logging.log(Logging.LEVEL_ERROR, "Unable to load svg:", ex);
            return null;
        }
        return img;
    }

    private static synchronized SVGUniverse getSvgUniverse() {
        if (svgUniverse == null) {
            svgUniverse = new SVGUniverse();
            // CVE-2017-5617: Allow only data scheme (see #14319)
            svgUniverse.setImageDataInlineOnly(true);
        }
        return svgUniverse;
    }

How to avoid MalformedURLException

When creating an SVG from a stream

SVGUniverse universe = new SVGUniverse();
URI uri = universe.loadSVG(new StringReader(svg), "graph");
SVGDiagram diagram = universe.getDiagram(uri);
diagram.render(graphics);

the output is correctly created, but these warnings are emitted:

Mär 26, 2017 5:06:10 PM com.kitfox.svg.SVGUniverse getElement
WARNUNG: Could not parse path svgSalamander:/transparent
java.net.MalformedURLException: unknown protocol: svgsalamander
	at java.net.URL.<init>(URL.java:593)
	at java.net.URL.<init>(URL.java:483)
	at java.net.URL.<init>(URL.java:432)
	at java.net.URI.toURL(URI.java:1089)
	at com.kitfox.svg.SVGUniverse.getElement(SVGUniverse.java:345)
	at com.kitfox.svg.SVGUniverse.getElement(SVGUniverse.java:310)
	at com.kitfox.svg.ShapeElement.renderShape(ShapeElement.java:206)
	at com.kitfox.svg.Polygon.render(Polygon.java:105)
	at com.kitfox.svg.Group.render(Group.java:205)
	at com.kitfox.svg.Group.render(Group.java:205)
	at com.kitfox.svg.SVGRoot.renderToViewport(SVGRoot.java:329)
	at com.kitfox.svg.SVGDiagram.render(SVGDiagram.java:105)

How can this be avoided?

Improve font handling

In Text.java

        for (int i = 0; i < families.length; ++i)
        {
            font = diagram.getUniverse().getFont(fontFamily);
            if (font != null)
            {
                break;
            }
        }
        
        if (font == null)
        {
//            System.err.println("Could not load font");

            font = new FontSystem(fontFamily, fontStyle, fontWeight, (int)fontSize);
//            java.awt.Font sysFont = new java.awt.Font(fontFamily, style | weight, (int)fontSize);
//            buildSysFont(sysFont);
//            return;
        }

  • font = diagram.getUniverse().getFont(fontFamily); should be
    font = diagram.getUniverse().getFont(families[i]);
  • If (font == null) should probably also do a loop over families.
  • A warning for unknown fonts would be nice.

Missing Text, if clipping in any object is present

If clip-path with a value that is not "none" is present it will clip the Content from any Text-Element.
We want to use salamander to render charts from a weblibrary for generating charts.

image
How it should look

image
How it looks rendered with salamander

Sample:

<svg version="1.1"  xmlns="http://www.w3.org/2000/svg" width="350" height="100">
    <defs>
        <clipPath id="clipping">
            <rect x="0" y="0" width="508" height="299" fill="none"></rect>
        </clipPath>
    </defs>
    <g clip-path="url(#clipping)">
        <path fill="rgb(124,181,236)" fill-opacity="0.5"
              d="M 27 14.5 A 22.5 22.5 0 1 1 37 34 Z" stroke="#7cb5ec"
              stroke-width="1" ></path>
    </g>
    <text x="100" text-anchor="middle"  style="color:#333333;font-size:18px;fill:#333333;" y="24">
        <tspan>Missing Text</tspan>
    </text>
</svg>

Rendering Code:

public final class SalamanderSvgConverter {
    private Dimension diagramSize(SVGDiagram diagram) throws IOException {
        int width = (int)Math.ceil((double)diagram.getWidth());
        int height = (int)Math.ceil((double)diagram.getHeight());
        if (width > 0 && height > 0) {
            return new Dimension(width, height);
        } else {
            try {
                Rectangle2D boundingBox = diagram.getRoot().getBoundingBox();
                return new Dimension((int)Math.ceil(boundingBox.getWidth()), (int)Math.ceil(boundingBox.getHeight()));
            } catch (SVGException var5) {
                throw new IOException(var5);
            }
        }
    }

    public void convertToPng(InputStream in, OutputStream out, Dimension size) throws IOException {
        SVGDiagram diagram = this.getDiagram(in);
        Dimension dSize = this.diagramSize(diagram);
        if (size == null) {
            size = new Dimension(dSize);
        }

        BufferedImage image = new BufferedImage(size.width, size.height, 2);
        Graphics2D g = image.createGraphics();

        try {
            g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
            g.setBackground(new Color(0, true));
            if (dSize.width > 0 && dSize.height > 0) {
                AffineTransform transform = new AffineTransform();
                transform.setToScale((double)size.width / (double)dSize.width, (double)size.height / (double)dSize.height);
                g.setTransform(transform);
            }

            try {
                diagram.render(g);
            } catch (SVGException var12) {
                throw new IOException(var12);
            }
        } finally {
            g.dispose();
        }

        ImageIO.write(image, "png", out);
    }

    private SVGDiagram getDiagram(InputStream in) throws IOException {
        SVGUniverse universe = SVGCache.getSVGUniverse();
        URI uri = universe.loadSVG(in, "/dummy", true);
        return universe.getDiagram(uri);
    }
}

SVG renders solid black shapes

No matter what I do, all I get are black shapes.

Here's my code below. Due to the nature of my project, I need to embed the SVG file, so it's stored as byte array (data variable below).

  private SVGDiagram getSvgDiagram() {
    if (svgDiagram == null) {
      ByteArrayInputStream bis = new ByteArrayInputStream(data);
      SVGUniverse universe = new SVGUniverse();
//      universe.setImageDataInlineOnly(true);
      //universe.setVerbose(true);
      try {
        URI url = universe.loadSVG(bis, "SVG-" + Integer.toHexString(new Random(System.currentTimeMillis()).nextInt()));
        svgDiagram = universe.getDiagram(url);  
        svgDiagram.setIgnoringClipHeuristic(true);
      } catch (IOException e) {
        LOG.error("Error loading SVG", e);
      }
    }
    return svgDiagram;
  }

to render it on my Graphics2D I use

svgDiagram.render(g2d);

Here's one of the files I tried loading, it loads as a solid black rectangle, but playing with alpha it's possible to see that all shapes are there, just black.

diylc.zip

can't easily get element's bounding box in device coordinates

I've been experimenting with using svgSalamander for rendering in a game written in Java. Overall it seems to work quite well.

However, I ran into one issue that caused me some trouble. The SVG I'm rendering in the game is fairly complex, so I can't afford to rerender the entire image every time anything changes. So when I update an SVG element (e.g. by changing its color), I'd like to call the Swing method repaint() with the element's bounding box, so that only the region around the element will be repainted. In my experiments I've found that's much faster.

The problem is getting the element's bounding box in device coordinates. svgSalamander does provide a method RenderableElement.getBoundingBox(), which at first looked like exactly what I needed. However, after a bunch of experimentation and reading the svgSalamander source code, I figured out that if I call getBoundingBox() on an SVG element such as a Polygon, I get a bounding box in image coordinates (not device coordinates) in the coordinate system of the element's parent, not the entire SVG image. In other words, even if elements that are higher up in the element hierarchy have their own transforms defined in the SVG file, getBoundingBox() does not apply those transforms. It only applies the transform (if any) defined by the element's immediate parent.

Now, because the documentation is sparse, I'm not sure whether this behavior is by design or a bug. In any case, I worked around it in my application as follows. After I update an SVG element, I call getBoundingBox() to get its bounding box. I then walk up the hierarchy of SVG elements by calling the getParent() method repeatedly. For each ancestor, I call getXForm() to get its transformation, if any. If there is one, I apply it to the bounding box.

When I'm done, I have a bounding box in the coordinates of the entire image. I now need to transform this to device coordinates. The transform viewXform in the SVGRoot object is exactly what I need, but I can't use it because as far as I can tell there is no publicly accessible method that will retrieve this transform or apply it for me. So instead I have to do the work myself. I know the image size (I can get it by calling getBoundingBox() on the SVGRoot object before I specify a viewport) and I know the viewport size, which is defined by my application. So I can construct a transformation between these.

Still, this is a bit inconvenient, and it took me quite a while to figure this out. I'd think this would be a common use case, so it would be great to have some way to get an element's bounding box in device coordinates directly. If there's some easy way to do this today which I haven't noticed, I'd be happy to hear about it.

Exception while reading image after 550d275a1c8a003bae690220ad846c7b18f43ba4

Failed to render after 550d275

Image

<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
  <path fill="#59A869" fill-rule="evenodd"
        d="M11.5888765,0.885512946 L11.588193,0.882969556 L14.0351517,3.16277885 L13.4644242,3.72015189 L12.2713304,3.2942937 L9.80566451,3.26144943 L9.80566451,7.72464124 L10.3057072,8.34015178 L10.3057072,15.7201519 L6.80540831,15.7201519 L6.80540831,8.33917045 L7.30545101,7.72015189 L7.30545101,3.24317703 L6.81758586,3.57940482 L6.45607428,3.72015189 L3.80515211,3.72015189 L3.80515211,0.720151895 L6.31214109,0.720151895 L6.78715064,0.946064019 C6.87649899,0.809997663 7.03045713,0.720151895 7.20539987,0.720151895 L11.2057842,0.720151895 L11.5888765,0.885512946 Z"
        transform="rotate(-45 8.92 8.22)"/>
</svg>

Problem in > L11.588193,0.882969556

Font family matching does not conform to the CSS Fonts 3 specification

There are some problems with the resolution of font family names that cause existing SVG files to render improperly.

The CSS Fonts 3 specification says that font family names must be matched case-insensitively (section 5.1). It also requires several standard font family names to be recognized: serif, sans-serif, cursive, fantasy, and monospace. These are not exactly the same as the default Java font family names, esp. Sans Serif (which is the default value in Text.java).

Is there a way to clone SVGIcon with it's current diagram into new SVGUniverse?

A bit tricky question here - is there a good way to clone/copy an SVGIcon instance with it's current diagram (with all modifications potentially made in runtime) into new SVGUniverse instance?

I know I can load the same SVG icon from it's URI again in a different SVGUniverse and configure it separately, but I really need to preserve any changes made to it's diagram in runtime.

Let me elaborate a little bit -

  1. Let's say I have some small SVG icon - leaf.svg:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
    <path d="m31.604 4.203c-3.461-2.623-8.787-4.189-14.247-4.189-6.754 0-12.257 2.358-15.1 6.469-1.335 1.931-2.073 4.217-2.194 6.796-.108 2.296.278 4.835 1.146 7.567 2.965-8.887 11.244-15.847 20.79-15.847 0 0-8.932 2.351-14.548 9.631-.003.004-.078.097-.207.272-1.128 1.509-2.111 3.224-2.846 5.166-1.246 2.963-2.4 7.03-2.4 11.931h4c0 0-.607-3.819.449-8.212 1.747.236 3.308.353 4.714.353 3.677 0 6.293-.796 8.231-2.504 1.736-1.531 2.694-3.587 3.707-5.764 1.548-3.325 3.302-7.094 8.395-10.01.292-.167.48-.468.502-.804s-.126-.659-.394-.862z" />
</svg>
  1. I'm using it in runtime as an Icon for a label:
public class SvgExample
{
    public static void main ( final String[] args )
    {
        SwingUtilities.invokeLater ( new Runnable ()
        {
            @Override
            public void run ()
            {
                // SVG icon
                final SVGIcon icon = new SVGIcon ();
                icon.setSvgURI ( new File ( "C:\\leaf.svg" ).toURI () );
                icon.setPreferredSize ( new Dimension ( 32, 32 ) );
                icon.setAntiAlias ( true );

                // Displaying it
                final JFrame frame = new JFrame ( "SVG Example" );
                final JLabel iconLabel = new JLabel ( icon );
                iconLabel.setBorder ( BorderFactory.createEmptyBorder ( 50, 50, 50, 50 ) );
                frame.add ( iconLabel );
                frame.setDefaultCloseOperation ( WindowConstants.EXIT_ON_CLOSE );
                frame.pack ();
                frame.setLocationRelativeTo ( null );
                frame.setVisible ( true );
            }
        } );
    }
}

A simple frame:

image

  1. Now let's say I modify it's diagram anyhow:
try
{
    final SVGDiagram diagram = icon.getSvgUniverse ().getDiagram ( icon.getSvgURI () );
    diagram.getRoot ().addAttribute ( "fill", AnimationElement.AT_XML, "#FF0000" );
}
catch ( final SVGElementException e )
{
    e.printStackTrace ();
}

Simple fill attribute with red color:

image

  1. Now is the tricky part, I need to create a copy of this red icon and adjust it further - for instance to add some more adjustments to it:
try
{
    final SVGDiagram diagram = icon.getSvgUniverse ().getDiagram ( icon.getSvgURI () );
    diagram.getRoot ().addAttribute ( "stroke", AnimationElement.AT_XML, "#0000FF" );
}
catch ( final SVGElementException e )
{
    e.printStackTrace ();
}

Problem is - if I do more adjustments - they will affect all other SVGIcons with the same URI within the same SVGUniverse. And if I load new SVGIcon from that URI into new SVGUniverse - I'll end up losing the red fill attribute I've added earlier.

I didn't really find any existing way to clone/copy SVGIcon or it's SVGDiagram from one SVGUniverse to another one.

I have some tools for recursive cloning of data & reflection access that can help me with that, but it will be quite a hack & there are also a lot of cross-references to SVGUniverse in different classes which will also get copied by those tools which is problem for that approach.

fails to render minified SVG due to `java.lang.NumberFormatException: For input string: "l"`

I'm observing the stacktrace from within JOSM (an editor for the OpenStreetMap that uses – as far as I can tell – the version release here: #70 (comment)):

java.lang.NumberFormatException: For input string: "l"
	at java.base/jdk.internal.math.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2054)
	at java.base/jdk.internal.math.FloatingDecimal.parseFloat(FloatingDecimal.java:122)
	at java.base/java.lang.Float.parseFloat(Float.java:461)
	at com.kitfox.svg.SVGElement.nextFloat(SVGElement.java:822)
	at com.kitfox.svg.SVGElement.parsePathList(SVGElement.java:893)
	at com.kitfox.svg.SVGElement.buildPath(SVGElement.java:946)
	at com.kitfox.svg.Path.build(Path.java:87)
	at com.kitfox.svg.Path.updateTime(Path.java:151)
	at com.kitfox.svg.Group.updateTime(Group.java:313)
	at com.kitfox.svg.SVGRoot.updateTime(SVGRoot.java:400)
	at com.kitfox.svg.SVGDiagram.updateTime(SVGDiagram.java:243)
	at com.kitfox.svg.SVGUniverse.loadSVG(SVGUniverse.java:621)
	at com.kitfox.svg.SVGUniverse.loadSVG(SVGUniverse.java:467)
	at com.kitfox.svg.SVGUniverse.loadSVG(SVGUniverse.java:444)
	at org.openstreetmap.josm.tools.ImageProvider.getIfAvailableLocalURL(ImageProvider.java:1144)
	at org.openstreetmap.josm.tools.ImageProvider.getIfAvailableImpl(ImageProvider.java:933)
(…)

The image in question is this and renders fine in other viewers (it should render a triangle pointing up, with rounded corners):

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 847.156 743.622" width="25" height="25">
  <path d="M423.584.876c-9.394 0-18.784 3.584-25.948 10.748a36.682 36.682 0 00-5.884 7.69l-19.057 32.695h-.088L6.23 687.059c-.068.121-.121.244-.19.366a36.735 36.735 0 00-4.283 9.888c-5.243 19.57 6.373 39.692 25.948 44.936a36.547 36.547 0 009.672 1.25h772.584c20.269 0 36.694-16.426 36.694-36.695 0-6.63-1.767-12.851-4.849-18.223-.024-.038-.044-.077-.067-.121L461.284 27.946c-4.829-8.33-7.065-11.63-11.758-16.322C442.364 4.46 432.974.876 423.584.876z" />
</svg>

Masks not supported

Hello. I use this chrome icon

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16">
  <defs>
    <circle id="chrome-a" cx="7" cy="7" r="7"/>
    <linearGradient id="chrome-c" x1="4.547%" x2="36.948%" y1="62.056%" y2="33.661%">
      <stop offset="0%" stop-color="#A52714" stop-opacity=".6"/>
      <stop offset="66%" stop-color="#A52714" stop-opacity="0"/>
    </linearGradient>
    <circle id="chrome-d" cx="7" cy="7" r="7"/>
    <linearGradient id="chrome-f" x1="83.873%" x2="36.313%" y1="87.776%" y2="66.355%">
      <stop offset="0%" stop-color="#055524" stop-opacity=".4"/>
      <stop offset="33%" stop-color="#055524" stop-opacity="0"/>
    </linearGradient>
    <circle id="chrome-g" cx="7" cy="7" r="7"/>
    <linearGradient id="chrome-i" x1="32.625%" x2="48.553%" y1="-4.841%" y2="45.414%">
      <stop offset="0%" stop-color="#EA6100" stop-opacity=".3"/>
      <stop offset="66%" stop-color="#EA6100" stop-opacity="0"/>
    </linearGradient>
    <circle id="chrome-j" cx="7" cy="7" r="7"/>
    <radialGradient id="chrome-k" cx="-4.872%" cy="-.248%" r="401.327%" fx="-4.872%" fy="-.248%" gradientTransform="matrix(.26722 0 0 1 -.036 0)">
      <stop offset="0%" stop-color="#3E2723" stop-opacity=".2"/>
      <stop offset="100%" stop-color="#3E2723" stop-opacity="0"/>
    </radialGradient>
    <circle id="chrome-m" cx="7" cy="7" r="7"/>
    <radialGradient id="chrome-n" cx="-.157%" cy=".104%" r="136.321%" fx="-.157%" fy=".104%" gradientTransform="scale(1 .84752)">
      <stop offset="0%" stop-color="#3E2723" stop-opacity=".2"/>
      <stop offset="100%" stop-color="#3E2723" stop-opacity="0"/>
    </radialGradient>
    <circle id="chrome-p" cx="7" cy="7" r="7"/>
    <radialGradient id="chrome-q" cx="10.33%" cy="-12.215%" r="226.352%" fx="10.33%" fy="-12.215%" gradientTransform="matrix(1 0 0 .49642 0 -.062)">
      <stop offset="0%" stop-color="#263238" stop-opacity=".2"/>
      <stop offset="100%" stop-color="#263238" stop-opacity="0"/>
    </radialGradient>
    <circle id="chrome-s" cx="7" cy="7" r="7"/>
    <radialGradient id="chrome-u" cx="14.935%" cy="13.644%" r="100.426%" fx="14.935%" fy="13.644%">
      <stop offset="0%" stop-color="#FFF" stop-opacity=".1"/>
      <stop offset="100%" stop-color="#FFF" stop-opacity="0"/>
    </radialGradient>
  </defs>
  <g fill="none" fill-rule="evenodd" transform="translate(1 1)">
    <mask id="chrome-b" fill="#fff">
      <use xlink:href="#chrome-a"/>
    </mask>
    <g fill-rule="nonzero" mask="url(#chrome-b)">
      <g transform="translate(.477 -.557)">
        <polygon fill="#DB4437" points=".077 0 .077 10.451 3.547 10.451 6.599 4.645 14.351 4.645 14.351 0"/>
        <polygon fill="url(#chrome-c)" points=".077 0 .077 10.451 3.547 10.451 6.599 4.645 14.351 4.645 14.351 0"/>
      </g>
    </g>
    <mask id="chrome-e" fill="#fff">
      <use xlink:href="#chrome-d"/>
    </mask>
    <g fill-rule="nonzero" mask="url(#chrome-e)">
      <g transform="translate(-.557 -.636)">
        <polygon fill="#0F9D58" points="0 14.863 7.187 14.863 10.523 11.251 10.523 8.546 4.578 8.546 0 .045"/>
        <polygon fill="url(#chrome-f)" points="0 14.863 7.187 14.863 10.523 11.251 10.523 8.546 4.578 8.546 0 .045"/>
      </g>
    </g>
    <mask id="chrome-h" fill="#fff">
      <use xlink:href="#chrome-g"/>
    </mask>
    <g fill-rule="nonzero" mask="url(#chrome-h)">
      <g transform="translate(6.364 3.898)">
        <polygon fill="#FFCD40" points=".358 0 3.286 4.847 0 10.341 7.795 10.341 7.795 0"/>
        <polygon fill="url(#chrome-i)" points=".412 0 3.789 4.847 0 10.341 8.989 10.341 8.989 0"/>
      </g>
    </g>
    <mask id="chrome-l" fill="#fff">
      <use xlink:href="#chrome-j"/>
    </mask>
    <polygon fill="url(#chrome-k)" fill-rule="nonzero" points="7.52 3.881 7.52 5.547 13.757 3.881" mask="url(#chrome-l)"/>
    <mask id="chrome-o" fill="#fff">
      <use xlink:href="#chrome-m"/>
    </mask>
    <polygon fill="url(#chrome-n)" fill-rule="nonzero" points="1.102 2.772 5.656 7.325 4.235 8.145" mask="url(#chrome-o)" transform="rotate(2 3.379 5.458)"/>
    <mask id="chrome-r" fill="#fff">
      <use xlink:href="#chrome-p"/>
    </mask>
    <polygon fill="url(#chrome-q)" fill-rule="nonzero" points="6.462 14.238 8.13 8.018 9.55 8.838" mask="url(#chrome-r)"/>
    <mask id="chrome-t" fill="#fff">
      <use xlink:href="#chrome-s"/>
    </mask>
    <g fill-rule="nonzero" mask="url(#chrome-t)">
      <g transform="translate(3.818 3.818)">
        <circle cx="3.182" cy="3.182" r="3.182" fill="#F1F1F1"/>
        <circle cx="3.182" cy="3.182" r="2.545" fill="#4285F4"/>
      </g>
    </g>
    <circle cx="7" cy="7" r="7" fill="url(#chrome-u)" fill-rule="nonzero"/>
  </g>
</svg>

as result i got wrong render

chrome

Problem with special chars

While using nidi3/graphviz-java with RandomStringUtils.random(10) from commons-lang, these exceptions occurred:

[Fatal Error] :476:17: Ungültiges XML-Zeichen (Unicode: 0x17) wurde im Kommentar gefunden.
Okt. 28, 2019 4:54:14 NACHM. com.kitfox.svg.SVGUniverse loadSVG
WARNUNG: Error processing svgSalamander://graph/
org.xml.sax.SAXParseException; lineNumber: 476; columnNumber: 17; Ungültiges XML-Zeichen (Unicode: 0x17) wurde im Kommentar gefunden.
	at java.xml/com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1243)
	at java.xml/com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:635)
	at com.kitfox.svg.SVGUniverse.loadSVG(SVGUniverse.java:608)
	at com.kitfox.svg.SVGUniverse.loadSVG(SVGUniverse.java:545)
	at com.kitfox.svg.SVGUniverse.loadSVG(SVGUniverse.java:502)
	at guru.nidi.graphviz.engine.SalamanderRasterizer.createDiagram(SalamanderRasterizer.java:60)
	at guru.nidi.graphviz.engine.SalamanderRasterizer.doRasterize(SalamanderRasterizer.java:32)
	at guru.nidi.graphviz.engine.SvgRasterizer.rasterize(SvgRasterizer.java:35)
	at guru.nidi.graphviz.engine.Renderer.toImage(Renderer.java:117)
	at guru.nidi.graphviz.engine.EngineResult.map(EngineResult.java:58)
	at guru.nidi.graphviz.engine.Renderer.toImage(Renderer.java:109)
	at guru.nidi.graphviz.engine.Renderer.toImage(Renderer.java:105)
	at de.szut.simNil.binaryMaple.gui.TreeVisualizer.getGraphvizImage(TreeVisualizer.java:187)
	at de.szut.simNil.binaryMaple.gui.AbstractController.lambda$updateGraphvizImage$10(AbstractController.java:232)
	at java.base/java.lang.Thread.run(Thread.java:834)
[WARNING] 
java.lang.NullPointerException
    at guru.nidi.graphviz.engine.SalamanderRasterizer.createDiagram (SalamanderRasterizer.java:62)
    at guru.nidi.graphviz.engine.SalamanderRasterizer.doRasterize (SalamanderRasterizer.java:32)
    at guru.nidi.graphviz.engine.SvgRasterizer.rasterize (SvgRasterizer.java:35)
    at guru.nidi.graphviz.engine.Renderer.toImage (Renderer.java:117)
    at guru.nidi.graphviz.engine.EngineResult.map (EngineResult.java:58)
    at guru.nidi.graphviz.engine.Renderer.toImage (Renderer.java:109)
    at guru.nidi.graphviz.engine.Renderer.toImage (Renderer.java:105)
    at de.szut.simNil.binaryMaple.gui.TreeVisualizer.getGraphvizImage (TreeVisualizer.java:187)
    at de.szut.simNil.binaryMaple.gui.AbstractController.lambda$updateGraphvizImage$10 (AbstractController.java:232)
    at java.lang.Thread.run (Thread.java:834)

See here nidi3/graphviz-java#130

no way to replace content of Text element

From looking at the svgSalamander source code (i.e. Text.java), I can't see any way that an application can replace the content of a Text element with a new string. There are public methods appendText() and appendTspan() that can append to the content. But it would additionally be very useful to be able to replace the content altogether.

How to obtain the geometrical bounding box of an imported svg?

Ive got this wonderful svg right here; kettcards-logo.zip, in firefox or gimp the bounding box is as follows:
grafik
However, if I try to use svgSalamander with Pdfbox the bounding box seems to be this:
grafik
and the does not seem to be a way to obtain the 'actual' bounding box anymore. Don't get me wrong, this is the actual clip path of the svg, but I would like to obtain the geometrical bounding box of the svg defined by its width and height.

This is the code I used to render the svg with pdfbox:

SVGUniverse svgUniverse = new SVGUniverse();
SVGDiagram diagram = svgUniverse.getDiagram(svgUniverse.loadSVG(file_url));

var adjusted_matrix = Matrix.getTranslateInstance(doc.getXOffset(), doc.getYOffset());
PdfBoxGraphics2D graphics = new PdfBoxGraphics2D(doc, diagram.getWidth(), diagram.getHeight());

try {
    diagram.render(graphics);
} catch (SVGException e) {
    e.printStackTrace();
} finally {
    graphics.dispose();
}

var form = graphics.getXFormObject();
form.setMatrix(adjusted_matrix.createAffineTransform());
doc.stream().drawForm(form);

//the box
PDPageContentStream stream = doc.stream();
stream.setLineWidth(1);
stream.moveTo(doc.getXOffset()                     , doc.getYOffset());
stream.lineTo(doc.getXOffset() + diagram.getWidth(), doc.getYOffset());
stream.lineTo(doc.getXOffset() + diagram.getWidth(), doc.getYOffset() + diagram.getHeight());
stream.lineTo(doc.getXOffset()                     , doc.getYOffset() + diagram.getHeight());
stream.closePath();
stream.stroke();

doc is just a class that inherits from PDDocument and has some extra data on it (like getXOffset()). There is however no change in functionality, its just for convenience. I only left it in for completeness sake, the result is the same without using any transform.

So my question is as follows, is there a way to obtain the actual geometrical bounding box of the diagram, and if there is how do I do it ;).

sodipodi + "Keyframe fractions must be increasing"

hello Mark,

we have a user who used an SVG document from sodipodi (maybe inkscape?)
which results in:

Caused by: com.kitfox.svg.SVGException: java.lang.IllegalArgumentException: Keyframe fractions must be increasing: 0.51143
	at com.kitfox.svg.ShapeElement.renderShape(ShapeElement.java:169)
	at com.kitfox.svg.Path.render(Path.java:94)
	at com.kitfox.svg.Group.render(Group.java:205)
	at com.kitfox.svg.Group.render(Group.java:205)
	at com.kitfox.svg.SVGRoot.renderToViewport(SVGRoot.java:329)
	at com.kitfox.svg.SVGDiagram.render(SVGDiagram.java:105)
	at com.kitfox.svg.app.beans.SVGIcon.paintIcon(SVGIcon.java:322)
	... 69 more
Caused by: java.lang.IllegalArgumentException: Keyframe fractions must be increasing: 0.51143
	at java.awt.MultipleGradientPaint.<init>(MultipleGradientPaint.java:184)
	at java.awt.RadialGradientPaint.<init>(RadialGradientPaint.java:459)
	at com.kitfox.svg.RadialGradient.getPaint(RadialGradient.java:133)
	at com.kitfox.svg.ShapeElement.renderShape(ShapeElement.java:167)
	... 75 more

Here is the SVG:
https://raw.githubusercontent.com/fnatter/svgtest/master/src/main/resources/rihard_minus.svg

It can be fixed by:
fnatter/svgtest@b9e2c3e

So I wonder whether you should allow gradient "stops" which are equal and not increasing
or we should report a bug against sodipodi/inkscape.
(even if it's wrong according to the spec, I think it's good to support this, because existing SVGs use ite).

Many Thanks and Best Regards,
Felix

SSRF (Server-Side Request Forgery) is possible [CVE-2017-5617]

If the library is being used in a web application for processing user supplied SVG files then the app is vulnerable to SSRF.

The attacker can send a specially crafted svg file, for example

<svg width="5cm" height="4cm" version="1.1"
     xmlns="http://www.w3.org/2000/svg" xmlns:xlink= "http://www.w3.org/1999/xlink">
	<image xlink:href="https://host-in-the-trusted-network.com/test.jpg" x="0" y="0" height="50px" width="50px"/>
</svg>

and the lib will send the request inside the trusted network to the host-in-the-trusted-network.com (bypassing the firewall). In general, the attacker can use any scheme supported by default (such as file://, jar:// etc) or use application specific scheme.

How to fix - any schemes apart from data in the xlink:href attribute should be disallowed by default at https://github.com/blackears/svgSalamander/blob/master/svg-core/src/main/java/com/kitfox/svg/ImageSVG.java#L120

Additional information:
https://cwe.mitre.org/data/definitions/918.html
http://www.slideshare.net/d0znpp/ssrf-attacks-and-sockets-smorgasbord-of-vulnerabilities

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.