在app的后台中,有时候为了标示版权,需要给图片加上水印。

在liunx中,IM4JAVA+GraphicsMagick是个高效处理图片的方案,图片的裁剪是使用了这个技术方案,为了减少不必要的开发成本和运维成本,对应水印,我们是打算继续采用这个方案。

但在开发的过程中,发现这个方案对中文水印支持得不好。

根据网上的搜索结果,就算采用了im4java的GMOperation,并将水印的字符串转成GBK的编码,添加中文水印时,对于奇数个数的中文,没问题;但对于偶数个数的中文,就出现乱码了。

试了多次后,发现这个问题没法解决,于是试了JMagick+ ImageMagick。

但是,在网上找到一份资料,http://javantsky.iteye.com/blog/747807, 里面提到JMagick+ImageMagick作为应用服务的缺点,并建议可以使用IM4JAVA:

The "JNI hazard" here is that if something you use (f.ex libtiff for reading

TIFF files) has a memory bug then it can make your whole JVM crash. Thats of

course frustrating and therefore its great to have im4java around, which

starts IM as an external process, so JVM crashes are avoided.

* *

Coolest thing would be if JMagick and im4java could have the same API so it

was easy to switch depending on luckyness. Ive asked the author of im4java

to attemt to be as compatible as possible, but as im4java is very much

different internally its limited how much can be done in that direction.

If you don't like the risk, stick to im4java. If your want optimal

performance give JMagick a try.

And, its not JMagick that is buggy, its what it depends on (hereunder IM)

that is not always (memory) bug free on long running processes.

I also have never seen a mismatch between JMagick binary and ImageMagick

binaries leading to crashes.

最后,采用了以下的方案视线图片的中文水印:

1.先把中文生成背景透明的png图片

2.把这些png图片作为图片水印贴在图上

代码如下:

package test;

import java.awt.BasicStroke;

import java.awt.Color;

import java.awt.Font;

import java.awt.Graphics;

import java.awt.Graphics2D;

import java.awt.Image;

import java.awt.Transparency;

import java.awt.font.FontRenderContext;

import java.awt.geom.AffineTransform;

import java.awt.geom.Rectangle2D;

import java.awt.image.BufferedImage;

import java.io.File;

import java.io.IOException;

import javax.imageio.ImageIO;

import org.im4java.core.CompositeCmd;

import org.im4java.core.ConvertCmd;

import org.im4java.core.GMOperation;

import org.im4java.core.GraphicsMagickCmd;

import org.im4java.core.IM4JavaException;

import org.im4java.core.IMOperation;

