隐形数字水印_Android 实现图片水印与隐形数字水印
当我们在知乎或微博上传图片时,常见现象是在这些平台上传图片时会自动添加文字水印。许多应用开发中需要开发者自行实现Canvas绘制图形水印的方法。今天我想在这里介绍一个名为AndroidWM的轻量级开源Android图片水印框架,并深入分析其实现原理及其独特应用场景。
水印
这个框架最大限度地简化了图片水印绘制的问题,并且提供了灵活的接口供用户使用。在绘制水印时,只需生成一个水印对象以及一个watermark初始化器对象,并将自定义的watermark对象传递给watermark初始化器即可完成。
实现水印第一步:引用类库 androidWM
当采用 Android Studio 进行软件开发时
dependencies {
...
implementation 'com.huangyz0918:androidwm:0.2.3'
...
}
然后点击同步 gradle,让其自动下载并且安装好依赖即可。
实现水印第二步:创建一个水印,完工!
androidWM 给我们提供了四种不同的水印:
图形水印
文字水印
隐形图形水印
隐形文字水印
为了达到个性化的水印效果需求,我们可以根据具体需求创建不同类型的水印对象,并根据实际应用场景选择合适的WatermarkText类实例。例如,在我的项目中我希望实现字符类型的水印效果时,则可以通过实例化一个WatermarkText对象来生成字符类型的水印,并配置相应的属性参数以满足特定的需求。
WatermarkText watermarkText = new WatermarkText(“Hello World”)
.setPositionX(0.5) // 横坐标
.setPositionY(0.5) // 纵坐标
.setTextAlpha(100) // 透明度
.setTextColor(Color.WHITE) // 文字水印文字颜色
.setTextFont(R.font.champagne) // 字体
.setTextShadow(0.1f, 5, 5, Color.BLUE); // 字体的阴影
我成功地获取了一个名为watermarkText的文字水印。然后,我还需要一位画师来将这个水印绘制在我希望的背景底图上。从而,我们需要创建并实例化一个WatermarkBuilder。
WatermarkBuilder.create(this, backgroundBitmap) // 加载背景底图
.loadWatermarkText(watermarkText) // 加载水印对象
.getWatermark() // 绘制带有水印的图片
.setToImageView(backgroundView); // 设置结果到 ImageView 里
整个过程一气呵成。首先输入一个上下文 context,并随后输入一张背景底图。这张背景图片可以从 ImageView 中获取(例如通过 R.drawable.image),也可以从系统资源中导入(例如直接上传一个 Bitmap)。在调用完 getWatermark() 方法之后(即生成水印后),androidWM 提供了一个简便的方法:可以直接将带有水印的图片设置为 ImageView 的显示内容;如果需要自定义,则可以通过调用 getOutputImage() 方法来获取输出的Bitmap
水印创建好啦!
同理,你也可以通过实例化一个 WatermarkImage 来创建一个图像水印:
WatermarkImage watermarkImage = new WatermarkImage(watermarkBitmap)
.setImageAlpha(80)
.setPositionX(0.5)
.setPositionY(0.5)
.setRotation(15)
.setSize(0.3);
WatermarkBuilder
.create(this, backgroundBitmap)
.loadWatermarkImage(watermarkImage)
.getWatermark()
.setToImageView(backgroundView);
Boom ! 画出来的水印长这样:
图片水印!小眼睛!
创建隐形水印
隐写技术是Android WM框架的一个显著特点,它能够提供两种不同的隐写方式
LSB 空域隐形水印
频域水印
如果想要创建隐形水印,则无需关注水印的具体位置、尺寸以及颜色参数;因为这些细节会被巧妙地嵌入到肉眼不可察觉的空间中,在这种情况下仅当采用框架中的特定方法时才能实现对水印的有效提取
生成一个隐藏的文字信息也是很简单的,并且我们可以使用 WatermarkBuilder 来创建一个隐形的文字信息或者是图形水印。
WatermarkBuilder
.create(this, backgroundBitmap)
.loadWatermarkImage(watermarkBitmap)
.setInvisibleWMListener(true, new BuildFinishListener() {
@Override
public void onSuccess(Bitmap object) {
if (object != null) {
// do something...
}
}
@Override
public void onFailure(String message) {
// do something...
}
});
在该方法 .setInvisibleWMListener() 中的第一个自定义参数被用来指定水印显示模式:
true 使用空域 LSB 方法绘制隐形水印
false 使用频域隐形水印
同样地,在隐形水印检测方面, 我们可以创建一个名为WatermarkDetector的水印检测器:
WatermarkDetector
.create(inputBitmap, true)
.detect(false, new DetectFinishListener() {
@Override
public void onSuccess(DetectionReturnValue returnValue) {
Bitmap watermarkImage = returnValue.getWatermarkBitmap();
String watermarkString = returnValue.getWatermarkString();
}
@Override
public void onFailure(String message) {
// do something...
}
});
当构建函数时
添加图片作为隐形水印
LSB 实现隐形水印的原理
我们已经介绍了框架的基本应用。接下来探讨 androidWM 中实现图片隐形水印的技术基础。首先介绍的是LSB空域水印技术。其中缩略语LSB代表 Least Significant Bits(最显著比特),即通过存储于图像中最不敏感的信息位来实现隐秘的信息编码。该方法因其相对简单而广受欢迎。值得注意的是,在数字图像中存在抗噪声能力这一特性,在此特性基础上分析了其工作原理:其特点在于最低有效位的变化对人眼感知的影响微乎其微。这些隐秘的信息通常被编码在每个像素值的最低几位中(通常是最低1位或2位)。
添加文字作为图片水印
为了嵌入隐秘水印信息,AndroidWM提取了图像中每个像素的全部信息。每个像素可分解为四个ARGB分量(包括Alpha、红色、绿色和蓝色),作为标准的ARGB编码方式。每一位均以0至255之间的整数值表示。由于人眼对最低位色阶的变化几乎察觉不到,在此方案中将这些值进行处理:将每个ARGB分量的最低位置零,并将其转换为二进制数据序列以存储隐藏的信息。
LSB 编码方式
在实际工程中, 我们将水印信息转换为二进制数据后, 并附加了非二进制的前后缀以实现程序检测的目的. 从而确保整个图像区域都能够被水印覆盖. 算法会周期性地将水印信息铺陈于背景图像上. 只要背景图像中包含至少一个有效的水印标记, 则能够成功进行检测.
对于 LSB 空域数字水印来说,其有如下优点:
支持的水印信息量大
对原图影响小
算法简单
但是其也有不可忽视地巨大缺点:
在空间域上绘制数字水印,水印会随着图片变化而破坏
稳定性差,不能抵抗图像的裁剪、缩放和 jpg 压缩
