Java应用:图片叠加

一. 功能目标

现有一张背景图片,一张水印图片,希望将水印图片叠加到背景图片上方的指定位置。

本代码基于Spring boot框架搭建而成,外部发起请求,可以下载到合成后的图片。

注意:

  1. 合成图片的难点不在代码,而在寻找素材。底图和水印图片的尺寸一定要固定。
  2. 只有不断地调试水印图片在底图上的坐标,才能使得合成后的图片更加自然。
  3. 如有必要,可以适当的缩放图片。
  • 背景图片:
    在这里插入图片描述
  • 水印图片:
    在这里插入图片描述
  • 希望实现的效果:
    在这里插入图片描述

二. 代码实现

2.1 依赖

maven:

 <parent>
   <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-parent</artifactId>
     <version>2.1.9.RELEASE</version>
 </parent>

 <dependencies>
     <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
     </dependency>
     <dependency>
         <groupId>org.projectlombok</groupId>
         <artifactId>lombok</artifactId>
         <optional>true</optional>
         <scope>provided</scope>
     </dependency>
 </dependencies>

2.2 图片叠加服务

  • 合成图片 入口方法
public File generate() throws IOException{
    // 底图
    File sourceFile = new File(this.getClass().getResource("/background.png").getFile());
    // 水印图片
    File waterFile = new File(this.getClass().getResource("/studentHead.png").getFile());
    // 最终合成
    String finalFilePath = waterFile.getParentFile().getAbsolutePath() + File.separator + "idPhoto.png";

    // 本次合成之前,删除上一次请求合成后留下的图片
    deleteFile(new File(finalFilePath));

    BufferedImage buffImg = watermark(sourceFile, waterFile, 1.0f);
    generateWaterFile(buffImg, finalFilePath);

    return new File(finalFilePath);
}
  • 合成并构造新图片
/**
*
* 构造图片
* 生成水印并返回java.awt.image.BufferedImage
* @param file 源文件(图片)
* @param waterFile 水印文件(图片)
* @param alpha 透明度, 选择值从0.0~1.0: 完全透明~完全不透明
* @return BufferedImage
* @throws IOException
*/
private BufferedImage watermark(File file, File waterFile, float alpha) throws IOException {
   // 获取底图
   BufferedImage buffImg = ImageIO.read(file);
   //获取底图的宽度
   int buffImgWidth = buffImg.getWidth();
   //获取底图的高度
   int buffImgHight = buffImg.getHeight();

   // 获取层图1
   BufferedImage waterImg1 = ImageIO.read(waterFile);
   // 创建Graphics2D对象,用在底图对象上绘图
   Graphics2D g2d = buffImg.createGraphics();
   // 获取层图的宽度
   int waterImgWidth1 = waterImg1.getWidth();
   // 获取层图的高度
   int waterImgHeight1 = waterImg1.getHeight();
   // 在图形和图像中实现混合和透明效果
   // 当底图和水印图片都是png时,不要开启混合透明效果,否则可能导致水印图片被底图部分遮盖
   //g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
   // 绘制
   //g2d.drawImage(waterImg1, 775,  450, waterImgWidth1, waterImgHeight1, null);
   g2d.drawImage(waterImg1, 755,  340, 350, 430, null);


   g2d.dispose();// 释放图形上下文使用的系统资源
   return buffImg;
}
  • 输出水印图片
/**
 * 输出水印图片
 *
 * @param buffImg 图像加水印之后的BufferedImage对象
 * @param savePath 图像加水印之后的保存路径
 */
private void generateWaterFile(BufferedImage buffImg, String savePath) {
    int temp = savePath.lastIndexOf(".") + 1;
    try {
        ImageIO.write(buffImg, savePath.substring(temp), new File(savePath));
    } catch (IOException e1) {
        e1.printStackTrace();
    }
}
  • 删除文件
private void deleteFile(File file) {
    if(!file.exists()) {
        return;
    }

    if(file.isFile() || file.list()==null) {
        file.delete();
    }
}
  • Controller
@Slf4j
@RestController
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class MgmController {
    final private PictureService pictureService;

    @GetMapping("/file")
    public DeferredResult<ResponseEntity<FileSystemResource>> generatorFile() {
        DeferredResult<ResponseEntity<FileSystemResource>> deferredResult = new DeferredResult<>(20 * 1000L);
        try {
            File file = pictureService.generate();
            if (file != null) {
                HttpHeaders headers = new HttpHeaders();
                headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
                headers.add("Content-Disposition", "attachment; filename=" + file.getName());
                headers.add("Pragma", "no-cache");
                headers.add("Expires", "0");
                headers.add("Last-Modified", new Date().toString());
                headers.add("ETag", String.valueOf(System.currentTimeMillis()));
                ResponseEntity<FileSystemResource> body = ResponseEntity.ok().headers(headers).contentLength(file.length())
                        .contentType(MediaType.parseMediaType("application/octet-stream")).body(new FileSystemResource(file));
                deferredResult.setResult(body);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        deferredResult.onTimeout(() -> {
            log.error("图片生成超时");
            deferredResult.setErrorResult("图片生成超时");
        });

        deferredResult.onError((throwable) -> {
            log.error("图片生成出错: " + throwable.getMessage());
            deferredResult.setErrorResult("图片生成出错");
        });

        return deferredResult;
    }
  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值