bodoni / svg Goto Github PK
View Code? Open in Web Editor NEWComposer and parser for SVG
License: Other
Composer and parser for SVG
License: Other
When the generated SVG is put into an HTML document and served into a browser, many browsers will autocorrect the markup. They will find tags that are not permitted to use />, and will automatically insert a closing tag.
E.g. becomes when loaded in an HTML page in Google Chrome.
Is it possible to disable the short version and force a verbose output ?
Edit: I'm using the to_string() method of Document to convert into string
It would be useful to have an interface for generating and parsing CDATA sections (<![CDATA[ ]]>
). These are used in SVG, e.g., to embed CSS rules inside a <style>
element (example).
ETA: I'm working on a PR for this feature.
This issue was found when trying to parse the logo of the lyon crate: https://github.com/nical/lyon/blob/master/assets/lyon-logo.svg.
The parser for paths uses Reader::consume_number which is modeled after https://www.w3.org/TR/SVG/types.html#DataTypeNumber.
This part of the spec does not mention scientific notation (like "2e-4"), most likely because of restrictions to the style sheet grammar.
However, scientific notation is explicitly supported by the path specification (see the grammar in https://www.w3.org/TR/SVG/paths.html#DAttribute).
Unfortunately SVG files generated by Inkscape (and probably many other vector graphics programs) are full of paths with numbers in scientific notation so it would be very useful for this library to support them at least in paths.
I'm new to rust so pardon me if I'm misunderstanding anything. It appears all the structs (Rectangle, etc) have an inner Element but this is private with no way for the user to access. Element is public and has methods to access its inner workings but the structs are missing this. Is there a reason for this?
Hi,
there should probably be no newlines around text nodes, as white space content of elements can be meaningful.
The newlines in titles like here could even render as ⤶
in some situations.
Thanks,
Auberi
If I have a SVG triangle with: d="m 58.966213,150.22576 6.60165,-67.629055 55.267647,39.531725 z"
, the svg
parser submits three Command::Relative
. However, the first event should be an Command::Absolute
, event, only the following are Command::Relative
events.
I.e. I get this:
Move(Relative, Parameters([58.966213, 150.22575, 6.60165, -67.62905, 55.267647, 39.531727]))
Close
What would be correct:
Move(Absolute, Parameters([58.966213, 150.22575]))
Move(Relative, Parameters([6.60165, -67.62905, 55.267647, 39.531727]))
Close
Hello,
Can you publish a new patch release of this library on crates.io? I would love to remove the dependence on my private fork since these changes were merged upstream: d272e76
Many thanks in advance!
I have been exploring the library and found most things quite intuitive, but I can't seem to figure out how to assign the text content for a Text
node after creating it with the following code:
use svg::node::element::Text;
let text = Text::new();
The target behavior is to generate a <text>
tag containing a string that I provide through the rust program like the following:
<text>Hello, world</text>
Thank you so much for your help!
It would be nice if the output had some indentation, e.g. 4 space per nesting, so it could be read more easily
Rather than having Value
always be a String
, something like this could be better:
enum Value {
String(String),
Integer(i64),
Float(f64),
}
And then the From
implementations would just set an Integer
or Float
. This would be nice because it means that numbers (which account for a lot of possible values) never have to allocate.
Doing deref
to str
wouldn't be the best thing with this change. Something like as_string() -> String
might be better suited.
How to get large-arc-flag and sweep-flag from Parameters? Does one simply cast from f32 to bool?
Would a helper method be possible, then? Or even a full page of methods for simple access with Parameters.
The library is nice, but this part seems particularly obscure.
Sadly, there is no documentation for any of the types in node::element
since most of the methods seem to be generated by macros.. Because of this, it seems to by impossible to use this library without diving into the source and deciphering the macros..
My specific question: How would I use the Polygon
type? How do I add points to a polygon?
Please update the README with the level of compliance this svg supports.
Does this library support SVG 1? SVG 1.1? SVG 2? What is the roadmap and what are the goals.
I've an SVG file and want to modify it. Among other things, I'd like to do is adding a "id" attribute to certain tags.
My approach is to read the file and create an svg::Parser
. Iterate over the parser to create an svg::Document
. I'll pass this svg::Document
around to functions that modify it. But that doesn't work.
Consider the following code:
let document = svg::Document::new()
.set("viewBox", (0, 0, 70, 70))
let element: Element = document.get_inner()
for child in element.get_children() {
child.assign("id", 3);
}
That fails to compile with:
error: the `assign` method cannot be invoked on a trait object
--> src/bin/optimize.rs:85:15
|
85 | child.assign("id", 3);
| ^^^^^^
|
::: /home/user/.cargo/registry/src/github.com-1ecc6299db9ec823/svg-0.10.0/src/node/mod.rs:34:15
|
34 | Self: Sized,
| ----- this has a `Sized` requirement
Even if this would work, how would I know whether the child
is a 'line', 'path' or any other tag is?
While experimenting with this, I noticed that's no way to construct a complete representation of the content of the parsed SVG file, because the contents of comments and processing instructions are inaccessible.
In fact, in the latter case, one could argue that it's a spec violation to not give the application access to the processing instructions, because SVG is XML-based and this is what the XML spec has to say about it:
"Processing instructions (PIs) allow documents to contain instructions for applications. PIs are not part of the character data of the document, but MUST be passed through to the application.
I want to define a pattern element, and don't see a struct for that. Is there currently any way to work with patterns? Or is adding support for them as simple as adding it to the list of elements created withimplement!
? If so, I can submit a pull request.
Sorry this isn't really an issue (or it's a documentation issue?) but I can't figure out how to use the Text
Node
to actually add text to a document. Can you help, please?
I'm trying to implement a function inside a struct which updates a Vector of Data elements.
struct Svg {
data: Vec<Data>,
}
impl Svg {
fn new() -> Self {
Self {
data: {
let mut vec = Vec::<Data>::with_capacity(10);
for _ in 0..10 {
vec.push(Data::new().move_to((0, 0)));
}
vec
},
}
}
fn update(&mut self) {
self.data[0].line_to((4,9));
}
}
When I compile this code I get the following error: move occurs because value has type "svg::node::element::path::Data", which does not implement the "Copy" trait
.
I'm new to rust but I guess the move occurs because the function line_to
takes mut self
as a parameter which moves the ownership.
Is there a way to make my code compile?
I need this code because I run a simulation which produces data every time step and I want to draw an svg picture from it. I therefore try to collect the data from the simulation inside a Data elements to draw Paths from them.
The example above is only a prototype for that. It's not for practical use yet.
I am using the example "Parsing" from the crates.io page.
How can I get the String out of the tuple struct Value?
let val = attributes.get("inkscape:groupmode");
if val.is_some(){
let val = val.unwrap();
let s = value.0; // ERROR: field
0of struct
svg::node::value::Value is private rustc(E0616)
}
Let's say I want insert labels for some dots in SVG picture.
I want this text to be below/up/left/right/centered to these dots.
To place it properly I need to get this Text node size. How can I get it before I append()
it to SVG?
Currently, set()
can take any valid string as input, which isn't desirable(?).
Note: Considering the number of elements there are, it's kind of understandable to have lax methods.
Question: What's the current reasoning for not having type safety, other than a lot of repetition and not as elegant macro implementation?
Adding set_strict()
which takes (name: enum, value: T)
, passes (name.to_string(), value)
to set()
internally.
Value can have type safety too, but I don't think I can do that without serde
specifically for hexadecimal colour.
set()
can be exposed as it is, while having set_strict()
as another option.set()
can be renamed to set_raw()
and set_strict()
replaces set()
. Giving both options of customizability and type safety.If I can get some direction and tips as I don't know much about svg
I would love to work on this.
Any ideas how text could be wrapped when being added?
As far as I can tell wrapping text is not really a SVG concept.
I'm trying to get a node from the children of an element, and copy it into another element, but I'm facing issues.
The output of get_children()
is &Vec<Box<dyn Node>>
, but the add / append functions will only accept actual Node
implementors. I tried dereferencing to get the inner Node from the box, but then the compiler complaining about Sized not being implemented. Node is a trait object so it cannot be Sized, but an unsized variable cannot be used as a function parameter, so how could I solve this?
Can I convert Box somehow back to it's original type (e.g. Circle)? I thought Box erases the actual type, so I'm not sure how would this be possible. If I have prior knowledge of the type, can I "cast" it maybe somehow?
Looks like Element::append will just put it inside a Box again anyways, so maybe there should be another append-like function which accepts already boxed Nodes?
It seems like internally, Attributes
is a std::collections::HashMap
. Would it be possible to use hashbrown::HashMap
? Probably behind a Cargo flag to make hashbrown
an optional dependency.
Reasoning: the HashMap
in collections is extremely collision resistant (SipHash), but this means it is slower and has a larger per-entry memory overhead than alternatives. hashbrown
uses ahash
which is much faster and has a smaller per-entry overhead (1/8 the size if I recall correctly). ahash
is not as collision resistant, but this is highly unlikely to be exploitable for this use case.
All the functions taking DefaultHasher
would need to become generic.
Alternatively, using ahash
directly without going through hashbrown
would provide the same results.
I have a trivial need which is to create an element with some attributes on it, outside of scope of the elements provided in this library, and I don't seem to find an API to allow this. Element::new(name) can be created but it doesn't allows to set attributes and the struct Element is private.
Thanks
Is there a reason for that? Or can I just add #[derive(Clone, Debug)]
above all the struct definitions I find in implement!
macros?
Currently, the reading and writing APIs are oddly asymmetrical, with reading being a pull-parser with textual node names, and writing being a DOM-style API requiring strongly typed tags.
This makes it very difficult when one wants to do something like taking an SVG file with pre-defined node IDs that was composed graphically in Inkscape, insert some stuff generated programmatically from a data source, and then write the output to a new SVG file.
Heck, I'm finding it hellishly annoying just trying to create an identity function which transforms the pull-parser input to the DOM output because:
Event::Tag
to valid output without manually mapping them back to Node
impls using a big match
statement.dyn Node
is unsized, Box<dyn Node>
doesn't impl Node
, and your DOM is immutable once constructed, I feel like I have to implement my own intermediate AST just to get the two halves of the same crate to talk to each other.With the current state of the APIs, it feels as if there's no point to forcing people to download the reader to get the writer or vice-versa, and it's just not worth it to try to get any form of compile-time correctness for SVG beyond what an XML crate without DTD validation would give me.
The <textPath>
element cannot set inner text
let text_path = TextPath::new(); // TextPath does not have arg to set text
let text = Text::new("xxxx"); // But Text does
the <textPath>
should look like this:
<text>
<textPath href="#MyPath">Quick brown fox jumps over the lazy dog.</textPath>
</text>
Hey,
Could you help me please. I cannot understand how to add a filter to the svg Document. Is it possible with your library? For example, I want to add feGaussianBlur. As I understand i should start something like this:
let filter = Filter::new().add(What exactly I should put here??);
let definitions = Definitions::new().add(filter);
let document = Document::new()
.set("viewBox", (0, 0, 70, 70))
.add(definitions)
........
I (ab)used the Text
node to insert Svg content into Svg
nodes to make nested Svg's. This is very useful when the content comes from users.
With v0.15 this does not work anymore because the text node now escapes it's content.
I think adding an additional method to the Svg
Node to insert an arbitrary string would be enough to make this use case work again. Alternatively, add the ability to turn off escaping when creating new Text
nodes.
If I am not mistaken, current API does not include support for transformations of the svgs.
This can likely be solved for those who need to apply transformations to their code by the .add("transformation", "rotate(45)")
, for example.
However, it would be nice to create some rust interface that enumerates the possible transformations and their parameters that is included in this repo, like the commands in the paths module.
It would be helpful to have a few more small examples. One thing in particular would be how to add multiple objects. Like a square and a circle, both with different stroke styles.
As it stands one might thing that the way to do this would be:
let front = square(start, size);
let path = Path::new()
.set("fill", "none")
.set("stroke", "black")
.set("stroke-width", 3)
.set("d", front);
let back = Data::new()
.move_to((start.0 - size / 5, start.1 + size / 5))
.line_by((0, size))
.line_by((size, 0))
.line_by((0, -size))
.close();
let other_path = Path::new()
.set("fill", "none")
.set("stroke", "black")
.set("stroke-width", 3)
.set("d", back);
path.add(other_path)
```
But no svg renderer accepts that as a valid output, they render only one of the 2 boxess.
Using the standard .add
method is nice when you have a static tree structure.
But how to add a slice of nodes to a parent node?
Something like append
would be nice.
May I create PR?
Came across an issue where the parser does not match correctly when a "<" is included in an attribute value. This seems to be a problem with all these special characters. Using the expected alternative to escape the characters, such as "<" has the same issue.
I'm using this code to add tooltips to boxes. If the string contents e.g. contains widgets >=3.0.9, <3.1.dev0
, the <
is not escaped and produces and invalid svg:
<rect fill="#FF780088" height="10" width="0.3088995" x="328.0725" y="120">
<title>
widgets >=3.0.9, <3.1.dev0
</title>
</rect>
It would be great to get rid of the unsafe code in Parser::new
.
As far as I can tell, I can't use svg::node::Text
because its Node
implementation is stubbed out, and I can't use svg::node::element::Text
because there's no way to set the actual text of the element.
If you just haven't gotten around to making text work yet, I'm happy to do that.
I really want it.
Is there any interest in abstracting the backend to support other outputs? I'm interested in using svg
with a different backend (bevy
) and would be happy to undertake the task as a PR (if it's of interest) rather than doing it in-my-code.
I'd like to programmatically generate layouts using this library and need to be able to get the size of elements in order to resize backgrounds based on their contents.
This is defined as getBBox in the standard.
If this seems like something that is outside the scope of this project then I could try hacking together the algorithm using the standard as reference.
When io::Chars
lands on stable, consider switching Reader
from str::Chars
to io::Chars
so that the crate could truly work with abstract Read
ers and Write
rs instead of in-memory String
s.
Hi,
Wondering if adding CSS support has been considered or if it's just plainly out of scope?
Thanks
I am struggling with this library and am wondering if I misunderstood something.
I expected to use the library like this (similar to the example on the docs.rs-page):
let mut data = Data::new();
for i in 0..3 {
&mut data.move_to((10, i + 10)).line_by((5,0));
}
data.close();
// etc
Apparently data
is moved through move_to()
and therefor cannot be used in a loop. A similar thing happens if I want to add data to the document within a loop.
What is the correct way of adding elements in a loop?
I run into this when trying to parse the logo of the lyon crate: https://github.com/nical/lyon/blob/master/assets/lyon-logo.svg
The SVG contains this metadata tag (generated by inkscape):
<metadata
id="metadata4812">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
The panic happens when parsing rdf:about=""
at https://github.com/bodoni/svg/blob/master/src/node/element/tag.rs#L65
thread 'main' panicked at 'begin <= end (1 <= 0) when slicing `"`', ../src/libcore/str/mod.rs:1692
Currently the following fragment
<!-- foo > -->
is incorrectly parsed as
Event::Comment, Event::Text("-->")
rather than the correct
Event::Comment
This happens because the following code allows Comment
s to end with a simple >
instead of requiring -->
:
Lines 72 to 82 in f945795
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.