Skip to content
Merged
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
Expand Up @@ -14,6 +14,8 @@
package org.eclipse.swt.graphics;


import static org.eclipse.swt.internal.image.ImageColorTransformer.DEFAULT_DISABLED_IMAGE_TRANSFORMER;

import java.io.*;
import java.util.*;
import java.util.function.*;
Expand Down Expand Up @@ -435,29 +437,21 @@ private void createRepFromSourceAndApplyFlag(NSBitmapImageRep srcRep, int srcWid
long data = rep.bitmapData();
C.memmove(data, srcData, srcWidth * srcHeight * 4);
if (flag != SWT.IMAGE_COPY) {
final int redOffset, greenOffset, blueOffset;
final int redOffset, greenOffset, blueOffset, alphaOffset;
if (srcBpp == 32 && (srcBitmapFormat & OS.NSAlphaFirstBitmapFormat) == 0) {
redOffset = 0;
greenOffset = 1;
blueOffset = 2;
alphaOffset = 3;
} else {
alphaOffset = 0;
redOffset = 1;
greenOffset = 2;
blueOffset = 3;
}
/* Apply transformation */
switch (flag) {
case SWT.IMAGE_DISABLE: {
Color zeroColor = this.device.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW);
RGB zeroRGB = zeroColor.getRGB();
byte zeroRed = (byte)zeroRGB.red;
byte zeroGreen = (byte)zeroRGB.green;
byte zeroBlue = (byte)zeroRGB.blue;
Color oneColor = this.device.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
RGB oneRGB = oneColor.getRGB();
byte oneRed = (byte)oneRGB.red;
byte oneGreen = (byte)oneRGB.green;
byte oneBlue = (byte)oneRGB.blue;
byte[] line = new byte[(int)srcBpr];
for (int y=0; y<srcHeight; y++) {
C.memmove(line, data + (y * srcBpr), srcBpr);
Expand All @@ -466,16 +460,12 @@ private void createRepFromSourceAndApplyFlag(NSBitmapImageRep srcRep, int srcWid
int red = line[offset+redOffset] & 0xFF;
int green = line[offset+greenOffset] & 0xFF;
int blue = line[offset+blueOffset] & 0xFF;
int intensity = red * red + green * green + blue * blue;
if (intensity < 98304) {
line[offset+redOffset] = zeroRed;
line[offset+greenOffset] = zeroGreen;
line[offset+blueOffset] = zeroBlue;
} else {
line[offset+redOffset] = oneRed;
line[offset+greenOffset] = oneGreen;
line[offset+blueOffset] = oneBlue;
}
int alpha = line[offset+alphaOffset] & 0xFF;
RGBA result = DEFAULT_DISABLED_IMAGE_TRANSFORMER.adaptPixelValue(red, green, blue, alpha);
line[offset+redOffset] = (byte) result.rgb.red;
line[offset+greenOffset] = (byte) result.rgb.green;
line[offset+blueOffset] = (byte) result.rgb.blue;
line[offset+alphaOffset] = (byte) result.alpha;
offset += 4;
}
C.memmove(data + (y * srcBpr), line, srcBpr);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*******************************************************************************
* Copyright (c) 2025 Vector Informatik GmbH and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.swt.internal.image;

import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;

public interface ImageColorTransformer {

public static final String IMAGE_DISABLEMENT_ALGORITHM_GRAYED = "grayed";
public static final String IMAGE_DISABLEMENT_ALGORITHM_GTK = "gtk";
public static final String IMAGE_DISABLEMENT_ALGORITHM_DESATURATED = "desaturated";
public static final String IMAGE_DISABLEMENT_ALGORITHM = System.getProperty("org.eclipse.swt.image.disablement",
IMAGE_DISABLEMENT_ALGORITHM_GRAYED).strip();

public static final ImageColorTransformer DEFAULT_DISABLED_IMAGE_TRANSFORMER = switch (IMAGE_DISABLEMENT_ALGORITHM) {
case IMAGE_DISABLEMENT_ALGORITHM_GTK -> ImageColorTransformer.forRGB(0.5f, 0.5f, 0.5f, 0.5f);
case IMAGE_DISABLEMENT_ALGORITHM_DESATURATED -> ImageColorTransformer.forHSB(1.0f, 0.2f, 0.9f, 0.5f);
default -> ImageColorTransformer.forGrayscaledContrastBrightness(0.2f, 2.9f);
};

RGBA adaptPixelValue(int red, int green, int blue, int alpha);

public static ImageColorTransformer forHSB(float hueFactor, float saturationFactor, float brightnessFactor,
float alphaFactor) {
return (red, green, blue, alpha) -> {
float[] hsba = new RGBA(red, green, blue, alpha).getHSBA();
float hue = Math.min(hueFactor * hsba[0], 1.0f);
float saturation = Math.min(saturationFactor * hsba[1], 1.0f);
float brightness = Math.min(brightnessFactor * hsba[2], 1.0f);
float alphaResult = Math.min(alphaFactor * hsba[3], 255.0f);
return new RGBA(hue, saturation, brightness, alphaResult);
};
}

public static ImageColorTransformer forRGB(float redFactor, float greenFactor, float blueFactor,
float alphaFactor) {
return (red, green, blue, alpha) -> {
int redResult = (int) Math.min(redFactor * red, 255.0f);
int greenResult = (int) Math.min(greenFactor * green, 255.0f);
int blueResult = (int) Math.min(blueFactor * blue, 255.0f);
int alphaResult = (int) Math.min(alphaFactor * alpha, 255.0f);
return new RGBA(redResult, greenResult, blueResult, alphaResult);
};
}

public static ImageColorTransformer forIntensityThreshold(Device device) {
RGBA lowIntensity = device.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW).getRGBA();
RGBA highIntensity = device.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND).getRGBA();
return (red, green, blue, alpha) -> {
int intensity = red * red + green * green + blue * blue;
RGBA usedGraytone = intensity < 98304 ? lowIntensity : highIntensity;
return new RGBA(usedGraytone.rgb.red, usedGraytone.rgb.green, usedGraytone.rgb.blue, alpha);
};
}

public static ImageColorTransformer forGrayscaledContrastBrightness(float contrast, float brightness) {
return (red, green, blue, alpha) -> {
int grayValue = Math.min((77 * red + 151 * green + 28 * blue) / 255, 255);
int resultValue = (int) Math.min(Math.max((contrast * (grayValue * brightness - 128) + 128), 0), 255);
return new RGBA(resultValue, resultValue, resultValue, alpha);
};
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
package org.eclipse.swt.graphics;


import static org.eclipse.swt.internal.image.ImageColorTransformer.DEFAULT_DISABLED_IMAGE_TRANSFORMER;

import java.io.*;
import java.util.*;

Expand Down Expand Up @@ -307,15 +309,30 @@ public Image(Device device, Image srcImage, int flag) {
byte[] line = new byte[stride];
for (int y=0; y<height; y++) {
C.memmove(line, data + (y * stride), stride);
for (int x=0, offset=0; x<width; x++, offset += 4) {
for (int x = 0, offset = 0; x < width; x++, offset += 4) {
int a = line[offset + oa] & 0xFF;
int r = line[offset + or] & 0xFF;
int g = line[offset + og] & 0xFF;
int b = line[offset + ob] & 0xFF;
line[offset + oa] = (byte) Math.round((double) a * 0.5);
line[offset + or] = (byte) Math.round((double) r * 0.5);
line[offset + og] = (byte) Math.round((double) g * 0.5);
line[offset + ob] = (byte) Math.round((double) b * 0.5);
// The alpha value is embedded into the RGB values as well, so extract it out
// of those values for transformation and reapply it afterwards
// Note: don't change execution order, e.g., using *= assignment, as this is
// integer arithmetics
if (hasAlpha && a != 0) {
r = r * 255 / a;
g = g * 255 / a;
b = b * 255 / a;
}
RGBA result = DEFAULT_DISABLED_IMAGE_TRANSFORMER.adaptPixelValue(r, g, b, a);
if (hasAlpha) {
result.rgb.red = result.rgb.red * result.alpha / 255;
result.rgb.green = result.rgb.green * result.alpha / 255;
result.rgb.blue = result.rgb.blue * result.alpha / 255;
}
line[offset + oa] = (byte) result.alpha;
line[offset + or] = (byte) result.rgb.red;
line[offset + og] = (byte) result.rgb.green;
line[offset + ob] = (byte) result.rgb.blue;
}
C.memmove(data + (y * stride), line, stride);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
package org.eclipse.swt.graphics;


import static org.eclipse.swt.internal.image.ImageColorTransformer.DEFAULT_DISABLED_IMAGE_TRANSFORMER;

import java.io.*;
import java.util.*;
import java.util.function.*;
Expand Down Expand Up @@ -669,11 +671,7 @@ void init() {

private ImageData applyDisableImageData(ImageData data, int height, int width) {
PaletteData palette = data.palette;
RGB[] rgbs = new RGB[3];
rgbs[0] = this.device.getSystemColor(SWT.COLOR_BLACK).getRGB();
rgbs[1] = this.device.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW).getRGB();
rgbs[2] = this.device.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND).getRGB();
ImageData newData = new ImageData(width, height, 8, new PaletteData(rgbs));
ImageData newData = new ImageData(width, height, 32, new PaletteData(0xFF, 0xFF00, 0xFF0000));
newData.alpha = data.alpha;
newData.alphaData = data.alphaData;
newData.maskData = data.maskData;
Expand All @@ -693,7 +691,6 @@ private ImageData applyDisableImageData(ImageData data, int height, int width) {
int greenShift = palette.greenShift;
int blueShift = palette.blueShift;
for (int y=0; y<height; y++) {
int offset = y * newData.bytesPerLine;
data.getPixels(0, y, width, scanline, 0);
if (mask != null) mask.getPixels(0, y, width, maskScanline, 0);
for (int x=0; x<width; x++) {
Expand All @@ -712,14 +709,10 @@ private ImageData applyDisableImageData(ImageData data, int height, int width) {
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;
}
RGBA result = DEFAULT_DISABLED_IMAGE_TRANSFORMER.adaptPixelValue(red, green, blue, data.getAlpha(x, y));
newData.setAlpha(x, y, result.alpha);
newData.setPixel(x, y, newData.palette.getPixel(result.rgb));
}
offset++;
}
}
return newData;
Expand Down
Loading