Skip to content

Commit

Permalink
Introduce SVG rasterizer logic
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael5601 committed Dec 3, 2024
1 parent 2ce8542 commit 4b5b094
Show file tree
Hide file tree
Showing 15 changed files with 246 additions and 13 deletions.
8 changes: 8 additions & 0 deletions bundles/org.eclipse.swt.svg/.classpath
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="lib" path="libs/jsvg-1.6.1.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>
28 changes: 28 additions & 0 deletions bundles/org.eclipse.swt.svg/.project
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.eclipse.swt.svg</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ManifestBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.SchemaBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
eclipse.preferences.version=1
encoding/<project>=UTF-8
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=17
org.eclipse.jdt.core.compiler.compliance=17
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
org.eclipse.jdt.core.compiler.release=enabled
org.eclipse.jdt.core.compiler.source=17
10 changes: 10 additions & 0 deletions bundles/org.eclipse.swt.svg/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: SvgPlugin
Bundle-SymbolicName: org.eclipse.swt.svg
Bundle-Version: 1.0.0.qualifier
Automatic-Module-Name: org.eclipse.swt.svgPlugin
Bundle-RequiredExecutionEnvironment: JavaSE-17
Export-Package: org.eclipse.swt.svg
Import-Package: org.eclipse.swt.graphics
Bundle-ClassPath: ., libs/jsvg-1.6.1.jar
5 changes: 5 additions & 0 deletions bundles/org.eclipse.swt.svg/build.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
source.. = src/
output.. = bin/
bin.includes = META-INF/,\
.,\
libs/jsvg-1.6.1.jar
Binary file added bundles/org.eclipse.swt.svg/libs/jsvg-1.6.1.jar
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package org.eclipse.swt.svg;

import static java.awt.RenderingHints.*;

import java.awt.*;
import java.awt.image.*;
import java.io.*;
import java.nio.charset.*;
import java.util.*;
import org.eclipse.swt.graphics.ISVGRasterizer;
import org.eclipse.swt.graphics.SVGRasterizerRegistry;

import com.github.weisj.jsvg.*;
import com.github.weisj.jsvg.geometry.size.*;
import com.github.weisj.jsvg.parser.*;

