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