草庐IT

java实现给图片添加水印(文字水印或图片水印)

12程序猿 2023-04-20 原文

本文介绍java实现在图片上加文字水印的方法,水印可以是图片或者文字,操作方便。

目录

java实现给图片添加水印实现步骤:
(1)获取原图片对象信息(本地图片或网络图片)
(2)添加水印(设置水印颜色、字体、坐标等)
(3)处理输出目标图片

一、java实现给图片添加文字水印

1.获取原图片对象信息

第一步:获取需要处理的图片

获取图片的方式,通常由两种:

  1. 一种是通过下载到本地,从本地读取(本地图片);

  2. 另外一种是通过网络地址进行读取(网络图片)

1.1 读取本地图片


通过代码实现读取本地目录(F:\image\1.png)下图片,代码如下:

// 读取原图片信息 得到文件
File srcImgFile = new File("F:/image/1.png");
//将文件对象转化为图片对象
Image srcImg = ImageIO.read(srcImgFile);
//获取图片的宽
int srcImgWidth = srcImg.getWidth(null);
//获取图片的高
int srcImgHeight = srcImg.getHeight(null);
System.out.println("图片的宽:"+srcImgWidth);
System.out.println("图片的高:"+srcImgHeight);

代码效果如下:

1.2 读取网络图片

//创建一个URL对象,获取网络图片的地址信息
URL url = new URL("https://pngimg.com/distr/img/ukraine.png");
//将URL对象输入流转化为图片对象 (url.openStream()方法,获得一个输入流)
Image srcImg = ImageIO.read(url.openStream());
//获取图片的宽
int srcImgWidth = srcImg.getWidth(null);
//获取图片的高
int srcImgHeight = srcImg.getHeight(null);
System.out.println("图片的宽:"+srcImgWidth);
System.out.println("图片的高:"+srcImgHeight);

代码效果如下:

2.添加水印

通过上面的步骤,我们已经获取到了原始图片信息,下面需要创建一个画笔进行水印的添加。水印包含文字水印、图片水印。

画笔可以设置水印颜色、字体大小、字体样式等。

BufferedImage bufImg = new BufferedImage(srcImgWidth, srcImgHeight, BufferedImage.TYPE_INT_RGB);
// 加水印
//创建画笔
Graphics2D g = bufImg.createGraphics();
//srcImg 为上面获取到的原始图片的图片对象
g.drawImage(srcImg, 0, 0, srcImgWidth, srcImgHeight, null);
//根据图片的背景设置水印颜色
g.setColor(new Color(255,255,255,128));
//设置字体  画笔字体样式为微软雅黑,加粗,文字大小为60pt
g.setFont(new Font("微软雅黑", Font.BOLD, 60));
//设置水印的坐标
//int x=200;
//int y=200;
int x=(srcImgWidth - getWatermarkLength(waterMarkContent, g)) / 2;
int y=srcImgHeight / 2;
//画出水印 第一个参数是水印内容,第二个参数是x轴坐标,第三个参数是y轴坐标
g.drawString("图片来源:https://image.baidu.com/", x, y);
g.dispose();

getWatermarkLength方法用于计算水印内容的长度

    /**
     * 获取水印文字的长度
     * @param waterMarkContent
     * @param g
     * @return
     */
    public static int getWatermarkLength(String waterMarkContent, Graphics2D g) {
        return g.getFontMetrics(g.getFont()).charsWidth(waterMarkContent.toCharArray(), 0, waterMarkContent.length());
    }

Font 字体说明:

Font 类的构造函数为: public Font(String familyName, int style, int size)
参数说明:第一个参数为字体类型,第二个参数为字体风格,第三个参数为字体大小

字体的风格有:

  • Font.PLAIN(普通)
  • Font.BOLD(加粗)
  • Font.ITALIC(斜体)
  • Font.BOLD+Font.ITALIC(粗斜体)

size字体大小 默认单位是pt(磅),数字越大,字就越大

需要注意是 水印坐标位置。设置不当,就看不到水印效果。

如何确定水印位置 ?
方法一:设置固定值

①首先,我们要知道图片上的坐标的表示法。具体如下:

②将图片保存到本地,然后选中图片点击右键,编辑,选择“画图”软件打开

③将鼠标移动到想要添加水印的位置,左下角可以看到鼠标点击位置对应的坐标值,拿到这个坐标值写入程序即可

