一、说明
若干张图片,一张是背景,其它图片需要合成到背景图中。
二、图片简单整合
素材
代码
/**
* @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。
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