2008年5月13日星期二

Java中的简单图像处理

近日在制作一个网站(http://campus.cslg.cn)的过程中,对于校友录的相册部分需要生成缩略图。很多网站上为了改变图像的大小,往往直接指定<img>标记中的width和height属性,造成图像变形,效果惨不忍睹。

在网上搜索资料的过程中,找到了一篇比较好的讲 Java 2D图像处理的文章 Ultimate Java Image Manipulation (http://www.javalobby.org/articles/ultimate-image/#11)

在该作者提供的代码的基础上,增加了按照指定高度或者宽度缩放图像的方法,解决了图像显示的问题

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import javax.imageio.ImageIO;

import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGEncodeParam;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

public class ImageUtil {
    /**
     * 从磁盘文件装载图像
     *
     * @param ref
     * @return
     */
    public static BufferedImage loadImage(String ref) {
        BufferedImage bimg = null;
        try {

            bimg = ImageIO.read(new File(ref));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bimg;
    }

    /**
     * 将图像改为新的宽度和高度
     *
     * @param img
     * @param newWidth
     * @param newHeight
     * @return
     */
    public static BufferedImage resize(BufferedImage img, int newWidth,
            int newHeight) {
        int w = img.getWidth();
        int h = img.getHeight();
        BufferedImage dimg = new BufferedImage(newWidth, newHeight, img
                .getType());
        Graphics2D g = dimg.createGraphics();
        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g.drawImage(img, 0, 0, newWidth, newHeight, 0, 0, w, h, null);
        g.dispose();
        return dimg;
    }

    /**
     * 将图像改为新的宽度
     *
     * @param img
     * @param newWidth
     * @return
     */
    public static BufferedImage resizeWithNewWidth(BufferedImage img,
            int newWidth) {
        int w = img.getWidth();
        int h = img.getHeight();
        int newHeight = (int) ((double) h * newWidth / w);
        BufferedImage dimg = new BufferedImage(newWidth, newHeight, img
                .getType());
        Graphics2D g = dimg.createGraphics();
        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g.drawImage(img, 0, 0, newWidth, newHeight, 0, 0, w, h, null);
        g.dispose();
        return dimg;
    }

    /**
     * 将图像改为新的高度
     *
     * @param img
     * @param newHeight
     * @return
     */
    public static BufferedImage resizeWithNewHeight(BufferedImage img,
            int newHeight) {
        int w = img.getWidth();
        int h = img.getHeight();
        int newWidth = (int) ((double) w * newHeight / h);
        BufferedImage dimg = new BufferedImage(newWidth, newHeight, img
                .getType());
        Graphics2D g = dimg.createGraphics();
        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g.drawImage(img, 0, 0, newWidth, newHeight, 0, 0, w, h, null);
        g.dispose();
        return dimg;
    }

    public static void saveImage(String ref, BufferedImage img) {
        BufferedOutputStream out;
        try {
            out = new BufferedOutputStream(new FileOutputStream(ref));
            JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
            JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(img);
            int quality = 5;
            quality = Math.max(0, Math.min(quality, 100));
            param.setQuality((float) quality / 100.0f, false);
            encoder.setJPEGEncodeParam(param);
            encoder.encode(img);
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Saves a BufferedImage to the given file, pathname must not have any
     * periods "." in it except for the one before the format, i.e.
     * C:/images/fooimage.png
     *
     * @param img
     * @param saveFile
     */
    public static void saveImage(BufferedImage img, String ref) {
        try {
            String format = (ref.endsWith(".png")) ? "png" : "jpg";
            ImageIO.write(img, format, new File(ref));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static BufferedImage loadTranslucentImage(String url,
            float transperancy) {
        // Load the image
        BufferedImage loaded = loadImage(url);
        // Create the image using the
        BufferedImage aimg = new BufferedImage(loaded.getWidth(), loaded
                .getHeight(), BufferedImage.TRANSLUCENT);
        // Get the images graphics
        Graphics2D g = aimg.createGraphics();
        // Set the Graphics composite to Alpha
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
                transperancy));
        // Draw the LOADED img into the prepared reciver image
        g.drawImage(loaded, null, 0, 0);
        // let go of all system resources in this Graphics
        g.dispose();
        // Return the image
        return aimg;
    }

    public static BufferedImage makeColorTransparent(String ref, Color color) {
        BufferedImage image = loadImage(ref);
        BufferedImage dimg = new BufferedImage(image.getWidth(), image
                .getHeight(), BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = dimg.createGraphics();
        g.setComposite(AlphaComposite.Src);
        g.drawImage(image, null, 0, 0);
        g.dispose();
        for (int i = 0; i < dimg.getHeight(); i++) {
            for (int j = 0; j < dimg.getWidth(); j++) {
                if (dimg.getRGB(j, i) == color.getRGB()) {
                    dimg.setRGB(j, i, 0x8F1C1C);
                }
            }
        }
        return dimg;
    }

    public static BufferedImage horizontalflip(BufferedImage img) {
        int w = img.getWidth();
        int h = img.getHeight();
        BufferedImage dimg = new BufferedImage(w, h, img.getType());
        Graphics2D g = dimg.createGraphics();
        g.drawImage(img, 0, 0, w, h, w, 0, 0, h, null);
        g.dispose();
        return dimg;
    }

    public static BufferedImage verticalflip(BufferedImage img) {
        int w = img.getWidth();
        int h = img.getHeight();
        BufferedImage dimg = new BufferedImage(w, h, img.getColorModel()
                .getTransparency());
        Graphics2D g = dimg.createGraphics();
        g.drawImage(img, 0, 0, w, h, 0, h, w, 0, null);
        g.dispose();
        return dimg;
    }

    public static BufferedImage rotate(BufferedImage img, int angle) {
        int w = img.getWidth();
        int h = img.getHeight();
        BufferedImage dimg = new BufferedImage(w, h, img.getType());
        Graphics2D g = dimg.createGraphics();
        g.rotate(Math.toRadians(angle), w / 2, h / 2);
        g.drawImage(img, null, 0, 0);
        return dimg;
    }

    public static BufferedImage[] splitImage(BufferedImage img, int cols,
            int rows) {
        int w = img.getWidth() / cols;
        int h = img.getHeight() / rows;
        int num = 0;
        BufferedImage imgs[] = new BufferedImage[w * h];
        for (int y = 0; y < rows; y++) {
            for (int x = 0; x < cols; x++) {
                imgs[num] = new BufferedImage(w, h, img.getType());
                // Tell the graphics to draw only one block of the image
                Graphics2D g = imgs[num].createGraphics();
                g.drawImage(img, 0, 0, w, h, w * x, h * y, w * x + w,
                        h * y + h, null);
                g.dispose();
                num++;
            }
        }
        return imgs;
    }

}

 

下面是用于改变图像大小的Servlet (使用格式: <img src="servlet/ImageResize?id=1&width=200&height=150"/>;可以指定高度、宽度或者宽度和高度)

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.naming.NamingException;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import cn.cslg.campus.database.DBPoolException;
import cn.cslg.campus.database.JndiBean;

import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

public class ImageResize extends HttpServlet {

    private static final long serialVersionUID = -8774962472747611326L;

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("image/jpeg");
        int id = 0;
        int height = 0;
        int width = 0;
        try {
            try {
                id = Integer.parseInt(request.getParameter("id"));
                String h = request.getParameter("height");
                String w = request.getParameter("width");
                if (h != null && h.length() != 0)
                    height = Integer.parseInt(h);
                if (w != null && w.length() != 0)
                    width = Integer.parseInt(w);
            } catch (NumberFormatException e) {
                return;
            }
            BufferedImage image = loadImage(id, width, height);
            ServletOutputStream out = response.getOutputStream();
            JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
            encoder.encode(image);
            out.close();
        } catch (Exception e) {
            throw new ServletException(e);
        }
    }

    public BufferedImage loadCachedImage(String fname, int width, int height)
            throws DBPoolException, NamingException, SQLException {
        BufferedImage image = null;
        ServletContext application = this.getServletContext();
        String folder = application.getRealPath("/photo/thumbnail");
        String ext = fname.substring(fname.lastIndexOf('.'));
        String pre = fname.substring(0, fname.lastIndexOf('.'));
        String cachedName = folder + "/" + pre + "-" + width + "-" + height
                + ext;
        File f = new File(cachedName);
        if (f.exists())
            image = ImageUtil.loadImage(cachedName);
        return image;
    }

    public void saveCachedImage(BufferedImage image, String fname, int width,
            int height) {
        ServletContext application = this.getServletContext();
        String folder = application.getRealPath("/photo/thumbnail");
        String ext = fname.substring(fname.lastIndexOf('.'));
        String pre = fname.substring(0, fname.lastIndexOf('.'));
        String cachedName = folder + "/" + pre + "-" + width + "-" + height
                + ext;
        ImageUtil.saveImage(image, cachedName);
    }

    public BufferedImage loadImage(int id, int width, int height)
            throws DBPoolException, NamingException, SQLException {
        ServletContext application = this.getServletContext();
        String uploadFolder = application.getRealPath("/photo");
        BufferedImage image = null;
        Connection conn = null;
        try {
            conn = JndiBean.getConnection();
            String sql = "select FileName from Album where PhotoId=" + id;
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery(sql);
            if (!rs.next())
                return null;
            String fname = rs.getString("FileName").trim();
            String pname = uploadFolder + "/" + fname;

            image = loadCachedImage(fname, width, height);
            if (image == null) {
                if (height != 0 && width != 0) {
                    image = ImageUtil.resize(ImageUtil.loadImage(pname), width,
                            height);
                } else if (height != 0 && width == 0)
                    image = ImageUtil.resizeWithNewHeight(ImageUtil
                            .loadImage(pname), height);
                else if (height == 0 && width != 0)
                    image = ImageUtil.resizeWithNewWidth(ImageUtil
                            .loadImage(pname), width);
                saveCachedImage(image, fname, width, height);
            }
            return image;
        } finally {
            conn.close();
        }
    }
}

没有评论:

发表评论