吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 4026|回复: 5
收起左侧

[其他原创] [C#]一个简单的QQ隐藏图生成算法 附成品

[复制链接]
huzpsb 发表于 2019-4-13 20:39
隐藏图不是什么新鲜的东西,
具体表现在大部分社交软件中,
预览图看到的是一张图,
而点开后看到的又是另一张(huang)图。
虽然很早就看到过这类图片,
但是一直没有仔细研究过它的原理,
今天思考了一下,
发现挺有趣的,
所以自己也写了个简单的算法把两张图片合成为一张隐藏图。
比如下面这张图。
redbag.png
隐藏图原理
  我们知道一张图片中具有透明度的像素会叠加一部分的背景色,    因此当背景色为白色时,所有具有透明度的白色像素全部显示为纯白色,    而当背景色为黑色时,    所有具有透明度的黑色会显示为纯黑色。    因此我们只需要把图片一的所有像素根据其灰度值转换成不同透明度的黑色,    将图片二的所有像素根据其灰度值转换成不同透明度的白色,    并将两图的所有像素按照任意规律交叉排列,    即可生成隐藏图。    这样当背景色为黑色时,    图一的所有像素将会显示为纯黑色,    图二的所有像素会因为其透明度不同显现出不同的灰色,    此时图一隐藏,    图二显现,    反之同理。

算法实现
  基本的算法思路上面已经提过了,    可以说是一个相当简单的算法了。    不过具体有几点需要注意:
1   由其原理可知,   隐藏图只能是黑白的,   不能是彩色的,   因此当遇到彩色像素时,   需要将其转换成灰度。   对于彩色转灰度,   心理学中有一个公式:   Gray = R*0.299 + G*0.587 + B*0.114,   我们需要做的是根据算出来的灰度设定像素透明度。   在白色背景下,黑色像素的灰度会随着像透明度增高而降低,   在黑色背景下,白色像素的灰度会随着透明度增高而增高。2   考虑到需要合成的两张图片尺寸不一致,   为了保证生成的隐藏图能够完成保留两张图片信息并且不发生变形,   我们需要将最终图片的长和宽设定为两张图片尺寸中最大的长和最大的宽。好的,接下来把我的代码实现贴出来吧
[C#] 纯文本查看 复制代码
using System;
using System.IO;
using System.Drawing;    

class MainClass
    {
        public static void Main(string[] args)
        {
            //图片一的文件路径
            Stream blackImageReader = new FileStream("/Users/shiyidu/Desktop//1.jpg", FileMode.Open);
            Bitmap blackImage = new Bitmap(blackImageReader);

            //图片二的文件路径
            Stream whiteImageReader = new FileStream("/Users/shiyidu/Desktop//2.jpg", FileMode.Open);
            Bitmap whiteImage = new Bitmap(whiteImageReader);

            //生成最终图片
            Bitmap finalImage = CalculateHiddenImage(blackImage, whiteImage);

            //最终图片保存路径
            Stream imageCreater = new FileStream("/Users/shiyidu/Desktop//final.png", FileMode.Create);
            finalImage.Save(imageCreater, System.Drawing.Imaging.ImageFormat.Png);
        }

        private static Bitmap CalculateHiddenImage(Bitmap blackImage, Bitmap whiteImage)
        {
            int b_width = blackImage.Width;
            int b_height = blackImage.Height;
            int w_width = whiteImage.Width;
            int w_height = whiteImage.Height;

            //设定最终图片的尺寸
            int f_width = Math.Max(b_width, w_width);
            int f_height = Math.Max(b_height, w_height);

            Bitmap result = new Bitmap(f_width, f_height);

            //黑色图片距离边缘的距离
            int b_widthOffset = b_width == f_width ? 0 : (f_width - b_width) / 2;
            int b_heightOffset = b_height == f_height ? 0 : (f_height - b_height) / 2;

            //白色图片离边缘距离
            int w_widthOffset = w_width == f_width ? 0 : (f_width - w_width) / 2;
            int w_heightOffset = w_height == f_height ? 0 : (f_height - w_height) / 2;

            for (int x = 0; x < f_width; x++) {
                for (int y = 0; y < f_height; y++) {
                    //上下左右交叉排列黑白像素
                    bool blackPixel = (x + y) % 2 == 0 ? true : false;

                    int coor_x;
                    int coor_y;
                    //决定当前像素位置是否对应图一或图二某像素,如果没有,跳过循环
                    bool validPixel = true;
                    if (blackPixel) {
                        coor_x = x - b_widthOffset;
                        if (coor_x > b_width - 1) validPixel = false;
                        coor_y = y - b_heightOffset;
                        if (coor_y > b_height - 1) validPixel = false;
                    } else {
                        coor_x = x - w_widthOffset;
                        if (coor_x > w_width - 1) validPixel = false;
                        coor_y = y - w_heightOffset;
                        if (coor_y > w_height - 1) validPixel = false;
                    }

                    validPixel = validPixel && coor_x >= 0 && coor_y >= 0;
                    if (!validPixel) continue;

                    //根据颜色计算像素灰度,设定透明度
                    if (blackPixel) {
                        Color origin = blackImage.GetPixel(coor_x, coor_y);
                        int gray = (origin.R * 19595 + origin.G * 38469 + origin.B * 7472) >> 16;
                        Color finalColor = Color.FromArgb(255 - gray, Color.Black);
                        result.SetPixel(x, y, finalColor);
                    } else {
                        Color origin = whiteImage.GetPixel(coor_x, coor_y);
                        int gray = (origin.R * 19595 + origin.G * 38469 + origin.B * 7472) >> 16;
                        Color finalColor = Color.FromArgb(gray, Color.White);
                        result.SetPixel(x, y, finalColor);
                    }
                }
            }

            return result;
        }
    }

最后给出成品(不是源代码) QQ隐藏图制作.zip (446.48 KB, 下载次数: 209)

免费评分

参与人数 2吾爱币 +6 热心值 +2 收起 理由
s_qiu + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
苏紫方璇 + 5 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

头像被屏蔽
ilhuyi 发表于 2019-4-13 21:16
提示: 作者被禁止或删除 内容自动屏蔽
newpowersky 发表于 2019-4-14 17:40
隰则有泮 发表于 2019-4-18 18:14
本帖最后由 隰则有泮 于 2019-4-18 18:15 编辑

这是楼主??

rickw 发表于 2019-4-19 12:31
这个很有去,这个方案很新奇。
记得很久以前是图片在windows预览是现实一个缩略图,打开时显示别的大图。
那个的原理是因为图片里面有保存不同的缩略图。
 楼主| huzpsb 发表于 2019-4-19 12:33

打扰一下
https://www.cnblogs.com/cjm123/p/9096308.html
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-16 07:53

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表