Android给图片添加水印的实现代码

 更新时间:2025年09月02日 10:49:35   作者:Katie。  
随着社交媒体、短视频平台、电商平台、新闻门户等应用的发展,图片的使用越来越广泛,为了防止图片被非法盗用、保护版权、突出品牌标识,在图片中添加水印 成为一种常见且有效的解决方案,所以本文介绍了Android实现图片添加水印,需要的朋友可以参考下

一、项目背景详细介绍

在当前的互联网时代,图片已经成为信息传递和社交传播的重要媒介。随着社交媒体、短视频平台、电商平台、新闻门户等应用的发展,图片的使用越来越广泛。然而,图片在传播过程中极易被他人下载、二次使用甚至篡改。为了防止图片被非法盗用、保护版权、突出品牌标识,在图片中添加水印 成为一种常见且有效的解决方案。

水印的作用主要包括:

  1. 版权保护
    在图片上添加公司名称、作者署名、Logo 等水印,能够有效防止盗用,至少在传播过程中能追溯图片来源。
  2. 品牌宣传
    通过统一的品牌 Logo 作为水印,可以在每一张图片中强化品牌认知,起到宣传作用。
  3. 内容标识
    在电商、新闻平台中,水印可以用来标注“官方”、“样图”、“仅供参考”等信息,避免误导用户。
  4. 个性化展示
    用户也可能在个人图片上添加文字签名或装饰性水印,提升独特性。

因此,图片加水印在 Android 应用开发中具有极为广泛的应用场景,例如:

  • 电商平台:商品图片加品牌 Logo。
  • 社交平台:用户上传图片自动加平台水印。
  • 摄影类应用:相机拍照后自动添加签名。
  • 教育平台:课件图片、答题截图加防盗用水印。

二、项目需求详细介绍

本项目的主要需求是 在 Android 应用中实现图片加水印功能,具体需求包括:

支持水印类型

  • 文字水印:可以添加任意文字,并支持字体大小、颜色、透明度、位置设置。
  • 图片水印:支持添加 PNG/JPG 图片作为水印,并可调整透明度与位置。

水印位置灵活

  • 需要支持常见的四个位置:左上角、右上角、左下角、右下角。
  • 允许设置偏移量(x/y 偏移)。

支持透明度

  • 无论文字水印还是图片水印,都要能控制透明度。

操作简便

  • 提供简单的 UI,用户可选择原图,点击按钮即可生成带水印的图片。

性能要求

  • 添加水印操作需在子线程中完成,避免主线程卡顿。
  • 输出图片需保持较高清晰度,避免严重失真。

保存与分享

  • 加水印后的图片需要保存到本地存储中,方便用户再次使用或分享。

三、相关技术详细介绍

要在 Android 中实现图片加水印,常用技术方案有以下几种:

使用 Canvas 绘制

  • Android 提供 Canvas 类,可以对 Bitmap 进行绘制。
  • 实现方式:先将原图绘制到 Canvas 上,再在其上绘制文字或水印图片。
  • 优点:简单高效,依赖 Android 原生 API。
  • 缺点:适合静态图片,不支持复杂滤镜。

使用 OpenGL 处理

  • 通过 OpenGL 渲染图片,然后叠加水印纹理。
  • 优点:适合批量处理和大图,性能高。
  • 缺点:实现复杂,不适合入门。

使用第三方库

  • GlidePicasso 主要做图片加载,本身不提供水印功能。
  • 可以使用一些专门的图片处理库,但多数仍然基于 Canvas 或 OpenGL。

在本项目中,我们选用 Canvas 绘制方案,因为它简单易懂,完全依赖 Android 原生 API,不需要额外引入大型库。

四、实现思路详细介绍

我们采用以下思路来实现:

选择图片

  • 使用 Android 系统文件选择器,用户从相册中选择图片。

加载图片

  • 将选择的图片转换为 Bitmap,用于后续绘制。

创建新 Bitmap

  • 新建一个与原图相同大小的 Bitmap,并在其上创建 Canvas。

绘制原图

  • 在 Canvas 上先绘制原始图片。

绘制水印

  • 如果是文字水印:使用 Paint.setTextSizesetColorsetAlpha 设置样式后绘制文字。
  • 如果是图片水印:加载水印图片 Bitmap,使用 canvas.drawBitmap() 绘制在指定位置。

保存新图片

  • 将合成的 Bitmap 保存到本地文件。

展示结果

  • 在 ImageView 中展示带水印的新图片。

五、完整实现代码

// ===================== 文件:MainActivity.java =====================
package com.example.imagewatermark;
 
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
 
import java.io.File;
import java.io.FileOutputStream;
 
/**
 * 主页面:选择图片并添加水印
 */
public class MainActivity extends AppCompatActivity {
 
