@@ -371,9 +371,7 @@ public Image(Device device, ImageData data) {
371371 super (device );
372372 if (data == null ) SWT .error (SWT .ERROR_NULL_ARGUMENT );
373373 initialNativeZoom = DPIUtil .getNativeDeviceZoom ();
374- int deviceZoom = getZoom ();
375- data = scaleImageData (data , deviceZoom , 100 );
376- init (data , deviceZoom );
374+ this .imageProvider = new PlainImageDataProviderWrapper (data );
377375 init ();
378376 this .device .registerResourceWithZoomSupport (this );
379377}
@@ -416,10 +414,7 @@ public Image(Device device, ImageData source, ImageData mask) {
416414 SWT .error (SWT .ERROR_INVALID_ARGUMENT );
417415 }
418416 initialNativeZoom = DPIUtil .getNativeDeviceZoom ();
419- source = scaleImageData (source , getZoom (), 100 );
420- mask = scaleImageData (mask , getZoom (), 100 );
421- mask = ImageData .convertMask (mask );
422- initIconHandle (this .device , source , mask , getZoom ());
417+ this .imageProvider = new MaskedImageDataProviderWrapper (source , mask );
423418 init ();
424419 this .device .registerResourceWithZoomSupport (this );
425420}
@@ -479,11 +474,9 @@ public Image(Device device, ImageData source, ImageData mask) {
479474 */
480475public Image (Device device , InputStream stream ) {
481476 super (device );
477+ if (stream == null ) SWT .error (SWT .ERROR_NULL_ARGUMENT );
482478 initialNativeZoom = DPIUtil .getNativeDeviceZoom ();
483- int deviceZoom = getZoom ();
484- ElementAtZoom <ImageData > imageCandidate = ImageDataLoader .load (stream , FileFormat .DEFAULT_ZOOM , deviceZoom );
485- ImageData data = scaleImageData (imageCandidate .element (), deviceZoom , imageCandidate .zoom ());
486- init (data , deviceZoom );
479+ this .imageProvider = new ImageDataLoaderStreamProviderWrapper (stream );
487480 init ();
488481 this .device .registerResourceWithZoomSupport (this );
489482}
@@ -524,10 +517,16 @@ public Image (Device device, String filename) {
524517 super (device );
525518 if (filename == null ) SWT .error (SWT .ERROR_NULL_ARGUMENT );
526519 initialNativeZoom = DPIUtil .getNativeDeviceZoom ();
527- int deviceZoom = getZoom ();
528- ElementAtZoom <ImageData > imageCandidate = ImageDataLoader .load (filename , FileFormat .DEFAULT_ZOOM , deviceZoom );
529- ImageData data = scaleImageData (imageCandidate .element (), deviceZoom , imageCandidate .zoom ());
530- init (data , deviceZoom );
520+ this .imageProvider = new ImageFileNameProviderWrapper (zoom -> {
521+ if (zoom == 100 ) {
522+ return filename ;
523+ }
524+ return null ;
525+ });
526+ if (imageProvider .getImageData (100 ) == null ) {
527+ SWT .error (SWT .ERROR_INVALID_ARGUMENT , null ,
528+ ": [" + filename + "] returns null ImageData at 100% zoom." );
529+ }
531530 init ();
532531 this .device .registerResourceWithZoomSupport (this );
533532}
@@ -1947,6 +1946,131 @@ protected void destroy() {
19471946 }
19481947}
19491948
1949+ private abstract class ImageFromImageDataProviderWrapper extends AbstractImageProviderWrapper {
1950+
1951+ protected abstract ElementAtZoom <ImageData > loadImageData (int zoom );
1952+
1953+ void initImage () {
1954+ // As the init call configured some Image attributes (e.g. type)
1955+ // it must be called
1956+ ImageData imageDataAt100 = getImageData (100 );
1957+ init (imageDataAt100 , 100 );
1958+ destroyHandleForZoom (100 );
1959+ }
1960+
1961+ @ Override
1962+ ImageData getImageData (int zoom ) {
1963+ if (zoomLevelToImageHandle .containsKey (zoom )) {
1964+ return zoomLevelToImageHandle .get (zoom ).getImageData ();
1965+ }
1966+ if (!zoomLevelToImageHandle .isEmpty ()) {
1967+ return getScaledImageData (zoom );
1968+ }
1969+ ElementAtZoom <ImageData > loadedImageData = loadImageData (zoom );
1970+ return DPIUtil .scaleImageData (device , loadedImageData , zoom );
1971+ }
1972+
1973+ @ Override
1974+ ImageHandle getImageMetadata (int zoom ) {
1975+ if (zoomLevelToImageHandle .containsKey (zoom )) {
1976+ return zoomLevelToImageHandle .get (zoom );
1977+ } else {
1978+ ImageData scaledImageData = getImageData (zoom );
1979+ ImageHandle imageHandle = init (scaledImageData , zoom );
1980+ return imageHandle ;
1981+ }
1982+ }
1983+ }
1984+
1985+ private class PlainImageDataProviderWrapper extends ImageFromImageDataProviderWrapper {
1986+ private ImageData imageDataAt100 ;
1987+
1988+ PlainImageDataProviderWrapper (ImageData imageData ) {
1989+ this .imageDataAt100 = (ImageData ) imageData .clone ();
1990+ initImage ();
1991+ }
1992+
1993+ @ Override
1994+ protected Rectangle getBounds (int zoom ) {
1995+ Rectangle rectangle = new Rectangle (0 , 0 , imageDataAt100 .width , imageDataAt100 .height );
1996+ return DPIUtil .scaleUp (rectangle , zoom );
1997+ }
1998+
1999+ @ Override
2000+ protected ElementAtZoom <ImageData > loadImageData (int zoom ) {
2001+ return new ElementAtZoom <>(imageDataAt100 , 100 );
2002+ }
2003+
2004+ @ Override
2005+ AbstractImageProviderWrapper createCopy (Image image ) {
2006+ return image .new PlainImageDataProviderWrapper (this .imageDataAt100 );
2007+ }
2008+ }
2009+
2010+ private class MaskedImageDataProviderWrapper extends ImageFromImageDataProviderWrapper {
2011+ private final ImageData srcAt100 ;
2012+ private final ImageData maskAt100 ;
2013+
2014+ MaskedImageDataProviderWrapper (ImageData srcAt100 , ImageData maskAt100 ) {
2015+ this .srcAt100 = (ImageData ) srcAt100 .clone ();
2016+ this .maskAt100 = (ImageData ) maskAt100 .clone ();
2017+ initImage ();
2018+ }
2019+
2020+ @ Override
2021+ protected Rectangle getBounds (int zoom ) {
2022+ Rectangle rectangle = new Rectangle (0 , 0 , srcAt100 .width , srcAt100 .height );
2023+ return DPIUtil .scaleUp (rectangle , zoom );
2024+ }
2025+
2026+ @ Override
2027+ protected ElementAtZoom <ImageData > loadImageData (int zoom ) {
2028+ ImageData scaledSource = DPIUtil .scaleImageData (device , srcAt100 , zoom , 100 );
2029+ ImageData scaledMask = DPIUtil .scaleImageData (device , maskAt100 , zoom , 100 );
2030+ scaledMask = ImageData .convertMask (scaledMask );
2031+ ImageData mergedData = applyMask (scaledSource , scaledMask );
2032+ return new ElementAtZoom <>(mergedData , zoom );
2033+ }
2034+
2035+ @ Override
2036+ AbstractImageProviderWrapper createCopy (Image image ) {
2037+ return image .new MaskedImageDataProviderWrapper (this .srcAt100 , this .maskAt100 );
2038+ }
2039+ }
2040+
2041+ private class ImageDataLoaderStreamProviderWrapper extends ImageFromImageDataProviderWrapper {
2042+ private byte [] inputStreamData ;
2043+
2044+ ImageDataLoaderStreamProviderWrapper (InputStream inputStream ) {
2045+ try {
2046+ this .inputStreamData = inputStream .readAllBytes ();
2047+ initImage ();
2048+ } catch (IOException e ) {
2049+ SWT .error (SWT .ERROR_INVALID_ARGUMENT , e );
2050+ }
2051+ }
2052+
2053+ private ImageDataLoaderStreamProviderWrapper (byte [] inputStreamData ) {
2054+ this .inputStreamData = inputStreamData ;
2055+ }
2056+
2057+ @ Override
2058+ protected ElementAtZoom <ImageData > loadImageData (int zoom ) {
2059+ return ImageDataLoader .load (new ByteArrayInputStream (inputStreamData ), FileFormat .DEFAULT_ZOOM , zoom );
2060+ }
2061+
2062+ @ Override
2063+ protected Rectangle getBounds (int zoom ) {
2064+ ImageData scaledImageData = getImageData (zoom );
2065+ return new Rectangle (0 , 0 , scaledImageData .width , scaledImageData .height );
2066+ }
2067+
2068+ @ Override
2069+ AbstractImageProviderWrapper createCopy (Image image ) {
2070+ return new ImageDataLoaderStreamProviderWrapper (inputStreamData );
2071+ }
2072+ }
2073+
19502074private class PlainImageProviderWrapper extends AbstractImageProviderWrapper {
19512075 private final int width ;
19522076 private final int height ;
0 commit comments