方法二:根据原图大小进行设置,如放置在原图的中间位置
x轴坐标:(原始图的宽度 - 水印的宽度) / 2
y轴坐标:(原始图的高度 - 水印的高度) / 2

3.获取目标图片

经过上面的操作后,我们的图片添加文字就已经处理完成了。但他现在还保存在Java对象中。
我们想要看得到效果,需要进行处理,保存图片到本地。

//待存储的地址
String tarImgPath="F:/image/t.png";
// 输出图片
FileOutputStream outImgStream = new FileOutputStream(tarImgPath);
ImageIO.write(bufImg, "png", outImgStream);
System.out.println("添加水印完成");
outImgStream.flush();
outImgStream.close();

执行效果:
执行,目标目录下多了一个t.png的图片:

t.png打开可以看到添加的文字水印,水印添加成功:

4.完成代码

package com.example.listdemo.utils;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 图片添加水印
 * @author qzz
 */
public class ImageUtils {

    public static void main(String[] args) throws IOException {
        // 读取原图片信息 得到文件(本地图片)
        File srcImgFile = new File("F:/image/1.png");
        //将文件对象转化为图片对象
        Image srcImg = ImageIO.read(srcImgFile);
        //获取图片的宽
        int srcImgWidth = srcImg.getWidth(null);
        //获取图片的高
        int srcImgHeight = srcImg.getHeight(null);
        System.out.println("图片的宽:"+srcImgWidth);
        System.out.println("图片的高:"+srcImgHeight);

        //创建一个URL对象,获取网络图片的地址信息(网络图片)
//        URL url = new URL("https://pngimg.com/distr/img/ukraine.png");
//        //将URL对象输入流转化为图片对象 (url.openStream()方法,获得一个输入流)
//        Image srcImg = ImageIO.read(url.openStream());
//        //获取图片的宽
//        int srcImgWidth = srcImg.getWidth(null);
//        //获取图片的高
//        int srcImgHeight = srcImg.getHeight(null);
//        System.out.println("图片的宽:"+srcImgWidth);
//        System.out.println("图片的高:"+srcImgHeight);



        BufferedImage bufImg = new BufferedImage(srcImgWidth, srcImgHeight, BufferedImage.TYPE_INT_RGB);
        // 加水印
        //创建画笔
        Graphics2D g = bufImg.createGraphics();
        //绘制原始图片
        g.drawImage(srcImg, 0, 0, srcImgWidth, srcImgHeight, null);
        //-------------------------文字水印 start----------------------------
        //根据图片的背景设置水印颜色
        g.setColor(new Color(255,255,255,128));
        //设置字体  画笔字体样式为微软雅黑,加粗,文字大小为60pt
        g.setFont(new Font("微软雅黑", Font.BOLD, 60));
        //水印内容
        String waterMarkContent="图片来源:https://image.baidu.com/";
        //设置水印的坐标(为原图片中间位置)
        int x=(srcImgWidth - getWatermarkLength(waterMarkContent, g)) / 2;
        int y=srcImgHeight / 2;
        //画出水印 第一个参数是水印内容,第二个参数是x轴坐标,第三个参数是y轴坐标
        g.drawString(waterMarkContent, x, y);
        g.dispose();
        //-------------------------文字水印 end----------------------------
        //待存储的地址
        String tarImgPath="F:/image/t.png";
        // 输出图片
        FileOutputStream outImgStream = new FileOutputStream(tarImgPath);
        ImageIO.write(bufImg, "png", outImgStream);
        System.out.println("添加水印完成");
        outImgStream.flush();
        outImgStream.close();

    }
    
    /**
     * 获取水印文字的长度
     * @param waterMarkContent
     * @param g
     * @return
     */
    public static int getWatermarkLength(String waterMarkContent, Graphics2D g) {
        return g.getFontMetrics(g.getFont()).charsWidth(waterMarkContent.toCharArray(), 0, waterMarkContent.length());
    }
}


二、java实现给图片添加图片水印

下载水印图片到本地:
水印图片位置:F:\image\s.png

1.添加图片水印方法:

// 水印文件
String waterMarkImage="F:/image/s.png";
Image srcWaterMark = ImageIO.read(new File(waterMarkImage));
//获取水印图片的宽度
int widthWaterMark= srcWaterMark.getWidth(null);
//获取水印图片的高度
int heightWaterMark = srcWaterMark.getHeight(null);
//设置 alpha 透明度:alpha 必须是范围 [0.0, 1.0] 之内(包含边界值)的一个浮点数字
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 0.9f));
//绘制水印图片  坐标为中间位置
g.drawImage(srcWaterMark, (srcImgWidth - widthWaterMark) / 2,
        (srcImgHeight - heightWaterMark) / 2, widthWaterMark, heightWaterMark, null);
