From 305078826f3f88542dc30968d20352e21b004142 Mon Sep 17 00:00:00 2001 From: Michael Bangas Date: Mon, 16 Sep 2024 17:55:31 +0200 Subject: [PATCH 1/2] Add support for SVG images SWT currently loads icons exclusively as raster graphics (e.g., PNGs) without support for vector formats like SVG (except for Linux). A major drawback of raster graphics is their inability to scale without degrading image quality. Additionally, generating icons of different sizes requires manually rasterization of SVGs as a preparatory step, leading to unnecessary effort and many icon files. This change introduces support for vector graphics in images, enabling SVGs to be used for images. An SVG rasterizer can be provided via an SWT fragment. This change adds an according fragment based on the JSVG library. An according FileFormat implementation is added, which utilized a present SVG rasterization fragment to rasterize images for the desired zoom factor. Fixes https://github.com/eclipse-platform/eclipse.platform.swt/issues/1438 Revert "Add support for SVG images" This reverts commit e03b214dc664848d0e1723a1ec80b4a419d2bd59. Introduce functionality for icon disablement with SVGs merge new API (flag parameter) into existing API ImageDataProvider functionality is ignored for now. --- .../org/eclipse/swt/svg/JSVGRasterizer.java | 105 +++++++++++++++++- .../eclipse/swt/graphics/ImageDataLoader.java | 8 +- .../swt/graphics/ImageDataProvider.java | 13 +++ .../org/eclipse/swt/graphics/ImageLoader.java | 12 +- .../swt/internal/image/FileFormat.java | 12 +- .../swt/internal/image/SVGFileFormat.java | 4 +- .../swt/internal/image/SVGRasterizer.java | 2 +- .../swt/internal/image/WinICOFileFormat.java | 2 +- .../win32/org/eclipse/swt/graphics/Image.java | 36 +++++- .../swt/graphics/InternalImageLoader.java | 4 +- 10 files changed, 173 insertions(+), 25 deletions(-) diff --git a/bundles/org.eclipse.swt.svg/src/org/eclipse/swt/svg/JSVGRasterizer.java b/bundles/org.eclipse.swt.svg/src/org/eclipse/swt/svg/JSVGRasterizer.java index 0da0c7872dc..a76bb5f450d 100644 --- a/bundles/org.eclipse.swt.svg/src/org/eclipse/swt/svg/JSVGRasterizer.java +++ b/bundles/org.eclipse.swt.svg/src/org/eclipse/swt/svg/JSVGRasterizer.java @@ -35,8 +35,11 @@ import java.awt.RenderingHints.Key; import java.awt.image.BufferedImage; import java.awt.image.DataBufferInt; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.util.Map; import org.eclipse.swt.SWT; @@ -44,6 +47,18 @@ import org.eclipse.swt.graphics.PaletteData; import org.eclipse.swt.internal.image.SVGRasterizer; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; + import com.github.weisj.jsvg.SVGDocument; import com.github.weisj.jsvg.geometry.size.FloatSize; import com.github.weisj.jsvg.parser.LoaderContext; @@ -71,7 +86,19 @@ public class JSVGRasterizer implements SVGRasterizer { ); @Override - public ImageData rasterizeSVG(InputStream inputStream, int zoom) throws IOException { + public ImageData rasterizeSVG(InputStream inputStream, int zoom, int flag) throws IOException { + switch(flag) { + case SWT.IMAGE_DISABLE: + inputStream = applyDisabledLook(inputStream); + break; + case SWT.IMAGE_GRAY: + inputStream = applyGrayLook(inputStream); + break; + case SWT.IMAGE_COPY: + break; + default: + SWT.error(SWT.ERROR_INVALID_IMAGE); + } SVGDocument svgDocument = loadSVG(inputStream); if (svgDocument == null) { SWT.error(SWT.ERROR_INVALID_IMAGE); @@ -133,4 +160,80 @@ private ImageData convertToSWTImageData(BufferedImage rasterizedImage) { } return imageData; } + + private static InputStream applyDisabledLook(InputStream svgInputStream) throws IOException { + Document svgDocument = parseSVG(svgInputStream); + addDisabledFilter(svgDocument); + try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + writeSVG(svgDocument, outputStream); + return new ByteArrayInputStream(outputStream.toByteArray()); + } + } + + private static InputStream applyGrayLook(InputStream svgInputStream) throws IOException { + Document svgDocument = parseSVG(svgInputStream); + addGrayFilter(svgDocument); + try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + writeSVG(svgDocument, outputStream); + return new ByteArrayInputStream(outputStream.toByteArray()); + } + } + + private static Document parseSVG(InputStream inputStream) throws IOException { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder; + try { + builder = factory.newDocumentBuilder(); + return builder.parse(inputStream); + } catch (SAXException | IOException | ParserConfigurationException e) { + throw new IOException(e.getMessage()); + } + } + + private static void addDisabledFilter(Document document) { + addFilter(document, 0.64f, 0.4f); + } + + private static void addGrayFilter(Document document) { + addFilter(document, 0.64f, 0.1f); + } + + private static void addFilter(Document document, float slope, float intercept) { + Element defs = (Element) document.getElementsByTagName("defs").item(0); + if (defs == null) { + defs = document.createElement("defs"); + document.getDocumentElement().appendChild(defs); + } + + Element filter = document.createElement("filter"); + filter.setAttribute("id", "customizedLook"); + + Element colorMatrix = document.createElement("feColorMatrix"); + colorMatrix.setAttribute("type", "saturate"); + colorMatrix.setAttribute("values", "0"); + filter.appendChild(colorMatrix); + + Element componentTransfer = document.createElement("feComponentTransfer"); + for (String channel : new String[] { "R", "G", "B" }) { + Element func = document.createElement("feFunc" + channel); + func.setAttribute("type", "linear"); + func.setAttribute("slope", Float.toString(slope)); + func.setAttribute("intercept", Float.toString(intercept)); + componentTransfer.appendChild(func); + } + filter.appendChild(componentTransfer); + defs.appendChild(filter); + document.getDocumentElement().setAttribute("filter", "url(#customizedLook)"); + } + + private static void writeSVG(Document document, OutputStream outputStream) throws IOException { + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + Transformer transformer; + try { + transformer = transformerFactory.newTransformer(); + transformer.transform(new DOMSource(document), new StreamResult(outputStream)); + } catch (TransformerException e) { + throw new IOException(e.getMessage()); + } + } } diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageDataLoader.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageDataLoader.java index c81cc6d27a7..df7ae831c13 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageDataLoader.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageDataLoader.java @@ -37,14 +37,14 @@ public static ImageData load(String filename) { return data[0]; } - public static ElementAtZoom load(InputStream stream, int fileZoom, int targetZoom) { - List> data = new ImageLoader().load(stream, fileZoom, targetZoom); + public static ElementAtZoom load(InputStream stream, int fileZoom, int targetZoom, int flag) { + List> data = new ImageLoader().load(stream, fileZoom, targetZoom, flag); if (data.isEmpty()) SWT.error(SWT.ERROR_INVALID_IMAGE); return data.get(0); } - public static ElementAtZoom load(String filename, int fileZoom, int targetZoom) { - List> data = new ImageLoader().load(filename, fileZoom, targetZoom); + public static ElementAtZoom load(String filename, int fileZoom, int targetZoom, int flag) { + List> data = new ImageLoader().load(filename, fileZoom, targetZoom, flag); if (data.isEmpty()) SWT.error(SWT.ERROR_INVALID_IMAGE); return data.get(0); } diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageDataProvider.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageDataProvider.java index bfa0ec70a73..8a9a5172de4 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageDataProvider.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageDataProvider.java @@ -43,4 +43,17 @@ public interface ImageDataProvider { */ ImageData getImageData (int zoom); +// /** +// * @since 4.0 +// */ +// default ImageData getCustomizedImageData(int zoom, int flag) { +// throw new UnsupportedOperationException(); +// } +// +// /** +// * @since 4.0 +// */ +// default boolean supportsRasterizationFlag(int flag) { +// return false; +// } } diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageLoader.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageLoader.java index a1de14f5fe4..88f6791c4d9 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageLoader.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageLoader.java @@ -150,14 +150,14 @@ void reset() { * */ public ImageData[] load(InputStream stream) { - load(stream, FileFormat.DEFAULT_ZOOM, FileFormat.DEFAULT_ZOOM); + load(stream, FileFormat.DEFAULT_ZOOM, FileFormat.DEFAULT_ZOOM, SWT.IMAGE_COPY); return data; } -List> load(InputStream stream, int fileZoom, int targetZoom) { +List> load(InputStream stream, int fileZoom, int targetZoom, int flag) { if (stream == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); reset(); - List> images = InternalImageLoader.load(stream, this, fileZoom, targetZoom); + List> images = InternalImageLoader.load(stream, this, fileZoom, targetZoom, flag); data = images.stream().map(ElementAtZoom::element).toArray(ImageData[]::new); return images; } @@ -181,14 +181,14 @@ List> load(InputStream stream, int fileZoom, int target * */ public ImageData[] load(String filename) { - load(filename, FileFormat.DEFAULT_ZOOM, FileFormat.DEFAULT_ZOOM); + load(filename, FileFormat.DEFAULT_ZOOM, FileFormat.DEFAULT_ZOOM, SWT.IMAGE_COPY); return data; } -List> load(String filename, int fileZoom, int targetZoom) { +List> load(String filename, int fileZoom, int targetZoom, int flag) { if (filename == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); try (InputStream stream = new FileInputStream(filename)) { - return load(stream, fileZoom, targetZoom); + return load(stream, fileZoom, targetZoom, flag); } catch (IOException e) { SWT.error(SWT.ERROR_IO, e); } diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/FileFormat.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/FileFormat.java index fd9c89a8347..9f7978f880e 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/FileFormat.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/FileFormat.java @@ -82,7 +82,7 @@ static abstract class StaticImageFileFormat extends FileFormat { abstract ImageData[] loadFromByteStream(); @Override - List> loadFromByteStream(int fileZoom, int targetZoom) { + List> loadFromByteStream(int fileZoom, int targetZoom, int flag) { return Arrays.stream(loadFromByteStream()).map(d -> new ElementAtZoom<>(d, fileZoom)).toList(); } } @@ -102,16 +102,16 @@ List> loadFromByteStream(int fileZoom, int targetZoom) * Format that do not implement {@link StaticImageFileFormat} MUST return * {@link ImageData} with the specified {@code targetZoom}. */ - abstract List> loadFromByteStream(int fileZoom, int targetZoom); + abstract List> loadFromByteStream(int fileZoom, int targetZoom, int flag); /** * Read the specified input stream, and return the * device independent image array represented by the stream. */ -public List> loadFromStream(LEDataInputStream stream, int fileZoom, int targetZoom) { +public List> loadFromStream(LEDataInputStream stream, int fileZoom, int targetZoom, int flag) { try { inputStream = stream; - return loadFromByteStream(fileZoom, targetZoom); + return loadFromByteStream(fileZoom, targetZoom, flag); } catch (Exception e) { if (e instanceof IOException) { SWT.error(SWT.ERROR_IO, e); @@ -126,14 +126,14 @@ public List> loadFromStream(LEDataInputStream stream, i * Read the specified input stream using the specified loader, and * return the device independent image array represented by the stream. */ -public static List> load(InputStream is, ImageLoader loader, int fileZoom, int targetZoom) { +public static List> load(InputStream is, ImageLoader loader, int fileZoom, int targetZoom, int flag) { LEDataInputStream stream = new LEDataInputStream(is); FileFormat fileFormat = determineFileFormat(stream).orElseGet(() -> { SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT); return null; }); fileFormat.loader = loader; - return fileFormat.loadFromStream(stream, fileZoom, targetZoom); + return fileFormat.loadFromStream(stream, fileZoom, targetZoom, flag); } /** diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/SVGFileFormat.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/SVGFileFormat.java index 001b9b6828d..aa095d3ac1d 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/SVGFileFormat.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/SVGFileFormat.java @@ -43,7 +43,7 @@ boolean isFileFormat(LEDataInputStream stream) throws IOException { } @Override - List> loadFromByteStream(int fileZoom, int targetZoom) { + List> loadFromByteStream(int fileZoom, int targetZoom, int flag) { if (RASTERIZER == null) { SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT, null, " [No SVG rasterizer found]"); } @@ -51,7 +51,7 @@ List> loadFromByteStream(int fileZoom, int targetZoom) SWT.error(SWT.ERROR_INVALID_ARGUMENT, null, " [Cannot rasterize SVG for zoom <= 0]"); } try { - ImageData rasterizedImageData = RASTERIZER.rasterizeSVG(inputStream, 100 * targetZoom / fileZoom); + ImageData rasterizedImageData = RASTERIZER.rasterizeSVG(inputStream, 100 * targetZoom / fileZoom, flag); return List.of(new ElementAtZoom<>(rasterizedImageData, targetZoom)); } catch (IOException e) { SWT.error(SWT.ERROR_INVALID_IMAGE, e); diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/SVGRasterizer.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/SVGRasterizer.java index 9586abfb5c6..e42e1237a6d 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/SVGRasterizer.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/SVGRasterizer.java @@ -31,5 +31,5 @@ public interface SVGRasterizer { * @return the {@link ImageData} for the rasterized image, or {@code null} if * the input is not a valid SVG file or cannot be processed. */ - public ImageData rasterizeSVG(InputStream stream, int zoom) throws IOException; + public ImageData rasterizeSVG(InputStream stream, int zoom, int flag) throws IOException; } diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/WinICOFileFormat.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/WinICOFileFormat.java index 9ab08b78877..33218572a89 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/WinICOFileFormat.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/WinICOFileFormat.java @@ -133,7 +133,7 @@ ImageData loadIcon(int[] iconHeader) { StaticImageFileFormat png = new PNGFileFormat(); if (png.isFileFormat(inputStream)) { png.loader = this.loader; - return png.loadFromStream(inputStream, DEFAULT_ZOOM, DEFAULT_ZOOM).get(0).element(); + return png.loadFromStream(inputStream, DEFAULT_ZOOM, DEFAULT_ZOOM, SWT.IMAGE_COPY).get(0).element(); } } catch (Exception e) { } diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java index 09fe28ec0be..02292bef6fb 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java @@ -247,6 +247,9 @@ public Image(Device device, Image srcImage, int flag) { long srcImageHandle = win32_getHandle(srcImage, getZoom()); switch (flag) { case SWT.IMAGE_COPY: { + if(createWithSVG(device, flag)) { + break; + } switch (type) { case SWT.BITMAP: /* Get the HDC for the device */ @@ -282,12 +285,18 @@ public Image(Device device, Image srcImage, int flag) { break; } case SWT.IMAGE_DISABLE: { + if(createWithSVG(device, flag)) { + break; + } ImageData data = srcImage.getImageData(srcImage.getZoom()); ImageData newData = applyDisableImageData(data, rect.height, rect.width); init (newData, getZoom()); break; } case SWT.IMAGE_GRAY: { + if(createWithSVG(device, flag)) { + break; + } ImageData data = srcImage.getImageData(srcImage.getZoom()); ImageData newData = applyGrayImageData(data, rect.height, rect.width); init (newData, getZoom()); @@ -300,6 +309,29 @@ public Image(Device device, Image srcImage, int flag) { this.device.registerResourceWithZoomSupport(this); } +private boolean createWithSVG(Device device, int flag) { + if (imageProvider instanceof DynamicImageProviderWrapper dynamicImageProvider) { + if (dynamicImageProvider.getProvider() instanceof ImageFileNameProvider imageFileNameProvider) { + ElementAtZoom fileName = DPIUtil.validateAndGetImagePathAtZoom(imageFileNameProvider, getZoom()); +// if (fileName.element().endsWith(".svg")) { + ElementAtZoom imageData = ImageDataLoader.load(fileName.element(), fileName.zoom(), getZoom(), + flag); + init(imageData.element(), getZoom()); + return true; +// } + } +// else if (imageProvider.getProvider() instanceof ImageDataProvider imageDataProvider) { +// if (imageDataProvider.supportsRasterizationFlag(flag)) { +// ImageData data = imageDataProvider.getCustomizedImageData(getZoom(), flag); +// ElementAtZoom imageData = new ElementAtZoom<>(data, getZoom()); +// init(imageData.element(), getZoom()); +// return true; +// } +// } + } + return false; +} + /** * Constructs an empty instance of this class with the * width and height of the specified rectangle. The result @@ -2056,7 +2088,7 @@ private ImageDataLoaderStreamProviderWrapper(byte[] inputStreamData) { @Override protected ElementAtZoom loadImageData(int zoom) { - return ImageDataLoader.load(new ByteArrayInputStream(inputStreamData), FileFormat.DEFAULT_ZOOM, zoom); + return ImageDataLoader.load(new ByteArrayInputStream(inputStreamData), FileFormat.DEFAULT_ZOOM, zoom, SWT.IMAGE_COPY); } @Override @@ -2221,7 +2253,7 @@ ImageData getImageData(int zoom) { ElementAtZoom imageDataAtZoom; if (nativeInitializedImage == null) { - imageDataAtZoom = ImageDataLoader.load(fileForZoom.element(), fileForZoom.zoom(), zoom); + imageDataAtZoom = ImageDataLoader.load(fileForZoom.element(), fileForZoom.zoom(), zoom, SWT.IMAGE_COPY); } else { imageDataAtZoom = new ElementAtZoom<>(nativeInitializedImage.getImageData(), fileForZoom.zoom()); destroyHandleForZoom(zoom); diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/InternalImageLoader.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/InternalImageLoader.java index e925542c18a..c9cc328b770 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/InternalImageLoader.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/InternalImageLoader.java @@ -21,8 +21,8 @@ class InternalImageLoader { - static List> load(InputStream stream, ImageLoader imageLoader, int fileZoom, int targetZoom) { - return FileFormat.load(stream, imageLoader, fileZoom, targetZoom); + static List> load(InputStream stream, ImageLoader imageLoader, int fileZoom, int targetZoom, int flag) { + return FileFormat.load(stream, imageLoader, fileZoom, targetZoom, flag); } static void save(OutputStream stream, int format, ImageLoader imageLoader) { From 4afe49962bb485cb19d74102981d81de007c6e4d Mon Sep 17 00:00:00 2001 From: Michael Bangas Date: Tue, 18 Mar 2025 13:27:37 +0100 Subject: [PATCH 2/2] Introduce ImageData customization for static images in FileFormat --- .../swt/internal/image/FileFormat.java | 141 +++++++++++++++++- 1 file changed, 140 insertions(+), 1 deletion(-) diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/FileFormat.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/FileFormat.java index 9f7978f880e..abc2592d869 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/FileFormat.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/FileFormat.java @@ -16,11 +16,13 @@ import java.io.*; import java.util.*; +import java.util.List; import java.util.function.*; import org.eclipse.swt.*; import org.eclipse.swt.graphics.*; import org.eclipse.swt.internal.DPIUtil.*; +import org.eclipse.swt.widgets.*; /** * Abstract factory class for loading/unloading images from files or streams @@ -83,7 +85,144 @@ static abstract class StaticImageFileFormat extends FileFormat { @Override List> loadFromByteStream(int fileZoom, int targetZoom, int flag) { - return Arrays.stream(loadFromByteStream()).map(d -> new ElementAtZoom<>(d, fileZoom)).toList(); + switch (flag) { + case SWT.IMAGE_COPY: { + return Arrays.stream(loadFromByteStream()).map(d -> new ElementAtZoom<>(d, fileZoom)).toList(); + } + case SWT.IMAGE_DISABLE: { + ImageData originalData = loadFromByteStream()[0]; + ImageData data = applyDisableImageData(originalData, originalData.width, originalData.height); + return List.of(new ElementAtZoom<>(data, fileZoom)); + } + case SWT.IMAGE_GRAY: { + ImageData originalData = loadFromByteStream()[0]; + ImageData data = applyGrayImageData(originalData, originalData.width, originalData.height); + return List.of(new ElementAtZoom<>(data, fileZoom)); + } default: + throw new IllegalArgumentException("Unexpected value: " + flag); + } + + } + + private ImageData applyDisableImageData(ImageData data, int height, int width) { + PaletteData palette = data.palette; + RGB[] rgbs = new RGB[3]; + rgbs[0] = Display.getDefault().getSystemColor(SWT.COLOR_BLACK).getRGB(); + rgbs[1] = Display.getDefault().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW).getRGB(); + rgbs[2] = Display.getDefault().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND).getRGB(); + ImageData newData = new ImageData(width, height, 8, new PaletteData(rgbs)); + newData.alpha = data.alpha; + newData.alphaData = data.alphaData; + newData.maskData = data.maskData; + newData.maskPad = data.maskPad; + if (data.transparentPixel != -1) newData.transparentPixel = 0; + + /* Convert the pixels. */ + int[] scanline = new int[width]; + int[] maskScanline = null; + ImageData mask = null; + if (data.maskData != null) mask = data.getTransparencyMask(); + if (mask != null) maskScanline = new int[width]; + int redMask = palette.redMask; + int greenMask = palette.greenMask; + int blueMask = palette.blueMask; + int redShift = palette.redShift; + int greenShift = palette.greenShift; + int blueShift = palette.blueShift; + for (int y=0; y>> -redShift : red << redShift; + green = pixel & greenMask; + green = (greenShift < 0) ? green >>> -greenShift : green << greenShift; + blue = pixel & blueMask; + blue = (blueShift < 0) ? blue >>> -blueShift : blue << blueShift; + } else { + red = palette.colors[pixel].red; + green = palette.colors[pixel].green; + blue = palette.colors[pixel].blue; + } + int intensity = red * red + green * green + blue * blue; + if (intensity < 98304) { + newData.data[offset] = (byte)1; + } else { + newData.data[offset] = (byte)2; + } + } + offset++; + } + } + return newData; + } + + private ImageData applyGrayImageData(ImageData data, int pHeight, int pWidth) { + PaletteData palette = data.palette; + ImageData newData = data; + if (!palette.isDirect) { + /* Convert the palette entries to gray. */ + RGB [] rgbs = palette.getRGBs(); + for (int i=0; i> 3; + color.red = color.green = color.blue = intensity; + } + } + newData.palette = new PaletteData(rgbs); + } else { + /* Create a 8 bit depth image data with a gray palette. */ + RGB[] rgbs = new RGB[256]; + for (int i=0; i>> -redShift : red << redShift; + int green = pixel & greenMask; + green = (greenShift < 0) ? green >>> -greenShift : green << greenShift; + int blue = pixel & blueMask; + blue = (blueShift < 0) ? blue >>> -blueShift : blue << blueShift; + int intensity = (red+red+green+green+green+green+green+blue) >> 3; + if (newData.transparentPixel == intensity) intensity = 255; + newData.data[offset] = (byte)intensity; + } else { + newData.data[offset] = (byte)254; + } + offset++; + } + } + } + return newData; } }