功能介绍
对图片生成图片水印或者文字水印 ,用户可以自定义自己的图片水印
思路就是将文字和图片水印合成到一张图片上面去,前台展示合成效果
后台合成后保存到cos上面,并在数据库保存相关信息,方便用户下次引用
前台样式
后端代码
接参DTO
@Data
public class WatermarkTemplateDTO extends BasePageParamDTO{
/**
* 主键ID
*/
@ApiModelProperty(value="主键ID")
private Long id;
/**
* 用户名
*/
@ApiModelProperty(value="用户名")
private Long userId;
/**
* 水印名称
*/
@ApiModelProperty(value="水印名称")
private String watermarkName;
/**
* 合成后的水印图片地址
*/
@ApiModelProperty(value="合成后的水印图片地址")
private String watermarkUrl;
/**
* 素材图片URL地址
*/
@ApiModelProperty(value="素材图片URL地址")
private String picUrl;
/**
* 图片透明度
*/
@ApiModelProperty(value="图片透明度")
private Integer picOpacity;
/**
* 图片左边距
*/
@ApiModelProperty(value="图片左边距")
private Integer picLeft;
/**
* 图片上边距
*/
@ApiModelProperty(value="图片上边距")
private Integer picTop;
/**
* 图片宽度
*/
@ApiModelProperty(value="图片宽度")
private Integer picWidth;
/**
* 图片高度
*/
@ApiModelProperty(value="图片高度")
private Integer picHeight;
/**
* 水印文字
*/
@ApiModelProperty(value="水印文字")
private String watermarkText;
/**
* 文字透明度
*/
@ApiModelProperty(value="文字透明度")
private Float textOpacity;
/**
* 文字字体大小
*/
@ApiModelProperty(value="文字字体大小")
private Integer textSize;
/**
* 文字字体颜色
*/
@ApiModelProperty(value="文字字体颜色")
private String textColor;
/**
* 文字位置-距离图片的左边距
*/
@ApiModelProperty(value="文字位置-距离图片的左边距")
private Integer textLeft;
/**
* 文字位置-距离图片的上边距
*/
@ApiModelProperty(value="文字位置-距离图片的上边距")
private Integer textTop;
/**
* 文字字体
*/
@ApiModelProperty(value="文字字体")
private String textFont;
/**
* 图片翻转,0:不翻转 1: 水平翻转 2 : 垂直翻转
*/
@ApiModelProperty(value="图片翻转,0:不翻转 1: 水平翻转 2 : 垂直翻转")
private Integer picTurn;
/**
* 图片旋转角度
*/
@ApiModelProperty(value="图片旋转角度")
private Integer picRotate;
/**
* 创建时间
*/
@ApiModelProperty(value="创建时间")
private Date createDate;
}
数据库实体类
/**
* 水印模板表
*/
@ApiModel(value = "com-menglar-soap-item-pojo-mysql-WatermarkTemplate")
@Data
@NoArgsConstructor
@TableName(value = "item_watermark_template")
public class WatermarkTemplate implements Serializable {
/**
* 主键ID
*/
@ApiModelProperty(value = "主键ID")
private Long id;
/**
* 用户名
*/
@ApiModelProperty(value = "用户名")
private Long userId;
/**
* 水印名称
*/
@ApiModelProperty(value = "水印名称")
private String watermarkName;
/**
* 合成后的水印图片地址
*/
@ApiModelProperty(value = "合成后的水印图片地址")
private String watermarkUrl;
/**
* 素材图片URL地址
*/
@ApiModelProperty(value = "素材图片URL地址")
private String picUrl;
/**
* 图片透明度
*/
@ApiModelProperty(value = "图片透明度")
private Integer picOpacity;
/**
* 图片左边距
*/
@ApiModelProperty(value = "图片左边距")
private Integer picLeft;
/**
* 图片上边距
*/
@ApiModelProperty(value = "图片上边距")
private Integer picTop;
/**
* 图片宽度
*/
@ApiModelProperty(value = "图片宽度")
private Integer picWidth;
/**
* 图片高度
*/
@ApiModelProperty(value = "图片高度")
private Integer picHeight;
/**
* 水印文字
*/
@ApiModelProperty(value = "水印文字")
private String watermarkText;
/**
* 文字透明度
*/
@ApiModelProperty(value = "文字透明度")
private Float textOpacity;
/**
* 文字字体大小
*/
@ApiModelProperty(value = "文字字体大小")
private Integer textSize;
/**
* 文字字体颜色
*/
@ApiModelProperty(value = "文字字体颜色")
private String textColor;
/**
* 文字位置-距离图片的左边距
*/
@ApiModelProperty(value = "文字位置-距离图片的左边距")
private Integer textLeft;
/**
* 文字位置-距离图片的上边距
*/
@ApiModelProperty(value = "文字位置-距离图片的上边距")
private Integer textTop;
/**
* 文字字体
*/
@ApiModelProperty(value = "文字字体")
private String textFont;
/**
* 图片翻转,0:不翻转 1: 水平翻转 2 : 垂直翻转
*/
@ApiModelProperty(value = "图片翻转,0:不翻转 1: 水平翻转 2 : 垂直翻转")
private Integer picTurn;
/**
* 图片旋转角度
*/
@ApiModelProperty(value = "图片旋转角度")
private Integer picRotate;
/**
* 创建时间
*/
@ApiModelProperty(value = "创建时间")
private Date createDate;
private static final long serialVersionUID = 1L;
}
水印生成方法
/**
* 上传水印模板
* @param wtDto
* @return
*/
@Override
public Result uploadWatermarkPic(WatermarkTemplateDTO wtDto) {
if (StringUtils.isBlank(wtDto.getPicUrl()) && StringUtils.isBlank(wtDto.getWatermarkText())) {
throw new BusinessException("素材图片/水印文字不能为空");
}
try {
BufferedImage output = new BufferedImage(800, 800, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = output.createGraphics();
output = g2.getDeviceConfiguration().createCompatibleImage(800, 800, Transparency.TRANSLUCENT);
g2 = output.createGraphics();
//调制透明度
for (int j1 = output.getMinY(); j1 < output.getHeight(); j1++) {
for (int j2 = output.getMinX(); j2 < output.getWidth(); j2++) {
int rgb = output.getRGB(j2, j1);
rgb = ((0 * 255 / 10) << 24) | (rgb & 0x00ffffff);
output.setRGB(j2, j1, rgb);
}
}
//1、先画一张完全透明的背景图
g2.drawImage(output, 0, 0, 800, 800, null);
//图片水印
if(StringUtils.isNotBlank(wtDto.getPicUrl())){
log.info("图片参数:opacity:{},height:{},picLeft:{},picTop:{},picWidth:{}"
, wtDto.getPicOpacity()
, wtDto.getPicHeight()
, wtDto.getPicLeft()
, wtDto.getPicTop()
, wtDto.getPicWidth());
Integer alpha = wtDto.getPicOpacity();
if(alpha == null
|| wtDto.getPicOpacity() == null
|| wtDto.getPicHeight() == null
|| wtDto.getPicLeft() == null
|| wtDto.getPicTop() == null
|| wtDto.getPicWidth() == null){
throw new BusinessException("图片参数错误!");
}
//检查透明度是否越界
if (alpha < 0) {
alpha = 0;
} else if (alpha > 10) {
alpha = 10;
}
InputStream inputStream = CompositeWatermarkUtil.downloadFile(wtDto.getPicUrl());
BufferedImage image = ImageIO.read(inputStream);
//2、再画水印素材图片
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,alpha.floatValue()/10));
g2.drawImage(image
, equalRatioCalculation(wtDto.getPicLeft())
, equalRatioCalculation(wtDto.getPicTop())
, equalRatioCalculation(wtDto.getPicWidth())
, equalRatioCalculation(wtDto.getPicHeight()), null);
}
//文字水印
if (StringUtils.isNotBlank(wtDto.getWatermarkText())) {
log.info("文字参数:textLeft:{},TextLeft:{},TextOpacity:{},TextColor:{},TextSize:{},TextFont:{}"
, wtDto.getTextLeft()
, wtDto.getTextTop()
, wtDto.getTextOpacity()
, wtDto.getTextColor()
, wtDto.getTextSize()
, wtDto.getTextFont());
if(wtDto.getTextLeft() == null
|| wtDto.getTextTop() == null
|| wtDto.getTextOpacity() == null
|| wtDto.getTextColor() == null
|| wtDto.getTextSize() == null
|| wtDto.getTextFont() == null){
throw new BusinessException("文字参数错误!");
}
try {
String[] availableFontFamilyNames = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
log.info("测试环境字体列表数组为:" + availableFontFamilyNames);
if(availableFontFamilyNames != null){
log.info("测试环境字体列表数组长度:" + availableFontFamilyNames.length);
log.info("测试环境字体列表获取首个:" + availableFontFamilyNames[0]);
}
for(String s : availableFontFamilyNames){
log.info(s);
}
} catch (Exception e) {
e.printStackTrace();
}
//3、画文字
String textColor = wtDto.getTextColor();
//字体
Font font = new Font(wtDto.getTextFont(), Font.BOLD, wtDto.getTextSize());//水印字体,大小
//颜色
Color color = new Color(Integer.decode(textColor));
g2.setFont(font);
g2.setColor(color);
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, wtDto.getTextOpacity()));
log.info("画文字开始");
g2.drawString(wtDto.getWatermarkText()
, equalRatioCalculation(wtDto.getTextLeft())
, equalRatioCalculation(wtDto.getTextTop()));
log.info("画文字结束");
}
//上传合成的水印
ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
ImageIO.write(output, "png", arrayOutputStream);
byte[] bytes = arrayOutputStream.toByteArray();
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
Long userId = SecurityUtils.getUserId();
//如果是编辑后保存,则有水印模板URL,使用原水印模板地址,新水印模板会替换掉旧的
if (BeanUtil.isNotEmpty(wtDto.getId())) {
WatermarkTemplate watermarkTemplate = watermarkTemplateMapper.selectOne(Wrappers.lambdaQuery(WatermarkTemplate.class)
.eq(WatermarkTemplate::getId, wtDto.getId()));
String key = cosClient.buildKey(watermarkTemplate.getWatermarkUrl());
cosClient.uploadFile(byteArrayInputStream, key);
BeanUtil.copyProperties(wtDto, watermarkTemplate, CopyOptions.create().setIgnoreError(true).ignoreNullValue());
watermarkTemplateMapper.updateByPrimaryKeySelective(watermarkTemplate);
} else {
//没有水印模板URL则是新增水印模板,生成新的
String key = cosClient.buildStoragePath(FileTypeEnum.IMAGE, "png", userId);
String watermarkTemplateUrl = cosClient.uploadFile(byteArrayInputStream, key);
WatermarkTemplate watermarkTemplate = new WatermarkTemplate();
BeanUtil.copyProperties(wtDto, watermarkTemplate, CopyOptions.create().setIgnoreError(true).ignoreNullValue());
watermarkTemplate.setWatermarkUrl(watermarkTemplateUrl);
watermarkTemplate.setCreateDate(new Date());
watermarkTemplate.setUserId(userId);
watermarkTemplateMapper.insert(watermarkTemplate);
}
return Result.ok(StatusCode.SUCCESS, "保存水印成功");
} catch (Exception e) {
e.printStackTrace();
return Result.errorMessage("保存水印失败,系统异常", StatusCode.FAILURE.code());
}
}
/**
* 水印素材位置等比例计算
* @param value
* @return
*/
private Integer equalRatioCalculation(Integer value){
BigDecimal waterSize = new BigDecimal(800);//水印最大尺寸
BigDecimal editerSize = new BigDecimal(500);//前端编辑框尺寸
BigDecimal ratio = editerSize.divide(waterSize);
BigDecimal valBd = new BigDecimal(value);
BigDecimal finalVal = valBd.divide(ratio);
int i = finalVal.intValue();
return i;
}