Code Monkey home page Code Monkey logo

jfreesvg's People

Contributors

aminfa avatar jfree avatar mikosik avatar mquinson 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  avatar  avatar  avatar  avatar  avatar  avatar

jfreesvg's Issues

svg font size units

Shouldn't the font size for text elements be in points rather than pixels? getSVGFontStyle() prints 'px' for the 'font-size' attribute.

drawImage method (Line 2520) perhaps needs a null check

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.

Compiling with JDK11

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?

How to add "letter-spacing"?

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?

Possible circular dependencies missing from JFreeChart 1.5

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!

Could/should SVGGraphics2D dimensions use double precision?

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.))

Question: How can I reduce the "size" of the generated SVG?

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

Download for 3.4 (or 3.4.3) is not available

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.

Painting JLabel with border not showing text but filled rectangle

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.

fontMetrics bug

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.

Missing semicolon in SVGGraphics2D#strokeStyle()

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));
}

Example:
grafik
grafik

Solution:
grafik
grafik

CMYK support

Hi,

I see that SVG supports cmyk. Im working with some print media, and would like to see CMYK support added to SVGGraphics2D

Problem when rotating to horizontal

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.

What lib would you use to parse SVG files?

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!

Faster double-to-string conversion

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.

Why does the Artifact ID not follow the Apache Maven guidelines (it prepends the Group ID)?

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 miterlimit is not applied

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));        
}

Class RyuDouble returns inappropriate values

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":

  1. Some of the results yielded by "RyuDouble.doubleToString" are clearly incorrect or incomplete. (i.e. results for values '0.0001' and '0.000000000001')

  2. 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.

  3. 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.

opacity in gradients

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,

Avoid writing double semicolon in SVG style attribute

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:

render-r-plot

FlyingSaucer handles ;; fine, but not ConTeXt.

Optimizations for smaller output

Configurable Features

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.

Configurable Element Output

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:

equation-9.txt

Here's the same SVG after minifying using svgcleaner:

equation-9-sm.txt

I'd like to get the output from JFreeSVG closer to the minified version to help improve downstream rendering performance.

Configurable Buffer Size

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?

Profiling

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

Drawing with path data string?

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.

SVGGraphics2D: drawRect and fillRect misaligned compared to Graphics2D

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.

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.