diff options
author | George Cheng | 2011-12-20 20:00:29 +0000 |
---|---|---|
committer | Carolyn MacLeod | 2011-12-20 20:00:29 +0000 |
commit | afd2596f7d0b684f40a6cde49ffd8b1e1885b748 (patch) | |
tree | de5b91ada4b5eab13de5c186800709887582c361 | |
parent | 4ddc80fac7dd7587f52e196fb30aea2e09d434af (diff) | |
download | eclipse.platform.swt-afd2596f7d0b684f40a6cde49ffd8b1e1885b748.tar.gz eclipse.platform.swt-afd2596f7d0b684f40a6cde49ffd8b1e1885b748.tar.xz eclipse.platform.swt-afd2596f7d0b684f40a6cde49ffd8b1e1885b748.zip |
Bug 96320 - ImageLoader.save cannot set JPEG compression ratio
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 0feebe2873..e866835597 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 967feb708d..af3722538c 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 28299db611..e90cdb175d 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 bf7a67914c..63228faa69 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 70eee2136f..cb473f01ca 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 11f9e7f593..69c1312582 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 b2a78802d8..6973182a54 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); |