在Java上传期间压缩图像

时间:2017-03-08 05:10:12

标签: java spring graphics2d jai

在我的Java Spring MVC Web Application中,我可以选择上传任意大小的图片。目前我有一个API,可以减少任何超过指定宽度的上传图像的大小。我使用以下代码:

import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.awt.image.renderable.ParameterBlock;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import javax.imageio.ImageIO;
import javax.media.jai.JAI;
import javax.media.jai.PlanarImage;
import javax.media.jai.RenderedOp;

public class ImageRescale 
{
    private static RenderingHints hints;

    static 
    {
        hints = new RenderingHints(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
        hints.put(RenderingHints.KEY_COLOR_RENDERING,RenderingHints.VALUE_COLOR_RENDER_QUALITY);
        hints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);

        /*
         * this block is to silence the warning that we're not using JAI
         * native acceleration but are using the pure java implementation.
         */
        Properties p = new Properties(System.getProperties());
        p.put("com.sun.media.jai.disableMediaLib", "true");
        System.setProperties(p);
    }  


    public static byte[] getScaledInstance(byte[] image, int maxWidth) 
    {
        InputStream in = new ByteArrayInputStream(image);
        BufferedImage img = null;
        try 
        {
            img = ImageIO.read(in);

        double scale = (double) maxWidth / img.getWidth();
        if ( scale > 1.0d ) 
        {
            return image;
        } 
        else if (scale > 0.5d && scale < 1.0d) 
        {
            return getByteArray(getScaledDownByGraphics(img, scale));
        } 
        else if (scale <= 0.5d) 
        {
            return getByteArray(getScaledDownByJAI(img, scale));
        }
        } 
        catch (IOException e) 
        {
            e.printStackTrace();
        }
        return image;
    }

    public static byte[] getByteArray(BufferedImage img)
    {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] imageInByte = null;
        try 
        {
            ImageIO.write( img, "jpg", baos );
            baos.flush();
            imageInByte = baos.toByteArray();
            baos.close();
        } 
        catch (IOException e) 
        {
            e.printStackTrace();
        }
        return imageInByte;
    }

    /**
     * See http://www.digitalsanctuary.com/tech-blog/java/how-to-resize-uploaded-images-using-java-better-way.html
     * This instance seems to produce quality images ONLY when you are
     * scaling down to something less than 50% of the original size.
     * @param img
     * @param scale
     * @return the scaled image
     */
    private static BufferedImage getScaledDownByJAI(BufferedImage img, double scale) 
    {
        if(scale > 1.0d) 
        {
            throw new RuntimeException("Can't scale according to " + scale + " : This method only scales down.");
        }
        PlanarImage originalImage = PlanarImage.wrapRenderedImage(img);
        // now resize the image
        ParameterBlock paramBlock = new ParameterBlock();
        paramBlock.addSource(originalImage); // The source image
        paramBlock.add(scale); // The xScale
        paramBlock.add(scale); // The yScale
        paramBlock.add(0.0); // The x translation
        paramBlock.add(0.0); // The y translation
        RenderedOp resizedImage = JAI.create("SubsampleAverage", paramBlock, hints);
        return resizedImage.getAsBufferedImage();      
    }

    /**
     * This method produces high quality images when target scale is greater
     * than 50% of the original.
     * @param img
     * @param scale
     * @return the scaled image
     */
    private static BufferedImage getScaledDownByGraphics(BufferedImage img, double scale) 
    {
        final float scaleFactor = 0.8f;

                BufferedImage ret = (BufferedImage)img;
                int w = img.getWidth();
                int h = img.getHeight();

                int targetWidth = (int)(img.getWidth() * scale);
                int targetHeight = (int)(img.getHeight() * scale);

                int loopCount = 0;
                int maxLoopCount = 20;
                BufferedImage tmp;
                do {
                        if (w > targetWidth) {
                                w *= scaleFactor;
                                if (w < targetWidth) {
                                        w = targetWidth;
                                }
                        }
                        if (h > targetHeight) {
                                h *= scaleFactor;
                                if (h < targetHeight) {
                                        h = targetHeight;
                                }
                        }
                        tmp = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
                        Graphics2D g2 = tmp.createGraphics();

                        g2.addRenderingHints(hints);
                        g2.drawImage(ret, 0, 0, w, h, null);
                        g2.dispose();

                        ret = tmp;
                        if(++loopCount > maxLoopCount) {
                                throw new RuntimeException("Hit maximum loop count " + maxLoopCount);
                        }
                } while (w != targetWidth || h != targetHeight);
                return ret;    
    }
}

但我现在想要的是一个API,压缩所有上传的图像并将其分辨率降低到大约72 dpi,我认为这是图像的网络标准。有什么方法可以达到这个目的。

1 个答案:

答案 0 :(得分:0)

你能检查这对你有帮助吗?

    /**
 *
 * @param bi image
 * @param mimeType type
 * @param quality quality
 * @return compressed image
 * @throws IOException on error
 */
private static BufferedImage compressImage(BufferedImage bi, String mimeType
        , float quality) throws IOException {
    // converting buffered image to byte array

    // do not compress GIFs
    if (mimeType.equalsIgnoreCase("image/gif")) {
        return bi;
    }

    ImageWriter writer = ImageIO.getImageWritersByMIMEType(mimeType).next();
    ImageWriteParam iwp = writer.getDefaultWriteParam();

    if (!mimeType.equalsIgnoreCase("image/png") && !mimeType.equalsIgnoreCase("image/bmp")) {
        iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
        iwp.setCompressionQuality(quality);
    }

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    BufferedOutputStream bos = new java.io.BufferedOutputStream(baos);
    ImageOutputStream ios = ImageIO.createImageOutputStream(bos);
    writer.setOutput(ios);

    IIOImage optimizedImage = new IIOImage(bi, null, null);
    writer.write(null, optimizedImage, iwp);
    writer.dispose();
    baos.flush();

    ByteArrayInputStream in = new ByteArrayInputStream(baos.toByteArray());
    return ImageIO.read(in);
}