// 水印文件结束
g.dispose();

2.完成代码

package com.example.listdemo.utils;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 图片添加水印
 * @author qzz
 */
public class ImageUtils {

    public static void main(String[] args) throws IOException {
        // 读取原图片信息 得到文件(本地图片)
        File srcImgFile = new File("F:/image/1.png");
        //将文件对象转化为图片对象
        Image srcImg = ImageIO.read(srcImgFile);
        //获取图片的宽
        int srcImgWidth = srcImg.getWidth(null);
        //获取图片的高
        int srcImgHeight = srcImg.getHeight(null);
        System.out.println("图片的宽:"+srcImgWidth);
        System.out.println("图片的高:"+srcImgHeight);

        //创建一个URL对象,获取网络图片的地址信息(网络图片)
//        URL url = new URL("https://pngimg.com/distr/img/ukraine.png");
//        //将URL对象输入流转化为图片对象 (url.openStream()方法,获得一个输入流)
//        Image srcImg = ImageIO.read(url.openStream());
//        //获取图片的宽
//        int srcImgWidth = srcImg.getWidth(null);
//        //获取图片的高
//        int srcImgHeight = srcImg.getHeight(null);
//        System.out.println("图片的宽:"+srcImgWidth);
//        System.out.println("图片的高:"+srcImgHeight);



        BufferedImage bufImg = new BufferedImage(srcImgWidth, srcImgHeight, BufferedImage.TYPE_INT_RGB);
        // 加水印
        //创建画笔
        Graphics2D g = bufImg.createGraphics();
        //绘制原始图片
        g.drawImage(srcImg, 0, 0, srcImgWidth, srcImgHeight, null);
        //-------------------------文字水印 start----------------------------
//        //根据图片的背景设置水印颜色
//        g.setColor(new Color(255,255,255,128));
//        //设置字体  画笔字体样式为微软雅黑,加粗,文字大小为60pt
//        g.setFont(new Font("微软雅黑", Font.BOLD, 60));
//        String waterMarkContent="图片来源:https://image.baidu.com/";
//        //设置水印的坐标(为原图片中间位置)
//        int x=(srcImgWidth - getWatermarkLength(waterMarkContent, g)) / 2;
//        int y=srcImgHeight / 2;
//        //画出水印 第一个参数是水印内容,第二个参数是x轴坐标,第三个参数是y轴坐标
//        g.drawString(waterMarkContent, x, y);
//        g.dispose();
        //-------------------------文字水印 end----------------------------

        //-------------------------图片水印 start----------------------------
        // 水印文件
        String waterMarkImage="F:/image/s.png";
        Image srcWaterMark = ImageIO.read(new File(waterMarkImage));
        //获取水印图片的宽度
        int widthWaterMark= srcWaterMark.getWidth(null);
        //获取水印图片的高度
        int heightWaterMark = srcWaterMark.getHeight(null);
        //设置 alpha 透明度:alpha 必须是范围 [0.0, 1.0] 之内(包含边界值)的一个浮点数字
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 0.9f));
        //绘制水印图片  坐标为中间位置
        g.drawImage(srcWaterMark, (srcImgWidth - widthWaterMark) / 2,
                (srcImgHeight - heightWaterMark) / 2, widthWaterMark, heightWaterMark, null);
        // 水印文件结束
        g.dispose();
        //-------------------------图片水印 end----------------------------

        //待存储的地址
        String tarImgPath="F:/image/t.png";
        // 输出图片
        FileOutputStream outImgStream = new FileOutputStream(tarImgPath);
        ImageIO.write(bufImg, "png", outImgStream);
        System.out.println("添加水印完成");
        outImgStream.flush();
        outImgStream.close();

    }
    
    /**
     * 获取水印文字的长度
     * @param waterMarkContent
     * @param g
     * @return
     */
    public static int getWatermarkLength(String waterMarkContent, Graphics2D g) {
        return g.getFontMetrics(g.getFont()).charsWidth(waterMarkContent.toCharArray(), 0, waterMarkContent.length());
    }
}

3.代码执行效果


t.png图片文件中 含有 水印图片,说明 图片水印添加成功!

