首页 > 其他分享 >png图片隐写实例之隐藏二维码

png图片隐写实例之隐藏二维码

时间:2024-11-14 17:56:35浏览次数:1  
标签:int 隐写 Length 二维码 file var byte buf png

图片隐写技术介绍: 【如何在图片中塞入二维码不被发现】 https://www.bilibili.com/video/BV12R4y1G72d/?share_source=copy_web&vd_source=d944df449598b7e51bbc29cddb033275 png图片格式介绍: https://www.cnblogs.com/senior-engineer/p/9548347.html https://zhuanlan.zhihu.com/p/23890809 图片隐写,借助的是图片的每个像素点的RGB值,比如取RGB中的B值,这个值的二级制的最低位是0还是1,在肉眼上看看不出丝毫区别,我们就可以利用这个数据位,我们知道二维码一般都是两种颜色,黑色和白色,黑色的像素点用1表示,白色用0表示,我们就把二维码的每个像素点转换成1和0,在把这些1和0存到承载二维码的本体图片的像素的一个颜色值通道的二进制值的最低位上。这就是大概原理。 如果要从载体图片读取二维码,需要知道二维码的长和宽,以便读取正确的二维码的1和0值,然后在把1和0反转成黑色或白色,就能解析出构成二维码了。所以我们需要把二维码的长和宽写入到载体图片中。 这就需要png格式的图片一定是要符合png的标准,否则在这一步会让图片损坏。要辨别png格式,不能只看文件的扩展名为png,需要看文件的署名是否是png规定的署名。符合png标准的png的文件用二进制编辑器打开,最开始的8个字节一定是:0x89 0x50 0x4e 0x47 0x0d 0x0a 0x1a 0x0a。只有先确认了这样的字节,才能进行接下来的步骤。 我们需要把二维码图片的长和宽的值写入png文件中,借助png的辅助数据块的格式tEXt,可以实现该目的。我们还需要知道一个IEND数据块,它一定是位于png二级制文件的最后,数据格式是固定的{x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82}。知道这些,我们就可以把tExt块写入iEND块之前。为了后续读取这个tExt块,需要把tExt的块的数据区域的最后一个位置写成整个tExt块数组的长度。具体看代码。 这就是我对实现png格式图片隐写二维码的总结。 扩展:处理隐藏二维码,其实还可以把一些数据编码成二级制也是可以隐藏这些信息的。RGB三个通道都可以同时做这样的写值处理。如果二维码不只是两种颜色,而且想要还原的时候保持与原二维码图一致的话,我的思路是,隐写二维码的像素点的颜色值前23位,载体的每个像素的RGB值的最低位按顺序写入二维码的23个二进制,这要求载体图片的长和宽大概是二维码图片的长和宽的8倍甚至更多,思路是一样的,只不过解析的时候,需要做像素之间的对应关系。 全部代码:代码中的路径使用了硬编码,如果需要运行代码,要自己准备图片和改路径名称

    public class PicHide
    {
        private Bitmap _map = null;
        private Bitmap _qrMap = null;
        private int _w = 0;
        private int _h = 0;
        private string _path = string.Empty;
        private string _qrPath = string.Empty;
        private int _qw = 0, _qh = 0;
        public PicHide(string picName, string qrPath)
        {
            _path = picName;
            _qrPath = qrPath;
            _map = new Bitmap(picName);
            _w = _map.Width;
            _h = _map.Height;

            _qrMap = new Bitmap(qrPath);
            _qw = _qrMap.Width;
            _qh = _qrMap.Height;
            if (_qw > _w || _qh > _h)
            {
                throw new Exception("隐写的二维码长宽必须小于图片本身的长宽");
            }
        }


        public Color GetRGB(int x, int y)
        {
            var c = _map.GetPixel(x, y);
            return c;
        }
        public void HidePic()
        {
            for (int i = 0; i < _w; i++)
            {
                for (int j = 0; j < _h; j++)
                {
                    if (i < _qw && j < _qh)
                    {
                        var rgb = _qrMap.GetPixel(i, j);

                        int cBit = 0;
                        if (rgb.R >= 128 && rgb.B >= 128 && rgb.G >= 128)
                        {
                            cBit = 1;
                        }
                        var curColor = _map.GetPixel(i, j);
                        var hideColor = convertRGB(curColor, cBit);
                        setColor(i, j, hideColor);
                    }
                    else
                    {
                        var c = GetRGB(i, j);
                        var nc = convertRGB(c);
                        setColor(i, j, nc);
                    }
                }
            }

            _map.Save("new1.png");
            _map.Dispose();
            _qrMap.Dispose();
            _qrMap = null;
            _map = null;
            AddQrCodeWH("new1.png", _qw, _qh);

        }
        public int b(int x, int y)
        {
            return GetRGB(x, y).B;
        }
        public static string GetHideQrCode(string path)
        {
            var str = GetWh(path);
            var arr = str.Split(",");

            int w = int.Parse(arr[0].Replace("w=", ""));
            int h = int.Parse(arr[1].Replace("h=", ""));

            var map = new Bitmap(path);
            var qrMap = new Bitmap(w, h);

            for (int i = 0; i < w; i++)
            {
                for (int j = 0; j < h; j++)
                {
                    var color = map.GetPixel(i, j);
                    int val = GetqrColorbit(color);
                    if (val == 0)
                    {
                        qrMap.SetPixel(i, j, Color.Black);
                    }
                    else
                    {
                        qrMap.SetPixel(i, j, Color.White);
                    }
                }
            }
            map.Dispose();
            qrMap.Save("newCode.png");
            qrMap.Dispose();
            map = null;
            qrMap = null;
            return "";

        }
        public static string GetWh(string path)
        {
            var file = File.OpenRead(path);
            var iEnd = new byte[12] { 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82 };

            file.Seek(file.Length - iEnd.Length - 5, SeekOrigin.Begin);
            var allLenArr = new byte[1];
            file.Read(allLenArr, 0, 1);
            var allLen = allLenArr[0];
            file.Seek(file.Length - iEnd.Length - allLen, SeekOrigin.Begin);
            var lenArr = new byte[4];

            file.Read(lenArr, 0, 4);
            file.Seek(4, SeekOrigin.Current);
            var len = (lenArr[0] << 24) | (lenArr[1] << 16) | (lenArr[2] << 8) | (lenArr[3]);
            var payload = new byte[len - 1];
            file.Read(payload, 0, len - 1);
            var str = System.Text.Encoding.UTF8.GetString(payload);
            file.Close();
            file.Dispose();
            return str;
        }

        public int bRemoveLast(int b)
        {
            var val = 0xFE;
            return b & val;
        }
        public Color convertRGB(Color c)
        {
            Color removeColor = Color.FromArgb(c.A, c.R, c.G, bRemoveLast(c.B));
            return removeColor;
        }
        public Color convertRGB(Color c, int i)
        {
            Color hideColor = Color.FromArgb(c.A, c.R, c.G, (bRemoveLast(c.B) | i));
            return hideColor;
        }
        public void setColor(int x, int y, Color c)
        {
            _map.SetPixel(x, y, c);
        }

        public static int GetqrColorbit(Color c)
        {
            var x = 0x01;
            return c.B & x;
        }
        private uint getCrc32(byte[] inStr)
        {
            uint[] crc32Table = new uint[256];
            uint i, j;
            uint crc;

            // 生成 CRC32 表
            for (i = 0; i < 256; i++)
            {
                crc = i;
                for (j = 0; j < 8; j++)
                {
                    if ((crc & 1) != 0)
                    {
                        crc = (crc >> 1) ^ 0xEDB88320;
                    }
                    else
                    {
                        crc >>= 1;
                    }
                }
                crc32Table[i] = crc;
            }

            crc = 0xffffffff;
            for (i = 0; i < inStr.Length; i++)
            {
                crc = (crc >> 8) ^ crc32Table[(crc & 0xFF) ^ inStr[i]];
            }

            crc ^= 0xFFFFFFFF;
            return crc;
        }

        public void AddQrCodeWH(string fileName, int w, int h)
        {
            var file = File.Open(fileName, FileMode.Open, FileAccess.ReadWrite);
            string payLoad = $"w={w},h={h}";
            var payArr = System.Text.Encoding.UTF8.GetBytes(payLoad);
            var len = payArr.Length + 1;
            var buf = new byte[12 + payArr.Length + 1];
            buf[0] = (byte)(len >> 24 & 0xff);
            buf[1] = (byte)(len >> 16 & 0xff);
            buf[2] = (byte)(len >> 8 & 0xff);
            buf[3] = (byte)(len & 0xff);
            buf[4] = Convert.ToByte('t');
            buf[5] = Convert.ToByte('E');
            buf[6] = Convert.ToByte('X');
            buf[7] = Convert.ToByte('t');

            for (int j = 0; j < payArr.Length; j++)
                buf[j + 8] = payArr[j];
            buf[payArr.Length + 8] = (byte)buf.Length;
            var crc = this.getCrc32(payArr);
            buf[len + 8] = (byte)(crc >> 24 & 0xff);
            buf[len + 9] = (byte)(crc >> 16 & 0xff);
            buf[len + 10] = (byte)(crc >> 8 & 0xff);
            buf[len + 11] = (byte)(crc & 0xff);

            var iEnd = new byte[12] { 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82 };
            var lenArr = new byte[4];

            file.Seek(file.Length - iEnd.Length, SeekOrigin.Begin);

            file.Write(buf, 0, buf.Length);
            file.Write(iEnd, 0, iEnd.Length);
            file.Close();
            file.Dispose();
            file = null;
        }

        //public string testwhInfo()
        //{
        //    var file = File.OpenRead(_path);
        //    var iEnd = new byte[12] { 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82 };

        //    file.Seek(file.Length - iEnd.Length-5, SeekOrigin.Begin);
        //    var allLenArr = new byte[1];
        //    file.Read(allLenArr, 0, 1);
        //    var allLen = allLenArr[0];
        //    file.Seek(file.Length - iEnd.Length - allLen, SeekOrigin.Begin);
        //    var lenArr = new byte[4];

        //    file.Read(lenArr, 0, 4);
        //    file.Seek(4, SeekOrigin.Current);
        //    var len = (lenArr[0] << 24) | (lenArr[1] << 16) | (lenArr[2] << 8) | (lenArr[3]);
        //    var payload=new byte[len-1];
        //    file.Read(payload, 0, len-1);
        //    var str=System.Text.Encoding.UTF8.GetString(payload);
        //    return str;
        //}
        //public void AddQrCodeWH(int w, int h)
        //{
        //    var file = File.Open(_path, FileMode.Open, FileAccess.ReadWrite);
        //    string payLoad = $"w={w},h={h}";
        //    var payArr = System.Text.Encoding.UTF8.GetBytes(payLoad);
        //    var len = payArr.Length + 1;
        //    var buf = new byte[12 + payArr.Length + 1];
        //    buf[0] = (byte)(len >> 24 & 0xff);
        //    buf[1] = (byte)(len >> 16 & 0xff);
        //    buf[2] = (byte)(len >> 8 & 0xff);
        //    buf[3] = (byte)(len & 0xff);
        //    buf[4] = Convert.ToByte('t');
        //    buf[5] = Convert.ToByte('E');
        //    buf[6] = Convert.ToByte('X');
        //    buf[7] = Convert.ToByte('t');

        //    for (int j = 0; j < payArr.Length; j++)
        //        buf[j + 8] = payArr[j];
        //    buf[payArr.Length + 8] = (byte)buf.Length;
        //    var crc = this.getCrc32(payArr);
        //    buf[len + 8] = (byte)(crc >> 24 & 0xff);
        //    buf[len + 9] = (byte)(crc >> 16 & 0xff);
        //    buf[len + 10] = (byte)(crc >> 8 & 0xff);
        //    buf[len + 11] = (byte)(crc & 0xff);

        //    var iEnd = new byte[12] { 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82 };
        //    var lenArr = new byte[4];

        //    file.Seek(file.Length - iEnd.Length, SeekOrigin.Begin);

        //    file.Write(buf, 0, buf.Length);
        //    file.Write(iEnd, 0, iEnd.Length);
        //    file.Close();
        //    file.Dispose();
        //    file = null;
        //}
    }
