Skip to content

Commit 2a30736

Browse files
committed
Introduce functionality for icon disablement with SVGs
merge new API (flag parameter) into existing API ImageDataProvider functionality is ignored for now.
1 parent c4b4a46 commit 2a30736

File tree

10 files changed

+174
-26
lines changed

10 files changed

+174
-26
lines changed

bundles/org.eclipse.swt.svg/src/org/eclipse/swt/svg/JSVGRasterizer.java

+104-1
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,30 @@
3535
import java.awt.RenderingHints.Key;
3636
import java.awt.image.BufferedImage;
3737
import java.awt.image.DataBufferInt;
38+
import java.io.ByteArrayInputStream;
39+
import java.io.ByteArrayOutputStream;
3840
import java.io.IOException;
3941
import java.io.InputStream;
42+
import java.io.OutputStream;
4043
import java.util.Map;
4144

4245
import org.eclipse.swt.SWT;
4346
import org.eclipse.swt.graphics.ImageData;
4447
import org.eclipse.swt.graphics.PaletteData;
4548
import org.eclipse.swt.internal.image.SVGRasterizer;
4649

50+
import javax.xml.parsers.DocumentBuilder;
51+
import javax.xml.parsers.DocumentBuilderFactory;
52+
import javax.xml.parsers.ParserConfigurationException;
53+
import javax.xml.transform.Transformer;
54+
import javax.xml.transform.TransformerException;
55+
import javax.xml.transform.TransformerFactory;
56+
import javax.xml.transform.dom.DOMSource;
57+
import javax.xml.transform.stream.StreamResult;
58+
import org.w3c.dom.Document;
59+
import org.w3c.dom.Element;
60+
import org.xml.sax.SAXException;
61+
4762
import com.github.weisj.jsvg.SVGDocument;
4863
import com.github.weisj.jsvg.geometry.size.FloatSize;
4964
import com.github.weisj.jsvg.parser.LoaderContext;
@@ -71,7 +86,19 @@ public class JSVGRasterizer implements SVGRasterizer {
7186
);
7287

7388
@Override
74-
public ImageData rasterizeSVG(InputStream inputStream, int zoom) throws IOException {
89+
public ImageData rasterizeSVG(InputStream inputStream, int zoom, int flag) throws IOException {
90+
switch(flag) {
91+
case SWT.IMAGE_DISABLE:
92+
inputStream = applyDisabledLook(inputStream);
93+
break;
94+
case SWT.IMAGE_GRAY:
95+
inputStream = applyGrayLook(inputStream);
96+
break;
97+
case SWT.IMAGE_COPY:
98+
break;
99+
default:
100+
SWT.error(SWT.ERROR_INVALID_IMAGE);
101+
}
75102
SVGDocument svgDocument = loadSVG(inputStream);
76103
if (svgDocument != null) {
77104
return generateRasterizedImageData(svgDocument, zoom);
@@ -139,4 +166,80 @@ private ImageData convertToSWTImageData(BufferedImage rasterizedImage) {
139166
}
140167
return imageData;
141168
}
169+
170+
private static InputStream applyDisabledLook(InputStream svgInputStream) throws IOException {
171+
Document svgDocument = parseSVG(svgInputStream);
172+
addDisabledFilter(svgDocument);
173+
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
174+
writeSVG(svgDocument, outputStream);
175+
return new ByteArrayInputStream(outputStream.toByteArray());
176+
}
177+
}
178+
179+
private static InputStream applyGrayLook(InputStream svgInputStream) throws IOException {
180+
Document svgDocument = parseSVG(svgInputStream);
181+
addGrayFilter(svgDocument);
182+
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
183+
writeSVG(svgDocument, outputStream);
184+
return new ByteArrayInputStream(outputStream.toByteArray());
185+
}
186+
}
187+
188+
private static Document parseSVG(InputStream inputStream) throws IOException {
189+
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
190+
DocumentBuilder builder;
191+
try {
192+
builder = factory.newDocumentBuilder();
193+
return builder.parse(inputStream);
194+
} catch (SAXException | IOException | ParserConfigurationException e) {
195+
throw new IOException(e.getMessage());
196+
}
197+
}
198+
199+
private static void addDisabledFilter(Document document) {
200+
addFilter(document, 0.64f, 0.4f);
201+
}
202+
203+
private static void addGrayFilter(Document document) {
204+
addFilter(document, 0.64f, 0.1f);
205+
}
206+
207+
private static void addFilter(Document document, float slope, float intercept) {
208+
Element defs = (Element) document.getElementsByTagName("defs").item(0);
209+
if (defs == null) {
210+
defs = document.createElement("defs");
211+
document.getDocumentElement().appendChild(defs);
212+
}
213+
214+
Element filter = document.createElement("filter");
215+
filter.setAttribute("id", "customizedLook");
216+
217+
Element colorMatrix = document.createElement("feColorMatrix");
218+
colorMatrix.setAttribute("type", "saturate");
219+
colorMatrix.setAttribute("values", "0");
220+
filter.appendChild(colorMatrix);
221+
222+
Element componentTransfer = document.createElement("feComponentTransfer");
223+
for (String channel : new String[] { "R", "G", "B" }) {
224+
Element func = document.createElement("feFunc" + channel);
225+
func.setAttribute("type", "linear");
226+
func.setAttribute("slope", Float.toString(slope));
227+
func.setAttribute("intercept", Float.toString(intercept));
228+
componentTransfer.appendChild(func);
229+
}
230+
filter.appendChild(componentTransfer);
231+
defs.appendChild(filter);
232+
document.getDocumentElement().setAttribute("filter", "url(#customizedLook)");
233+
}
234+
235+
private static void writeSVG(Document document, OutputStream outputStream) throws IOException {
236+
TransformerFactory transformerFactory = TransformerFactory.newInstance();
237+
Transformer transformer;
238+
try {
239+
transformer = transformerFactory.newTransformer();
240+
transformer.transform(new DOMSource(document), new StreamResult(outputStream));
241+
} catch (TransformerException e) {
242+
throw new IOException(e.getMessage());
243+
}
244+
}
142245
}

bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageDataLoader.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,14 @@ public static ImageData load(String filename) {
3737
return data[0];
3838
}
3939

40-
public static ElementAtZoom<ImageData> load(InputStream stream, int fileZoom, int targetZoom) {
41-
List<ElementAtZoom<ImageData>> data = new ImageLoader().load(stream, fileZoom, targetZoom);
40+
public static ElementAtZoom<ImageData> load(InputStream stream, int fileZoom, int targetZoom, int flag) {
41+
List<ElementAtZoom<ImageData>> data = new ImageLoader().load(stream, fileZoom, targetZoom, flag);
4242
if (data.isEmpty()) SWT.error(SWT.ERROR_INVALID_IMAGE);
4343
return data.get(0);
4444
}
4545

46-
public static ElementAtZoom<ImageData> load(String filename, int fileZoom, int targetZoom) {
47-
List<ElementAtZoom<ImageData>> data = new ImageLoader().load(filename, fileZoom, targetZoom);
46+
public static ElementAtZoom<ImageData> load(String filename, int fileZoom, int targetZoom, int flag) {
47+
List<ElementAtZoom<ImageData>> data = new ImageLoader().load(filename, fileZoom, targetZoom, flag);
4848
if (data.isEmpty()) SWT.error(SWT.ERROR_INVALID_IMAGE);
4949
return data.get(0);
5050
}

bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageDataProvider.java

+13
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,17 @@ public interface ImageDataProvider {
4343
*/
4444
ImageData getImageData (int zoom);
4545

46+
// /**
47+
// * @since 4.0
48+
// */
49+
// default ImageData getCustomizedImageData(int zoom, int flag) {
50+
// throw new UnsupportedOperationException();
51+
// }
52+
//
53+
// /**
54+
// * @since 4.0
55+
// */
56+
// default boolean supportsRasterizationFlag(int flag) {
57+
// return false;
58+
// }
4659
}

bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageLoader.java

+6-6
Original file line numberDiff line numberDiff line change
@@ -150,14 +150,14 @@ void reset() {
150150
* </ul>
151151
*/
152152
public ImageData[] load(InputStream stream) {
153-
load(stream, FileFormat.DEFAULT_ZOOM, FileFormat.DEFAULT_ZOOM);
153+
load(stream, FileFormat.DEFAULT_ZOOM, FileFormat.DEFAULT_ZOOM, SWT.IMAGE_COPY);
154154
return data;
155155
}
156156

157-
List<ElementAtZoom<ImageData>> load(InputStream stream, int fileZoom, int targetZoom) {
157+
List<ElementAtZoom<ImageData>> load(InputStream stream, int fileZoom, int targetZoom, int flag) {
158158
if (stream == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
159159
reset();
160-
List<ElementAtZoom<ImageData>> images = InternalImageLoader.load(stream, this, fileZoom, targetZoom);
160+
List<ElementAtZoom<ImageData>> images = InternalImageLoader.load(stream, this, fileZoom, targetZoom, flag);
161161
data = images.stream().map(ElementAtZoom::element).toArray(ImageData[]::new);
162162
return images;
163163
}
@@ -181,14 +181,14 @@ List<ElementAtZoom<ImageData>> load(InputStream stream, int fileZoom, int target
181181
* </ul>
182182
*/
183183
public ImageData[] load(String filename) {
184-
load(filename, FileFormat.DEFAULT_ZOOM, FileFormat.DEFAULT_ZOOM);
184+
load(filename, FileFormat.DEFAULT_ZOOM, FileFormat.DEFAULT_ZOOM, SWT.IMAGE_COPY);
185185
return data;
186186
}
187187

188-
List<ElementAtZoom<ImageData>> load(String filename, int fileZoom, int targetZoom) {
188+
List<ElementAtZoom<ImageData>> load(String filename, int fileZoom, int targetZoom, int flag) {
189189
if (filename == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
190190
try (InputStream stream = new FileInputStream(filename)) {
191-
return load(stream, fileZoom, targetZoom);
191+
return load(stream, fileZoom, targetZoom, flag);
192192
} catch (IOException e) {
193193
SWT.error(SWT.ERROR_IO, e);
194194
}

bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/FileFormat.java

+6-6
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ static abstract class StaticImageFileFormat extends FileFormat {
8282
abstract ImageData[] loadFromByteStream();
8383

8484
@Override
85-
List<ElementAtZoom<ImageData>> loadFromByteStream(int fileZoom, int targetZoom) {
85+
List<ElementAtZoom<ImageData>> loadFromByteStream(int fileZoom, int targetZoom, int flag) {
8686
return Arrays.stream(loadFromByteStream()).map(d -> new ElementAtZoom<>(d, fileZoom)).toList();
8787
}
8888
}
@@ -102,16 +102,16 @@ List<ElementAtZoom<ImageData>> loadFromByteStream(int fileZoom, int targetZoom)
102102
* Format that do not implement {@link StaticImageFileFormat} MUST return
103103
* {@link ImageData} with the specified {@code targetZoom}.
104104
*/
105-
abstract List<ElementAtZoom<ImageData>> loadFromByteStream(int fileZoom, int targetZoom);
105+
abstract List<ElementAtZoom<ImageData>> loadFromByteStream(int fileZoom, int targetZoom, int flag);
106106

107107
/**
108108
* Read the specified input stream, and return the
109109
* device independent image array represented by the stream.
110110
*/
111-
public List<ElementAtZoom<ImageData>> loadFromStream(LEDataInputStream stream, int fileZoom, int targetZoom) {
111+
public List<ElementAtZoom<ImageData>> loadFromStream(LEDataInputStream stream, int fileZoom, int targetZoom, int flag) {
112112
try {
113113
inputStream = stream;
114-
return loadFromByteStream(fileZoom, targetZoom);
114+
return loadFromByteStream(fileZoom, targetZoom, flag);
115115
} catch (Exception e) {
116116
if (e instanceof IOException) {
117117
SWT.error(SWT.ERROR_IO, e);
@@ -126,14 +126,14 @@ public List<ElementAtZoom<ImageData>> loadFromStream(LEDataInputStream stream, i
126126
* Read the specified input stream using the specified loader, and
127127
* return the device independent image array represented by the stream.
128128
*/
129-
public static List<ElementAtZoom<ImageData>> load(InputStream is, ImageLoader loader, int fileZoom, int targetZoom) {
129+
public static List<ElementAtZoom<ImageData>> load(InputStream is, ImageLoader loader, int fileZoom, int targetZoom, int flag) {
130130
LEDataInputStream stream = new LEDataInputStream(is);
131131
FileFormat fileFormat = determineFileFormat(stream).orElseGet(() -> {
132132
SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT);
133133
return null;
134134
});
135135
fileFormat.loader = loader;
136-
return fileFormat.loadFromStream(stream, fileZoom, targetZoom);
136+
return fileFormat.loadFromStream(stream, fileZoom, targetZoom, flag);
137137
}
138138

139139
/**

bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/SVGFileFormat.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,15 @@ boolean isFileFormat(LEDataInputStream stream) throws IOException {
4343
}
4444

4545
@Override
46-
List<ElementAtZoom<ImageData>> loadFromByteStream(int fileZoom, int targetZoom) {
46+
List<ElementAtZoom<ImageData>> loadFromByteStream(int fileZoom, int targetZoom, int flag) {
4747
if (RASTERIZER == null) {
4848
SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT, null, " [No SVG rasterizer found]");
4949
}
5050
if (targetZoom <= 0) {
5151
SWT.error(SWT.ERROR_INVALID_ARGUMENT, null, " [Cannot rasterize SVG for zoom <= 0]");
5252
}
5353
try {
54-
ImageData rasterizedImageData = RASTERIZER.rasterizeSVG(inputStream, 100 * targetZoom / fileZoom);
54+
ImageData rasterizedImageData = RASTERIZER.rasterizeSVG(inputStream, 100 * targetZoom / fileZoom, flag);
5555
return List.of(new ElementAtZoom<>(rasterizedImageData, targetZoom));
5656
} catch (IOException e) {
5757
SWT.error(SWT.ERROR_INVALID_IMAGE, e);

bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/SVGRasterizer.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,5 @@ public interface SVGRasterizer {
3232
* the input is not a valid SVG file or cannot be processed.
3333
* @throws IOException
3434
*/
35-
public ImageData rasterizeSVG(InputStream stream, int zoom) throws IOException;
35+
public ImageData rasterizeSVG(InputStream stream, int zoom, int flag) throws IOException;
3636
}

bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/WinICOFileFormat.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ ImageData loadIcon(int[] iconHeader) {
133133
StaticImageFileFormat png = new PNGFileFormat();
134134
if (png.isFileFormat(inputStream)) {
135135
png.loader = this.loader;
136-
return png.loadFromStream(inputStream, DEFAULT_ZOOM, DEFAULT_ZOOM).get(0).element();
136+
return png.loadFromStream(inputStream, DEFAULT_ZOOM, DEFAULT_ZOOM, SWT.IMAGE_COPY).get(0).element();
137137
}
138138
} catch (Exception e) {
139139
}

bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java

+35-3
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,9 @@ public Image(Device device, Image srcImage, int flag) {
247247
long srcImageHandle = win32_getHandle(srcImage, getZoom());
248248
switch (flag) {
249249
case SWT.IMAGE_COPY: {
250+
if(createWithSVG(device, flag)) {
251+
break;
252+
}
250253
switch (type) {
251254
case SWT.BITMAP:
252255
/* Get the HDC for the device */
@@ -282,12 +285,18 @@ public Image(Device device, Image srcImage, int flag) {
282285
break;
283286
}
284287
case SWT.IMAGE_DISABLE: {
288+
if(createWithSVG(device, flag)) {
289+
break;
290+
}
285291
ImageData data = srcImage.getImageData(srcImage.getZoom());
286292
ImageData newData = applyDisableImageData(data, rect.height, rect.width);
287293
init (newData, getZoom());
288294
break;
289295
}
290296
case SWT.IMAGE_GRAY: {
297+
if(createWithSVG(device, flag)) {
298+
break;
299+
}
291300
ImageData data = srcImage.getImageData(srcImage.getZoom());
292301
ImageData newData = applyGrayImageData(data, rect.height, rect.width);
293302
init (newData, getZoom());
@@ -300,6 +309,29 @@ public Image(Device device, Image srcImage, int flag) {
300309
this.device.registerResourceWithZoomSupport(this);
301310
}
302311

312+
private boolean createWithSVG(Device device, int flag) {
313+
if (imageProvider instanceof DynamicImageProviderWrapper dynamicImageProvider) {
314+
if (dynamicImageProvider.getProvider() instanceof ImageFileNameProvider imageFileNameProvider) {
315+
ElementAtZoom<String> fileName = DPIUtil.validateAndGetImagePathAtZoom(imageFileNameProvider, getZoom());
316+
// if (fileName.element().endsWith(".svg")) {
317+
ElementAtZoom<ImageData> imageData = ImageDataLoader.load(fileName.element(), fileName.zoom(), getZoom(),
318+
flag);
319+
init(imageData.element(), getZoom());
320+
return true;
321+
// }
322+
}
323+
// else if (imageProvider.getProvider() instanceof ImageDataProvider imageDataProvider) {
324+
// if (imageDataProvider.supportsRasterizationFlag(flag)) {
325+
// ImageData data = imageDataProvider.getCustomizedImageData(getZoom(), flag);
326+
// ElementAtZoom<ImageData> imageData = new ElementAtZoom<>(data, getZoom());
327+
// init(imageData.element(), getZoom());
328+
// return true;
329+
// }
330+
// }
331+
}
332+
return false;
333+
}
334+
303335
/**
304336
* Constructs an empty instance of this class with the
305337
* width and height of the specified rectangle. The result
@@ -481,7 +513,7 @@ public Image (Device device, InputStream stream) {
481513
super(device);
482514
initialNativeZoom = DPIUtil.getNativeDeviceZoom();
483515
int deviceZoom = getZoom();
484-
ElementAtZoom<ImageData> imageCandidate = ImageDataLoader.load(stream, FileFormat.DEFAULT_ZOOM, deviceZoom);
516+
ElementAtZoom<ImageData> imageCandidate = ImageDataLoader.load(stream, FileFormat.DEFAULT_ZOOM, deviceZoom, SWT.IMAGE_COPY);
485517
ImageData data = scaleImageData(imageCandidate.element(), deviceZoom, imageCandidate.zoom());
486518
init(data, deviceZoom);
487519
init();
@@ -525,7 +557,7 @@ public Image (Device device, String filename) {
525557
if (filename == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
526558
initialNativeZoom = DPIUtil.getNativeDeviceZoom();
527559
int deviceZoom = getZoom();
528-
ElementAtZoom<ImageData> imageCandidate = ImageDataLoader.load(filename, FileFormat.DEFAULT_ZOOM, deviceZoom);
560+
ElementAtZoom<ImageData> imageCandidate = ImageDataLoader.load(filename, FileFormat.DEFAULT_ZOOM, deviceZoom, SWT.IMAGE_COPY);
529561
ImageData data = scaleImageData(imageCandidate.element(), deviceZoom, imageCandidate.zoom());
530562
init(data, deviceZoom);
531563
init();
@@ -2097,7 +2129,7 @@ ImageData getImageData(int zoom) {
20972129

20982130
ElementAtZoom<ImageData> imageDataAtZoom;
20992131
if (nativeInitializedImage == null) {
2100-
imageDataAtZoom = ImageDataLoader.load(fileForZoom.element(), fileForZoom.zoom(), zoom);
2132+
imageDataAtZoom = ImageDataLoader.load(fileForZoom.element(), fileForZoom.zoom(), zoom, SWT.IMAGE_COPY);
21012133
} else {
21022134
imageDataAtZoom = new ElementAtZoom<>(nativeInitializedImage.getImageData(), fileForZoom.zoom());
21032135
destroyHandleForZoom(zoom);

bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/InternalImageLoader.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121

2222
class InternalImageLoader {
2323

24-
static List<ElementAtZoom<ImageData>> load(InputStream stream, ImageLoader imageLoader, int fileZoom, int targetZoom) {
25-
return FileFormat.load(stream, imageLoader, fileZoom, targetZoom);
24+
static List<ElementAtZoom<ImageData>> load(InputStream stream, ImageLoader imageLoader, int fileZoom, int targetZoom, int flag) {
25+
return FileFormat.load(stream, imageLoader, fileZoom, targetZoom, flag);
2626
}
2727

2828
static void save(OutputStream stream, int format, ImageLoader imageLoader) {

0 commit comments

Comments
 (0)