summaryrefslogtreecommitdiffstatsabout
diff options
context:
space:
mode:
authorGeorge Cheng2011-12-20 15:00:29 (EST)
committer Carolyn MacLeod2011-12-20 15:00:29 (EST)
commitafd2596f7d0b684f40a6cde49ffd8b1e1885b748 (patch)
treede5b91ada4b5eab13de5c186800709887582c361
parent4ddc80fac7dd7587f52e196fb30aea2e09d434af (diff)
downloadeclipse.platform.swt-afd2596f7d0b684f40a6cde49ffd8b1e1885b748.zip
eclipse.platform.swt-afd2596f7d0b684f40a6cde49ffd8b1e1885b748.tar.gz
eclipse.platform.swt-afd2596f7d0b684f40a6cde49ffd8b1e1885b748.tar.bz2
Bug 96320 - ImageLoader.save cannot set JPEG compression ratio
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageLoader.java17
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGFileFormat.java1
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngEncoder.java24
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/common_j2me/org/eclipse/swt/internal/Compatibility.java4
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/common_j2se/org/eclipse/swt/internal/Compatibility.java7
-rw-r--r--examples/org.eclipse.swt.examples/src/examples_images.properties2
-rw-r--r--examples/org.eclipse.swt.examples/src/org/eclipse/swt/examples/imageanalyzer/ImageAnalyzer.java137
7 files changed, 175 insertions, 17 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageLoader.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageLoader.java
index 0feebe2..e866835 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageLoader.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageLoader.java
@@ -81,6 +81,22 @@ public class ImageLoader {
* The default is 1. A value of 0 means 'display repeatedly'
*/
public int repeatCount;
+
+ /**
+ * This is the compression used when saving jpeg and png files.
+ * <p>
+ * When saving jpeg files, the value is from 1 to 100,
+ * where 1 is very high compression but low quality, and 100 is
+ * no compression and high quality; default is 75.
+ * </p><p>
+ * When saving png files, the value is from 0 to 3, but they do not impact the quality
+ * because PNG is lossless compression. 0 is uncompressed, 1 is low compression and fast,
+ * 2 is default compression, and 3 is high compression but slow.
+ * </p>
+ *
+ * @since 3.8
+ */
+ public int compression;
/*
* the set of ImageLoader event listeners, created on demand
@@ -104,6 +120,7 @@ void reset() {
logicalScreenHeight = 0;
backgroundPixel = -1;
repeatCount = 1;
+ compression = -1;
}
/**
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGFileFormat.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGFileFormat.java
index 967feb7..af37225 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGFileFormat.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGFileFormat.java
@@ -1768,6 +1768,7 @@ void unloadIntoByteStream(ImageLoader loader) {
}
quantizationTables = new int[4][];
JPEGQuantizationTable chromDQT = JPEGQuantizationTable.defaultChrominanceTable();
+ int encoderQFactor = loader.compression >= 1 && loader.compression <= 100 ? loader.compression : 75;
chromDQT.scaleBy(encoderQFactor);
int[] jpegDQTKeys = chromDQT.getQuantizationTablesKeys();
int[][] jpegDQTValues = chromDQT.getQuantizationTablesValues();
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngEncoder.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngEncoder.java
index 28299db..e90cdb1 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngEncoder.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngEncoder.java
@@ -29,6 +29,11 @@ final class PngEncoder extends Object {
static final byte TAG_IDAT[] = {(byte) 'I', (byte) 'D', (byte) 'A', (byte) 'T'};
static final byte TAG_IEND[] = {(byte) 'I', (byte) 'E', (byte) 'N', (byte) 'D'};
+ static final int NO_COMPRESSION = 0;
+ static final int BEST_SPEED = 1;
+ static final int BEST_COMPRESSION = 9;
+ static final int DEFAULT_COMPRESSION = -1;
+
ByteArrayOutputStream bytes = new ByteArrayOutputStream(1024);
PngChunk chunk;
@@ -232,8 +237,22 @@ void writeTransparency() {
void writeImageData() throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
- OutputStream os = Compatibility.newDeflaterOutputStream(baos);
- if (os == null) os = baos;
+ OutputStream os = null;
+ switch (loader.compression) {
+ case 0:
+ os = Compatibility.newDeflaterOutputStream(baos, NO_COMPRESSION);
+ break;
+ case 1:
+ os = Compatibility.newDeflaterOutputStream(baos, BEST_SPEED);
+ break;
+ case 3:
+ os = Compatibility.newDeflaterOutputStream(baos, BEST_COMPRESSION);
+ break;
+ default:
+ os = Compatibility.newDeflaterOutputStream(baos, DEFAULT_COMPRESSION);
+ break;
+ }
+ if (os == null) os = baos; // returns null for J2ME
if (colorType == 3) {
@@ -312,6 +331,7 @@ void writeImageData() throws IOException {
byte[] compressed = baos.toByteArray();
if (os == baos) {
+ /* Use PngDeflater for J2ME. */
PngDeflater deflater = new PngDeflater();
compressed = deflater.deflate(compressed);
}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common_j2me/org/eclipse/swt/internal/Compatibility.java b/bundles/org.eclipse.swt/Eclipse SWT/common_j2me/org/eclipse/swt/internal/Compatibility.java
index bf7a679..63228fa 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/common_j2me/org/eclipse/swt/internal/Compatibility.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common_j2me/org/eclipse/swt/internal/Compatibility.java
@@ -191,7 +191,7 @@ public static int pow2(int n) {
}
/**
- * Create an DeflaterOutputStream if such things are supported.
+ * Create a DeflaterOutputStream if such things are supported.
*
* @param stream the output stream
* @return a deflater stream or <code>null</code>
@@ -199,7 +199,7 @@ public static int pow2(int n) {
*
* @since 3.4
*/
-public static OutputStream newDeflaterOutputStream(OutputStream stream) throws IOException {
+public static OutputStream newDeflaterOutputStream(OutputStream stream, int level) throws IOException {
return null;
}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common_j2se/org/eclipse/swt/internal/Compatibility.java b/bundles/org.eclipse.swt/Eclipse SWT/common_j2se/org/eclipse/swt/internal/Compatibility.java
index 70eee21..cb473f0 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/common_j2se/org/eclipse/swt/internal/Compatibility.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common_j2se/org/eclipse/swt/internal/Compatibility.java
@@ -15,6 +15,7 @@ import java.io.*;
import java.text.MessageFormat;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
+import java.util.zip.Deflater;
import java.util.zip.InflaterInputStream;
import java.util.zip.DeflaterOutputStream;
@@ -159,7 +160,7 @@ public static int pow2(int n) {
}
/**
- * Create an DeflaterOutputStream if such things are supported.
+ * Create a DeflaterOutputStream if such things are supported.
*
* @param stream the output stream
* @return a deflater stream or <code>null</code>
@@ -167,8 +168,8 @@ public static int pow2(int n) {
*
* @since 3.4
*/
-public static OutputStream newDeflaterOutputStream(OutputStream stream) throws IOException {
- return new DeflaterOutputStream(stream);
+public static OutputStream newDeflaterOutputStream(OutputStream stream, int level) throws IOException {
+ return new DeflaterOutputStream(stream, new Deflater(level));
}
/**
diff --git a/examples/org.eclipse.swt.examples/src/examples_images.properties b/examples/org.eclipse.swt.examples/src/examples_images.properties
index 11f9e7f..69c1312 100644
--- a/examples/org.eclipse.swt.examples/src/examples_images.properties
+++ b/examples/org.eclipse.swt.examples/src/examples_images.properties
@@ -24,6 +24,7 @@ Transparent = Transparent
Transparent_lc = transparent
Mask = Mask
Background = Background
+Save_group = Save
Animation = Animation
Previous = < &Previous
Next = &Next >
@@ -53,6 +54,7 @@ Delay_used = Delay: {0,number,integer} ms
Repeats_initial = Repeats:
Repeats_value = Repeats: {0,number,integer}
Repeats_forever = Repeats: {0,number,integer} (forever)
+Compression = Compression:
Palette_initial = Palette:
Palette_direct = Palette: Direct
Palette_value = Palette size: {0,number,integer}
diff --git a/examples/org.eclipse.swt.examples/src/org/eclipse/swt/examples/imageanalyzer/ImageAnalyzer.java b/examples/org.eclipse.swt.examples/src/org/eclipse/swt/examples/imageanalyzer/ImageAnalyzer.java
index b2a7880..6973182 100644
--- a/examples/org.eclipse.swt.examples/src/org/eclipse/swt/examples/imageanalyzer/ImageAnalyzer.java
+++ b/examples/org.eclipse.swt.examples/src/org/eclipse/swt/examples/imageanalyzer/ImageAnalyzer.java
@@ -31,8 +31,8 @@ public class ImageAnalyzer {
Label typeLabel, sizeLabel, depthLabel, transparentPixelLabel,
timeToLoadLabel, screenSizeLabel, backgroundPixelLabel,
locationLabel, disposalMethodLabel, delayTimeLabel,
- repeatCountLabel, paletteLabel, dataLabel, statusLabel;
- Combo backgroundCombo, scaleXCombo, scaleYCombo, alphaCombo;
+ repeatCountLabel, compressionRatioLabel, paletteLabel, dataLabel, statusLabel;
+ Combo backgroundCombo, imageTypeCombo, compressionCombo, scaleXCombo, scaleYCombo, alphaCombo;
Button incrementalCheck, transparentCheck, maskCheck, backgroundCheck;
Button previousButton, nextButton, animateButton;
StyledText dataText;
@@ -45,6 +45,7 @@ public class ImageAnalyzer {
int paletteWidth = 140; // recalculated and used as a width hint
int ix = 0, iy = 0, py = 0; // used to scroll the image and palette
+ int compression; // used to modify the compression ratio of the image
float xscale = 1, yscale = 1; // used to scale the image
int alpha = 255; // used to modify the alpha value of the image
boolean incremental = false; // used to incrementally display an image
@@ -71,8 +72,8 @@ public class ImageAnalyzer {
static final int ALPHA_X = 1;
static final int ALPHA_Y = 2;
static final String[] OPEN_FILTER_EXTENSIONS = new String[] {
- "*.bmp; *.gif; *.ico; *.jfif; *.jpeg; *.jpg; *.png; *.tif; *.tiff",
- "*.bmp", "*.gif", "*.ico", "*.jpg; *.jpeg; *.jfif", "*.png", "*.tif; *.tiff" };
+ "*.bmp;*.gif;*.ico;*.jfif;*.jpeg;*.jpg;*.png;*.tif;*.tiff",
+ "*.bmp", "*.gif", "*.ico", "*.jpg;*.jpeg;*.jfif", "*.png", "*.tif;*.tiff" };
static final String[] OPEN_FILTER_NAMES = new String[] {
bundle.getString("All_images") + " (bmp, gif, ico, jfif, jpeg, jpg, png, tif, tiff)",
"BMP (*.bmp)", "GIF (*.gif)", "ICO (*.ico)", "JPEG (*.jpg, *.jpeg, *.jfif)",
@@ -83,7 +84,6 @@ public class ImageAnalyzer {
"Uncompressed BMP (*.bmp)", "RLE Compressed BMP (*.bmp)", "GIF (*.gif)",
"ICO (*.ico)", "JPEG (*.jpg)", "PNG (*.png)",
"TIFF (*.tif)", "OS/2 BMP (*.bmp)" };
-
class TextPrompter extends Dialog {
String message = "";
String result = null;
@@ -260,6 +260,60 @@ public class ImageAnalyzer {
}
});
+ // Combo to change the compression ratio.
+ group = new Group(controls, SWT.NONE);
+ group.setLayout(new GridLayout(3, true));
+ group.setText(bundle.getString("Save_group"));
+ imageTypeCombo = new Combo(group, SWT.DROP_DOWN | SWT.READ_ONLY);
+ String[] types = {"JPEG", "PNG", "GIF", "ICO", "TIFF", "BMP"};
+ for (int i = 0; i < types.length; i++) {
+ imageTypeCombo.add(types[i]);
+ }
+ imageTypeCombo.select(imageTypeCombo.indexOf("JPEG"));
+ imageTypeCombo.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent event) {
+ int index = imageTypeCombo.getSelectionIndex();
+ switch(index) {
+ case 0:
+ compressionCombo.setEnabled(true);
+ compressionRatioLabel.setEnabled(true);
+ if (compressionCombo.getItemCount() == 100) break;
+ compressionCombo.removeAll();
+ for (int i = 0; i < 100; i++) {
+ compressionCombo.add(String.valueOf(i + 1));
+ }
+ compressionCombo.select(compressionCombo.indexOf("75"));
+ break;
+ case 1:
+ compressionCombo.setEnabled(true);
+ compressionRatioLabel.setEnabled(true);
+ if (compressionCombo.getItemCount() == 10) break;
+ compressionCombo.removeAll();
+ for (int i = 0; i < 4; i++) {
+ compressionCombo.add(String.valueOf(i));
+ }
+ compressionCombo.select(0);
+ break;
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ compressionCombo.setEnabled(false);
+ compressionRatioLabel.setEnabled(false);
+ break;
+ }
+ }
+ });
+ imageTypeCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ compressionRatioLabel = new Label(group, SWT.NONE);
+ compressionRatioLabel.setText(bundle.getString("Compression"));
+ compressionRatioLabel.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false));
+ compressionCombo = new Combo(group, SWT.DROP_DOWN | SWT.READ_ONLY);
+ for (int i = 0; i < 100; i++) {
+ compressionCombo.add(String.valueOf(i + 1));
+ }
+ compressionCombo.select(compressionCombo.indexOf("75"));
+ compressionCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
// Combo to change the x scale.
String[] values = {
"0.1", "0.2", "0.3", "0.4", "0.5", "0.6", "0.7", "0.8", "0.9", "1",
@@ -862,7 +916,7 @@ public class ImageAnalyzer {
lastPath = fileChooser.getFilterPath();
if (filename == null)
return;
-
+ showFileType(filename);
Cursor waitCursor = display.getSystemCursor(SWT.CURSOR_WAIT);
shell.setCursor(waitCursor);
imageCanvas.setCursor(waitCursor);
@@ -1040,8 +1094,9 @@ public class ImageAnalyzer {
try {
// Save the current image to the current file.
loader.data = new ImageData[] {imageData};
+ if (imageData.type == SWT.IMAGE_JPEG) loader.compression = compressionCombo.indexOf(compressionCombo.getText()) + 1;
+ if (imageData.type == SWT.IMAGE_PNG) loader.compression = compressionCombo.indexOf(compressionCombo.getText());
loader.save(fileName, imageData.type);
-
} catch (SWTException e) {
showErrorDialog(bundle.getString("Saving_lc"), fileName, e);
} catch (SWTError e) {
@@ -1065,10 +1120,30 @@ public class ImageAnalyzer {
if (nameStart > -1) {
name = name.substring(nameStart + 1);
}
- fileChooser.setFileName(name);
+ fileChooser.setFileName(name.substring(0, name.indexOf(".")) + "." + imageTypeCombo.getText().toLowerCase());
}
fileChooser.setFilterExtensions(SAVE_FILTER_EXTENSIONS);
fileChooser.setFilterNames(SAVE_FILTER_NAMES);
+ switch (imageTypeCombo.getSelectionIndex()) {
+ case 0:
+ fileChooser.setFilterIndex(4);
+ break;
+ case 1:
+ fileChooser.setFilterIndex(5);
+ break;
+ case 2:
+ fileChooser.setFilterIndex(2);
+ break;
+ case 3:
+ fileChooser.setFilterIndex(3);
+ break;
+ case 4:
+ fileChooser.setFilterIndex(6);
+ break;
+ case 5:
+ fileChooser.setFilterIndex(0);
+ break;
+ }
String filename = fileChooser.open();
lastPath = fileChooser.getFilterPath();
if (filename == null)
@@ -1118,6 +1193,7 @@ public class ImageAnalyzer {
}
if (!multi) loader.data = new ImageData[] {imageData};
+ loader.compression = compressionCombo.indexOf(compressionCombo.getText());
loader.save(filename, filetype);
/* Restore the previous transparency setting. */
@@ -1298,8 +1374,7 @@ public class ImageAnalyzer {
} else {
imageCanvas.setBackground(null);
}
- }
-
+ }
/*
* Called when the ScaleX combo selection changes.
*/
@@ -2374,6 +2449,48 @@ public class ImageAnalyzer {
return SWT.IMAGE_UNDEFINED;
}
+ void showFileType(String filename) {
+ String ext = filename.substring(filename.lastIndexOf('.') + 1);
+ if (ext.equalsIgnoreCase("jpg") || ext.equalsIgnoreCase("jpeg") || ext.equalsIgnoreCase("jfif")) {
+ imageTypeCombo.select(0);
+ compressionCombo.setEnabled(true);
+ compressionRatioLabel.setEnabled(true);
+ if (compressionCombo.getItemCount() == 100) return;
+ compressionCombo.removeAll();
+ for (int i = 0; i < 100; i++) {
+ compressionCombo.add(String.valueOf(i + 1));
+ }
+ compressionCombo.select(compressionCombo.indexOf("75"));
+ return;
+ }
+ if (ext.equalsIgnoreCase("png")) {
+ imageTypeCombo.select(1);
+ compressionCombo.setEnabled(true);
+ compressionRatioLabel.setEnabled(true);
+ if (compressionCombo.getItemCount() == 10) return;
+ compressionCombo.removeAll();
+ for (int i = 0; i < 4; i++) {
+ compressionCombo.add(String.valueOf(i));
+ }
+ compressionCombo.select(0);
+ return;
+ }
+ if (ext.equalsIgnoreCase("bmp")) {
+ imageTypeCombo.select(5);
+ }
+ if (ext.equalsIgnoreCase("gif")) {
+ imageTypeCombo.select(2);
+ }
+ if (ext.equalsIgnoreCase("ico")) {
+ imageTypeCombo.select(3);
+ }
+ if (ext.equalsIgnoreCase("tif") || ext.equalsIgnoreCase("tiff")) {
+ imageTypeCombo.select(4);
+ }
+ compressionCombo.setEnabled(false);
+ compressionRatioLabel.setEnabled(false);
+ }
+
static String createMsg(String msg, Object[] args) {
MessageFormat formatter = new MessageFormat(msg);
return formatter.format(args);