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
  • 相关阅读:
    .net core读取appsettings.config中文乱码问题
    vs2017错误:当前页面的脚本发生错误
    VS Code中无法识别npm命令
    Visual Studio报错/plugin.vs.js,行:1074,错误:缺少标识符、字符串或数字
    记录一次在生成数据库服务器上出现The timeout period elapsed prior to completion of the operation or the server is not responding.和Exception has been thrown by the target of an invocation的解决办法
    Java集合框架
    java hash表
    Java Dictionary 类存储键值
    java数据结构 栈stack
    java封装
  • 原文地址:https://www.cnblogs.com/loytime/p/9957092.html
Copyright © 2011-2022 走看看