public class Watermark {

/**

* 按九宫格位置添加水印

* @param srcPath原图片路径

* @param distPath新图片路径

* @param watermarkImg水印图片路径

* @param position九宫格位置[1-9],从上往下,从左到右排序

* @param x 横向边距

* @param y 纵向边距

* @param alpha透明度

* @throws IOException

* @throws InterruptedException

* @throws IM4JavaException

*/

public void WatermarkImg(String srcPath,String distPath,String watermarkImg, int position, int x, int y, int alpha) throws IOException, InterruptedException, IM4JavaException{

int[] watermarkImgSide = getImageSide(watermarkImg);

int[] srcImgSide = getImageSide(srcPath);

int[] xy = getXY(srcImgSide, watermarkImgSide, position, y, x);

watermarkImg(srcPath,distPath,watermarkImg,watermarkImgSide[0],watermarkImgSide[1],xy[0],xy[1],alpha);

}

private int[] getImageSide(String imgPath) throws IOException {

int[] side = new int[2];

Image img = ImageIO.read(new File(imgPath));

side[0] = img.getWidth(null);

side[1] =img.getHeight(null);

return side;

}

/**

* 添加图片水印

* @param srcPath原图片路径

* @param distPath新图片路径

* @param watermarkImg水印图片路径

* @param width水印宽度(可以于水印图片大小不同)

* @param height水印高度(可以于水印图片大小不同)

* @param x水印开始X坐标

* @param y水印开始Y坐标

* @param alpha透明度[0-100]

* @throws IOException

* @throws InterruptedException

* @throws IM4JavaException

*/

private synchronized void watermarkImg(String srcPath,String distPath,String watermarkImg, int width, int height, int x, int y, int alpha) throws IOException, InterruptedException, IM4JavaException{

CompositeCmd cmd = new CompositeCmd(true);

String path = "C://Program Files//GraphicsMagick-1.3.19-Q8";

cmd.setSearchPath(path);

IMOperation op = new IMOperation();

op.dissolve(alpha);

op.geometry(width, height, x, y);

op.addImage(watermarkImg);

op.addImage(srcPath);

op.addImage(distPath);

cmd.run(op);

}

private int[] getXY(int[] image, int[] watermark, int position, int x, int y) {

int[] xy = new int[2];

if(position==1){

xy[0] = x;

xy[1] = y;

}else if(position==2){

xy[0] = (image[0]-watermark[0])/2;//横向边距

xy[1] = y; //纵向边距

}else if(position==3){

xy[0] = image[0]-watermark[0]-x;

xy[1] = y;

}else if(position==4){

xy[0] = x;

xy[1] = (image[1]-watermark[1])/2;

}else if(position==5){

xy[0] = (image[0]-watermark[0])/2;

xy[1] = (image[1]-watermark[1])/2;

}else if(position==6){

xy[0] = image[0]-watermark[0]-x;

xy[1] = (image[1] - watermark[1])/2;

}else if(position==7){

xy[0] = x;

xy[1] = image[1] - watermark[1] - y;

}else if(position==8){

xy[0] = (image[0]-watermark[0])/2;

xy[1] = image[1] - watermark[1] - y;

}else{

xy[0] = image[0]-watermark[0]-x;

xy[1] = image[1] - watermark[1] - y;

}

return xy;

}

/**

* 把文字转化为一张背景透明的png图片

* @param str 文字的内容

* @param fontType 字体,例如宋体

* @param fontSize 字体大小

* @param colorStr 字体颜色,不带#号,例如"990033"

* @param outfile png图片的路径

* @throws Exception

*/

public void converFontToImage(String str,String fontType,int fontSize,String colorStr, String outfile) throws Exception{

Font font=new Font(fontType,Font.BOLD,fontSize);

File file=new File(outfile);

//获取font的样式应用在str上的整个矩形

Rectangle2D r=font.getStringBounds(str, new FontRenderContext(AffineTransform.getScaleInstance(1, 1),false,false));

int unitHeight=(int)Math.floor(r.getHeight());//获取单个字符的高度

//获取整个str用了font样式的宽度这里用四舍五入后+1保证宽度绝对能容纳这个字符串作为图片的宽度

int width=(int)Math.round(r.getWidth())+1;

int height=unitHeight+3;//把单个字符的高度+3保证高度绝对能容纳字符串作为图片的高度

//创建图片

BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

Graphics2D g2d = image.createGraphics();

image = g2d.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);

g2d.dispose();

g2d = image.createGraphics();

g2d.setColor(Color.WHITE);

g2d.setStroke(new BasicStroke(1));

g2d.setColor(new Color(Integer.parseInt(colorStr, 16)));//在换成所需要的字体颜色

g2d.setFont(font);

g2d.drawString(str, 0,font.getSize());

ImageIO.write(image, "png", file);//输出png图片

}

}

测试实例:

package test;

import java.awt.BasicStroke;

import java.awt.Color;

import java.awt.Font;

import java.awt.Graphics;

import java.awt.Graphics2D;

import java.awt.Transparency;

import java.awt.font.FontRenderContext;

import java.awt.geom.AffineTransform;

import java.awt.geom.Rectangle2D;

import java.awt.image.BufferedImage;

import java.io.File;

import javax.imageio.ImageIO;

import org.im4java.core.CompositeCmd;

import org.im4java.core.ConvertCmd;

import org.im4java.core.GMOperation;

import org.im4java.core.IMOperation;

