之前在 抖音 见过这样的视频,给某个好友发一张图片,好友看到的是第一张图片,当点开后,会出现另一张图片。。。
就像这样:
默认图片是这张:
隐藏图片是这张
发给好友是这样
好友点开后是这样
先贴上github源码
原理
png 图片是有透明度的,根据图片背景的不同,可以通过控制透过的光来显示不同的图片。
举个栗子:小时候大家可能见过那种相机胶卷,拿着这种胶卷对着阳光,可以透过阳光看到胶卷中的景象。但是不对着阳光,这张胶卷就是黑色的
再举个栗子:就像医院里面,拍的片子。医生会把片子放在白色的显示屏上,看你的x光片。
这些图像都是在光透过薄片后才显示图像的
所以当白光穿过半透明的 png 图片时,会显示灰白色,当背景是黑色时,png图片会显示灰黑色。
而图片其实是一个个的像素点组成的。每一个像素点又包含rgb三种通道。对应三原色。
把像素点想象成一个个的方块,假设现在有两个方块,一个是完全不透明的黑色方块,一个是透明的方块,当摆放方块的下方是白色的时候,人的视觉看上去就是一黑一白,当下面是黑色的时候,看上去就是两个黑色方块。
开始敲代码
省略创建项目和选择图片。等等的介绍。直接写如何实现。
遍历每一个像素点
把选中的图片转换成bitmap
val disImg: Bitmap = ImageUtil.getBitmap(displayImgPath, 640, 480)
val hideImg: Bitmap = ImageUtil.getBitmap(hideImgPath, 640, 480)
saveBitmap = ImgMixUtil.INSTANCE.CalculateHiddenImage(this@MainActivity, disImg, hideImg)
创建一张新图片
val result = Bitmap.createBitmap(f_width, f_height, Bitmap.Config.ARGB_8888);
然后遍历每一个像素点。
for (x in 0 until f_width) {
for (y in 0 until f_height) {
...
// 1.上下左右交叉排列黑白像素
val blackPixel = (x + y) % 2 == 0
...
// 2. 将彩色图片转成黑白色图片
val gray =
(Color.red(origin) * 0.3 + Color.green(origin) * 0.59 + Color.blue(origin) * 0.11).toInt()
...
if (blackPixel) {
// 3. 颜色反转
val tmpGray = 255 - gray
finalColor =
Color.argb(
tmpGray,
Color.red(Color.WHITE),
Color.green(Color.WHITE),
Color.blue(Color.WHITE)
)
}
}
}
注意点:
- 在遍历的时候,需要将两张图片合成,所以每隔一个像素点就要切换到另一张图片,也就是交叉排列
- 遍历的时候,由于打开图片的时候,qq只会有黑白两色,所以,要把图片的每一个像素转换成黑白图。
- 在白色背景下,需要对像素点进行颜色的反转
在将图片转换成黑白图后,把颜色的色值当做透明度,然后rgb使用纯色填充,如果要在黑色背景下显示,则使用纯白填充,白色背景显示,则使用纯黑填充。
然后将色值填充到新创建的 bitmap
中
result.setPixel(x, y, finalColor);
保存到本地
private fun saveToFile(bitmap: Bitmap) {
try {
val outputStream: FileOutputStream =
FileOutputStream(Environment.getExternalStorageDirectory().absolutePath + File.separator + "save.png")
bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream)
outputStream.flush()
outputStream.close()
} catch (e: Exception) {
Log.e("save to file error:%s", Log.get(e))
}
}
注意要保存成 png
格式,因为只有png格式才能实现透明度。
如果是其它背景颜色会怎么显示?
前面说了,原理是通过控制 alpha 通道的光来显示不同的图片,那么,如果通过的不是白色,或者黑色呢?下面灰色背景下,生成的图片的显示效果
灰色介于白色和黑色之间,所以两张图片都模糊显示了。。。
想看详细实现代码->github源码
使其支持彩色图片
其实图片是可以支持彩色的,但是由于背景只有黑白,所以,如果支持彩色, 显示效果非常不好。所以没有实现。只要修改代码中
ImgMixUtil
就可以了
原来代码:
if (blackPixel) {
val tmpGray = 255 - gray
finalColor =
Color.argb(
tmpGray,
Color.red(Color.BLACK),
Color.green(Color.BLACK),
Color.blue(Color.BLACK)
)
} else {
val tmpGray = gray
finalColor =
Color.argb(
tmpGray,
Color.red(Color.WHITE),
Color.green(Color.WHITE),
Color.blue(Color.WHITE)
)
}
修改后:
if (blackPixel) {
val tmpGray = 255 - gray
finalColor =
Color.argb(
tmpGray,
Color.red(origin),
Color.green(origin),
Color.blue(origin)
)
} else {
val tmpGray = gray
finalColor =
Color.argb(
tmpGray,
Color.red(origin),
Color.green(origin),
Color.blue(origin)
)
}
生成出来的图片效果: