Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*******************************************************************************
* Copyright (c) 2025 Patrick Ziegler and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Patrick Ziegler - initial API and implementation
*******************************************************************************/

package org.eclipse.draw2d.examples.image;

import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.SWTGraphics;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.internal.FileImageFileNameProvider;

public class ImageExample {
private static final Image LOGO1 = FileImageFileNameProvider.createImage(ImageExample.class, "images/GEF.svg"); //$NON-NLS-1$
private static final Dimension LOGO_SIZE;

static {
ImageData data = LOGO1.getImageData(100);
LOGO_SIZE = new Dimension(data.width, data.height);
}

public static void main(String[] args) {
Point size = new Point(600, 500);

Shell shell = new Shell();
shell.setSize(size);

shell.addPaintListener(event -> {
GC gc = event.gc;
gc.setBackground(ColorConstants.blue);
gc.fillRectangle(0, 0, size.x, size.y / 2);
gc.setBackground(ColorConstants.green);
gc.fillRectangle(0, size.y / 2, size.x, size.y / 2);

int x1 = 0;
for (int i = 1; i <= 5; ++i) {
SWTGraphics g = new SWTGraphics(gc);
g.scale(i);
g.drawImage(LOGO1, x1, 0);
g.dispose();
gc.setTransform(null);
x1 += LOGO_SIZE.width / 2;
}

int x2 = 0;
for (int i = 1; i <= 5; ++i) {
gc.drawImage(LOGO1, x2, 250, LOGO_SIZE.width * i, LOGO_SIZE.height * i);
x2 += LOGO_SIZE.width * i;
}
});

shell.open();

Display d = shell.getDisplay();
while (!shell.isDisposed()) {
while (!d.readAndDispatch()) {
d.sleep();
}
}
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
import org.eclipse.draw2d.XYLayout;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.draw2d.internal.FileImageDataProvider;
import org.eclipse.draw2d.internal.FileImageFileNameProvider;
import org.eclipse.draw2d.parts.Thumbnail;

/**
Expand All @@ -39,11 +39,11 @@
*/

public class ZoomExample {
private static final Image IMG_CLASS = FileImageDataProvider.createImage(UMLClassFigure.class,
private static final Image IMG_CLASS = FileImageFileNameProvider.createImage(UMLClassFigure.class,
"images/class_obj.svg"); //$NON-NLS-1$
private static final Image IMG_FIELD_PRIVATE = FileImageDataProvider.createImage(UMLClassFigure.class,
private static final Image IMG_FIELD_PRIVATE = FileImageFileNameProvider.createImage(UMLClassFigure.class,
"images/field_private_obj.svg"); //$NON-NLS-1$
private static final Image IMG_METHOD_PUBLIC = FileImageDataProvider.createImage(UMLClassFigure.class,
private static final Image IMG_METHOD_PUBLIC = FileImageFileNameProvider.createImage(UMLClassFigure.class,
"images/methpub_obj.svg"); //$NON-NLS-1$
private static Figure contents;

Expand Down
6 changes: 3 additions & 3 deletions org.eclipse.draw2d/src/org/eclipse/draw2d/CheckBox.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

import org.eclipse.swt.graphics.Image;

import org.eclipse.draw2d.internal.FileImageDataProvider;
import org.eclipse.draw2d.internal.FileImageFileNameProvider;

/**
* A Checkbox is a toggle figure which toggles between the checked and unchecked
Expand All @@ -24,8 +24,8 @@
public final class CheckBox extends Toggle {
private Label label = null;

static final Image UNCHECKED = FileImageDataProvider.createImage(CheckBox.class, "images/checkboxenabledoff.svg"); //$NON-NLS-1$
static final Image CHECKED = FileImageDataProvider.createImage(CheckBox.class, "images/checkboxenabledon.svg"); //$NON-NLS-1$
static final Image UNCHECKED = FileImageFileNameProvider.createImage(CheckBox.class, "images/checkboxenabledoff.svg"); //$NON-NLS-1$
static final Image CHECKED = FileImageFileNameProvider.createImage(CheckBox.class, "images/checkboxenabledon.svg"); //$NON-NLS-1$

/**
* Constructs a CheckBox with no text.
Expand Down
33 changes: 31 additions & 2 deletions org.eclipse.draw2d/src/org/eclipse/draw2d/SWTGraphics.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2000, 2024 IBM Corporation and others.
* Copyright (c) 2000, 2025 IBM Corporation and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
Expand All @@ -21,6 +21,7 @@
import org.eclipse.swt.graphics.FontMetrics;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.LineAttributes;
import org.eclipse.swt.graphics.Path;
import org.eclipse.swt.graphics.PathData;
Expand Down Expand Up @@ -416,7 +417,35 @@ public void drawFocus(int x, int y, int w, int h) {
@Override
public void drawImage(Image srcImage, int x, int y) {
checkGC();
gc.drawImage(srcImage, x + translateX, y + translateY);
if (transform == null) {
gc.drawImage(srcImage, x + translateX, y + translateY);
} else {
float[] transformElements = new float[6];
transform.getElements(transformElements);

float scaleHor = transformElements[0];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For #926 I brushed up my knowledge on vector math and transformation matrices. If you want to be correct in cases when rotation is applied then you need to take the elements 1 and 2 also into account.

float scaleVer = transformElements[3];

if (scaleHor == 1.0 && scaleVer == 1.0) {
gc.drawImage(srcImage, x + translateX, y + translateY);
return;
}

ImageData srcImageData = srcImage.getImageData(100);
int scaledX = (int) ((x + translateX) * scaleHor);
int scaledY = (int) ((y + translateY) * scaleVer);
int scaledWidth = (int) (srcImageData.width * scaleHor);
int scaledHeight = (int) (srcImageData.height * scaleVer);

transform.scale(1 / scaleHor, 1 / scaleVer);
gc.setTransform(transform);
try {
gc.drawImage(srcImage, scaledX, scaledY, scaledWidth, scaledHeight);
} finally {
transform.scale(scaleHor, scaleVer);
gc.setTransform(transform);
}
}
Comment on lines +420 to +448
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's probably safer to add a new drawImage(Image,int,int,int,int) method, rather than changing the behavior of an existing method.

}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@

package org.eclipse.draw2d.internal;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.file.Files;

import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.ImageDataProvider;
import org.eclipse.swt.graphics.ImageFileNameProvider;

/**
* This class behaves similarly to the JFace ImageDescriptors in that it allows
Expand All @@ -28,37 +31,59 @@
* as an argument to an image, the image data is automatically reloaded upon DPI
* changes.
*/
public class FileImageDataProvider implements ImageDataProvider {
private static final Logger LOGGER = Logger.getLogger(FileImageDataProvider.class);
public class FileImageFileNameProvider implements ImageFileNameProvider {
private static final Logger LOGGER = Logger.getLogger(FileImageFileNameProvider.class);
private final Class<?> clazz;
private final String basePath;
private final String fileExtension;
private final boolean svg;
private final String imagePath100;
private final String imagePath200;

public FileImageDataProvider(Class<?> clazz, String path) {
public FileImageFileNameProvider(Class<?> clazz, String path) {
int separator = path.lastIndexOf("."); //$NON-NLS-1$
this.clazz = clazz;
this.basePath = path.substring(0, separator);
this.fileExtension = path.substring(separator + 1);
this.svg = "svg".equals(fileExtension); //$NON-NLS-1$
this.imagePath100 = createImagePath(basePath + '.' + fileExtension);
this.imagePath200 = svg ? null : createImagePath(basePath + "@2x." + fileExtension); //$NON-NLS-1$
}

@Override
public ImageData getImageData(int zoom) {
if (zoom == 100 || "svg".equals(fileExtension)) { //$NON-NLS-1$
return createImageData(basePath + '.' + fileExtension);
public String getImagePath(int zoom) {
if (zoom == 100 || svg) {
return imagePath100;
}
if (zoom == 200) {
return createImageData(basePath + "@2x." + fileExtension); //$NON-NLS-1$
return imagePath200;
}
return null;
}

private ImageData createImageData(String name) {
try (InputStream stream = clazz.getResourceAsStream(name)) {
return new ImageData(stream);
} catch (IOException ioe) {
LOGGER.error(ioe.getLocalizedMessage(), ioe);
private String createImagePath(String name) {
URL resource = clazz.getResource(name);
if (resource == null) {
return null;
}

if ("file".equals(resource.getProtocol())) { //$NON-NLS-1$
return resource.getFile();
}

try {
File tmpImage = Files.createTempFile(null, null).toFile();
tmpImage.deleteOnExit();
try (FileOutputStream os = new FileOutputStream(tmpImage)) {
try (InputStream is = resource.openStream()) {
is.transferTo(os);
}
}
return tmpImage.getAbsolutePath();
} catch (IOException e) {
LOGGER.error(e.getMessage(), e);
}
return null;
}

/**
Expand All @@ -67,6 +92,6 @@ private ImageData createImageData(String name) {
* at an appropriate time.
*/
public static Image createImage(Class<?> clazz, String name) {
return new Image(null, new FileImageDataProvider(clazz, ImageUtils.getEffectiveFileName(name)));
return new Image(null, new FileImageFileNameProvider(clazz, ImageUtils.getEffectiveFileName(name)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.draw2d.internal.FileImageDataProvider;
import org.eclipse.draw2d.internal.FileImageFileNameProvider;
import org.eclipse.draw2d.internal.InternalDraw2dUtils;

/**
Expand All @@ -91,7 +91,7 @@ public class Graph extends FigureCanvas implements IContainer2 {
// CLASS CONSTANTS
public static final int ANIMATION_TIME = 500;
public static final int FISHEYE_ANIMATION_TIME = 100;
private static final Image BACK_ARROW = FileImageDataProvider.createImage(Graph.class, "/icons/back_arrow.svg"); //$NON-NLS-1$
private static final Image BACK_ARROW = FileImageFileNameProvider.createImage(Graph.class, "/icons/back_arrow.svg"); //$NON-NLS-1$

// @tag CGraph.Colors : These are the colour constants for the graph, they
// are disposed on clean-up
Expand Down
Loading