Index: src/main/java/com/xpn/xwiki/plugin/image/ImagePlugin.java
===================================================================
--- src/main/java/com/xpn/xwiki/plugin/image/ImagePlugin.java	(revision 30824)
+++ src/main/java/com/xpn/xwiki/plugin/image/ImagePlugin.java	(working copy)
@@ -31,8 +31,11 @@
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
+import java.util.Iterator;
 
-import javax.imageio.ImageIO;
+import javax.imageio.*;
+import javax.imageio.stream.*;
+import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
 
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.logging.Log;
@@ -55,6 +58,9 @@
     /** Logging helper object. */
     protected static final Log LOG = LogFactory.getLog(ImagePlugin.class);
 
+    /** Default JPEG image quality **/
+    protected static float defaultQuality = 0.3f;
+
     /** The image formats supported by the image plugin. */
     public enum SupportedFormat
     {
@@ -138,6 +144,18 @@
     {
         super.init(context);
         initCache(context);
+
+        String qualityParam = "";
+        try {
+            qualityParam = context.getWiki().Param("xwiki.plugin.image.quality");
+            if (!StringUtils.isBlank(qualityParam) && StringUtils.isNumeric(qualityParam.trim())) {
+                this.defaultQuality = Float.parseFloat(qualityParam.trim());
+                if (this.defaultQuality > 1)
+                  this.defaultQuality = 1;
+            }
+        } catch (NumberFormatException ex) {
+            LOG.error("Error in ImagePlugin reading quality: " + qualityParam, ex);
+        }
     }
 
     public void initCache(XWikiContext context)
@@ -155,7 +173,6 @@
             LOG.warn("Cannot create temporary files", ex);
         }
         configuration.put("cache.path", imgTempDir.getAbsolutePath());
-
         // Set cache constraints
         LRUEvictionConfiguration lru = new LRUEvictionConfiguration();
         configuration.put(LRUEvictionConfiguration.CONFIGURATIONID, lru);
@@ -202,6 +219,7 @@
     {
         int height = 0;
         int width = 0;
+        float quality = this.defaultQuality;
         XWikiAttachment attachmentClone = null;
 
         if (!this.isSupportedImageFormat(attachment.getMimeType(context))) {
@@ -210,9 +228,11 @@
 
         String sheight = context.getRequest().getParameter("height");
         String swidth = context.getRequest().getParameter("width");
+        String squality = context.getRequest().getParameter("quality");
 
         // If no scaling is needed, return the original image.
-        if ((StringUtils.isBlank(sheight) || !StringUtils.isNumeric(sheight))
+        if ((StringUtils.isBlank(squality))
+            && (StringUtils.isBlank(sheight) || !StringUtils.isNumeric(sheight)) 
             && (StringUtils.isBlank(swidth) || !StringUtils.isNumeric(swidth))) {
             return attachment;
         }
@@ -228,11 +248,14 @@
             if (swidth != null) {
                 width = Integer.parseInt(swidth);
             }
+            if (squality != null) {
+                quality = Float.parseFloat(squality);
+            }
 
             attachmentClone = (XWikiAttachment) attachment.clone();
             String key =
                 attachmentClone.getId() + "-" + attachmentClone.getVersion() + "-" + SupportedFormat.PNG.getCode()
-                    + "-" + width + "-" + height;
+                    + "-" + width + "-" + height + "-" + quality;
 
             if (this.imageCache != null) {
                 byte[] data = this.imageCache.get(key);
@@ -241,25 +264,33 @@
                     attachmentClone.setContent(data);
                 } else {
                     if (width == 0) {
-                        attachmentClone = this.getImageByHeight(attachmentClone, height, context);
+                        attachmentClone = this.getImageByHeight(attachmentClone, height, quality, context);
                     } else if (height == 0) {
-                        attachmentClone = this.getImageByWidth(attachmentClone, width, context);
+                        attachmentClone = this.getImageByWidth(attachmentClone, width, quality, context);
                     } else {
-                        attachmentClone = this.getImage(attachmentClone, width, height, context);
+                        attachmentClone = this.getImage(attachmentClone, width, height, quality, context);
                     }
 
                     this.imageCache.set(key, attachmentClone.getContent(context));
                 }
             } else {
-                attachmentClone = this.getImageByHeight(attachmentClone, height, context);
+               if (width == 0) {
+                    attachmentClone = this.getImageByHeight(attachmentClone, height, quality, context);
+               } else if (height == 0) {
+                    attachmentClone = this.getImageByWidth(attachmentClone, width, quality, context);
+               } else {
+                    attachmentClone = this.getImage(attachmentClone, width, height, quality, context);
+               }
             }
-        } catch (Exception e) {
+        } catch (Throwable e) {
+            // we need to report the conversion problem
+            e.printStackTrace();
             attachmentClone = attachment;
         }
         return attachmentClone;
     }
 
