一、说明

若干张图片,一张是背景,其它图片需要合成到背景图中。

二、图片简单整合

素材

java 图片追加文字 java 添加图片_Image


代码

/**
     * @param backgroundPath 背景图片
     * @param targetPath     添加的图片
     * @param outPutPath     输出路径
     * @param x              添加位置坐标
     * @param y              添加位置坐标
     * @param width          图片大小
     * @param height         图片大小
     * @return
     */
    public static File combinationImage(String backgroundPath,
                                        String targetPath,
                                        String outPutPath,
                                        int x,
                                        int y,
                                        int width,
                                        int height) {
        try {
            //背景底图设置图片大小
            BufferedImage background = ImageIO.read(new File(backgroundPath));
            //添加的图片
            BufferedImage image = resizeBufferedImage(width, height, ImageIO.read(new File(targetPath)));
            //在背景图片上添加图片
            Graphics2D g = background.createGraphics();
            g.drawImage(image, x, y, image.getWidth(), image.getHeight(), null);
            // 关闭 Graphics2D 上下文
            g.dispose();
            File out = new File(outPutPath + System.currentTimeMillis() + ".jpg");
            ImageIO.write(background, "jpg", out);
            return out;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
	
	/**
     * @param newWidth  新的宽度和高度(单位:像素)
     * @param newHeight 新的宽度和高度(单位:像素)
     * @param bfi
     * @return
     * @throws IOException
     */
    public static BufferedImage resizeBufferedImage(int newWidth, int newHeight, BufferedImage bfi) {
        Image image = bfi.getScaledInstance(newWidth, newHeight, Image.SCALE_DEFAULT);
        // 创建 Graphics2D 对象,用于进行缩放操作
        BufferedImage resizedImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d = (Graphics2D) resizedImage.createGraphics();
        g2d.drawImage(image, 0, 0, null);
        g2d.dispose();
        return resizedImage;
    }

    public static void main(String[] args) {
        combinationImage("D:\\work\\图像识别\\AI图像素材\\扫码支付背景.jpg",
                "D:\\work\\图像识别\\AI图像素材\\二维码.jpg",
                "D:\\work\\图像识别\\AI图像素材\\",
                450,
                790,
                1500,
                1500);
    }

效果图

二、添加不透明度

/**
     * @param backgroundPath 背景图片
     * @param targetPath     添加的图片
     * @param outPutPath     输出路径
     * @param x              添加位置坐标
     * @param y              添加位置坐标
     * @param width          图片大小
     * @param height         图片大小
     * @param alpha          透明度
     * @return
     */
    public static File combinationImage(String backgroundPath,
                                        String targetPath,
                                        String outPutPath,
                                        int x,
                                        int y,
                                        int width,
                                        int height,
                                        float alpha) {
        try {
            //背景底图设置图片大小
            BufferedImage background = ImageIO.read(new File(backgroundPath));
            //添加的图片
            BufferedImage image = resizeBufferedImage(width, height, ImageIO.read(new File(targetPath)));
            //在背景图片上添加图片
            Graphics2D g = background.createGraphics();
            // 设置透明度(0-1之间)
            Composite originalComposite = g.getComposite();
            AlphaComposite composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha);
            g.setComposite(composite);
            g.drawImage(image, x, y, image.getWidth(), image.getHeight(), null);
            // 还原原始的组合模式
            g.setComposite(originalComposite);
            // 关闭 Graphics2D 上下文
            g.dispose();
            File out = new File(outPutPath + System.currentTimeMillis() + ".jpg");
            ImageIO.write(background, "jpg", out);
            return out;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

效果

三、添加文本

/**
     * @param backgroundPath 背景图片
     * @param text           添加的文本
     * @param outPutPath     输出路径
     * @param x              添加位置坐标
     * @param y              添加位置坐标
     * @param color          字体颜色
     * @param font           字体类型
     * @param alpha          透明度
     * @return
     */
    public static File addTextToImage(String backgroundPath,
                                      String text,
                                      String outPutPath,
                                      int x,
                                      int y,
                                      Color color,
                                      Font font,
                                      float alpha) {
        try {
            //背景底图设置图片大小
            BufferedImage background = ImageIO.read(new File(backgroundPath));
            if (background == null) {
                log.info("获取原始素材失败");
                return null;
            }

            Graphics2D g = background.createGraphics();
            // 设置透明度(0-1之间)
            Composite originalComposite = g.getComposite();
            AlphaComposite composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha);
            g.setComposite(composite);
            //在背景图片上添加文本
            g.setColor(color);
            g.setFont(font);
            g.drawString(text, x, y);
            // 还原原始的组合模式
            g.setComposite(originalComposite);
            // 关闭 Graphics2D 上下文
            g.dispose();
            File out = new File(outPutPath + System.currentTimeMillis() + ".jpg");
            ImageIO.write(background, "jpg", out);
            return out;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

效果图

四、图片路径使用url

@Controller
@RequestMapping("/img")
public class CreateImageController {
    private final static Logger logger = LoggerFactory.getLogger(CreateImageController.class);
 
    @RequestMapping("/getImg")
    public void createNewImg(HttpServletResponse response){
        try {
            BufferedImage banner = ImageIO.read(new File("D:\\work\\图像识别\\AI图像素材\\扫码支付背景.jpg"));
            BufferedImage code = getBufferedImageDestUrl("图片所在的url路径");
            logger.info("Width: " + code.getWidth());
            logger.info("Height: " + code.getHeight());
            //调整图片大小
            code = resizeImage(code,370,370);
            if(banner == null || code == null ){
                logger.info("生成图片失败");
                return ;
            }
            Graphics2D g = banner.createGraphics();
            int x = 345;    //x轴偏移
            int y = 540 ;   //y轴偏移
            g.drawImage(code, x, y, code.getWidth(), code.getHeight(), null);
            g.dispose();
            ImageIO.write(banner,"png",response.getOutputStream());
 
        } catch (IOException e) {
            e.printStackTrace();
        }
        logger.info("图片生成成功");
    }
    /**
     * 远程图片转BufferedImage
     * @param destUrl    远程图片地址
     * @return
     */
    public static BufferedImage getBufferedImageDestUrl(String destUrl) {
        HttpURLConnection conn = null;
        BufferedImage image;
        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 {
            if (conn != null) {
                conn.disconnect();
            }
        }
        return null;
    }
 	/**
     * 通过BufferedImage图片流调整图片大小
     */
    public static BufferedImage resizeImage(BufferedImage originalImage, int targetWidth, int targetHeight) throws IOException {
        Image resultingImage = originalImage.getScaledInstance(targetWidth, targetHeight, Image.SCALE_AREA_AVERAGING);
        BufferedImage outputImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_RGB);
        outputImage.getGraphics().drawImage(resultingImage, 0, 0, null);
        return outputImage;
    }
}

五、其它

java-ImageIO.read存在的javax.imageio.IIOException: Unsupported Image Type异常

javax.imageio.IIOException: Unsupported Image Type
at com.sun.imageio.plugins.jpeg.JPEGImageReader.readInternal(JPEGImageReader.java:1079)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.read(JPEGImageReader.java:1050)
at javax.imageio.ImageIO.read(ImageIO.java:1448)
at javax.imageio.ImageIO.read(ImageIO.java:1352)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

原因
Java的ImageIO万年不更新,已经跟不上时代,如果在PS等软件中导出CMYK颜色模式的图片,它不能处理CMYK色彩的图片。Java自带的ImageIO是不支持的。

ImageIO.read() 无法处理ps过后的图片,P过的图片保存为jpg格式时,默认的模式是CMYK模式。

只能读取png模式

解决方案
使用插件
https://github.com/haraldk/TwelveMonkeys

TwelveMonkeys ImageIO是Java ImageIO的扩展,在使用上非常方便,直接导入相关的jar包依赖即可,不需要在原有代码上进行修改,代码上层依然使用的是Java的ImageIO。

java 图片追加文字 java 添加图片_java 图片追加文字_02

mvn管理

<!--图片处理 start -->
<dependency>
    <groupId>com.twelvemonkeys.imageio</groupId>
    <artifactId>imageio-jpeg</artifactId>
    <version>3.6</version>
</dependency>
<dependency>
    <groupId>com.twelvemonkeys.imageio</groupId>
    <artifactId>imageio-tiff</artifactId>
    <version>3.6</version>
</dependency>
<!--
Optional dependency. Needed only if you deploy `ImageIO` plugins as part of a web app.
Make sure you add the `IIOProviderContextListener` to your `web.xml`, see above.
-->
<dependency>
    <groupId>com.twelvemonkeys.servlet</groupId>
    <artifactId>servlet</artifactId>
    <version>3.6</version>
</dependency>
<!--图片处理 end -->

六、附:RGB色彩和CMYK色彩的区别和换算

RGB色彩
自然界中绝大部分的可见光谱可以用红、绿和蓝三色光按不同比例和强度的混合来表示。RGB分别代表着3种颜色:R代表红色,G代表绿色、B代表蓝色。RGB模型也称为加色模型,通常用于光照、视频和屏幕图像编辑。RGB色彩模式使用RGB模型为图像中每一个像素的RGB分量分配一个0~255范围内的强度值。

CMYK色彩
CMYK色彩模式以打印油墨在纸张上的光线吸收特性为基础,图像中每个像素都是由靛青(C)、品红(M)、黄(Y)和黑(K)色按照不同的比例合成。每个像素的每种印刷油墨会被分配一个百分比值,最亮(高光)的颜色分配较低的印刷油墨颜色百分比值,较暗(暗调)的颜色分配较高的百分比值。

CMYK转RGB的换算方法

R = 255*(100-C)(100-K)/10000
 G = 255(100-M)(100-K)/10000
 B = 255(100-Y)*(100-K)/10000
RGB转CMYK的换算方法
 这个转换理论上是不存在的,主要是因为K值的存在。当k=0时的公式为:
 C = 100 - R * 100 / 255
 M = 100 - G * 100 / 255
 Y = 100 - B * 100 / 255