该程序要用到eclipse中的swt插件来实现可视化编程
插件的安装及使用操作可在我这一篇博客中获取
https://blog.csdn.net/leon9dragon/article/details/91864590
运行结果在本文最后放出
该程序仅支持jpg,png和bmp三种格式
有需要的朋友可自行魔改程序中获取图片格式部分的代码即可增加格式类型
图片格式类型的获取是通过文件流来进行获取的
通过判断对比文件头然后来给图片添加水印
下面列举了部分文件头
常用文件的文件头如下:(以前六位为准)
JPEG (jpg),文件头:FFD8FF
PNG (png),文件头:89504E47
GIF (gif),文件头:47494638
TIFF (tif),文件头:49492A00
Windows Bitmap (bmp),文件头:424D
CAD (dwg),文件头:41433130
Adobe Photoshop (psd),文件头:38425053
Rich Text Format (rtf),文件头:7B5C727466
XML (xml),文件头:3C3F786D6C
HTML (html),文件头:68746D6C3E
Email [thorough only] (eml),文件头:44656C69766572792D646174653A
Outlook Express (dbx),文件头:CFAD12FEC5FD746F
Outlook (pst),文件头:2142444E
MS Word/Excel (xls.or.doc),文件头:D0CF11E0
MS Access (mdb),文件头:5374616E64617264204A
WordPerfect (wpd),文件头:FF575043
Postscript (eps.or.ps),文件头:252150532D41646F6265
Adobe Acrobat (pdf),文件头:255044462D312E
Quicken (qdf),文件头:AC9EBD8F
Windows Password (pwl),文件头:E3828596
ZIP Archive (zip),文件头:504B0304
RAR Archive (rar),文件头:52617221
Wave (wav),文件头:57415645
AVI (avi),文件头:41564920
Real Audio (ram),文件头:2E7261FD
Real Media (rm),文件头:2E524D46
MPEG (mpg),文件头:000001BA
MPEG (mpg),文件头:000001B3
Quicktime (mov),文件头:6D6F6F76
Windows Media (asf),文件头:3026B2758E66CF11
MIDI (mid),文件头:4D546864
ps1:
这个程序本来是我毕设设计的系统的其中一个界面
是可以获取登录用户的名字然后打在水印上的
但这里我进行了删除了这部分内容,并不影响整个程序的运行
这里默认的图片作者名字是null
有需要的朋友可以根据自己设计的系统再重新嵌入这部分代码
ps2:
同时这部分代码中默认的图片输出格式是bmp格式
因为获取文件头的时候是取的前6位
然而bmp格式的文件头只有4位
为了省事,直接默认进行bmp格式的输出
有需要的朋友可以再在判断格式这部分通过字符串对比的方法进行修改
package com.blog.watermark;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Image;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JTextField;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.awt.event.ActionEvent;
import javax.swing.JLabel;
public class testWatermark extends JFrame {
private JPanel contentPane;
private JTextField pathField;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
testWatermark frame = new testWatermark();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public testWatermark() {
setTitle("\u6DFB\u52A0\u6C34\u5370\u754C\u9762");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
pathField = new JTextField();
pathField.setBounds(52, 99, 240, 21);
contentPane.add(pathField);
pathField.setColumns(10);
JButton cpathBton = new JButton("\u9009\u62E9\u56FE\u7247");
cpathBton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
cpathaction(arg0);
}
});
cpathBton.setBounds(297, 98, 93, 23);
contentPane.add(cpathBton);
markBton = new JButton("\u6DFB\u52A0\u6C34\u5370");
markBton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
try {
markaction(arg0);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
markBton.setBounds(155, 130, 93, 23);
contentPane.add(markBton);
JLabel lbljpg = new JLabel("\u652F\u6301jpg/png/bmp\u683C\u5F0F\u7684\u56FE\u7247");
lbljpg.setFont(new Font("黑体", Font.BOLD, 15));
lbljpg.setForeground(Color.RED);
lbljpg.setBounds(52, 74, 240, 15);
contentPane.add(lbljpg);
}
public String imgname = null;//文件名称,包括了后缀
public String imgpath = null;//文件所在的文件夹路径
private JButton markBton;
//选择图片路径事件
public void cpathaction(ActionEvent arg0){
JFileChooser fileChooser=new JFileChooser("C:/Users/Administrator/Desktop/");//默认首先搜寻路径,可根据自己的需要进行修改
if(fileChooser.showOpenDialog(null)==JFileChooser.APPROVE_OPTION){
pathField.setText(fileChooser.getSelectedFile().getPath());//文本框给出路径
imgname = fileChooser.getSelectedFile().getName();//获取加密文件名
imgpath = pathField.getText() ;
imgpath = imgpath.substring(0,imgpath.length()-imgname.length());//获取加密的文件所在的文件夹
}
}
//添加水印按钮事件
public void markaction(ActionEvent arg0) throws Exception{
String path = pathField.getText();//获取图片路径
String markimg = imgpath + "(watermark)" + imgname;
String authorname = null;
/**
这部分本来是获取数据库中用户名的代码
删除掉并不影响程序的实现
若有需要可自行编写
*/
// 原图位置, 输出图片位置, 水印文字颜色, 水印文字+作者名字
new testWatermark().addmark(path, markimg,Color.red, "图片作者:" + authorname);
}
//添加水印的功能实现,同时通过文件流来检测图片的类型,仅支持jpg和png和bmp格式
public void addmark(String srcImgPath, String outImgPath, Color markColor, String waterMarkContent) {
try {//参数分别是(要添加水印的图片的路径,添加水印后图片输出路径,水印文字的颜色,水印的文字)
File srcImgFile = new File(srcImgPath);
//检测图片文件是否存在
if(!srcImgFile.exists()) {
JOptionPane.showMessageDialog(null, "请先选择图片");
throw new NullPointerException("Watermark file is empty");
}
// 读取原图片
Image srcImg = ImageIO.read(srcImgFile);
int srcImgWidth = srcImg.getWidth(null);
int srcImgHeight = srcImg.getHeight(null);
// 加水印
BufferedImage buffImg = new BufferedImage(srcImgWidth, srcImgHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D g = buffImg.createGraphics();//得到画笔对象
g.drawImage(srcImg, 0, 0, srcImgWidth, srcImgHeight, null);
Font font = new Font("黑体", Font.PLAIN, 25);//设置水印的字体
g.setFont(font);
g.setColor(markColor); // 设置水印颜色
int x = srcImgWidth - getWatermarkLength(waterMarkContent, g) - 3;//设置水印的坐标(x,y)
int y = srcImgHeight - 3;
g.drawString(waterMarkContent, x, y);//waterMarkContent是设置的内容,后面两个参数是文字在图片上的坐标位置(x,y)
g.dispose();
//获取图片类型后缀,用文件流进行判断
FileInputStream filetype = new FileInputStream(srcImgPath);
byte[] b = new byte[3];
filetype.read(b, 0, b.length);
String prefix = bytesToHexString(b);
prefix = prefix.toUpperCase();
String suffix = checkType(prefix);
System.out.println("后缀名是:" + suffix);
// 输出图片,因为获取了图片的后缀,png和bmp也可以输出
FileOutputStream outImgStream = new FileOutputStream(outImgPath);
ImageIO.write(buffImg, suffix, outImgStream);
outImgStream.flush();
outImgStream.close();
JOptionPane.showMessageDialog(null, "添加水印成功");
} catch (Exception e) {
e.printStackTrace();
JOptionPane.showMessageDialog(null, "添加水印失败");
}
}
//获取水印文字总长度
public int getWatermarkLength(String waterMarkContent, Graphics2D g) {
return g.getFontMetrics(g.getFont()).charsWidth(waterMarkContent.toCharArray(), 0, waterMarkContent.length());
}
//返回文件格式后缀
//由于bmp文件的文件头只有4位,而文件流获取的是6位,因此无法比较,所以默认输出格式是bmp
//有想法的朋友可以给我留言给出修改意见,谢谢
public static String checkType(String xxxx) {
switch (xxxx) {
case "FFD8FF": return "jpg";
case "89504E": return "png";
default: return "bmp";
}
}
public static String bytesToHexString(byte[] src) {
StringBuilder stringBuilder = new StringBuilder();
if (src == null || src.length <= 0) {
return null;
}
for (int i = 0; i < src.length; i++) {
int v = src[i] & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
return stringBuilder.toString();
}
}
1)选择图片
2)添加水印,控制台也会输出图片后缀名,不需要的话可以删除这部分代码
3)图片效果
没添加水印的原图
这是笔者花了3秒钟画的,很好看吧~
添加水印后的图片
如图右下角出现了红色水印(被csdn的白色水印盖住了一点…)
水印的颜色,字体,大小等都可以在代码中进行调整
作者名字如开头所说,可以通过连接数据库获取
也可直接设定变量authorname=你所需要的名字