Bug 553240: ImageLoader save() creates striped images on Linux
A previous patch hardcoded all saved images to 32bit, meaning 4
bytes per pixel. However there was some leftover logic where a
24 bit image without an alpha channel could be loaded and saved
with 3 bytes per pixel. This caused weirdness as the data saving
algorithm was expecting 4 bytes per pixel and therefore some
pixels were not saved correctly.
Tested on Fedora 31, GTK3.24 with the snippet attached, as
well as previous ImageLoader snippets and a child Eclipse. No
AllNonBrowser JUnit tests fails.
Change-Id: I5c7184a2158f07879bd651cca81d8167c36f3d76
Signed-off-by: Eric Williams <ericwill@redhat.com>
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/ImageLoader.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/ImageLoader.java
index a1f6489..cb1c42c 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/ImageLoader.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/ImageLoader.java
@@ -465,7 +465,7 @@
int width = imgData.width;
int height = imgData.height;
int n_channels = imgData.bytesPerLine / width; // original n_channels 3 or 4
- int bytes_per_pixel = imgData.bytesPerLine / width; // n_channels for original ImageData (width * height * bytes_per_pixel) = imgData.length
+ int bytes_per_pixel = 4; // all images saved are 32 bit, if there is no alpha we set it to 255
/*
* Destination offsets, GdkPixbuf data is stored in RGBA format.
@@ -488,12 +488,8 @@
ob = 0;
}
- if (has_alpha && bytes_per_pixel == 3) {
- bytes_per_pixel = 4;
- }
-
- // We use alpha by default now so just hard code bytes per pixel to 4
- byte[] srcData = new byte[(width * height * 4)];
+ // We use alpha by default now so bytes_per_pixel is always 4
+ byte[] srcData = new byte[(width * height * bytes_per_pixel)];
int alpha_offset = n_channels == 4 ? 1 : 0;
if (has_alpha) {
diff --git a/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug553240_ImageLoaderSavingStriped.java b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug553240_ImageLoaderSavingStriped.java
new file mode 100644
index 0000000..bd356fb
--- /dev/null
+++ b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug553240_ImageLoaderSavingStriped.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Red Hat 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
+ *
+ * Contributors:
+ * Red Hat - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.tests.gtk.snippets;
+
+import java.io.File;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.ImageLoader;
+import org.eclipse.swt.layout.RowData;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+public class Bug553240_ImageLoaderSavingStriped {
+
+ public static void main(final String[] args) {
+ try {
+ initUI();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ static void initUI() throws Exception {
+ final File file = File.createTempFile("swt", "example");
+ final Display display = new Display();
+ final Shell shell = new Shell();
+
+ shell.setLayout(new RowLayout());
+ shell.setText("Bug 553240: Saving a PNG results in a striped Image");
+
+ Label label = new Label(shell, SWT.BORDER);
+ label.setText("This snippet loads an Image, saves it, then loads it again.\n"
+ + "The first Image is saved in a temporary file shown in the Text widget.\n"
+ + "The Image loaded the second time is drawn on the Canvas.");
+ final Text text = new Text(shell, SWT.BORDER);
+ text.setBounds(0, 50, 450, 75);
+
+ ImageLoader loader = new ImageLoader();
+ final ImageData[] loadedImageData = loader.load("./images/map.png");
+ final ImageData tileImageData = loadedImageData[0];
+ final ImageLoader imageLoader = new ImageLoader();
+ imageLoader.data = new ImageData[] { tileImageData };
+
+ final int imageType = tileImageData.type;
+ file.delete();
+ final String imageFilePath = file.getAbsolutePath();
+ imageLoader.save(imageFilePath, imageType);
+ text.setText(file.getAbsolutePath());
+
+ Composite composite = new Composite(shell, SWT.NONE);
+ RowData layoutData = new RowData(256, 256);
+ composite.setLayoutData(layoutData);
+
+ composite.setLayout(new RowLayout());
+ Canvas canvas = new Canvas(composite, SWT.NONE);
+ layoutData = new RowData(256, 256);
+ canvas.setLayoutData(layoutData);
+
+ canvas.addPaintListener(e -> {
+ ImageLoader canvasLoader = new ImageLoader();
+ final ImageData[] cloadedImageData = canvasLoader.load(file.getAbsolutePath());
+ final ImageData ctileImageData = cloadedImageData[0];
+ canvasLoader.data = new ImageData[] { ctileImageData };
+
+ Image imageToDraw = new Image(display, ctileImageData);
+ e.gc.drawImage(imageToDraw, 0, 0);
+ imageToDraw.dispose();
+ });
+
+ shell.pack();
+ shell.open();
+
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ file.delete();
+ }
+}
diff --git a/tests/org.eclipse.swt.tests.gtk/images/map.png b/tests/org.eclipse.swt.tests.gtk/images/map.png
new file mode 100644
index 0000000..2117178
--- /dev/null
+++ b/tests/org.eclipse.swt.tests.gtk/images/map.png
Binary files differ