Android给图片添加水印的实现代码
作者:Katie。
一、项目背景详细介绍
在当前的互联网时代,图片已经成为信息传递和社交传播的重要媒介。随着社交媒体、短视频平台、电商平台、新闻门户等应用的发展,图片的使用越来越广泛。然而,图片在传播过程中极易被他人下载、二次使用甚至篡改。为了防止图片被非法盗用、保护版权、突出品牌标识,在图片中添加水印 成为一种常见且有效的解决方案。
水印的作用主要包括:
- 版权保护
在图片上添加公司名称、作者署名、Logo 等水印,能够有效防止盗用,至少在传播过程中能追溯图片来源。 - 品牌宣传
通过统一的品牌 Logo 作为水印,可以在每一张图片中强化品牌认知,起到宣传作用。 - 内容标识
在电商、新闻平台中,水印可以用来标注“官方”、“样图”、“仅供参考”等信息,避免误导用户。 - 个性化展示
用户也可能在个人图片上添加文字签名或装饰性水印,提升独特性。 
因此,图片加水印在 Android 应用开发中具有极为广泛的应用场景,例如:
- 电商平台:商品图片加品牌 Logo。
 - 社交平台:用户上传图片自动加平台水印。
 - 摄影类应用:相机拍照后自动添加签名。
 - 教育平台:课件图片、答题截图加防盗用水印。
 
二、项目需求详细介绍
本项目的主要需求是 在 Android 应用中实现图片加水印功能,具体需求包括:
支持水印类型
- 文字水印:可以添加任意文字,并支持字体大小、颜色、透明度、位置设置。
 - 图片水印:支持添加 PNG/JPG 图片作为水印,并可调整透明度与位置。
 
水印位置灵活
- 需要支持常见的四个位置:左上角、右上角、左下角、右下角。
 - 允许设置偏移量(x/y 偏移)。
 
支持透明度
- 无论文字水印还是图片水印,都要能控制透明度。
 
操作简便
- 提供简单的 UI,用户可选择原图,点击按钮即可生成带水印的图片。
 
性能要求
- 添加水印操作需在子线程中完成,避免主线程卡顿。
 - 输出图片需保持较高清晰度,避免严重失真。
 
保存与分享
- 加水印后的图片需要保存到本地存储中,方便用户再次使用或分享。
 
三、相关技术详细介绍
要在 Android 中实现图片加水印,常用技术方案有以下几种:
使用 Canvas 绘制
- Android 提供 
Canvas类,可以对Bitmap进行绘制。 - 实现方式:先将原图绘制到 Canvas 上,再在其上绘制文字或水印图片。
 - 优点:简单高效,依赖 Android 原生 API。
 - 缺点:适合静态图片,不支持复杂滤镜。
 
使用 OpenGL 处理
- 通过 OpenGL 渲染图片,然后叠加水印纹理。
 - 优点:适合批量处理和大图,性能高。
 - 缺点:实现复杂,不适合入门。
 
使用第三方库
- 如 
Glide、Picasso主要做图片加载,本身不提供水印功能。 - 可以使用一些专门的图片处理库,但多数仍然基于 Canvas 或 OpenGL。
 
在本项目中,我们选用 Canvas 绘制方案,因为它简单易懂,完全依赖 Android 原生 API,不需要额外引入大型库。
四、实现思路详细介绍
我们采用以下思路来实现:
选择图片
- 使用 Android 系统文件选择器,用户从相册中选择图片。
 
加载图片
- 将选择的图片转换为 Bitmap,用于后续绘制。
 
创建新 Bitmap
- 新建一个与原图相同大小的 Bitmap,并在其上创建 Canvas。
 
绘制原图
- 在 Canvas 上先绘制原始图片。
 
绘制水印
- 如果是文字水印:使用 
Paint.setTextSize、setColor、setAlpha设置样式后绘制文字。 - 如果是图片水印:加载水印图片 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:可以通过循环 drawText 或 drawBitmap 实现平铺效果。
Q:能否支持用户自定义字体?
A:可以使用 Typeface.createFromAsset() 设置自定义字体。
九、扩展方向与性能优化
支持平铺水印
将文字或 Logo 平铺整个图片,增加防盗效果。
支持动态参数配置
允许用户在界面上自定义水印文字、颜色、透明度、位置。
支持批量处理
一次性对多个图片批量加水印,适用于电商平台。
支持 GPU 加速
使用 OpenGL 处理大图,提高性能。
与相机结合
在拍照完成后自动加水印,而不是事后处理。
以上就是Android实现图片添加水印的示例代码的详细内容,更多关于Android图片添加水印的资料请关注脚本之家其它相关文章!