    private Button btnSelectImage;
    private Button btnAddTextWatermark;
    private Button btnAddImageWatermark;
    private ImageView imageView;
 
    private Bitmap selectedBitmap;
 
    // 文件选择器
    private ActivityResultLauncher<String> imagePickerLauncher =
            registerForActivityResult(new ActivityResultContracts.GetContent(), uri -> {
                if (uri != null) {
                    try {
                        selectedBitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
                        imageView.setImageBitmap(selectedBitmap);
                        Toast.makeText(this, "选择图片成功", Toast.LENGTH_SHORT).show();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });
 
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        btnSelectImage = findViewById(R.id.btn_select_image);
        btnAddTextWatermark = findViewById(R.id.btn_add_text_watermark);
        btnAddImageWatermark = findViewById(R.id.btn_add_image_watermark);
        imageView = findViewById(R.id.image_view);
 
        // 选择图片
        btnSelectImage.setOnClickListener(v -> {
            imagePickerLauncher.launch("image/*");
        });
 
        // 添加文字水印
        btnAddTextWatermark.setOnClickListener(v -> {
            if (selectedBitmap == null) {
                Toast.makeText(this, "请先选择图片", Toast.LENGTH_SHORT).show();
                return;
            }
            Bitmap watermarked = WatermarkUtils.addTextWatermark(selectedBitmap, "MyWatermark", 50, 50);
            imageView.setImageBitmap(watermarked);
            saveBitmap(watermarked, "text_watermark.png");
        });
 
        // 添加图片水印
        btnAddImageWatermark.setOnClickListener(v -> {
            if (selectedBitmap == null) {
                Toast.makeText(this, "请先选择图片", Toast.LENGTH_SHORT).show();
                return;
            }
            Bitmap watermarkLogo = WatermarkUtils.decodeResource(this, R.drawable.logo);
            Bitmap watermarked = WatermarkUtils.addImageWatermark(selectedBitmap, watermarkLogo, 50, 50);
            imageView.setImageBitmap(watermarked);
            saveBitmap(watermarked, "image_watermark.png");
        });
    }
 
    /**
     * 保存 Bitmap 到本地文件
     */
    private void saveBitmap(Bitmap bitmap, String fileName) {
        try {
            File output = new File(getExternalFilesDir(null), fileName);
            FileOutputStream out = new FileOutputStream(output);
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
            out.flush();
            out.close();
            Toast.makeText(this, "保存成功:" + output.getAbsolutePath(), Toast.LENGTH_LONG).show();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
 
 
// ===================== 文件:WatermarkUtils.java =====================
package com.example.imagewatermark;
 
import android.content.Context;
import android.graphics.*;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
 
public class WatermarkUtils {
 
    /**
     * 添加文字水印
     * @param src 原始图片
     * @param text 水印文字
     * @param x X坐标
     * @param y Y坐标
     * @return 新的带水印图片
     */
    public static Bitmap addTextWatermark(Bitmap src, String text, int x, int y) {
        Bitmap result = src.copy(Bitmap.Config.ARGB_8888, true);
        Canvas canvas = new Canvas(result);
        Paint paint = new Paint();
        paint.setColor(Color.RED); // 水印颜色
        paint.setTextSize(60); // 字体大小
        paint.setAlpha(180); // 透明度
        paint.setAntiAlias(true); // 抗锯齿
        canvas.drawText(text, x, y, paint);
        return result;
    }
 
    /**
     * 添加图片水印
     * @param src 原始图片
     * @param watermark 水印图片
     * @param x X坐标
     * @param y Y坐标
     * @return 新的带水印图片
     */
    public static Bitmap addImageWatermark(Bitmap src, Bitmap watermark, int x, int y) {
        Bitmap result = src.copy(Bitmap.Config.ARGB_8888, true);
        Canvas canvas = new Canvas(result);
        Paint paint = new Paint();
        paint.setAlpha(180); // 透明度
        canvas.drawBitmap(watermark, x, y, paint);
        return result;
    }
 
    /**
     * 将资源文件转换为 Bitmap
     */
    public static Bitmap decodeResource(Context context, int resId) {
        Drawable drawable = context.getResources().getDrawable(resId);
        if (drawable instanceof BitmapDrawable) {
            return ((BitmapDrawable) drawable).getBitmap();
        }
        return null;
    }
}
 
 
// ===================== 文件:res/layout/activity_main.xml =====================
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="20dp">
 
    <Button
        android:id="@+id/btn_select_image"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="选择图片" />
 
    <Button
        android:id="@+id/btn_add_text_watermark"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="添加文字水印"
        android:layout_marginTop="20dp"/>
 
    <Button
        android:id="@+id/btn_add_image_watermark"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="添加图片水印"
        android:layout_marginTop="20dp"/>
 
    <ImageView
        android:id="@+id/image_view"
        android:layout_width="match_parent"
        android:layout_height="400dp"
        android:layout_marginTop="20dp"
        android:scaleType="fitCenter"/>
</LinearLayout>

六、代码详细解读

MainActivity

  • 负责 UI 逻辑,包括选择图片、调用水印工具类生成新图片,并保存到本地。

WatermarkUtils

  • addTextWatermark():在原图上绘制文字水印,支持位置、字体大小、透明度。
  • addImageWatermark():在原图上绘制一张 PNG 图片作为水印。
  • decodeResource():将资源文件的图片转换为 Bitmap,用作水印素材。

activity_main.xml

  • 包含三个按钮和一个 ImageView,分别用于选择图片、添加文字水印、添加图片水印,并显示结果。

七、项目详细总结

通过本项目,我们实现了一个完整的 Android 图片加水印功能,主要特点:

  • 使用原生 API(Canvas + Paint),实现简单、依赖少。
  • 支持 文字水印图片水印
  • 支持设置透明度、位置,满足大多数场景需求。
  • 图片最终保存到本地,方便后续分享或使用。

八、项目常见问题及解答

Q:如何设置水印在右下角?

A:只需根据原图宽高计算水印绘制的起点坐标即可,比如 x = src.getWidth() - watermark.getWidth() - 20

Q:如何设置文字旋转角度?

A:在 canvas.drawText() 前调用 canvas.rotate(angle, x, y) 即可。

Q:如何提高绘制效率?

A:避免每次都解码大图,尽量压缩后再绘制。

Q:能否实现平铺式水印?

A:可以通过循环 drawTextdrawBitmap 实现平铺效果。

Q:能否支持用户自定义字体?

A:可以使用 Typeface.createFromAsset() 设置自定义字体。

九、扩展方向与性能优化

支持平铺水印

将文字或 Logo 平铺整个图片,增加防盗效果。

支持动态参数配置

允许用户在界面上自定义水印文字、颜色、透明度、位置。

支持批量处理

一次性对多个图片批量加水印,适用于电商平台。

支持 GPU 加速

使用 OpenGL 处理大图,提高性能。

与相机结合

在拍照完成后自动加水印,而不是事后处理。

以上就是Android实现图片添加水印的示例代码的详细内容,更多关于Android图片添加水印的资料请关注脚本之家其它相关文章!

相关文章

  • Android实现基于ZXing快速集成二维码扫描功能

    Android实现基于ZXing快速集成二维码扫描功能

    这篇文章主要为大家详细介绍了Android二维码扫描ZXing快速项目集成的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-07-07
  • Android给scrollView截图超过屏幕大小形成长图

    Android给scrollView截图超过屏幕大小形成长图

    这篇文章主要为大家详细介绍了Android给scrollView截图超过屏幕大小形成长图,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-12-12
  • Android轻松画出触摸轨迹

    Android轻松画出触摸轨迹

    这篇文章主要为大家详细介绍了Android轻松画出触摸轨迹的实现方法,为大家分享了一个触摸轨迹类,感兴趣的小伙伴们可以参考一下
    2016-03-03
  • Android客户端程序Gradle如何打包

    Android客户端程序Gradle如何打包

    这篇文章主要介绍了Android客户端程序Gradle如何打包 的相关资料,需要的朋友可以参考下
    2016-01-01
  • Android  ActionBar控件操作使用详解

    Android  ActionBar控件操作使用详解

    这篇文章主要介绍了Android  ActionBar控件操作使用,ActionBar是Android常用的导航控件,位于activity的顶部,用于显示标题,导航icon和actions等等
    2023-04-04
  • Android仿微信输入框效果的实现代码

    Android仿微信输入框效果的实现代码

    这篇文章主要介绍了Android仿微信输入框效果的实现代码,需要的朋友参考下吧
    2017-05-05
  • 如何在Android App中集成支付宝和微信支付功能

    如何在Android App中集成支付宝和微信支付功能

    支付是各位Android开发者们在日常工作中经常会遇到的一个需求,下面这篇文章主要给大家介绍了关于如何在Android App中集成支付宝和微信支付功能的相关资料,文中通过示例代码介绍的非常详细,需要的朋友下面随着小编来一起学习学习吧
    2018-05-05
  • android textview 显示html方法解析

    android textview 显示html方法解析

    现在网络的繁盛时代,光文字是不能满足人们的胃口的,图片,flash,音频,视频就成为浏览网页的主流显示,在手机上也一样,本文将详细介绍此功能的实现方法
    2012-11-11
  • Android系统添加自己写的工具

    Android系统添加自己写的工具

    今天小编就为大家分享一篇关于Android系统添加自己写的工具的文章,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-10-10
  • kotlin使用建造者模式自定义对话框

    kotlin使用建造者模式自定义对话框

    这篇文章主要为大家详细介绍了kotlin使用建造者模式自定义对话框的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-07-07

最新评论