世界上的文字可以被四個字節完全覆蓋,也就是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