-    public XWikiAttachment getImageByHeight(XWikiAttachment attachment, int thumbnailHeight, XWikiContext context)
+    public XWikiAttachment getImageByHeight(XWikiAttachment attachment, int thumbnailHeight, float thumbnailQuality, XWikiContext context)
         throws Exception
     {
         if (getType(attachment.getMimeType(context)) == 0) {
@@ -272,19 +303,22 @@
         int imgOriWidth = imgOri.getWidth(null);
         int imgOriHeight = imgOri.getHeight(null);
 
-        if (thumbnailHeight >= imgOriHeight) {
+        if (thumbnailHeight > imgOriHeight) {
             throw new PluginException(PLUGIN_NAME, XWikiException.ERROR_XWIKI_DIFF_METADATA_ERROR,
                 "Thumbnail image not created: the height is higher than the original one.");
+        } else if (thumbnailHeight==0) {
+            thumbnailHeight = imgOriHeight;
+
         }
 
         double imageRatio = (double) imgOriWidth / (double) imgOriHeight;
         int thumbnailWidth = (int) (thumbnailHeight * imageRatio);
-        createThumbnail(thumbnailWidth, thumbnailHeight, imgOri, attachment);
+        createThumbnail(thumbnailWidth, thumbnailHeight, thumbnailQuality, imgOri, attachment, context);
         return attachment;
     }
 
     public XWikiAttachment getImage(XWikiAttachment attachment, int thumbnailWidth, int thumbnailHeight,
-        XWikiContext context) throws Exception
+        float thumbnailQuality, XWikiContext context) throws Exception
     {
 
         if (getType(attachment.getMimeType(context)) == 0) {
@@ -297,17 +331,17 @@
         int imgOriWidth = imgOri.getWidth(null);
         int imgOriHeight = imgOri.getHeight(null);
 
-        if (thumbnailHeight >= imgOriHeight) {
+        if (thumbnailHeight > imgOriHeight) {
             throw new PluginException(PLUGIN_NAME, XWikiException.ERROR_XWIKI_DIFF_METADATA_ERROR,
                 "Thumbnail image not created: the height is higher than the original one.");
         }
 
-        if (thumbnailWidth >= imgOriWidth) {
+        if (thumbnailWidth > imgOriWidth) {
             throw new PluginException(PLUGIN_NAME, XWikiException.ERROR_XWIKI_DIFF_METADATA_ERROR,
                 "Thumbnail image not created: the width is higher than the original one.");
         }
 
-        createThumbnail(thumbnailWidth, thumbnailHeight, imgOri, attachment);
+        createThumbnail(thumbnailWidth, thumbnailHeight, thumbnailQuality, imgOri, attachment, context);
         return attachment;
     }
 
@@ -323,7 +357,7 @@
         return imgOri;
     }
 
-    public XWikiAttachment getImageByWidth(XWikiAttachment attachment, int thumbnailWidth, XWikiContext context)
+    public XWikiAttachment getImageByWidth(XWikiAttachment attachment, int thumbnailWidth, float thumbnailQuality, XWikiContext context)
         throws Exception
     {
 
@@ -336,31 +370,63 @@
         int imgOriWidth = imgOri.getWidth(null);
         int imgOriHeight = imgOri.getHeight(null);
 
-        if (thumbnailWidth >= imgOriWidth) {
+        if (thumbnailWidth > imgOriWidth) {
             throw new PluginException(PLUGIN_NAME, XWikiException.ERROR_XWIKI_DIFF_METADATA_ERROR,
                 "Thumbnail image not created: the width is higher than the original one.");
+        } else if (thumbnailWidth==0) {
+            thumbnailWidth = imgOriWidth;
         }
 
         double imageRatio = (double) imgOriWidth / (double) imgOriHeight;
         int thumbnailHeight = (int) (thumbnailWidth / imageRatio);
 
-        createThumbnail(thumbnailWidth, thumbnailHeight, imgOri, attachment);
+        createThumbnail(thumbnailWidth, thumbnailHeight, thumbnailQuality, imgOri, attachment, context);
         return attachment;
     }
 
-    private void createThumbnail(int thumbnailWidth, int thumbnailHeight, Image imgOri, XWikiAttachment attachment)
-        throws IOException
+    private void createThumbnail(int thumbnailWidth, int thumbnailHeight, float thumbnailQuality, Image imgOri, XWikiAttachment attachment, XWikiContext context)
+        throws IOException, PluginException
     {
         // draw original image to thumbnail image object and
         // scale it to the new size on-the-fly
         BufferedImage imgTN = new BufferedImage(thumbnailWidth, thumbnailHeight, BufferedImage.TYPE_INT_RGB);
         Graphics2D graphics2D = imgTN.createGraphics();
         graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
-        graphics2D.drawImage(imgOri, 0, 0, thumbnailWidth, thumbnailHeight, null);
-
+        // we should test the return code here because an exception can be throw but caught
+        if (graphics2D.drawImage(imgOri, 0, 0, thumbnailWidth, thumbnailHeight, null)==false) {
+           // conversion failed
+           throw new PluginException(PLUGIN_NAME, XWikiException.ERROR_XWIKI_UNKNOWN, "Failed to resize image");
+        }
+         
         // save thumbnail image to bout
         ByteArrayOutputStream bout = new ByteArrayOutputStream();
-        ImageIO.write(imgTN, "PNG", bout);
+        String outputFormat = "PNG";
+        int format = getType(attachment.getMimeType(context));
+        if (format==1)  {
+           // Find a jpeg writer 
+           ImageWriter writer = null; 
+           Iterator iter = ImageIO.getImageWritersByFormatName("jpg");
+           if (iter.hasNext()) { 
+             writer = (ImageWriter)iter.next();
+           } 
+           JPEGImageWriteParam iwp = new JPEGImageWriteParam(null);
+           iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
+           if (thumbnailQuality>=0)
+              iwp.setCompressionQuality(thumbnailQuality);
+
+           // Prepare output file 
+           ImageOutputStream ios = ImageIO.createImageOutputStream(bout); 
+           writer.setOutput(ios); 
+
+           // Write the image 
+           writer.write(null, new IIOImage(imgTN, null, null), iwp); 
+           // Cleanup
+           ios.flush();
+           writer.dispose(); 
+           ios.close(); 
+        } else {
+           ImageIO.write(imgTN, outputFormat, bout);
+        }
         attachment.setContent(bout.toByteArray());
     }
 