public class test {

public static void main(String[] args) {

try {

String src="D://src.jpg"; //需要加水印的源图片

String desc="D://desc.jpg"; //生成的水印图片的路径

String water="D://water.png"; //用中文转换成的背景透明的png图片

String fontType="C:\\Windows\\Fonts\\simsun.ttc"; //指定字体文件为宋体

String colorStr="990033"; //颜色

int fontSize=18;

Watermark watermark=new Watermark();

/*

* 把文字转化为一张背景透明的png图片

* @param str 文字的内容

* @param fontType 字体,例如宋体

* @param fontSize 字体大小

* @param colorStr 字体颜色,不带#号,例如"990033"

* @param outfile png图片的路径

* @throws Exception

*/

watermark.converFontToImage("中华人们", fontType, fontSize, colorStr, water);

/*

* 把文字的png图片贴在原图上,生成水印

* @param srcPath原图片路径

* @param distPath新图片路径

* @param watermarkImg水印图片路径

* @param position九宫格位置[1-9],从上往下,从左到右排序

* @param x 横向边距

* @param y 纵向边距

* @param alpha透明度

*/

watermark.WatermarkImg(src, desc, water, 1, 20,20, 100);

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

源码已放在github:https://github.com/newjueqi/ChineseWaterMark#

如果您觉得这系列的文章对你有所帮助,欢迎打赏。

支付宝账号:190678908@qq.com 收款人:曾健生

新建了“app后端技术” 交流qq群:254659220

[文章作者]曾健生

[作者邮箱]h6k65@126.com

[作者QQ]190678908

[新浪微博] @newjueqi

[博客]http://blog.csdn.net/newjueqi

版权声明:本文为博主原创文章,未经博主允许不得转载。

im4java 水印_app后端设计(13)--IM4JAVA+GraphicsMagick实现中文水印相关推荐

  1. Graphicsmagick linux 中文水印乱码-new

    文章目录 Graphicsmagick linux 中文水印l乱码(中文显示成正方形) 本人在Windows上安装Graphicsmagick 并使用Graphicsmagick 添加中文水印成功,但 ...

  2. gm(GraphicsMagick)图片中文水印乱码问题

    1.GraphicsMagick图片中文水印乱码问题处理方式 如出现乱码是由于服务器中缺少中文字库所致,为避免系统中存在多个中文字库冲突, 所以没有必要在安装GraphicsMagick时就将字库文件 ...

  3. app后端设计(php)

    来源:http://blog.csdn.net/column/details/mobilebackend.html?page=1 做了3年app相关的系统架构,api设计,先后在3个创业公司中工作,经 ...

  4. app后端设计(12)--图片的处理

    app上线后,不断接受用户的反馈,于是,反馈非常差的情况下,都会有app的改版. 一旦app的改版,都会有比较大的UI改动,一改动UI,那么图片的尺寸也就必须要改变. 在app后端设计(1)-api( ...

  5. 《CMOS集成电路后端设计与实战》——导读

    前 言 在当今信息化的社会中,集成电路已成为各行各业实现信息化.智能化的基础.无论是在军事还是民用上,它已起着不可替代的作用.集成电路产业是全球范围内的核心高科技产业之一,具有战略性和市场性双重特性. ...

  6. 基于MATLAB的小波变换数字图像水印系统GUI设计与实现

    摘 要 通过对数字水印的原理和算法的分析,了解信息隐藏的实现手段与效果.在信息加载和提取过程中,突破传统的加密技术,用更具专业性的检测手段来保护专属的信息产权.本文利用了水印良好的鲁棒性和不可感知性, ...

  7. 物理综合:关于UDSM后端设计总结

    随着科技的发展,65nm及65nm以下的工艺节点成为设计的主流 随着工艺的发展,绝对的物理变异导致相对较大的电气特性变异 随着工艺的发展,时序收敛变得越来越困难 可制造性的问题(DFM)变得越来越关键 ...

  8. 数字IC后端设计实现流程之initial design

    数字IC后端设计实现流程之initial design 前端提供的文件 门级网表 (Gate Level Netlist) 数字前端工程师或者是 R2N 的同事在 release 东西给后端工程师做 ...

  9. 数字IC后端设计实现流程之floorplan及powerplan规划

    数字IC后端设计实现floorplan及powerplan规划 数字 IC 后端设计实现流程之 initial design 初始化 Initial 模块形状 估算完模块的面积后,block owne ...

最新文章

  1. 干货丨从概念到实践,我们该如何构建自动微分库
  2. Ubuntu的which、whereis、locate和find命令
  3. python遇到错误跳过_python except异常处理之后不退出,解决异常继续执行的实现
  4. OpenCASCADE:读IGES
  5. Kubernetes事件离线工具kube-eventer正式开源
  6. web developer tips (48):IIS7应用程序池的“Ping”设置可能影响调试
  7. IOS基础学习日志(七)利用dispatch_once创建单例及使用
  8. 通过build.xml在Eclipse中导入工程
  9. 万字长文丨大白话带你由浅入深Python编程语言
  10. 游程编码用matlab实现代码_二值图像游程编码算法的Matlab实现 -
  11. ipython 安装
  12. jquery将html转换word,将网页内容导出word文档jQuery插件
  13. CT重建学习笔记(一)
  14. 计算机向文档中插入文本框,Word怎么插入文本框和编辑文本框
  15. 图书馆在计算机房旁边用英语怎么说,PEP四年级下学期英语期末复习
  16. 布兰迪斯大学计算机美国大学排名,布兰迪斯大学2021年US News美国最佳大学排名第几?...
  17. SSD固态硬盘:掉盘的四大类原因
  18. 网优5g前景_5G网络优化工程师的前景和待遇
  19. 玩游戏键盘一按就打开计算机,win10电脑玩游戏时按键盘会自动弹字
  20. android 一分钟掌握圆形布局原理--圆形菜单控件 so easy

热门文章

  1. 富受贿数额为45437元
  2. 什么是Bugzilla
  3. ubuntu14.04搜狗输入法中文无法切换英文
  4. 那些android你需要知道的事
  5. 成年人的崩溃一触即发,掌握学习能力才能突破认知结界,干货满满!并带你分享你如何掉入互联网大佬的各种陷阱...
  6. nginx安装教程(centos系统)
  7. 监控平台设计 之 Graphite、Prometheus 竞对
  8. Magic Number魔数是什么
  9. Python BeautifulSoup简介
  10. inet_aton mysql_MySQL_IP处理函数inet_aton()和inet_ntoa()使用说明,MYSql的IP对int的转换函数 select i - phpStudy...