Skip to content

Commit 18c5758

Browse files
committed
Use Path to represent file-system paths for ImageData creation
Use java.nio.file.Path to model file-system paths instead of String to represent file-system paths. Add the new way to create ImageData as static factory instead of a constructor, because a constructor is not really suitable to create a copy of the first element of an array of ImageData. Also inline the ImageDataLoader and use the new ImageData.load() factories instead.
1 parent 3e59697 commit 18c5758

File tree

9 files changed

+461
-183
lines changed

9 files changed

+461
-183
lines changed

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

Lines changed: 67 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616

1717
import java.io.*;
18+
import java.nio.file.Path;
1819
import java.util.*;
1920
import java.util.function.*;
2021

@@ -130,9 +131,9 @@ public final class Image extends Resource implements Drawable {
130131
static final int DEFAULT_SCANLINE_PAD = 4;
131132

132133
/**
133-
* ImageFileNameProvider to provide file names at various Zoom levels
134+
* ImageFileProvider to provide files at various Zoom levels
134135
*/
135-
private ImageFileNameProvider imageFileNameProvider;
136+
private ImageFileProvider imageFileProvider;
136137

137138
/**
138139
* ImageDataProvider to provide ImageData at various Zoom levels
@@ -391,11 +392,11 @@ public Image(Device device, Image srcImage, int flag) {
391392
/* Create the 100% representation for the new image from source image & apply flag */
392393
createRepFromSourceAndApplyFlag(srcImage.getRepresentation (100), srcWidth, srcHeight, flag);
393394

394-
imageFileNameProvider = srcImage.imageFileNameProvider;
395+
imageFileProvider = srcImage.imageFileProvider;
395396
imageDataProvider = srcImage.imageDataProvider;
396397
imageGcDrawer = srcImage.imageGcDrawer;
397398
this.styleFlag = srcImage.styleFlag | flag;
398-
if (imageFileNameProvider != null || imageDataProvider != null ||srcImage.imageGcDrawer != null) {
399+
if (imageFileProvider != null || imageDataProvider != null ||srcImage.imageGcDrawer != null) {
399400
/* If source image has 200% representation then create the 200% representation for the new image & apply flag */
400401
NSBitmapImageRep rep200 = srcImage.getRepresentation (200);
401402
if (rep200 != null) createRepFromSourceAndApplyFlag(rep200, srcWidth * 2, srcHeight * 2, flag);
@@ -653,18 +654,11 @@ public Image(Device device, ImageData source, ImageData mask) {
653654
* </p>
654655
* <pre>
655656
* static Image loadImage (Display display, Class clazz, String string) {
656-
* InputStream stream = clazz.getResourceAsStream (string);
657-
* if (stream == null) return null;
658-
* Image image = null;
659-
* try {
660-
* image = new Image (display, stream);
661-
* } catch (SWTException ex) {
662-
* } finally {
663-
* try {
664-
* stream.close ();
665-
* } catch (IOException ex) {}
666-
* }
667-
* return image;
657+
* try (InputStream stream = clazz.getResourceAsStream(string)){
658+
* if (stream == null) return null;
659+
* return new Image (display, stream);
660+
* } catch (SWTException | IOException ex) {
661+
* }
668662
* }
669663
* </pre>
670664
* <p>
@@ -695,7 +689,7 @@ public Image(Device device, InputStream stream) {
695689
NSAutoreleasePool pool = null;
696690
if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
697691
try {
698-
initWithSupplier(zoom -> ImageDataLoader.load(stream, FileFormat.DEFAULT_ZOOM, zoom));
692+
initWithSupplier(zoom -> ImageData.load(stream, FileFormat.DEFAULT_ZOOM, zoom));
699693
init();
700694
} finally {
701695
if (pool != null) pool.release();
@@ -740,8 +734,9 @@ public Image(Device device, String filename) {
740734
if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
741735
try {
742736
if (filename == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
743-
initNative(filename);
744-
if (this.handle == null) initWithSupplier(zoom -> ImageDataLoader.load(filename, FileFormat.DEFAULT_ZOOM, zoom));
737+
Path file = Path.of(filename);
738+
initNative(file);
739+
if (this.handle == null) initWithSupplier(zoom -> ImageData.load(file, FileFormat.DEFAULT_ZOOM, zoom));
745740
init();
746741
} finally {
747742
if (pool != null) pool.release();
@@ -776,28 +771,63 @@ public Image(Device device, String filename) {
776771
* <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
777772
* </ul>
778773
* @since 3.104
774+
* @deprecated Instead use {@link #Image(Device, ImageFileProvider)}
779775
*/
776+
@Deprecated(since = "2025-06")
780777
public Image(Device device, ImageFileNameProvider imageFileNameProvider) {
778+
this(device, DPIUtil.asImageFileProvider(imageFileNameProvider));
779+
}
780+
781+
/**
782+
* Constructs an instance of this class by loading its representation
783+
* from the file retrieved from the {@link ImageFileProvider}. Throws an
784+
* error if an error occurs while loading the image, or if the result
785+
* is an image of an unsupported type.
786+
* <p>
787+
* This constructor is provided for convenience for loading image as
788+
* per DPI level.
789+
*
790+
* @param device the device on which to create the image
791+
* @param imageFileProvider the {@link ImageFileProvider} object that is
792+
* to be used to get the file
793+
*
794+
* @exception IllegalArgumentException <ul>
795+
* <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
796+
* <li>ERROR_NULL_ARGUMENT - if the ImageFileNameProvider is null</li>
797+
* <li>ERROR_INVALID_ARGUMENT - if the fileName provided by ImageFileNameProvider is null at 100% zoom</li>
798+
* </ul>
799+
* @exception SWTException <ul>
800+
* <li>ERROR_IO - if an IO error occurs while reading from the file</li>
801+
* <li>ERROR_INVALID_IMAGE - if the image file contains invalid data </li>
802+
* <li>ERROR_UNSUPPORTED_DEPTH - if the image file describes an image with an unsupported depth</li>
803+
* <li>ERROR_UNSUPPORTED_FORMAT - if the image file contains an unrecognized format</li>
804+
* </ul>
805+
* @exception SWTError <ul>
806+
* <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
807+
* </ul>
808+
* @since 3.130
809+
*/
810+
public Image(Device device, ImageFileProvider imageFileProvider) {
781811
super(device);
782-
if (imageFileNameProvider == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
783-
this.imageFileNameProvider = imageFileNameProvider;
784-
String filename = imageFileNameProvider.getImagePath(100);
785-
if (filename == null) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
812+
if (imageFileProvider == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
813+
this.imageFileProvider = imageFileProvider;
814+
Path file = imageFileProvider.getImagePath(100);
815+
if (file == null) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
786816
NSAutoreleasePool pool = null;
787817
if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
788818
try {
789-
initNative(filename);
790-
if (this.handle == null) init(ImageDataLoader.load(filename, 100, 100).element());
819+
initNative(file);
820+
if (this.handle == null) init(ImageData.load(file, 100, 100).element());
791821
init();
792-
String filename2x = imageFileNameProvider.getImagePath(200);
793-
if (filename2x != null) {
822+
Path file2x = imageFileProvider.getImagePath(200);
823+
if (file2x != null) {
794824
alphaInfo_200 = new AlphaInfo();
795-
id id = NSImageRep.imageRepWithContentsOfFile(NSString.stringWith(filename2x));
825+
id id = NSImageRep.imageRepWithContentsOfFile(NSString.stringWith(file2x.toString()));
796826
NSImageRep rep = new NSImageRep(id);
797827
handle.addRepresentation(rep);
798828
} else {
799829
// Try to natively scale up the image (e.g. possible if it's an SVG)
800-
ElementAtZoom<ImageData> imageData2x = ImageDataLoader.load(filename, 100, 200);
830+
ElementAtZoom<ImageData> imageData2x = ImageData.load(file, 100, 200);
801831
if (imageData2x.zoom() == 200) {
802832
alphaInfo_200 = new AlphaInfo();
803833
NSBitmapImageRep rep = createRepresentation (imageData2x.element(), alphaInfo_200);
@@ -878,7 +908,7 @@ public Image(Device device, ImageDataProvider imageDataProvider) {
878908
* <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
879909
* <li>ERROR_NULL_ARGUMENT - if the ImageGcDrawer is null</li>
880910
* </ul>
881-
* @since 3.129
911+
* @since 3.130
882912
*/
883913
public Image(Device device, ImageGcDrawer imageGcDrawer, int width, int height) {
884914
super(device);
@@ -921,7 +951,7 @@ private ImageData drawWithImageGcDrawer(ImageGcDrawer imageGcDrawer, int width,
921951

922952
private AlphaInfo _getAlphaInfoAtCurrentZoom (NSBitmapImageRep rep) {
923953
int deviceZoom = DPIUtil.getDeviceZoom();
924-
if (deviceZoom != 100 && (imageFileNameProvider != null || imageDataProvider != null)) {
954+
if (deviceZoom != 100 && (imageFileProvider != null || imageDataProvider != null)) {
925955
if (alphaInfo_100.alphaData != null && alphaInfo_200 != null) {
926956
if (alphaInfo_200.alphaData == null) initAlpha_200(rep);
927957
return alphaInfo_200;
@@ -1195,8 +1225,8 @@ public boolean equals (Object object) {
11951225
if (device != image.device || alphaInfo_100.transparentPixel != image.alphaInfo_100.transparentPixel) return false;
11961226
if (imageDataProvider != null && image.imageDataProvider != null) {
11971227
return styleFlag == image.styleFlag && imageDataProvider.equals (image.imageDataProvider);
1198-
} else if (imageFileNameProvider != null && image.imageFileNameProvider != null) {
1199-
return styleFlag == image.styleFlag && imageFileNameProvider.equals (image.imageFileNameProvider);
1228+
} else if (imageFileProvider != null && image.imageFileProvider != null) {
1229+
return styleFlag == image.styleFlag && imageFileProvider.equals (image.imageFileProvider);
12001230
} else if (imageGcDrawer != null && image.imageGcDrawer != null) {
12011231
return styleFlag == image.styleFlag && imageGcDrawer.equals(image.imageGcDrawer) && width == image.width
12021232
&& height == image.height;
@@ -1434,8 +1464,8 @@ NSBitmapImageRep createImageRep(NSSize targetSize) {
14341464
public int hashCode () {
14351465
if (imageDataProvider != null) {
14361466
return imageDataProvider.hashCode();
1437-
} else if (imageFileNameProvider != null) {
1438-
return imageFileNameProvider.hashCode();
1467+
} else if (imageFileProvider != null) {
1468+
return imageFileProvider.hashCode();
14391469
} else if (imageGcDrawer != null) {
14401470
return Objects.hash(imageGcDrawer, height, width);
14411471
} else {
@@ -1545,7 +1575,8 @@ void initAlpha_100(NSBitmapImageRep nativeRep) {
15451575

15461576
}
15471577

1548-
void initNative(String filename) {
1578+
void initNative(Path file) {
1579+
String filename = file.toString();
15491580
NSAutoreleasePool pool = null;
15501581
NSImage nativeImage = null;
15511582

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

Lines changed: 109 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2000, 2016 IBM Corporation and others.
2+
* Copyright (c) 2000, 2025 IBM Corporation and others.
33
*
44
* This program and the accompanying materials
55
* are made available under the terms of the Eclipse Public License 2.0
@@ -15,9 +15,12 @@
1515

1616

1717
import java.io.*;
18+
import java.nio.file.Path;
19+
import java.util.*;
1820

1921
import org.eclipse.swt.*;
2022
import org.eclipse.swt.internal.*;
23+
import org.eclipse.swt.internal.DPIUtil.*;
2124

2225
/**
2326
* Instances of this class are device-independent descriptions
@@ -239,6 +242,97 @@ public final class ImageData implements Cloneable {
239242
{ 0x000000, 0x800000, 0x200000, 0xa00000, 0x080000, 0x880000, 0x280000, 0xa80000 }
240243
};
241244

245+
/**
246+
* Creates an {@code ImageData} loaded from the specified file. Throws an error
247+
* if an error occurs loading the image, or if the image has an unsupported
248+
* type.
249+
* <p>
250+
* This factory is provided for convenience when loading a single image only. If
251+
* the file contains multiple images, only the first one will be loaded. To load
252+
* multiple images, use {@link ImageLoader#load(Path)}.
253+
* </p>
254+
*
255+
* @param file the file to load the image from (must not be null)
256+
*
257+
* @exception IllegalArgumentException <ul>
258+
* <li>ERROR_NULL_ARGUMENT - if the file name is null</li>
259+
* </ul>
260+
* @exception SWTException <ul>
261+
* <li>ERROR_IO - if an IO error occurs while reading from the file</li>
262+
* <li>ERROR_INVALID_IMAGE - if the image file contains invalid data</li>
263+
* <li>ERROR_UNSUPPORTED_FORMAT - if the image file contains an unrecognized format</li>
264+
* </ul>
265+
* @since 3.130
266+
*/
267+
public static ImageData load(Path file) {
268+
return first(new ImageLoader().load(file));
269+
}
270+
271+
/**
272+
* Creates an <code>ImageData</code> loaded from the specified input stream.
273+
* Throws an error if an error occurs while loading the image, or if the image
274+
* has an unsupported type. Application code is still responsible for closing
275+
* the input stream.
276+
* <p>
277+
* This factory is provided for convenience when loading a single image only. If
278+
* the stream contains multiple images, only the first one will be loaded. To
279+
* load multiple images, use {@link ImageLoader#load(InputStream)}.
280+
* </p>
281+
* <p>
282+
* This factory may be used to load a resource as follows:
283+
* </p>
284+
*
285+
* <pre>
286+
* static ImageData loadImageData(Class clazz, String string) {
287+
* try (InputStream stream = clazz.getResourceAsStream(string)) {
288+
* if (stream == null) return null;
289+
* return ImageData.load(stream);
290+
* } catch (SWTException | IOException ex) {
291+
* // handle exception appropriately
292+
* }
293+
* }
294+
* </pre>
295+
*
296+
* @param stream the input stream to load the image from (must not be null)
297+
*
298+
* @exception IllegalArgumentException <ul>
299+
* <li>ERROR_NULL_ARGUMENT - if the stream is null</li>
300+
* </ul>
301+
* @exception SWTException <ul>
302+
* <li>ERROR_IO - if an IO error occurs while reading from the stream</li>
303+
* <li>ERROR_INVALID_IMAGE - if the image stream contains invalid data</li>
304+
* <li>ERROR_UNSUPPORTED_FORMAT - if the image stream contains an unrecognized format</li>
305+
* </ul>
306+
*
307+
* @see ImageLoader#load(InputStream)
308+
* @since 3.130
309+
*/
310+
public static ImageData load(InputStream stream) {
311+
return first(new ImageLoader().load(stream));
312+
}
313+
314+
private static <T> T first(T[] data) {
315+
if (data.length < 1) {
316+
SWT.error(SWT.ERROR_INVALID_IMAGE);
317+
}
318+
return data[0];
319+
}
320+
321+
static ElementAtZoom<ImageData> load(InputStream stream, int fileZoom, int targetZoom) {
322+
return first(new ImageLoader().load(stream, fileZoom, targetZoom));
323+
}
324+
325+
static ElementAtZoom<ImageData> load(Path file, int fileZoom, int targetZoom) {
326+
return first(new ImageLoader().load(file, fileZoom, targetZoom));
327+
}
328+
329+
private static <T> T first(List<T> data) {
330+
if (data.isEmpty()) {
331+
SWT.error(SWT.ERROR_INVALID_IMAGE);
332+
}
333+
return data.get(0);
334+
}
335+
242336
/**
243337
* Constructs a new, empty ImageData with the given width, height,
244338
* depth and palette. The data will be initialized to an (all zero)
@@ -296,24 +390,18 @@ scanlinePad, checkData(data), 0, null,
296390
* This constructor is provided for convenience when loading a single
297391
* image only. If the stream contains multiple images, only the first
298392
* one will be loaded. To load multiple images, use
299-
* <code>ImageLoader.load()</code>.
393+
* {@link ImageLoader#load(InputStream)}.
300394
* </p><p>
301395
* This constructor may be used to load a resource as follows:
302396
* </p>
303397
* <pre>
304398
* static ImageData loadImageData (Class clazz, String string) {
305-
* InputStream stream = clazz.getResourceAsStream (string);
306-
* if (stream == null) return null;
307-
* ImageData imageData = null;
308-
* try {
309-
* imageData = new ImageData (stream);
310-
* } catch (SWTException ex) {
311-
* } finally {
312-
* try {
313-
* stream.close ();
314-
* } catch (IOException ex) {}
399+
* try (InputStream stream = clazz.getResourceAsStream (string)) {
400+
* if (stream == null) return null;
401+
* return ImageData.load(stream);
402+
* } catch (SWTException |IOException ex) {
403+
* // handle exception appropriately
315404
* }
316-
* return imageData;
317405
* }
318406
* </pre>
319407
*
@@ -329,9 +417,11 @@ scanlinePad, checkData(data), 0, null,
329417
* </ul>
330418
*
331419
* @see ImageLoader#load(InputStream)
420+
* @deprecated Instead use {@link #load(InputStream)}
332421
*/
422+
@Deprecated(since = "2025-06")
333423
public ImageData(InputStream stream) {
334-
ImageData i = ImageDataLoader.load(stream);
424+
ImageData i = load(stream);
335425
setAllFields(
336426
i.width,
337427
i.height,
@@ -360,7 +450,7 @@ public ImageData(InputStream stream) {
360450
* This constructor is provided for convenience when loading a single
361451
* image only. If the file contains multiple images, only the first
362452
* one will be loaded. To load multiple images, use
363-
* <code>ImageLoader.load()</code>.
453+
* {@link ImageLoader#load(String)}.
364454
* </p>
365455
*
366456
* @param filename the name of the file to load the image from (must not be null)
@@ -373,9 +463,12 @@ public ImageData(InputStream stream) {
373463
* <li>ERROR_INVALID_IMAGE - if the image file contains invalid data</li>
374464
* <li>ERROR_UNSUPPORTED_FORMAT - if the image file contains an unrecognized format</li>
375465
* </ul>
466+
* @deprecated Instead use {@link #load(Path)}
376467
*/
468+
@Deprecated(since = "2025-06")
377469
public ImageData(String filename) {
378-
ImageData i = ImageDataLoader.load(filename);
470+
if (filename == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
471+
ImageData i = load(Path.of(filename));
379472
setAllFields(
380473
i.width,
381474
i.height,

0 commit comments

Comments
 (0)