Bug 568215 - [JFace] Support SVG ImageDescriptor/Icons/Images
Summary: [JFace] Support SVG ImageDescriptor/Icons/Images
Status: NEW
Alias: None
Product: Platform
Classification: Eclipse Project
Component: UI (show other bugs)
Version: 4.14   Edit
Hardware: All All
: P3 enhancement with 2 votes (vote)
Target Milestone: ---   Edit
Assignee: Platform-UI-Inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on: 568325
Blocks:
  Show dependency tree
 
Reported: 2020-10-25 07:56 EDT by Christoph Laeubrich CLA
Modified: 2020-11-01 10:50 EST (History)
6 users (show)

See Also:


Attachments
screenshot of scaled icons with different zoom (11.82 KB, image/png)
2020-10-26 08:24 EDT, Christoph Laeubrich CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Christoph Laeubrich CLA 2020-10-25 07:56:46 EDT
Currently only SWT supported raster images can be used. With the change form Bug 568194 it is enhanced to support at least scalable symbols, but this is limited to font glyphs and can only have one color.

What in my opinion would boost the whole image/icon thing to a new level would be at least basic svg support.

I have already created a swt-based rendererthat uses the batik-parser package to read svg into dom and translate this into swt gc paint commands that works quite well on a subset that is suitable for my icon needs.

As Eclipse already contains the required batik dependencies as far as I can can try to polish the code an contribute it to the platform if there is any interest. 

Based on this a SVGImageDescriptior can be written, I also have created a SVGCanvas component that can be used to display the SVG inside SWT Applications.

The problem I see here is that this would require to add some more dependencies to jface what might be undesired.