有关java实现给图片添加水印(文字水印或图片水印)的更多相关文章

  1. ruby - 我需要将 Bundler 本身添加到 Gemfile 中吗? - 2

    当我使用Bundler时,是否需要在我的Gemfile中将其列为依赖项?毕竟,我的代码中有些地方需要它。例如,当我进行Bundler设置时:require"bundler/setup" 最佳答案 没有。您可以尝试,但首先您必须用鞋带将自己抬离地面。 关于ruby-我需要将Bundler本身添加到Gemfile中吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/4758609/

  2. ruby - 如何使用文字标量样式在 YAML 中转储字符串? - 2

    我有一大串格式化数据(例如JSON),我想使用Psychinruby​​同时保留格式转储到YAML。基本上,我希望JSON使用literalstyle出现在YAML中:---json:|{"page":1,"results":["item","another"],"total_pages":0}但是,当我使用YAML.dump时,它不使用文字样式。我得到这样的东西:---json:!"{\n\"page\":1,\n\"results\":[\n\"item\",\"another\"\n],\n\"total_pages\":0\n}\n"我如何告诉Psych以想要的样式转储标量?解

  3. ruby - 将 Bootstrap Less 添加到 Sinatra - 2

    我有一个ModularSinatra应用程序,我正在尝试将Bootstrap添加到应用程序中。get'/bootstrap/application.css'doless:"bootstrap/bootstrap"end我在views/bootstrap中有所有less文件,包括bootstrap.less。我收到这个错误:Less::ParseErrorat/bootstrap/application.css'reset.less'wasn'tfound.Bootstrap.less的第一行是://CSSReset@import"reset.less";我尝试了所有不同的路径格式,但它

  4. ruby - 续集在添加关联时访问many_to_many连接表 - 2

    我正在使用Sequel构建一个愿望list系统。我有一个wishlists和itemstable和一个items_wishlists连接表(该名称是续集选择的名称)。items_wishlists表还有一个用于facebookid的额外列(因此我可以存储opengraph操作),这是一个NOTNULL列。我还有Wishlist和Item具有续集many_to_many关联的模型已建立。Wishlist类也有:selectmany_to_many关联的选项设置为select:[:items.*,:items_wishlists__facebook_action_id].有没有一种方法可以

  5. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  6. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  7. ruby-on-rails - Ruby on Rails - 为文本区域和图片生成列 - 2

    我是Rails的新手,所以请原谅简单的问题。我正在为一家公司创建一个网站。那家公司想在网站上展示它的客户。我想让客户自己管理这个。我正在为“客户”生成一个表格,我想要的三列是:公司名称、公司描述和Logo。对于名称,我使用的是name:string但不确定如何在脚本/生成脚手架终端命令中最好地创建描述列(因为我打算将其设置为文本区域)和图片。我怀疑描述(我想成为一个文本区域)应该仍然是描述:字符串,然后以实际形式进行调整。不确定如何处理图片字段。那么……说来话长:我在脚手架命令中输入什么来生成描述和图片列? 最佳答案 对于“文本”数

  8. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

  9. ruby - 字符串文字中的转义状态作为 `String#tr` 的参数 - 2

    对于作为String#tr参数的单引号字符串文字中反斜杠的转义状态,我觉得有些神秘。你能解释一下下面三个例子之间的对比吗?我特别不明白第二个。为了避免复杂化,我在这里使用了'd',在双引号中转义时不会改变含义("\d"="d")。'\\'.tr('\\','x')#=>"x"'\\'.tr('\\d','x')#=>"\\"'\\'.tr('\\\d','x')#=>"x" 最佳答案 在tr中转义tr的第一个参数非常类似于正则表达式中的括号字符分组。您可以在表达式的开头使用^来否定匹配(替换任何不匹配的内容)并使用例如a-f来匹配一

  10. ruby - 可以通过多少种方法将方法添加到 ruby​​ 对象? - 2

    当谈到运行时自省(introspection)和动态代码生成时,我认为ruby​​没有任何竞争对手,可能除了一些lisp方言。前几天,我正在做一些代码练习来探索ruby​​的动态功能,我开始想知道如何向现有对象添加方法。以下是我能想到的3种方法:obj=Object.new#addamethoddirectlydefobj.new_method...end#addamethodindirectlywiththesingletonclassclass这只是冰山一角,因为我还没有探索instance_eval、module_eval和define_method的各种组合。是否有在线/离线资

随机推荐