View Code
 internal class Program
 {
     static PicHide picHide = null;
     static void Main(string[] args)
     {
         Console.WriteLine("Hello, World!");
         picHide = new PicHide("o.png", "qrCode.png");
         picHide.HidePic();
         Console.WriteLine("hiden ok");
         Thread.Sleep(3000);
         PicHide.GetHideQrCode("new1.png");
     }
 }
调用

 

标签:int,隐写,Length,二维码,file,var,byte,buf,png
From: https://www.cnblogs.com/HelloQLQ/p/18546534

相关文章

  • 微信小程序——实现二维码扫描功能(含代码)
    ✅作者简介:2022年博客新星第八。热爱国学的Java后端开发者,修心和技术同步精进。......
  • 用PNGMaker.io快速生成透明PNG图像——使用者分享体验
    摘要:PNGMaker.io是一个在线的免费PNG制作工具,可以轻松将文字转换成透明背景的PNG图像,适合各类设计需求。在日常设计工作中,我们常常需要透明背景的PNG图像,但要用专业设计软件制作,步骤多且费时。最近我试用了PNGMaker.io,它可以在线、免费地生成带透明背景的PNG图像,操作简单,效果也......
  • 使用halcon完成一维码、二维码的识别
    图片素材 通过网盘分享的文件:图片5链接:https://pan.baidu.com/s/1r9SG4lZ3ZQ5S-NGVsFx70w?pwd=BFDJ提取码:BFDJ读码一维码创建读码句柄create_bar_code_model([],[],BarCodeHandle)参数一:输入通用参数可以调整条形码模型的名称。参数二:通用参数可以调整条形码......
  • Html5QRCode扫描条形码+二维码
    代码:<html><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><metaname="viewport"content="width=device-width,initial-scale=1.0"&......
  • Halcon 二维码识别
        二维条形码(2-DimensionalBarCode)在水平和竖直方向的二维空间存储信息,其特点是信息容量大、安全性强、保密性高(可加密)、识别率高、编码范围广等。除此之外,二维条形码还可将汉字、图像等信息进行优化编码处理具有全方位识别,并可引入加密机制的功能。因此,二维条形码......
  • jpeg,png,bmp转换成icon,windows本地导出icon文件
    前言通过软件icon-maker实现将文件格式转换目前主流皆为网页在线转换,有时迫于环境原因,需要离线状态的转换工作于是有了本篇文章目录前言安装链接安装移动软件位置(可选)输入注册码安装链接官方链接:https://zh.softorbits.net/icon-maker/软件分享链接(百度网盘):......
  • 给DedeCMS增加二维码功能
    问题:如何给DedeCMS增加二维码功能?解决方法:修改 extend.func.php 文件:打开 include/extend.func.php 文件,在文件末尾添加以下内容:functionqr_code($id,$size=200){return'https://api.qrserver.com/v1/create-qr-code/?size='.$size.'x'.$size.'&data=&......
  • Scifi Modern flat themed GUI UI kit - over 700 PNG files PSD AI sources
    一款完整的现代主题UI套件,专为科幻游戏和应用设计。主要特点包括:六种颜色主题的窗口,涵盖暂停、设置、商店、库存、任务等多个功能页面。提供138个独特的项目和图标,支持5种尺寸(32x32至512x512像素)。丰富的按钮类型,包括常规按钮、轮廓按钮、带图标按钮等,每种按钮有2-3......
  • qt标题,解决title的png图片scaled后显示有明显锯齿
    一、通用方法(使用Qlabel)//添加窗口图标iconLabel=newQLabel(this);QPixmapiconPixmap(":/ico.png");//替换成你的图标文件路径iconLabel->setPixmap(iconPixmap.scaled(125,35,Qt::KeepAspectRatio,Qt::SmoothTransformation));iconLayout->addWidget(iconLabel);......
  • 简单的Java二维码应用
    闲来无事做一个java的小应用玩玩,可以模拟微信小程序刷二维码。需要解决的主要问题:二维码获取二维码展示1.抓包微信小程序,获取所需信息微信电脑版可以登录小程序,通过Charles可以抓包。配置Charles,可以参考文章:charles使用教程,只要配置好证书就行运行Charles,打开微信小......