jfree / jfreesvg Goto Github PK
View Code? Open in Web Editor NEWA fast, lightweight Java library for creating Scalable Vector Graphics (SVG) output.
Home Page: http://www.jfree.org/jfreesvg
License: GNU General Public License v3.0
A fast, lightweight Java library for creating Scalable Vector Graphics (SVG) output.
Home Page: http://www.jfree.org/jfreesvg
License: GNU General Public License v3.0
Shouldn't the font size for text elements be in points rather than pixels? getSVGFontStyle() prints 'px' for the 'font-size' attribute.
like this, can help web identify element name.
I'm using PDFBox > PDFRenderer.renderPageToGraphics to create an SVG from a PDF page and i was getting a NullPointerException every time, then, after a long backtrace i found this: drawImage(img, null, null) on their code, and i'm not really sure if the problem is in your code but this is what i found on the Java Specification:
(https://docs.oracle.com/javase/8/docs/api/java/awt/Graphics2D.html)
If an AffineTransform is passed to drawImage(Image, AffineTransform, ImageObserver), the AffineTransform is used to transform the bounding box from image space to user space. If no AffineTransform is supplied, the bounding box is treated as if it is already in user space.
I'm guessing you need to do a null check on that method.
Thanks.
From the JFreeSVG forum:
When compiling the library jfreesvg with JDK11 I get the following error:
/[....]/org/jfree/graphics2d/svg/SVGGraphics2D.java:90: error: package javax.xml.bind is not visible
import javax.xml.bind.DatatypeConverter;
(package javax.xml.bind is declared in module java.xml.bind, which is not in the module graph)
Others seem to have similar issues, e.g. tomdesair/tus-java-server#14 (just found by searching). They say:
In JDK11 the javax.xml.bind package was removed. You use the javax.xml.bind.DatatypeConverter for Base64 encoding. Maybe you can replace this with java.util.Base64 from Java 8 or other implementation?
Not sure it is the same issue though. Any ideas?
Hello! I use a font that have TRACKING = 0.45. But when i create svg and 'drawString' with this font, it seems that this property is being ignored. I looked through svg documentation and found that i should use "letter-spacing".
So, how i can add letter-spacing to my text?
https://search.maven.org/search?q=jfreesvg
The latest version there is 3.4
I see multiple writeToSVG methods are included in SVGUtils, but I'm wondering if I can also load an existing SVG to add it to the SVG I'm creating?
I was updating Gentoo ebuilds for jfree related packages. I ran into a problem with JFreeSVG 3.2. It seems to be using classes from an older version of JFreeChart that are not in JFreeChart 1.5.
import org.jfree.chart.drawable.GradientPainter;
import org.jfree.chart.drawable.ColorPainter;
import org.jfree.chart.ChartUtilities;
Likely in a past version. Gentoo has JFreeChart 1.0.19 but that depends on JFreeSVG 2.1.x. I rather avoid the older versions. Not to mention the circular dependencies.
Could JFreeSVG be updated to newer JFreeChart?
Seems only a few classes are missing. If not I can see about using the existing Gentoo ebuilds. Just seems odd to have to have multiple older versions to build the latest. Need JFreeSVG 2.1.x for JFreeChart 1.0.19. Which in turn JFreeChart 1.0.19 is used by JFreeSVG 3.2. Need 2 older versions of each for the latest versions of each. Thanks!
TL;DR:
Why not use double precision for width and height in SVGGraphics2D?
When applying the matrix:
PlanarMatrix transformation = new PlanarMatrix().translate(x, y).scale(1.0, -1.0);
To a created svg, I encountered an odd behaviour and that lead to some questions.
The matrix is used to mirror shapes on the y axis in place. Meaning: The x and y translation is used to translate the mirrored shapes back to their original position, after they have been mirrored.
This matrix had originally been defined and applied to paths rendered to BufferedImage objects.
However if this same method is applied to the SVG, then the position will be off.
The reason is rather obvious:
My translation assumes that the Graphics dimensions equal the dimensions of the contained path. but the svg paths (as is true for paths in general) does not really need to have integer dimensions. A SVG could easily have a height of 5.678, but the used Graphics would have a height of 6px.
Obviously I have to adapt this to reflect the fact, that the path dimensions and the Graphics dimensions can differ. Easy and not a problem at all.
Question:
But what about SVGGraphics2D? Why does it use Integer dimensions in the first place?
(I am fully aware, that I am talking about differences <1 here, and that this might seem to be a non-issue - but the differences are just big enough to be visible and that bothers me. (although I can fix this on my end however.))
Hi,
I am using JFreeSVG in combination with JFreeChart to produce SVG images to be embedded later on in HTML.
My problem is that the generated SVG file is huge (as example: plotting a single measurement where the sampling rate is 1ms, the time (X) is 270 seconds long (270k data points) produces an SVG file of 180MB. The picture is perfect but it simpy kills any browser I try to open with.
Question: How can I reduce (drastically) the generated SVG size?
The code generating the SVG (Kotlin):
val chart = createChart(sigData) ?: return@action
val g2 = SVGGraphics2D(600, 400).apply {
shapeRendering = "optimizeSpeed"
}
chart.draw(g2, Rectangle(0, 0, 600, 400))
SVGUtils.writeToSVG(calculateExportFile(), g2.svgElement)
I also tried using SVGHints
with no luck.
Thanks a lot,
David
Reported in the forum at jfree.org : http://www.jfree.org/forum/viewtopic.php?f=32&t=120857
The website says that Java 11 is needed for the current version. Unfortunately, I have an application that is using Java 8 for the development environment. The website says that JFreeSVG 3.4.3 is recommended in that case. However, when I go to Downloads that version is not listed. So, either the website needs to not recommend the old version, or make the old version available.
I will be updating the application to a newer version of Java in the next few months but at the moment want to try a compatible library to see if it will work better than the Batik implementation that I used previously.
I found the 3.4.3 jar file on Maven Central so my issue is mainly suggesting cleanup to the JFreeSVG web page instructions for 3.4.3.
Creating SVG of a JLabel with a colored border with SVGGraphics2D paints a filled rectangle in the size of the label instead of a text surrounded by a rectangle:
JLabel label = new JLabel("Label with border");
label.setBorder(BorderFactory.createLineBorder(Color.YELLOW)); // removing border shows text
label.setSize(label.getPreferredSize());
SVGGraphics2D graphics = new SVGGraphics2D(100, 40);
label.printAll(graphics);
Sorry for filing in another issue. We just tested JFreeSVG for generating SVG in our application. This and issue #24 are the two major issues we found.
The graphics object created from fmImage must have KEY_FRACTIONALMETRICS hint set to ON.
Without it the FontMetrics won't be able to properly measure text, i.e. the stringWidth(str) function will return an incorrect value.
A semicolon is missing for the miterLimit.
I did not check, whether you already fixed this issue in the most recent version. Sorry for the inconvenience - simply close this issue in that case.
It should be:
if (Math.abs(DEFAULT_MITER_LIMIT - miterLimit) > 0.001) {
b.append("stroke-miterlimit: ").append(geomDP(miterLimit)).append(";");
}
But it is:
if (Math.abs(DEFAULT_MITER_LIMIT - miterLimit) > 0.001) {
b.append("stroke-miterlimit: ").append(geomDP(miterLimit));
}
how to read svg file and convert it to png?
Hi,
I see that SVG supports cmyk. Im working with some print media, and would like to see CMYK support added to SVGGraphics2D
Please add support for SVG filters effects. I would be great if SVG Salamander could render the SVGram filter effects.
I'm seeing an issue when I run the following test:
@Test
void testSvgProblem() throws Exception {
SVGGraphics2D g2 = new SVGGraphics2D(4986, 3216);
int marker_size = 65;
int local_diameter = 600;
int radius = local_diameter/2;
double arc_size = Math.PI / 12;
g2.translate(1000, 500);
g2.setColor(Color.BLUE);
g2.setStroke(new BasicStroke(2));
g2.drawOval(-radius, -radius, local_diameter, local_diameter);
// draw sector lines
g2.drawLine(0, -radius - marker_size / 2, 0, -radius + marker_size / 2);
g2.rotate(arc_size*2); // rotate past the orbit arc
// draw sector lines
int halfMarkerSize = marker_size / 2;
g2.drawLine(0, -radius - halfMarkerSize, 0, -radius + halfMarkerSize);
for (int i = 0; i < 6; i++) {
g2.rotate(arc_size);
g2.drawLine(0, -radius - halfMarkerSize, 0, -radius + halfMarkerSize);
g2.drawString(Integer.toString(i), 0, -radius);
}
String result = g2.getSVGDocument();
Files.writeString(TestConstants.ACTUAL_RESULTS_DIR.resolve("TestSvgProblem.svg"), result);
}
It creates a circle and then creates a series of lines that are perpendicular to the circle. When the line is horizontal (as in line 3), the transformation matrix looks like it is incorrect.
Hi!
I'm currently using Batik for parsing SVG files into our custom internal format. it's got issues and the devs are well hidden.
If you were me, what library would you use instead?
Thanks!
Hi again,
I'll leave this here.
/**
* Responsible for converting a double value into a string with a specified
* precision.
*/
public final class FastDouble {
private static final int[] POW10 = {1, 10, 100, 1000, 10000, 100000, 1000000};
private static final StringBuilder BUFFER = new StringBuilder();
/**
* Converts the given value to a string.
*
* @param value The value to convert to a string.
* @param precision The number of decimal places.
* @return The string representation of the given value.
* @see <a href="https://stackoverflow.com/a/10554128/59087">source</a>
*/
public static String toString( double value, final int precision ) {
assert precision >= 0;
assert precision < POW10.length;
final var sb = BUFFER;
sb.setLength( 0 );
if( value < 0 ) {
sb.append( '-' );
value = -value;
}
final int exp = POW10[ precision ];
final long lval = (long) (value * exp + 0.5);
sb.append( lval / exp ).append( '.' );
final long fval = lval % exp;
for( int p = precision - 1; p > 0 && fval < POW10[ p ]; p-- ) {
sb.append( '0' );
}
sb.append( fval );
return sb.toString();
}
}
Feel free to benchmark it against RyuDouble. Depending on the precision, this could be a faster replacement.
Note: This isn't thread safe, but that can be changed by moving the buffer allocation into the method itself.
This also applies to JFreePDF (Documented tonight as Issue #1 in that repository).
The Artifact ID includes the Group ID, but this is unnecessary and possibly problematic, as the two go together to form the Unique ID, and the latter should not include the former in its direct specification. It should match the JAR name (minus version number or snapshot). At least, according to the Apache Maven guidelines (and most projects I have seen so far).
https://maven.apache.org/guides/mini/guide-naming-conventions.html
This is the convention I am using in my own just-posted projects, and the one that I encounter in most of what I am seeing at the moment. The Group ID often is the reverse domain of one's GitHub account, as group owner of individual projects whose names (as all-lowercase with no special characters) form the artifact ID and also the JAR name.
Custom miterlimits are seemingly not applied, when drawing pathes. This is caused by a minor flaw in one of the if statements in "SVGGraphics2D.strokeStyle()"
The statement's (assumed) intended behaviour:
Only if the absolute difference between the set miterlimit and the default miter limit(4) surpasses 0.001 a custom miter limit shall be appended to the style String.
For this reason:
It is:
if (Math.abs(DEFAULT_MITER_LIMIT - miterLimit) < 0.001) {
b.append("stroke-miterlimit: ").append(geomDP(miterLimit));
}
But it should be:
if (Math.abs(DEFAULT_MITER_LIMIT - miterLimit) > 0.001) {
b.append("stroke-miterlimit: ").append(geomDP(miterLimit));
}
First of all:
This is a nice and simple solution and I really like it!
Issue:
Using this fine library I tried to draw a path that contained a point with the Y-coordinate 9.62E-4.
In the created SVG the Y-coordinate for said point was set to 9.62 instead, which lead to a unrecognizable Glyph in the result.
Observations:
Following this, I tried to find the cause of the issue and ended up playing arround with the class "RyuDouble" at the end.
As far as I understood it, Ryu is a method to create a String representing a floating point number (with increased speed and performance, when compared to other methods) and as far as I could see your intention was, to not only implement that method, but to also limit the maximum number of fractional digits to 4.
I tried to pinpoint my issue, by comparing the results of "RyuDouble.doubleToString(double value, int decimals)" to those of a simple DecimalFormat (which is simply dropping fractional digits beyond 4):
public static String doubleToString(double value, int decimals) {
DecimalFormat decimalFormat = new DecimalFormat("#.#");
decimalFormat.setMaximumFractionDigits(decimals);
DecimalFormatSymbols decimalFormatSymbols = new DecimalFormatSymbols();
decimalFormatSymbols.setDecimalSeparator('.');
decimalFormat.setDecimalFormatSymbols(decimalFormatSymbols);
return decimalFormat.format(value);
}
My results were as follows:
>>> LIMIT ALL VALUES TO 4 FRACTION DIGITS
VALUE: '0'
RYU_DOUBLE: '0.0'
DECIMAL_FORMAT: '0'
VALUE: '0.000000000001'
RYU_DOUBLE: '1.'
DECIMAL_FORMAT: '0'
VALUE: '-1'
RYU_DOUBLE: '-1.0'
DECIMAL_FORMAT: '-1'
VALUE: '-0.0001'
RYU_DOUBLE: '-1.0E-'
DECIMAL_FORMAT: '-0.0001'
VALUE: '0.0001'
RYU_DOUBLE: '1.0E-'
DECIMAL_FORMAT: '0.0001'
VALUE: '0.01'
RYU_DOUBLE: '0.01'
DECIMAL_FORMAT: '0.01'
VALUE: '1000'
RYU_DOUBLE: '1000.0'
DECIMAL_FORMAT: '1000'
VALUE: '10000'
RYU_DOUBLE: '10000.0'
DECIMAL_FORMAT: '10000'
VALUE: '1000000000'
RYU_DOUBLE: '1.0E9'
DECIMAL_FORMAT: '1000000000'
Issues with "RyuDouble":
Some of the results yielded by "RyuDouble.doubleToString" are clearly incorrect or incomplete. (i.e. results for values '0.0001' and '0.000000000001')
I am not entirely sure, whether SVG does support the scientific notation at all!? Hence I did enforce a "raw number format" in my approach.
Even though I could find a recommendation to only use 2 fractional digits in SVG paths, I don't know whether I like the intended loss of precision (4 fractional digits). Is it really necessary to do this? I tried replacing "doubleToString" in "SVGGraphics2D" with my primitive approach - not limiting the maximum number of fractional digits - and the resulting SVG displayed just fine. (If it is necessary, I would rather round values?)
Assumption:
I did not read the paper concerning the Ryu method, therefore I can not claim this to be correct: But I would assume, that the combination of the Ryu method and the limitting of the fractional digits may cause the issue here.
My .svg file is really big. is there a way to produce it in compressed form?
Thanks very much.
Hi.
Is it possible to get the latest version on the Maven Central Repository, please?
Thank you.
Currently opacity is not handled in gradients at all.
Svg linearGradient stop can either accept an rgba color, or have a stop-opacity style attribute, neither of which are present in the current code. The rgbaColorStr function exists but is not used,
When exporting a plot from Renjin as SVG, a double semicolon is written. For example:
svg("/tmp/filename.svg");
plot(rnorm(5));
dev.off();
Renjin uses JFreeSVG, which produces:
<ellipse
cx="61.5" cy="219.5" rx="2.5" ry="2.5"
style="...snip... stroke-linecap: square;; fill: none" ...snip... />
Unfortunately, the ConTeXt typesetting engine has a bug that ignores styles after a null entry is detected in the style list, resulting in all such diagrams being rendered as a big black square (because the fill:none
isn't honoured).
Any idea what's causing the ;;
to be generated?
ConTeXt (PDF) on the left and FlyingSaucer (XHTML) on the right:
FlyingSaucer handles ;;
fine, but not ConTeXt.
What do you think SVG of having pluggable features that can be disabled? For my purposes, I don't need linear gradients, radial gradients, embedded images, or clipping. At the moment, instantiating SVGGraphics2D
also allocates hash maps and array lists, without necessity (in my case). Additionally, the filePrefix
and fileSuffix
variables are assigned, even though those values will never be used. Same for the defsKeyPrefix
and call to System.nanoTime()
.
By default all these features can be enabled, yet having a configurable way to disable them (builder pattern, maybe?) would be handy. Something like:
new SVGGraphics2D.Builder()
.setLinearGradients(false)
.setRadialGradients(false)
.setEmbeddedImages(false)
.setDefinitionKeys(false)
.setEmbeddedFonts(false)
.build()
The setEmbeddedFonts(false)
would be synonymous with setting the rendering hint key of KEY_DRAW_STRING_TYPE
to the value of VALUE_DRAW_STRING_TYPE_VECTOR
.
Along the lines of configurable features, having a bit more control over the SVG output would be amazing. For example, I'd like to eliminate the xmlns:jfreesvg
namespace attribute declaration along with xmlns:xlink
and <defs>
. This releates to the configurable features idea. Since I know I don't need gradients or clips, those inner loops will never execute. Having the ability to suppress <defs></defs>
altogether would be grand.
Here's an SVG generated with JFreeSVG:
Here's the same SVG after minifying using svgcleaner:
I'd like to get the output from JFreeSVG closer to the minified version to help improve downstream rendering performance.
SVGGraphics2D
calls the default StringBuilder
constructor, which is sized to about 16 bytes. This will result in memory reallocations and array copies. We know that the minimum size for SVG contents will exceed 16 bytes.
The constructor provides a way to provide a StringBuilder
of a preallocated size, but that strikes me as an implementation detail that shouldn't be exposed to calling classes. Rather, how about the following:
public SVGGraphics2D( width, height, units, bufferSize )
This would allow for reusing the buffer (as opposed to reallocating it) by calling setLength()
on the buffer. Moreover, since we know the start of the SVG is static, we can do:
StringBuilder buffer = new StringBuilder(bufferSize);
String prefix = "<?xml version='1.0'?><svg ";
buffer.append( prefix );
// ... code that uses the SVGGraphics2D
// ... then, internally, reset back to the starting point, no need to re-append:
buffer.setLength( prefix.length() );
The constructor comment appears to be incorrect:
This constructor is used by the {@link #create()} method, but won't normally be called directly by user code.
Instead, it may be more accurate to note that clients can use this constructor to provide a custom buffer (to avoid micro-reallocations); it did not appear that the create
method called this particular constructor. Maybe an outdated comment?
Here's a profile dump of the application's hot spot:
--- 2539794705 ns (8.27%), 254 samples
[ 0] jdk.internal.math.FloatingDecimal$BinaryToASCIIBuffer.dtoa
[ 1] jdk.internal.math.FloatingDecimal.getBinaryToASCIIConverter
[ 2] jdk.internal.math.FloatingDecimal.getBinaryToASCIIConverter
[ 3] java.text.DigitList.set
[ 4] java.text.DecimalFormat.doubleSubformat
[ 5] java.text.DecimalFormat.format
[ 6] java.text.DecimalFormat.format
[ 7] java.text.NumberFormat.format
[ 8] org.jfree.svg.SVGGraphics2D.geomDP
[ 9] org.jfree.svg.SVGGraphics2D.getSVGPathData
[10] org.jfree.svg.SVGGraphics2D.fill
[11] org.jfree.svg.SVGGraphics2D.drawGlyphVector
[12] sun.font.ExtendedTextSourceLabel.handleDraw
[13] sun.font.Decoration.drawTextAndDecorations
[14] sun.font.ExtendedTextSourceLabel.draw
[15] java.awt.font.TextLine.draw
[16] java.awt.font.TextLayout.draw
[17] org.jfree.svg.SVGGraphics2D.drawString
[18] org.jfree.svg.SVGGraphics2D.drawString
[19] org.jfree.svg.SVGGraphics2D.drawString
[20] java.awt.Graphics.drawChars
[21] be.ugent.caagt.jmathtex.CharBox.draw
[22] be.ugent.caagt.jmathtex.HorizontalBox.draw
[23] com.whitemagicsoftware.tex.TeXFormulaTest.test_MathML_SimpleFormula_Success
[24] com.whitemagicsoftware.tex.TeXFormulaTest.main
It would be great if all the geometries could be assigned absolute sizes. (Perhaps a mode switch that would let me define what the unit dimensions would be).
More information on why it seems to be a solution to get get SVGs of an absolute size
Is drawing a path directly using the standard path data format supported? I can't seem to find any methods that look like they might do that in the API docs.
In Graphics2D drawing a filled rectangle with a 1-pixel border shows a correctly filled rectangle, applying the same code with SVGGraphics2D results in a misalignment of the border and the filled rectangle:
SVGGraphics2D graphics = new SVGGraphics2D(40, 40);
graphics.drawRect(10, 10, 20, 10); // 1- pixel border
graphics.setColor(Color.BLUE);
graphics.fillRect(11, 11, 19, 9);
The method drawRect of Graphics2D internally draws four lines to get a rectangle, it seems in SVG the x,y starting-coordinate of lines is not the top-left corner but the middle of the lines which causes the misaligment.
Unfortunately the class SVGGraphics2D is final so no easy workaround can be implemented.
Hi guys, need your help.
Let's say, I need to import SVG image to jfreesvg. How should I do it ?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.