使用Thumbnails处理图片(自定义文本水印位置)
图片水印admin 发布于:2015-12-15 16:57:52
阅读:loading
记得以前弄java生成gif动画图片的时候,了解过java操作图片的一个库Thumbnails,发现它并不能创建gif图片,故并没有深入研究,但发现网上对它的评价很高,是一款处理图片很好的解决方案。
最近有要给图片加上一个动态水印的需求,也就是一张图片,谁看就显示谁的工号水印,让我想起来这个并未深入了解的组件,于是才终于有了想法去了解它。
通过一系列的网上搜索发现它能解决的主流功能有:图片放大、缩小(按指定宽高、比例)、图片旋转、图片格式转换、图片裁切、图片水印等几项,看了下网上示例也大多围绕这几项而来的,那么作为学习了解我也照搬这几项吧。主要做了以下几个示例:
1)缩放图片
按照设置的宽高去缩小、放大图片,同时可以设置是否保持原图比例;另外支持按图片的比例缩放。示例(以下示例图片为同一个)中原图采用600x600的大小,按宽高比例将图片缩小3倍,大小为200x200的比例大小;按宽高放大1.5倍,大小为900x900的比例大小;按比例缩小至30%,则大小为180x180比例大小;按原图大小放大3倍,则大小为1800x1800比例大小;
2)旋转图片
可按弧(角)度进行旋转,示例中采用旋转45度,90度,135度来实现;
3)裁切图片
裁切图片主要分为两种,一种是按它预置好的9个位置再按坐标进行四周扩散,9个位置分别为:也就是可以从以上9个点中以任何一个部分作为0,0坐标的位置 开始向其他坐标点位置发散,根据两个点的位置和宽和高而截取一个矩形(没有研究是不是可以按其他图形进行裁切)。示例中从正中间裁切400像素再缩小为200像素大小的图片;从顶部中间裁切400像素再缩小为200像素大小的图片;按自定义坐标裁切图片,此处这个自定义坐标我觉得需要画图说明一下,参考如下图:
4)图片水印
由于本次捡起来这个组件是从给图片添加水印而来的,故对这个添加水印的功能坐的更加详细的实现,其中主要的功能涉及有:按9个方向位置进行设置水印、自定义坐标位置、加长版本图片的多个水印、图片水印、文本水印、文本水印字体、字体大小、颜色、旋转角度、透明度、水印是否为透明图等等细节功能。至于显示位置的坐标就得去精确找位置了。
5)图片格式转换
此组件可将图片的格式比如png转换为jpg格式等,感觉项目中此功能作用不是很大,故跳过。
6)其他
a、很多时候都是直接读取一个图片文件,将一些水印或者其他的处理直接在内存中进行cao作,cao作完成后直接返回OutputStream输出至浏览器;
b、以上一些图片的处理中,发现添加水印的动作是比较消耗性能的;
c、不知道其它一些cao作图片的库使用起来若何?
附上几个操作的原图和效果图,如下:
(原图)
(按比例缩小3倍)
(90度旋转)
(长图多个水印)
package com;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import net.coobird.thumbnailator.Thumbnails;
import net.coobird.thumbnailator.Thumbnails.Builder;
import net.coobird.thumbnailator.geometry.Coordinate;
import net.coobird.thumbnailator.geometry.Position;
import net.coobird.thumbnailator.geometry.Positions;
public class ImageHandle {
/**
* 按宽高进行缩放,此时有几个图片宽度与高度大小的逻辑处理
*/
public static void zoomSize(File srcFile , File outFile , int width , int height){
try {
Thumbnails.of(srcFile).size(width, height).toFile(outFile);
//也可将图片输出至OutputStream
//是否使用等比缩放,keepAspectRatio(false)
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 将图片进行等比例缩放,0~~1之间的为缩小,大于1的为放大
*/
public static void zoomScaling(File srcFile , File outFile , double scale){
try {
Thumbnails.of(srcFile).scale(scale).toFile(outFile);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 按角度旋转
*/
public static void rotateAngle(File srcFile , File outFile , double rotate){
try {
Thumbnails.of(srcFile).scale(1).rotate(rotate).toFile(outFile);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 按坐标位置裁切图片,先按位置获取指定的图片范围,再按指定宽高存储
*/
public static void corpRegion(File srcFile , File outFile , Positions postition , int width , int height , int x , int y){
try {
Thumbnails.of(srcFile).sourceRegion(postition, x, y).size(width, height).toFile(outFile);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 按坐标位置裁切图片,先按位置获取指定的图片范围,再按指定宽高存储
* x1,x2为左上角的坐标点
* y1,y2为以左上角为0,0坐标位置的相对坐标(或者x1+要裁切图片宽度=y1,y1+要裁切图片高度=y2的坐标)
*/
public static void corpRegion(File srcFile , File outFile , int width , int height , int x1 , int y1 , int x2 , int y2){
try {
Thumbnails.of(srcFile).sourceRegion(x1, y1, x2, y2).size(width, height).keepAspectRatio(false).toFile(outFile);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 添加文本水印,也可添加图片水印
*/
public static void watermark(File srcFile , File outFile , Position position , String text , double rotate , float opacity){
//从原图中找出300x300的大小来显示水印文本
BufferedImage bi = new BufferedImage(300, 300 ,BufferedImage.TYPE_INT_RGB);
Graphics2D g = bi.createGraphics();
//设置绘图区域透明
bi = g.getDeviceConfiguration().createCompatibleImage(300, 300,Transparency.TRANSLUCENT);
g.dispose();
//字体、字体大小,透明度,旋转角度
g = bi.createGraphics();
g.setFont(new Font("微软雅黑", Font.BOLD, 26));
char[] data = text.toCharArray();
g.rotate(rotate);
g.setColor(Color.RED);
//设置文本显示坐标,以上述中的300x300位置为0,0点
g.drawChars(data, 0, data.length, -70, 200);
try {
Thumbnails.of(srcFile).scale(1).watermark(position, bi, opacity).toFile(outFile);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
String imgPath = "D:\\demo\\源宝宝.jpg";//原图
File srcFile = new File(imgPath);
BufferedImage image = ImageIO.read(srcFile);
int width = image.getWidth();
int height = image.getHeight();
//原图大小为:600,600
System.out.println("原图宽度为:" + width + " ,高度为 " + height);
System.out.println("=========缩放图片=========");
//按宽高缩小3倍,200x200
zoomSize(srcFile, new File(srcFile.getParent() , "按宽高缩小3倍.jpg"), width/3, height/3);
//按宽高放大1.5倍,900x900
zoomSize(srcFile, new File(srcFile.getParent() , "按宽高放大1.5倍.jpg"), (int)(width*1.5), (int)(height*1.5));
//按比例缩小3倍,600*0.3=180
zoomScaling(srcFile, new File(srcFile.getParent() , "按比例缩小3倍.jpg"), 0.3);
//按比例放大3倍,600*3=1800
zoomScaling(srcFile, new File(srcFile.getParent() , "按比例放大3倍.jpg"), 3);
System.out.println("=========旋转图片=========");
rotateAngle(srcFile , new File(srcFile.getParent() , "旋转45度.jpg") , 45);
rotateAngle(srcFile , new File(srcFile.getParent() , "旋转90度.jpg") , 90);
rotateAngle(srcFile , new File(srcFile.getParent() , "旋转135度.jpg") , 135);
System.out.println("=========裁切图片=========");
corpRegion(srcFile , new File(srcFile.getParent() , "从正中间裁切400像素再缩小为200像素大小.jpg") , Positions.CENTER , 200 , 200 , 400 , 400);
corpRegion(srcFile , new File(srcFile.getParent() , "从顶部中间裁切400像素再缩小为200像素大小.jpg") , Positions.TOP_CENTER , 200 , 200 , 400 , 400);
corpRegion(srcFile, new File(srcFile.getParent() , "按自定义坐标裁切图片.jpg"), 350, 300, 150, 200, 350, 300);
System.out.println("=========水印图片=========");
//此功能由于项目中使用了此种方式,故代码比较多,功能相对比较多,但具体的代码,参数应该自行设置
//水印可以同时添加多个,添加方式为:.watermark(顶部).watermark(中部).watermark(底部)
watermark(srcFile, new File(srcFile.getParent() , "图片正中间水印旋转45度.jpg") , Positions.CENTER , "http://www.chendd.cn" , -0.5 , 0.5f);
watermark(srcFile, new File(srcFile.getParent() , "自定义位置添加水印.jpg") , new Coordinate(100 , 300) , "http://www.chendd.cn" , -0.5 , 0.5f);
//给较长图添加一屏一个水印
File longImg = new File(srcFile.getParent() , "加长版.jpg");
watermarkLongImage(longImg, new File(longImg.getParent() , "加长版图片水印.jpg"));
System.out.println("=========图片格式转换貌似使用较少,此处省略=========");
}
private static void watermarkLongImage(File srcFile , File outFile) {
//从原图中找出300x300的大小来显示水印文本
BufferedImage bi = new BufferedImage(300, 100 ,BufferedImage.TYPE_INT_RGB);
Graphics2D g = bi.createGraphics();
//设置绘图区域透明
bi = g.getDeviceConfiguration().createCompatibleImage(300, 100,Transparency.TRANSLUCENT);
g.dispose();
//字体、字体大小,透明度,旋转角度
g = bi.createGraphics();
g.setFont(new Font("微软雅黑", Font.BOLD, 26));
char[] data = "http://www.chendd.cn".toCharArray();
g.setColor(Color.RED);
//设置文本显示坐标,以上述中的300x300位置为0,0点
g.drawChars(data, 0, data.length, 10, 20);
try {
BufferedImage image = ImageIO.read(srcFile);
int height = image.getHeight();
//假设此图在手机端访问,手机的高度为400,则每超过400部分显示一个水印
Builder<File> builder = Thumbnails.of(srcFile).scale(1);
int mod = (int) Math.ceil(height / 400);
for(int i=1 ; i < mod ; i++){
int x = 200;
int y = (i) * 400;
System.out.println(x + "," + y);
builder.watermark(new Coordinate(x , y), bi, 1);
}
builder.toFile(outFile);
} catch (IOException e) {
e.printStackTrace();
}
}
}
===========================================================
<dependency>
<groupId>net.coobird</groupId>
<artifactId>thumbnailator</artifactId>
<version>0.4.8</version>
</dependency>
所有的图片下载地址为:http://yunpan.cn/c3bc2IkYHvMhj (提取码:956d)(时至今日该链接肯定已经失效)
@2020-08-16 补充
① thumbnailator 组件有了2020的最新版本,0.4.11;
② 该组件对于图片水印支持的非常好,但是对于文本水印的方式则没有提供(或许是我不知道),本文特补充一下关于图片增加文本水印时的位置支持,分别是:左上、中上、右上、中左、中、中右、左下、下中、右下,共计9个位置,具体实现是使用java.awt.FontMetrics类提供的API实现,它支持根据字体样式获取该文本所占宽度大小,代码及生成图片样例参考如下:
点赞