/**
* @since 3.128
*/
public class SVGRasterizer implements ISVGRasterizer {

public static void register() {
SVGRasterizerRegistry.register(new SVGRasterizer());
}

private final static Map<Object, Object> RENDERING_HINTS = Map.of(KEY_ANTIALIASING, VALUE_ANTIALIAS_ON,
KEY_ALPHA_INTERPOLATION, VALUE_ALPHA_INTERPOLATION_QUALITY, KEY_COLOR_RENDERING, VALUE_COLOR_RENDER_QUALITY,
KEY_DITHERING, VALUE_DITHER_DISABLE, KEY_FRACTIONALMETRICS, VALUE_FRACTIONALMETRICS_ON, KEY_INTERPOLATION,
VALUE_INTERPOLATION_BICUBIC, KEY_RENDERING, VALUE_RENDER_QUALITY, KEY_STROKE_CONTROL, VALUE_STROKE_PURE,
KEY_TEXT_ANTIALIASING, VALUE_TEXT_ANTIALIAS_ON);

@Override
public BufferedImage rasterizeSVG(byte[] bytes, int zoom) throws IOException {
SVGLoader loader = new SVGLoader();
SVGDocument svgDocument = null;
if (this.isSVGFile(bytes)) {
try (InputStream stream = new ByteArrayInputStream(bytes)) {
svgDocument = loader.load(stream, null, LoaderContext.createDefault());
} catch (Exception e) {
e.printStackTrace();
}
if (svgDocument != null) {
double scalingFactor = zoom / 100.0;
FloatSize size = svgDocument.size();
double originalWidth = size.getWidth();
double originalHeight = size.getHeight();
int scaledWidth = (int) Math.round(originalWidth * scalingFactor);
int scaledHeight = (int) Math.round(originalHeight * scalingFactor);
BufferedImage image = new BufferedImage(scaledWidth, scaledHeight, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = image.createGraphics();
g.setRenderingHints(RENDERING_HINTS);
g.scale(scalingFactor, scalingFactor);
svgDocument.render(null, g);
g.dispose();
return image;
}
}
return null;
}

private boolean isSVGFile(byte[] data) throws IOException {
String content = new String(data, 0, Math.min(data.length, 512), StandardCharsets.UTF_8);
return content.contains("<svg");
}

@Override
public boolean isSVGFile(InputStream inputStream) throws IOException {
if (inputStream == null) {
throw new IllegalArgumentException("InputStream cannot be null");
}
byte[] data = inputStream.readNBytes(512);
return isSVGFile(data);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.eclipse.swt.graphics;

import java.awt.image.*;
import java.io.*;

/**
* @since 3.129
*/
public interface ISVGRasterizer {
public BufferedImage rasterizeSVG(byte[] bytes, int zoom) throws IOException;

public boolean isSVGFile(InputStream inputStream) throws IOException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,14 @@ scanlinePad, checkData(data), 0, null,
* @see ImageLoader#load(InputStream)
*/
public ImageData(InputStream stream) {
ImageData[] data = ImageDataLoader.load(stream);
this(stream, 0);
}

/**
* @since 3.129
*/
public ImageData(InputStream stream, int zoom) {
ImageData[] data = ImageDataLoader.load(stream, zoom);
if (data.length < 1) SWT.error(SWT.ERROR_INVALID_IMAGE);
ImageData i = data[0];
setAllFields(
Expand Down Expand Up @@ -377,7 +384,14 @@ public ImageData(InputStream stream) {
* </ul>
*/
public ImageData(String filename) {
ImageData[] data = ImageDataLoader.load(filename);
this(filename, 0);
}

/**
* @since 3.129
*/
public ImageData(String filename, int zoom) {
ImageData[] data = ImageDataLoader.load(filename, zoom);
if (data.length < 1) SWT.error(SWT.ERROR_INVALID_IMAGE);
ImageData i = data[0];
setAllFields(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,16 @@ public static ImageData[] load(InputStream stream) {
return new ImageLoader().load(stream);
}

public static ImageData[] load(String filename) {
public static ImageData[] load(InputStream stream, int zoom) {
return new ImageLoader().load(stream, zoom);
}

public static ImageData[] load(String filename) {
return new ImageLoader().load(filename);
}

public static ImageData[] load(String filename, int zoom) {
return new ImageLoader().load(filename, zoom);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.eclipse.swt.graphics;

/**
* @since 3.129
*/
public class SVGRasterizerRegistry {

private static ISVGRasterizer rasterizer;

public static void register(ISVGRasterizer implementation) {
if(rasterizer == null) {
rasterizer = implementation;
}
}

public static ISVGRasterizer getRasterizer() {
return rasterizer;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
* TabFolder-Like behaviour (e.g. only showing all component at the full size
* of the composite stacked onto each other)
*
* @since 3.128
* @since 3.129
*/
public class TabFolderLayout extends Layout {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ public Image(Device device, ImageData source, ImageData mask) {
public Image (Device device, InputStream stream) {
super(device);
initialNativeZoom = DPIUtil.getNativeDeviceZoom();
ImageData data = DPIUtil.autoScaleUp(device, new ElementAtZoom<>(new ImageData (stream), 100));
ImageData data = DPIUtil.autoScaleUp(device, new ElementAtZoom<>(new ImageData (stream, getZoom()), 100));
init(data, getZoom());
init();
this.device.registerResourceWithZoomSupport(this);
Expand Down Expand Up @@ -510,7 +510,7 @@ public Image (Device device, String filename) {
super(device);
if (filename == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
initialNativeZoom = DPIUtil.getNativeDeviceZoom();
ImageData data = DPIUtil.autoScaleUp(device, new ElementAtZoom<>(new ImageData (filename), 100));
ImageData data = DPIUtil.autoScaleUp(device, new ElementAtZoom<>(new ImageData (filename, getZoom()), 100));
init(data, getZoom());
init();
this.device.registerResourceWithZoomSupport(this);
Expand Down Expand Up @@ -553,10 +553,10 @@ public Image(Device device, ImageFileNameProvider imageFileNameProvider) {
if (fileName.zoom() == getZoom()) {
ImageHandle imageMetadata = initNative (fileName.element(), getZoom());
if (imageMetadata == null) {
init(new ImageData (fileName.element()), getZoom());
init(new ImageData (fileName.element(), getZoom()), getZoom());
}
} else {
ImageData resizedData = DPIUtil.autoScaleImageData (device, new ImageData (fileName.element()), fileName.zoom());
ImageData resizedData = DPIUtil.autoScaleImageData (device, new ImageData (fileName.element(), getZoom()), fileName.zoom());
init(resizedData, getZoom());
}
init();
Expand Down Expand Up @@ -753,7 +753,7 @@ private ImageHandle getImageMetadata(int zoom) {

if (imageFileNameProvider != null) {
ElementAtZoom<String> imageCandidate = DPIUtil.validateAndGetImagePathAtZoom (imageFileNameProvider, zoom);
ImageData imageData = new ImageData (imageCandidate.element());
ImageData imageData = new ImageData (imageCandidate.element(), zoom);
if (imageCandidate.zoom() == zoom) {
/* Release current native resources */
ImageHandle imageMetadata = initNative(imageCandidate.element(), zoom);
Expand Down Expand Up @@ -1389,7 +1389,7 @@ public ImageData getImageData (int zoom) {
return DPIUtil.scaleImageData (device, data.element(), zoom, data.zoom());
} else if (imageFileNameProvider != null) {
ElementAtZoom<String> fileName = DPIUtil.validateAndGetImagePathAtZoom (imageFileNameProvider, zoom);
return DPIUtil.scaleImageData (device, new ImageData (fileName.element()), zoom, fileName.zoom());
return DPIUtil.scaleImageData (device, new ImageData (fileName.element(), zoom), zoom, fileName.zoom());
}

// if a GC is initialized with an Image (memGC != null), the image data must not be resized, because it would
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,12 @@
package org.eclipse.swt.graphics;


import java.awt.image.*;
import java.io.*;
import java.util.*;

import javax.imageio.*;

import org.eclipse.swt.*;
import org.eclipse.swt.internal.image.*;

Expand Down Expand Up @@ -149,9 +152,43 @@ void reset() {
* </ul>
*/
public ImageData[] load(InputStream stream) {
return load(stream, 0);
}

/**
* @since 3.129
*/
public ImageData[] load(InputStream stream, int zoom) {
if (stream == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
reset();
data = FileFormat.load(stream, this);
reset();
byte[] bytes = null;
try {
bytes = stream.readAllBytes();
} catch (IOException e) {
SWT.error(SWT.ERROR_IO, e);
}
ISVGRasterizer rasterizer = SVGRasterizerServiceLoader.getRasterizer();
if (rasterizer != null && zoom != 0) {
try {
BufferedImage image = rasterizer.rasterizeSVG(bytes, zoom);
if(image != null) {
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
ImageIO.write(image, "png", baos);
try (InputStream in = new ByteArrayInputStream(baos.toByteArray())) {
data = FileFormat.load(in, this);
return data;
}
}
}
} catch (IOException e) {
// try standard method
}
}
try (InputStream fallbackStream = new ByteArrayInputStream(bytes)) {
data = FileFormat.load(fallbackStream, this);
} catch (IOException e) {
SWT.error(SWT.ERROR_IO, e);
}
return data;
}

Expand All @@ -174,9 +211,15 @@ public ImageData[] load(InputStream stream) {
* </ul>
*/
public ImageData[] load(String filename) {
return load(filename, 0);
}
/**
* @since 3.129
*/
public ImageData[] load(String filename, int zoom) {
if (filename == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
try (InputStream stream = new FileInputStream(filename)) {
return load(stream);
return load(stream, zoom);
} catch (IOException e) {
SWT.error(SWT.ERROR_IO, e);
}
Expand Down

0 comments on commit 4b5b094

Please sign in to comment.