Skip to content

Commit 909a985

Browse files
amartya4256fedejeanne
authored andcommitted
Smooth Scaling Rounding error fix for win32 eclipse-platform#62
This commit contributes to fixing the implementation of Smooth scaling of the ImageData to get rid of the rounding errors because of multiple scale ups and downs with fractional scale factor. The commit replicates and modifies the DPIUtil::autoScaleImageData method implementation in Image class to adapt the same. contributes to eclipse-platform#62 and eclipse-platform#127
1 parent b91e012 commit 909a985

File tree

2 files changed

+54
-10
lines changed
  • bundles/org.eclipse.swt/Eclipse SWT

2 files changed

+54
-10
lines changed

bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/DPIUtil.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ private static ImageData autoScaleImageData (Device device, final ImageData imag
292292
int height = imageData.height;
293293
int scaledWidth = Math.round (width * scaleFactor);
294294
int scaledHeight = Math.round (height * scaleFactor);
295-
boolean useSmoothScaling = autoScaleMethod == AutoScaleMethod.SMOOTH && imageData.getTransparencyType() != SWT.TRANSPARENCY_MASK;
295+
boolean useSmoothScaling = isSmoothScalingEnabled() && imageData.getTransparencyType() != SWT.TRANSPARENCY_MASK;
296296
if (useSmoothScaling) {
297297
Image original = new Image (device, (ImageDataProvider) zoom -> imageData);
298298
/* Create a 24 bit image data with alpha channel */
@@ -316,6 +316,10 @@ private static ImageData autoScaleImageData (Device device, final ImageData imag
316316
}
317317
}
318318

319+
public static boolean isSmoothScalingEnabled() {
320+
return autoScaleMethod == AutoScaleMethod.SMOOTH;
321+
}
322+
319323
/**
320324
* Returns a new rectangle as per the scaleFactor.
321325
*/
@@ -628,6 +632,10 @@ public static boolean useCairoAutoScale() {
628632
}
629633

630634
public static int getZoomForAutoscaleProperty (int nativeDeviceZoom) {
635+
return getZoomForAutoscaleProperty(nativeDeviceZoom, autoScaleValue);
636+
}
637+
638+
private static int getZoomForAutoscaleProperty (int nativeDeviceZoom, String autoScaleValue) {
631639
int zoom = 0;
632640
if (autoScaleValue != null) {
633641
if ("false".equalsIgnoreCase (autoScaleValue)) {

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

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ public Image(Device device, ImageData data) {
372372
if (data == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
373373
initialNativeZoom = DPIUtil.getNativeDeviceZoom();
374374
int deviceZoom = getZoom();
375-
data = DPIUtil.scaleImageData(device, new ElementAtZoom<>(data, 100), deviceZoom);
375+
data = scaleImageData(data, deviceZoom, 100);
376376
init(data, deviceZoom);
377377
init();
378378
this.device.registerResourceWithZoomSupport(this);
@@ -416,8 +416,8 @@ public Image(Device device, ImageData source, ImageData mask) {
416416
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
417417
}
418418
initialNativeZoom = DPIUtil.getNativeDeviceZoom();
419-
source = DPIUtil.autoScaleUp(device, source);
420-
mask = DPIUtil.autoScaleUp(device, mask);
419+
source = scaleImageData(source, getZoom(), 100);
420+
mask = scaleImageData(mask, getZoom(), 100);
421421
mask = ImageData.convertMask(mask);
422422
initIconHandle(this.device, source, mask, getZoom());
423423
init();
@@ -481,7 +481,8 @@ public Image (Device device, InputStream stream) {
481481
super(device);
482482
initialNativeZoom = DPIUtil.getNativeDeviceZoom();
483483
int deviceZoom = getZoom();
484-
ImageData data = DPIUtil.scaleImageData(device, ImageDataLoader.load(stream, FileFormat.DEFAULT_ZOOM, deviceZoom), deviceZoom);
484+
ElementAtZoom<ImageData> imageCandidate = ImageDataLoader.load(stream, FileFormat.DEFAULT_ZOOM, deviceZoom);
485+
ImageData data = scaleImageData(imageCandidate.element(), deviceZoom, imageCandidate.zoom());
485486
init(data, deviceZoom);
486487
init();
487488
this.device.registerResourceWithZoomSupport(this);
@@ -524,7 +525,8 @@ public Image (Device device, String filename) {
524525
if (filename == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
525526
initialNativeZoom = DPIUtil.getNativeDeviceZoom();
526527
int deviceZoom = getZoom();
527-
ImageData data = DPIUtil.scaleImageData(device, ImageDataLoader.load(filename, FileFormat.DEFAULT_ZOOM, deviceZoom), deviceZoom);
528+
ElementAtZoom<ImageData> imageCandidate = ImageDataLoader.load(filename, FileFormat.DEFAULT_ZOOM, deviceZoom);
529+
ImageData data = scaleImageData(imageCandidate.element(), deviceZoom, imageCandidate.zoom());
528530
init(data, deviceZoom);
529531
init();
530532
this.device.registerResourceWithZoomSupport(this);
@@ -1264,7 +1266,7 @@ private ImageData getScaledImageData (int zoom) {
12641266
}
12651267
TreeSet<Integer> availableZooms = new TreeSet<>(zoomLevelToImageHandle.keySet());
12661268
int closestZoom = Optional.ofNullable(availableZooms.higher(zoom)).orElse(availableZooms.lower(zoom));
1267-
return DPIUtil.scaleImageData (device, getImageMetadata(closestZoom).getImageData(), zoom, closestZoom);
1269+
return scaleImageData(getImageMetadata(closestZoom).getImageData(), zoom, closestZoom);
12681270
}
12691271

12701272

@@ -1854,6 +1856,40 @@ public void setBackground(Color color) {
18541856
zoomLevelToImageHandle.values().forEach(imageHandle -> imageHandle.setBackground(backgroundColor));
18551857
}
18561858

1859+
private ImageData scaleImageData(final ImageData imageData, int targetZoom, int currentZoom) {
1860+
if (imageData == null || targetZoom == currentZoom || (device != null && !device.isAutoScalable())) return imageData;
1861+
float scaleFactor = (float) targetZoom / (float) currentZoom;
1862+
int width = imageData.width;
1863+
int height = imageData.height;
1864+
int scaledWidth = Math.round (width * scaleFactor);
1865+
int scaledHeight = Math.round (height * scaleFactor);
1866+
boolean useSmoothScaling = DPIUtil.isSmoothScalingEnabled() && imageData.getTransparencyType() != SWT.TRANSPARENCY_MASK;
1867+
if (useSmoothScaling) {
1868+
return scaleToUsingSmoothScaling(scaledWidth, scaledHeight, imageData);
1869+
}
1870+
return imageData.scaledTo (scaledWidth, scaledHeight);
1871+
}
1872+
1873+
private ImageData scaleToUsingSmoothScaling(int width, int height, ImageData imageData) {
1874+
Image original = new Image (device, (ImageDataProvider) zoom -> imageData);
1875+
/* Create a 24 bit image data with alpha channel */
1876+
final ImageData resultData = new ImageData (width, height, 24, new PaletteData (0xFF, 0xFF00, 0xFF0000));
1877+
resultData.alphaData = new byte [width * height];
1878+
Image resultImage = new Image (device, (ImageDataProvider) zoom -> resultData);
1879+
GC gc = new GC (resultImage);
1880+
gc.setAntialias (SWT.ON);
1881+
gc.drawImage (original, 0, 0, imageData.width, imageData.height,
1882+
/* E.g. destWidth here is effectively DPIUtil.autoScaleDown (scaledWidth), but avoiding rounding errors.
1883+
* Nevertheless, we still have some rounding errors due to the point-based API GC#drawImage(..).
1884+
*/
1885+
0, 0, width, height, false);
1886+
gc.dispose ();
1887+
original.dispose ();
1888+
ImageData result = resultImage.getImageData (resultImage.getZoom());
1889+
resultImage.dispose ();
1890+
return result;
1891+
}
1892+
18571893
private int getZoom() {
18581894
return DPIUtil.getZoomForAutoscaleProperty(initialNativeZoom);
18591895
}
@@ -2073,7 +2109,7 @@ ImageData getImageData(int zoom) {
20732109

20742110
private ImageData scaleIfNecessary(ElementAtZoom<ImageData> imageDataAtZoom, int zoom) {
20752111
if (imageDataAtZoom.zoom() != zoom) {
2076-
return DPIUtil.scaleImageData(device, imageDataAtZoom, zoom);
2112+
return scaleImageData(imageDataAtZoom.element(), zoom, imageDataAtZoom.zoom());
20772113
} else {
20782114
return imageDataAtZoom.element();
20792115
}
@@ -2298,13 +2334,13 @@ private class ImageDataProviderWrapper extends BaseImageProviderWrapper<ImageDat
22982334
@Override
22992335
ImageData getImageData(int zoom) {
23002336
ElementAtZoom<ImageData> data = DPIUtil.validateAndGetImageDataAtZoom (provider, zoom);
2301-
return DPIUtil.scaleImageData (device, data.element(), zoom, data.zoom());
2337+
return scaleImageData(data.element(), zoom, data.zoom());
23022338
}
23032339

23042340
@Override
23052341
ImageHandle getImageMetadata(int zoom) {
23062342
ElementAtZoom<ImageData> imageCandidate = DPIUtil.validateAndGetImageDataAtZoom (provider, zoom);
2307-
ImageData resizedData = DPIUtil.scaleImageData (device, imageCandidate.element(), zoom, imageCandidate.zoom());
2343+
ImageData resizedData = scaleImageData(imageCandidate.element(), zoom, imageCandidate.zoom());
23082344
ImageData newData = adaptImageDataIfDisabledOrGray(resizedData);
23092345
init(newData, zoom);
23102346
return zoomLevelToImageHandle.get(zoom);

0 commit comments

Comments
 (0)