An alternative would be to enhance the URLImageDescripto to looking for special content types of the returned connection, then the svg support can reside in a separate module and provide a URLStreamHandler that supplies image-data objects in an internal format that can the be used to reconstruct a rasterized image on the receiver side.
Comment 1 Alexander Fedorov CLA 2020-10-25 15:18:49 EDT
My vote is for the dedicated bundle that will focus on SVG support.
Comment 2 Wim Jongman CLA 2020-10-25 18:03:33 EDT
(In reply to Alexander Fedorov from comment #1)
> My vote is for the dedicated bundle that will focus on SVG support.

Yes, I tend to agree. Christian, the Batik round-trip you describe sounds complicated. Having said this. I don't know how complex writing such a thing is.

We do have SVG support in Nebula that we can move to JFace. I don't know how complete it is.

https://github.com/eclipse/nebula/tree/master/widgets/cwt/org.eclipse.nebula.cwt/src/org/eclipse/nebula/cwt/svg
Comment 3 Christoph Laeubrich CLA 2020-10-26 00:01:35 EDT
(In reply to Wim Jongman from comment #2)
> the Batik round-trip you describe sounds complicated.

What do you mean by roundtrip? Batik is used to parse the SVG, its sublanguages and the CSS and I just added an SWT renderer.

> I don't know how complex writing such a thing is.

Writing an own parser for SVG/CSS or using batik? Batik is used in the eclipse-images project to render the PNG icons.
That would also be possible here to render the image first into an BufferedImage and then transform this into SWT-Image.

> We do have SVG support in Nebula that we can move to JFace. I don't know how
> complete it is.

I'll take a look at it and make some test, if we can use some kind of code that could be embedded directly it would make things a lot easier and more flexible instead of having an own module, I just know that writing (an maintaining) own parser for SVG/CSS could become tedious but in the end I don't mind the parser/renderer used if I can avoid converting my SVGs into numerous raster images :-)

What would be really nice (but I can't contribute for that much) would be if SWT itself would include native SVG support.
Comment 5 Christoph Laeubrich CLA 2020-10-26 00:55:03 EDT
BTW swt-gtk3 can already load SVG images (with poor text support but working quite well for icons) and could also scale them if desired [1], I opened an enhancement request that gtk supports scaled (file) instances.

For Windows there are also SVG support [2] but I don't know if it is already available.
For OSX I haven't found yet any hint that it is possible natively to load svg images.

rsvg library [3] seems to be available for linux/windows (haven't find information  about mac support).

[1] https://developer.gnome.org/gdk-pixbuf/stable/gdk-pixbuf-File-Loading.html#gdk-pixbuf-new-from-file-at-scale
[2] https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.media.imaging.svgimagesource?view=winrt-19041
[3] https://en.wikipedia.org/wiki/Librsvg
Comment 6 Christoph Laeubrich CLA 2020-10-26 01:39:16 EDT
(In reply to Wim Jongman from comment #2)
> SVG support in Nebula

I checked with my sample files and found the following issues:

- no support for text (might be not so important for icons)
- can't parse % length (that's a bit strange as it uses a percentage length as its default, but I was able to work around this by falling back to viewBox instead)
- misses support for rgb(1,180,156) color pattern (should not be to complicated to add)
- it seems the code tries to (reflectively) load org.eclipse.nebula.cwt.SwtAdapter for gradients but I can't found that class in the repository
- references are not supported see [1] for example, that might be a bit harder as it requires recursive parsing/search inside the document. As far as I understand, currently no XML parser is used but the file is scanned in a linear way.

The last point is really something that I find problematic, parsing/interpretation of SVG alone is not always easy, why add the burden to additionally implement an XML parser where java itself offers descent, mature support for it at different flavors? (DOM, push/pull,...)?

[1] eclipse.platform.images/org.eclipse.images/eclipse-svg/org.eclipse.ui/icons/full/elcl16/backward_nav.svg
Comment 7 Thomas Schindl CLA 2020-10-26 03:05:28 EDT
(In reply to Christoph Laeubrich from comment #0)
> Currently only SWT supported raster images can be used. With the change form
> Bug 568194 it is enhanced to support at least scalable symbols, but this is
> limited to font glyphs and can only have one color.
> 
> What in my opinion would boost the whole image/icon thing to a new level
> would be at least basic svg support.
> 

Let‘s please not add a half baked solution, like our CSS story. I agree batik is the only possible cross platform way to get at least decent support which works reliable on all platforms and i don‘t think the bufferedimage roundtrip is so bad, swt-GC simply misses too many APIs and fails at sooo many HiDPI edge cases (on win32)

I would probably cache the result so it is only a one time hit.
Comment 8 Christoph Laeubrich CLA 2020-10-26 04:02:03 EDT
(In reply to Thomas Schindl from comment #7)
> swt-GC simply misses too many APIs 

That's something I also noticed in the past, together with the anoint fact that its a final class (instead of an abstract or interface or ...) so its hard to interfere with it outside of SWT internals.

> I would probably cache the result so it is only a one time hit.
As ImageDescritors have full control over it, caching of the resulting imagedata is possible and is also the default behavior for raster images.
Comment 9 Christoph Laeubrich CLA 2020-10-26 08:24:06 EDT
Created attachment 284566 [details]
screenshot of scaled icons with different zoom

I have creates a proof-of-concept image descriptor that uses a Transcoder to convert BufferedImage from Batik to ImageData, works like a charm see attached screenshot :-)

I think that's the way to go, I'll try to investigate how this can be integrated for best convenience.

The only problem is that at the moment not all required batik bundles are available on orbit and thus might require a committer to create an IP-Request for them, the complete list of missing ones is the following:

org.apache.xmlgraphics.batik-anim (Version "1.13.0")
org.apache.xmlgraphics.batik-bridge (Version "1.13.0")
org.apache.xmlgraphics.batik-gvt (Version="1.13.0")
org.apache.xmlgraphics.batik-transcoder (Version="1.13.0")
org.apache.xmlgraphics.batik-svg-dom (Version="1.13.0")
org.apache.xmlgraphics.batik-dom (Version="1.13.0")
org.apache.xmlgraphics.batik-ext (Version="1.13.0")
org.apache.xmlgraphics.batik-xml (Version="1.13.0")
org.apache.xmlgraphics.batik-parser (Version="1.13.0")
org.apache.xmlgraphics.batik-script (Version="1.13.0")
org.apache.xmlgraphics.batik-awt-util (Version="1.13.0")
org.apache.xmlgraphics.xmlgraphics-commons (Version="2.4.0")

as some of them are already there as an older version it might be not that problematic but maybe a platfrom committer can still trigger the necessary steps already?
Comment 10 Thomas Schindl CLA 2020-10-26 12:00:31 EDT
(In reply to Christoph Laeubrich from comment #8)
> (In reply to Thomas Schindl from comment #7)
> > swt-GC simply misses too many APIs 
> 
> That's something I also noticed in the past, together with the anoint fact
> that its a final class (instead of an abstract or interface or ...) so its
> hard to interfere with it outside of SWT internals.
> 
> > I would probably cache the result so it is only a one time hit.
> As ImageDescritors have full control over it, caching of the resulting
> imagedata is possible and is also the default behavior for raster images.

Well I thought about caching them on disk so on the next start, ... you can reuse the rastered image.
Comment 11 Christoph Laeubrich CLA 2020-10-26 12:20:45 EDT
Even though this would be possible this will open a lot hassle with where to store, stale caches, how to find good cache keys and so on that I just would start if there is a clear indication that is significantly helps to improve performance.
Comment 12 Wim Jongman CLA 2020-10-26 12:32:43 EDT
(In reply to Christoph Laeubrich from comment #11)
> Even though this would be possible this will open a lot hassle with where to
> store, stale caches, how to find good cache keys and so on that I just would
> start if there is a clear indication that is significantly helps to improve
> performance.

It is a good point though, because caching is quite the memory leak. Ideally, we want to render these things one time.
Comment 13 Christoph Laeubrich CLA 2020-10-26 13:48:51 EDT
And because of all thos "hard-disk-caches" I have to regulary clear then to reclaim space on my hard drive for al those maven, p2, bundle_pool whatever... :-)

Anyways I really like to focus on getting at least SVG support to the platform even if it is considerable slower than loading the same from a png, gif or whatever.. caching or any optimization can then be build upon those.
Comment 14 Wim Jongman CLA 2020-10-26 14:15:21 EDT
(In reply to Christoph Laeubrich from comment #13)

> Anyways I really like to focus on getting at least SVG support

Agreed, let's not think in blockers. That would be very cool.
Comment 15 Christoph Laeubrich CLA 2020-10-27 01:26:20 EDT
What certainly would work (but requires an additional step of encoding/decoding) to supply an URL handler for e.g. svg:<whateverurl> that renders the svg given in <whateverurl> into a PNG file (what will then be decoded into image data afterwards).
I have checked SWT and there seems no generic way to plug in new image file-types like with java ImageIO.

Then JFace ImageDescriptors can work the following way:
- peek into the first bytes of the file/url stream
- if there is '<svg' withing the first few bytes open a new connection to the svg: url and use that data instead
- if zoomed variants are requested (and the descriptor not revealed its an svg before), first try the usual ways, if none of them succeeds, open a connection to svg:<url basename>.svg

Alternatively either add an image-format extension mechanism to SWT (this would then work across all codes) or JFace (would work for all ImageDescriptors) and use those.

--- completely different approach ---
As I have already written a small code to translate BufferedImage -> ImageData we can completely bypass the SWT (native) Image loading, use ImageIO to read streams/files into BufferedImage and convert them to ImageData, then it would be possible for us to plugin svg-reader support into ImageIO or even a more complete lib [1] that adds a whole bunch of supported formats.

Alternatively this can be even placed inside SWT: First try the native format readers, if none match fall back to ImageIO/BufferedImage conversion...

[1] https://github.com/haraldk/TwelveMonkeys
Comment 16 Wim Jongman CLA 2020-10-27 06:01:30 EDT
(In reply to Christoph Laeubrich from comment #15)

> What certainly would work (but requires an additional step of
> encoding/decoding) to supply an URL handler for e.g. svg:<whateverurl> that
> renders the svg given in <whateverurl> into a PNG file (what will then be
> decoded into image data afterwards).

That is another good idea. Maybe also instruct the url handler to spit out something other that PNG.

> 
> --- completely different approach ---
> As I have already written a small code to translate BufferedImage ->
> ImageData we can completely bypass the SWT (native) Image loading, use

Adding methods to SWT/JFace using your ImageIO approach would be considerd "native" too, IMO.

Wouldn't the url handler require this logic anyway? If so, I think you should go this route first and later look at the url handler.