【原创】一种将文本编码为图片格式的方法
世界上的文字可以被四个字节完全覆盖,也就是UTF-32,其他都是变长的格式。而恰好ARGB加起来四个字节,于是完全可以把一个字符映射为一个像素点嘛!
并且图片上的字节可以再次加密,非常好玩!我仅演示的超级无敌简单的取反操作。
我自己习惯看方形的图片,于是开平方取整,如果字符数量不足就从字符本身随机取一段,这是为了图片尾部不会几个像素留白,炒鸡不美观,以白色(0xFFFFFFFF)作为终止字符。
static Bitmap ArgbTextEncode(string input) { var x = 0; var y = 0; var lenth = input.Length; var yValue = (int)(Math.Sqrt(input.Length) + 1); var fill = (yValue * yValue) % (Encoding.Unicode.GetByteCount(input) / 4); input += input.Substring(Rnd.random.Next(input.Length - fill - 1), fill); var image = new Bitmap(yValue, yValue); //fill for (int i = 0; i < yValue * yValue; i++) { if (i == lenth - 1) { image.SetPixel(x, y, Color.White); } else { byte[] bytes = Encoding.Unicode.GetBytes(input[i].ToString()); var prefix = 4 - bytes.Length; bytes = Enumerable.Repeat<byte>(0, prefix).Concat(bytes).ToArray(); Encrypt(bytes); image.SetPixel(x, y, Color.FromArgb(bytes[0], bytes[1], bytes[2], bytes[3])); } //Console.WriteLine("{0},{1} = {2}", x, y, input[i]); x++; if (x % yValue == 0) { x = 0; y++; } } return image; }
找了一个日志文本,看看效果
解码函数
static string DecodeTextFromArgb(Bitmap image) { //ComplexImage comp = ComplexImage.FromBitmap(image); //comp.BackwardFourierTransform(); var str = ""; for (int i = 0; i < image.Height; i++) { for (int j = 0; j < image.Width; j++) { var color = image.GetPixel(j, i); if (color.A == 255 && color.R == 255 && color.G == 255 && color.B == 255) return str; var bytes = new byte[] { color.A, color.R, color.G, color.B }; Decrypt(bytes); int skip = 0; if (bytes[0] == 0) { if (bytes[1] == 0) { skip = 2; } else { skip = 1; } } else { skip = 0; } var t = Encoding.Unicode.GetString(bytes.Skip(skip).ToArray()); //Console.WriteLine("{0},{1} = {2}", j, i, t); str += t; } } return str; }
里面用到的Encrypt和Decrypt是取反的,不然图片一片漆黑,啥看不见。这句是我刚想到真的用取反操作符来,实际我是用的255去减的。
unchecked((byte)~(byte)value)
Encrypt和Decrypt,其实一样的。。哈哈
static byte[] Encrypt(byte[] values) { for (int i = 0; i < values.Length; i++) { values[i] = (byte)(255 - values[i]); } return values; } static byte[] Decrypt(byte[] values) { for (int i = 0; i < values.Length; i++) { values[i] = (byte)(255 - values[i]); } return values; }
本程序完整代码如下:
class Program { static void Main(string[] args) { if (!args.Any()) { return; } else if (args[0].EndsWith(".txt", StringComparison.OrdinalIgnoreCase)) { var textRaw = File.ReadAllText(args[0], Encoding.Unicode); var image = ArgbTextEncode(textRaw); var imagePath = Path.ChangeExtension(args[0], ".png"); image.Save(imagePath, ImageFormat.Png); image.Dispose(); Console.WriteLine("TXT->PNG, " + imagePath); try { Process.Start(imagePath); } catch { } } else if (args[0].EndsWith(".png", StringComparison.OrdinalIgnoreCase)) { var image = (Bitmap)Bitmap.FromFile(args[0]); string text = ""; try { text = DecodeTextFromArgb(image); } catch (Exception ex) { Console.WriteLine("PNG->TXT, 转换失败"); return; } var txtPath = Path.ChangeExtension(args[0], ".txt"); File.WriteAllText(txtPath, text, Encoding.Unicode); Console.WriteLine("PNG->TXT, " + txtPath); try { Process.Start(txtPath); } catch { } } else { Console.WriteLine("只支持TXT和PNG文件"); } } static Bitmap ArgbTextEncode(string input) { var x = 0; var y = 0; var lenth = input.Length; var yValue = (int)(Math.Sqrt(input.Length) + 1); var fill = (yValue * yValue) % (Encoding.Unicode.GetByteCount(input) / 4); input += input.Substring(Rnd.random.Next(input.Length - fill - 1), fill); var image = new Bitmap(yValue, yValue); //fill for (int i = 0; i < yValue * yValue; i++) { if (i == lenth - 1) { image.SetPixel(x, y, Color.White); } else { byte[] bytes = Encoding.Unicode.GetBytes(input[i].ToString()); var prefix = 4 - bytes.Length; bytes = Enumerable.Repeat<byte>(0, prefix).Concat(bytes).ToArray(); Encrypt(bytes); image.SetPixel(x, y, Color.FromArgb(bytes[0], bytes[1], bytes[2], bytes[3])); } //Console.WriteLine("{0},{1} = {2}", x, y, input[i]); x++; if (x % yValue == 0) { x = 0; y++; } } return image; } static byte[] Encrypt(byte[] values) { for (int i = 0; i < values.Length; i++) { values[i] = (byte)(255 - values[i]); } return values; } static byte[] Decrypt(byte[] values) { for (int i = 0; i < values.Length; i++) { values[i] = (byte)(255 - values[i]); } return values; } static string DecodeTextFromArgb(Bitmap image) { //ComplexImage comp = ComplexImage.FromBitmap(image); //comp.BackwardFourierTransform(); var str = ""; for (int i = 0; i < image.Height; i++) { for (int j = 0; j < image.Width; j++) { var color = image.GetPixel(j, i); if (color.A == 255 && color.R == 255 && color.G == 255 && color.B == 255) return str; var bytes = new byte[] { color.A, color.R, color.G, color.B }; Decrypt(bytes); int skip = 0; if (bytes[0] == 0) { if (bytes[1] == 0) { skip = 2; } else { skip = 1; } } else { skip = 0; } var t = Encoding.Unicode.GetString(bytes.Skip(skip).ToArray()); //Console.WriteLine("{0},{1} = {2}", j, i, t); str += t; } } return str; } }
源码地址:https://gitee.com/kstudio/ArgbText