zoukankan      html  css  js  c++  java
  • Java实现图片的叠加与拼接

    关于Java实现图片的叠加与拼接的文章网络上确实很多,碰巧小编开发工作中也遇到这些问题,就做了简要的梳理,作为笔记以备不时之需。

    Java对图片的处理主要使用的是BufferedImage类。

    BufferedImage 子类描述具有可访问图像数据缓冲区的 ImageBufferedImage 由图像数据的 ColorModel 和 Raster 组成。Raster 的 SampleModel 中 band 的数量和类型必须与 ColorModel 所要求的数量和类型相匹配,以表示其颜色和 alpha 分量。所有 BufferedImage 对象的左上角坐标都为 (0, 0)。因此,用来构造 BufferedImage 的任何 Raster 都必须满足:minX=0 且 minY=0。此类依靠 Raster 的数据获取方法、数据设置方法,以及 ColorModel 的颜色特征化方法。 

    以上主要来源于官方文档,我们来时直接写实践代码吧。

    首先将文件转化为BufferedImage对象,这里给出两种读取文件并转化为BufferedImage对象的方法。

        /**
         * @param fileUrl 文件绝对路径或相对路径
         * @return 读取到的缓存图像
         * @throws IOException 路径错误或者不存在该文件时抛出IO异常
         */
        public static BufferedImage getBufferedImage(String fileUrl)
                throws IOException {
            File f = new File(fileUrl);
            return ImageIO.read(f);
        }    
        
        /**
         * 远程图片转BufferedImage
         * @param destUrl    远程图片地址
         * @return
         */
        public static BufferedImage getBufferedImageDestUrl(String destUrl) {
            HttpURLConnection conn = null;
            BufferedImage image = null;
            try {
                URL url = new URL(destUrl);
                conn = (HttpURLConnection) url.openConnection();
                if (conn.getResponseCode() == 200) {
                    image = ImageIO.read(conn.getInputStream());
                    return image;
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                conn.disconnect();
            }
            return image;
        }

    接下来是将BufferedImage对象保存到本地,具体方法如下:

        /**
         * 输出图片
         * @param buffImg  图像拼接叠加之后的BufferedImage对象
         * @param savePath 图像拼接叠加之后的保存路径
         */
        public static void generateSaveFile(BufferedImage buffImg, String savePath) {
            int temp = savePath.lastIndexOf(".") + 1;
            try {
                File outFile = new File(savePath);
                if(!outFile.exists()){
                    outFile.createNewFile();
                }
                ImageIO.write(buffImg, savePath.substring(temp), outFile);
                System.out.println("ImageIO write...");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    以上作为准备部分,现在开始图片叠加的实现方法


      /**
         * 
         * @Title: 构造图片
         * @Description: 生成水印并返回java.awt.image.BufferedImage
         * @param buffImg 源文件(BufferedImage)
         * @param waterFile 水印文件(BufferedImage)
         * @param x 距离右下角的X偏移量
         * @param y  距离右下角的Y偏移量
         * @param alpha  透明度, 选择值从0.0~1.0: 完全透明~完全不透明
         * @return BufferedImage
         * @throws IOException
         */
        public static BufferedImage overlyingImage(BufferedImage buffImg, BufferedImage waterImg, int x, int y, float alpha) throws IOException {
    
            // 创建Graphics2D对象,用在底图对象上绘图
            Graphics2D g2d = buffImg.createGraphics();
            int waterImgWidth = waterImg.getWidth();// 获取层图的宽度
            int waterImgHeight = waterImg.getHeight();// 获取层图的高度
            // 在图形和图像中实现混合和透明效果
            g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
            // 绘制
            g2d.drawImage(waterImg, x, y, waterImgWidth, waterImgHeight, null);
            g2d.dispose();// 释放图形上下文使用的系统资源
            return buffImg;
        }

    图片拼接的实现方法

        /**
         * 待合并的两张图必须满足这样的前提,如果水平方向合并,则高度必须相等;如果是垂直方向合并,宽度必须相等。
         * mergeImage方法不做判断,自己判断。 
    *
    @param img1 待合并的第一张图 * @param img2 带合并的第二张图 * @param isHorizontal 为true时表示水平方向合并,为false时表示垂直方向合并 * @return 返回合并后的BufferedImage对象 * @throws IOException */ public static BufferedImage mergeImage(BufferedImage img1, BufferedImage img2, boolean isHorizontal) throws IOException { int w1 = img1.getWidth(); int h1 = img1.getHeight(); int w2 = img2.getWidth(); int h2 = img2.getHeight(); // 从图片中读取RGB int[] ImageArrayOne = new int[w1 * h1]; ImageArrayOne = img1.getRGB(0, 0, w1, h1, ImageArrayOne, 0, w1); // 逐行扫描图像中各个像素的RGB到数组中 int[] ImageArrayTwo = new int[w2 * h2]; ImageArrayTwo = img2.getRGB(0, 0, w2, h2, ImageArrayTwo, 0, w2); // 生成新图片 BufferedImage DestImage = null; if (isHorizontal) { // 水平方向合并 DestImage = new BufferedImage(w1+w2, h1, BufferedImage.TYPE_INT_RGB); DestImage.setRGB(0, 0, w1, h1, ImageArrayOne, 0, w1); // 设置上半部分或左半部分的RGB DestImage.setRGB(w1, 0, w2, h2, ImageArrayTwo, 0, w2); } else { // 垂直方向合并 DestImage = new BufferedImage(w1, h1 + h2, BufferedImage.TYPE_INT_RGB); DestImage.setRGB(0, 0, w1, h1, ImageArrayOne, 0, w1); // 设置上半部分或左半部分的RGB DestImage.setRGB(0, h1, w2, h2, ImageArrayTwo, 0, w2); // 设置下半部分的RGB } return DestImage; }

    测试方法如下:

    /**
         * Java 测试图片叠加方法
         */
        public static void overlyingImageTest() {
    
            String sourceFilePath = "D://test//test1.jpg";
            String waterFilePath = "D://test//test2.jpg";
            String saveFilePath = "D://test//overlyingImageNew.jpg";
            try {
                BufferedImage bufferImage1 = getBufferedImage(sourceFilePath);
                BufferedImage bufferImage2 = getBufferedImage(waterFilePath);
    
                // 构建叠加层
                BufferedImage buffImg = overlyingImage(bufferImage1, bufferImage2, 0, 0, 1.0f);
                // 输出水印图片
                generateSaveFile(buffImg, saveFilePath);
            } catch (IOException e) {
                e.printStackTrace();
            }
    
        }
        
        
        /**
         * Java 测试图片合并方法
         */
        public static void imageMargeTest() {
            // 读取待合并的文件
            BufferedImage bi1 = null;
            BufferedImage bi2 = null;
            // 调用mergeImage方法获得合并后的图像
            BufferedImage destImg = null;
            System.out.println("下面是垂直合并的情况:");
            String saveFilePath = "D://test//new1.jpg";
            String divingPath = "D://test//new2.jpg";
            String margeImagePath = "D://test//margeNew.jpg";
            try {
                bi1 = getBufferedImage(saveFilePath);
                bi2 = getBufferedImage(divingPath);
                // 调用mergeImage方法获得合并后的图像
                destImg = mergeImage(bi1, bi2, false);
            } catch (IOException e) {
                e.printStackTrace();
            }
            // 保存图像
            generateSaveFile(destImg, margeImagePath);
            System.out.println("垂直合并完毕!");
        }
    
        public static void main(String[] args) {
            // 测试图片的叠加
            overlyingImageTest();
            // 测试图片的垂直合并
            imageMargeTest();
        }
    View Code

    整体代码如下:

      1 package ImagePackage;
      2 
      3 import java.awt.AlphaComposite;
      4 import java.awt.Graphics2D;
      5 import java.awt.image.BufferedImage;
      6 import java.io.File;
      7 import java.io.IOException;
      8 import java.net.HttpURLConnection;
      9 import java.net.URL;
     10 
     11 import javax.imageio.ImageIO;
     12 
     13 /**
     14 
     15  * 该类实现了图片的合并功能,可以选择水平合并或者垂直合并。
     16  * 当然此例只是针对两个图片的合并,如果想要实现多个图片的合并,只需要自己实现方法 BufferedImage
     17  * mergeImage(BufferedImage[] imgs, boolean isHorizontal)即可;
     18  * 而且这个方法更加具有通用性,但是时间原因不实现了,方法和两张图片实现是一样的
     19  */
     20 
     21 public class ImageMerge {
     22 
     23     /**
     24      * @param fileUrl
     25      *            文件绝对路径或相对路径
     26      * @return 读取到的缓存图像
     27      * @throws IOException
     28      *             路径错误或者不存在该文件时抛出IO异常
     29      */
     30     public static BufferedImage getBufferedImage(String fileUrl)
     31             throws IOException {
     32         File f = new File(fileUrl);
     33         return ImageIO.read(f);
     34     }
     35     
     36     
     37     /**
     38      * 远程图片转BufferedImage
     39      * @param destUrl    远程图片地址
     40      * @return
     41      */
     42     public static BufferedImage getBufferedImageDestUrl(String destUrl) {
     43         HttpURLConnection conn = null;
     44         BufferedImage image = null;
     45         try {
     46             URL url = new URL(destUrl);
     47             conn = (HttpURLConnection) url.openConnection();
     48             if (conn.getResponseCode() == 200) {
     49                 image = ImageIO.read(conn.getInputStream());
     50                 return image;
     51             }
     52         } catch (Exception e) {
     53             e.printStackTrace();
     54         } finally {
     55             conn.disconnect();
     56         }
     57         return image;
     58     }
     59     
     60     /**
     61      * 输出图片
     62      * 
     63      * @param buffImg
     64      *            图像拼接叠加之后的BufferedImage对象
     65      * @param savePath
     66      *            图像拼接叠加之后的保存路径
     67      */
     68     public static void generateSaveFile(BufferedImage buffImg, String savePath) {
     69         int temp = savePath.lastIndexOf(".") + 1;
     70         try {
     71             File outFile = new File(savePath);
     72             if(!outFile.exists()){
     73                 outFile.createNewFile();
     74             }
     75             ImageIO.write(buffImg, savePath.substring(temp), outFile);
     76             System.out.println("ImageIO write...");
     77         } catch (IOException e) {
     78             e.printStackTrace();
     79         }
     80     }
     81     
     82     /**
     83      * 
     84      * @Title: 构造图片
     85      * @Description: 生成水印并返回java.awt.image.BufferedImage
     86      * @param buffImg
     87      *            源文件(BufferedImage)
     88      * @param waterFile
     89      *            水印文件(BufferedImage)
     90      * @param x
     91      *            距离右下角的X偏移量
     92      * @param y
     93      *            距离右下角的Y偏移量
     94      * @param alpha
     95      *            透明度, 选择值从0.0~1.0: 完全透明~完全不透明
     96      * @return BufferedImage
     97      * @throws IOException
     98      */
     99     public static BufferedImage overlyingImage(BufferedImage buffImg, BufferedImage waterImg, int x, int y, float alpha) throws IOException {
    100 
    101         // 创建Graphics2D对象,用在底图对象上绘图
    102         Graphics2D g2d = buffImg.createGraphics();
    103         int waterImgWidth = waterImg.getWidth();// 获取层图的宽度
    104         int waterImgHeight = waterImg.getHeight();// 获取层图的高度
    105         // 在图形和图像中实现混合和透明效果
    106         g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
    107         // 绘制
    108         g2d.drawImage(waterImg, x, y, waterImgWidth, waterImgHeight, null);
    109         g2d.dispose();// 释放图形上下文使用的系统资源
    110         return buffImg;
    111     }
    112     
    113     
    114     /**
    115      * 待合并的两张图必须满足这样的前提,如果水平方向合并,则高度必须相等;如果是垂直方向合并,宽度必须相等。
    116      * mergeImage方法不做判断,自己判断。
    117      *
    118      * @param img1
    119      *            待合并的第一张图
    120      * @param img2
    121      *            带合并的第二张图
    122      * @param isHorizontal
    123      *            为true时表示水平方向合并,为false时表示垂直方向合并
    124      * @return 返回合并后的BufferedImage对象
    125      * @throws IOException
    126      */
    127     public static BufferedImage mergeImage(BufferedImage img1,
    128             BufferedImage img2, boolean isHorizontal) throws IOException {
    129         int w1 = img1.getWidth();
    130         int h1 = img1.getHeight();
    131         int w2 = img2.getWidth();
    132         int h2 = img2.getHeight();
    133 
    134         // 从图片中读取RGB
    135         int[] ImageArrayOne = new int[w1 * h1];
    136         ImageArrayOne = img1.getRGB(0, 0, w1, h1, ImageArrayOne, 0, w1); // 逐行扫描图像中各个像素的RGB到数组中
    137         int[] ImageArrayTwo = new int[w2 * h2];
    138         ImageArrayTwo = img2.getRGB(0, 0, w2, h2, ImageArrayTwo, 0, w2);
    139 
    140         // 生成新图片
    141         BufferedImage DestImage = null;
    142         if (isHorizontal) { // 水平方向合并
    143             DestImage = new BufferedImage(w1+w2, h1, BufferedImage.TYPE_INT_RGB);
    144             DestImage.setRGB(0, 0, w1, h1, ImageArrayOne, 0, w1); // 设置上半部分或左半部分的RGB
    145             DestImage.setRGB(w1, 0, w2, h2, ImageArrayTwo, 0, w2);
    146         } else { // 垂直方向合并
    147             DestImage = new BufferedImage(w1, h1 + h2, BufferedImage.TYPE_INT_RGB);
    148             DestImage.setRGB(0, 0, w1, h1, ImageArrayOne, 0, w1); // 设置上半部分或左半部分的RGB
    149             DestImage.setRGB(0, h1, w2, h2, ImageArrayTwo, 0, w2); // 设置下半部分的RGB
    150         }
    151 
    152         return DestImage;
    153     }
    154 
    155     /**
    156      * Java 测试图片叠加方法
    157      */
    158     public static void overlyingImageTest() {
    159 
    160         String sourceFilePath = "D://test//test1.jpg";
    161         String waterFilePath = "D://test//test2.jpg";
    162         String saveFilePath = "D://test//overlyingImageNew.jpg";
    163         try {
    164             BufferedImage bufferImage1 = getBufferedImage(sourceFilePath);
    165             BufferedImage bufferImage2 = getBufferedImage(waterFilePath);
    166 
    167             // 构建叠加层
    168             BufferedImage buffImg = overlyingImage(bufferImage1, bufferImage2, 0, 0, 1.0f);
    169             // 输出水印图片
    170             generateSaveFile(buffImg, saveFilePath);
    171         } catch (IOException e) {
    172             e.printStackTrace();
    173         }
    174 
    175     }
    176     
    177     
    178     /**
    179      * Java 测试图片合并方法
    180      */
    181     public static void imageMargeTest() {
    182         // 读取待合并的文件
    183         BufferedImage bi1 = null;
    184         BufferedImage bi2 = null;
    185         // 调用mergeImage方法获得合并后的图像
    186         BufferedImage destImg = null;
    187         System.out.println("下面是垂直合并的情况:");
    188         String saveFilePath = "D://test//new1.jpg";
    189         String divingPath = "D://test//new2.jpg";
    190         String margeImagePath = "D://test//margeNew.jpg";
    191         try {
    192             bi1 = getBufferedImage(saveFilePath);
    193             bi2 = getBufferedImage(divingPath);
    194             // 调用mergeImage方法获得合并后的图像
    195             destImg = mergeImage(bi1, bi2, false);
    196         } catch (IOException e) {
    197             e.printStackTrace();
    198         }
    199         // 保存图像
    200         generateSaveFile(destImg, margeImagePath);
    201         System.out.println("垂直合并完毕!");
    202     }
    203 
    204     public static void main(String[] args) {
    205         // 测试图片的叠加
    206         overlyingImageTest();
    207         // 测试图片的垂直合并
    208         imageMargeTest();
    209     }
    210 
    211 } 
    View Code
  • 相关阅读:
    剑指 Offer 67. 把字符串转换成整数 && Leetcode 8 字符串转换整数 (atoi)
    剑指 Offer 49. 丑数 && Leetcode 264. 丑数 II
    [LeetCode] Implement strStr()
    [LeetCode] Rotate Image
    [LeetCode] Remove Duplicates from Sorted List II
    [LeetCode] Gas Station
    OpenCV-paper detection & perspective transformation 相关资料
    Install PIL on mac osX10.9
    为什么是 n(n+1)/2 ?
    数组排序
  • 原文地址:https://www.cnblogs.com/loytime/p/9957092.html
Copyright © 2011-2022 走看看