public static byte[] DataSeparation(ref Cjpeg cj, int embed_bits, int offset, int color, int b_idx) { byte[] dst = new byte[1 + (int)(embed_bits/8)]; dst.Initialize(); for (int i = offset; i < (offset + embed_bits); i++) { if (cj.cb.data[color][b_idx][i] < -1) { dst[(int)(i / 8)] += (byte)((-cj.cb.data[color][b_idx][i] % 2) << (7 - (i % 8))); cj.cb.data[color][b_idx][i] += (-cj.cb.data[color][b_idx][i] % 2); } else if (cj.cb.data[color][b_idx][i] > 1) { dst[(int)(i / 8)] += (byte)((cj.cb.data[color][b_idx][i] % 2) << (7 - (i % 8))); cj.cb.data[color][b_idx][i] -= (cj.cb.data[color][b_idx][i] % 2); } else { if (cj.cb.data[color][b_idx][i] != 0) { dst[(int)(i / 8)] += (byte)(1 << (7 - (i % 8))); cj.cb.data[color][b_idx][i] = 0; } } } return dst; }
public WaterMarking(ref Cjpeg cj) { this.cj = cj; error = new byte[cj.cb.b_len]; temp = new int[3][][]; for (int k = 0; k < 3; k++) { temp[k] = new int[cj.cb.b_len][]; for (int i = 0; i < cj.cb.b_len; i++) { temp[k][i] = new int[64]; } } for (int k = 0; k < 3; k++) { for (int i = 0; i < cj.cb.b_len; i++) { for (int j = 0; j < 64; j++) { temp[k][i][j] = cj.cb.data[k][i][j]; } } } }
public static int[] Check(ref Cjpeg temp, string passwd, int embed_bits, int offset, int color) { Cjpeg cj = new Cjpeg(temp); int[] error = new int[cj.cb.b_len]; error.Initialize(); int err_count = 0; byte[] extract_data; byte[] hash_key; byte[] hash_value; SHA256 sha = SHA256.Create(); UnDiffDC(ref cj); for (int k = 0; k < 3; k++) { for (int i = 0; i < cj.cb.b_len; i++) { extract_data = DataSeparation(ref cj, embed_bits, offset, k, i); hash_key = GetHashKey(ref cj, passwd, k, i); hash_value = sha.ComputeHash(hash_key); error[i] += CheckHash(extract_data, hash_value, embed_bits); err_count += error[i]; } } return error; }
public static int GetValue(ref Cjpeg cj, int v_length) { if (v_length == 0) { return 0; } int msb = cj.sos.cbs.GetBit(); int dst = 0; if (msb == 1) { dst += 1 << (v_length - 1); for (int i = 1; i < v_length; i++) { dst += (cj.sos.cbs.GetBit() << (v_length - i - 1)); } } else { dst += 1 << (v_length - 1); for (int i = 1; i < v_length; i++) { dst += ( (cj.sos.cbs.GetBit()^1) << (v_length - i - 1)); } dst = -dst; } return dst; }
public Cjpeg(Cjpeg prev) { app0 = new APP0(prev.app0); dqt = new DQT(prev.dqt); dht = new DHT(prev.dht); sof = new SOF0(prev.sof); sos = new SOS(prev.sos); cb = new CBlock(prev.cb); }
//埋込 public static void Embed(ref Cjpeg cj, string passwd, int embed_bits, int offset, int color) { UnDiffDC(ref cj); //UnQuantize(); int[][][] temp = GetCbTemp(ref cj); ValueCombing(ref cj, embed_bits, offset, color); EmbedHash(ref cj, temp, passwd, embed_bits, offset, color); //AddRand(embed_bits, offset, color); DiffDC(ref cj); //Quantize(); }
public void CheckError(ref Cjpeg cj, int[] error, int check_count) { for (int i = 0; i < cj.cb.block_width; i++) { for (int j = 0; j < cj.cb.block_height; j++) { if (error[i + (j * cj.cb.block_width)] >= check_count) { SetPixel(i * 8, j * 8, i * 8 + 8, j * 8 + 8, 0, 0, 0); } } } }
/// <summary> /// ルートから探索 /// </summary> /// <returns></returns> public static int GetValueLength(ref Cjpeg cj, int t_sel, int ac_dc) { int seek=0; int RL; while (true) { RL = cj.sos.cbs.GetBit(); seek = cj.dht.table[t_sel, ac_dc].nodes[seek].child[RL]; if (cj.dht.table[t_sel, ac_dc].nodes[seek].is_reaf == true) { return cj.dht.table[t_sel, ac_dc].nodes[seek].value; } } }
/// <summary> /// 値長からコードを取得 /// </summary> /// <param name="value"></param> /// <returns></returns> public static void GetCode(ref Cjpeg cj, int v_len, int YCbCr, int AC_DC, out int v_code, out int c_len) { int dst_node = 0; int dst = 0; int seek = 0; int code_len = 0; c_len = 0; v_code = 0; CbinaryTree cbt = cj.dht.table[cj.sof.t_sel[YCbCr], AC_DC]; //葉探索、終着ノードを求める for (int i = 0; i < cbt.t_reaf.Length; i++) { if (cbt.nodes[cbt.t_reaf[i]].value == v_len) { dst_node = cbt.t_reaf[i]; code_len = cbt.nodes[dst_node].depth; seek = dst_node; c_len = code_len; break; } } if (dst_node == 0) { return; } //ルート探索、見ている親ノードと見ているノードが一致するか //for (int i = 0; i < code_len; i++) for (int i = 0; seek > 0; i++) { for (int j = 0; j < 2; j++) { if (cbt.nodes[cbt.nodes[seek].parent].child[j] == seek) { //Console.Write(j); dst += (j << i); seek = cbt.nodes[seek].parent; break; } } } v_code = dst; }
public static void HuffmanDecode(ref Cjpeg cj) { int count = 0; int c_value; int v_length; int z_run; for (int i = 0; i < (cj.cb.block_width * cj.cb.block_height); i++) { for (int k = 0; k < 3; k++) { //DC c_value = GetValueLength(ref cj, t_sel[k], DC); cj.cb.data[k][i][0] = GetValue(ref cj, c_value); //AC for (int j = 1; j < 64;j++) { c_value = GetValueLength(ref cj, t_sel[k], AC); if (c_value == EOB) { break; } else { z_run = (c_value & 0xf0) >> 4; if (z_run != 0) { int aaa; } j += z_run; if (j > 63) { break; } v_length = (c_value & 0x0f); cj.cb.data[k][i][j] = GetValue(ref cj, v_length); //Console.Write(cj.cb.data[count][i, j] + ","); } } //count = ((count + 1) % 3); } } }
public static void WriteImgData(ref Cjpeg cj, ref BinaryWriter bw) { byte v_len; byte zero_run; int code; int v_code; int l_code; int EOB_idx; CBitWriter cbw = new CBitWriter(ref bw); //ブロック長ループ for (int i = 0; i < cj.cb.b_len; i++) { //色ループ for (int j = 0; j < 3; j++) { if (i == 4095) { int aaaaa; } EOB_idx = SearchEOBStart(ref cj, j, i); //DC v_len = GetValueLength(cj.cb.data[j][i][0]); GetCode(ref cj, v_len, j, DC, out v_code,out l_code); cbw.WriteBit(v_code, l_code); cbw.WriteBit(cj.cb.data[j][i][0], v_len); //AC zero_run = 0; for (int k = 1; k < 64; k++) { if (k == EOB_idx) { GetCode(ref cj, EOB, j, AC, out v_code, out l_code); cbw.WriteBit(v_code, l_code); break; } else if (cj.cb.data[j][i][k] == 0) { zero_run++; if (zero_run == 16) { GetCode(ref cj, ZRL, j, AC, out v_code, out l_code); cbw.WriteBit(v_code, l_code); zero_run = 0; } } else { v_len = (byte)((zero_run << 4) + GetValueLength(cj.cb.data[j][i][k])); GetCode(ref cj, v_len, j, AC, out v_code, out l_code); cbw.WriteBit(v_code, l_code); cbw.WriteBit(cj.cb.data[j][i][k], v_len&0x0f); zero_run = 0; } } } } cbw.WriteFinal(); }
//差分化 static void DiffDC(ref Cjpeg cj) { int buf = cj.cb.data[0][0][0]; for (int i = cj.cb.b_len-1; i > 0; i--) { for (int j = 0; j < 3; j++) { cj.cb.data[j][i][0] -= cj.cb.data[j][i - 1][0]; } } }
static void Main(string[] args) { Cjpeg cj = null; CBitmap cbmp = null; WaterMarking wm = null; int embed_bits = 8; int offset = 0; int color = 3; string path = @"c:\dst.jpg"; string passwd = "aaaaa"; string dst_path; string dst_files = ""; Cjpeg cj_raw = null; //CJpegDecoderT.HuffmanDecode(ref cj_raw); FileInfo fi = null; Cjpeg temp = null; int[] err; switch (Console.ReadLine()) { case "r": for (int i = 0; i < args.Length; i++) { cj_raw = new Cjpeg(args[i]); CJpegDecoderT.HuffmanDecode(ref cj_raw); fi = new FileInfo(args[i]); //Directory.CreateDirectory(args[i]+"\\"); dst_files = args[i]; dst_files += " "; for (int bits = 0; bits < 65; bits++) { temp = new Cjpeg(cj_raw); WaterMarkingT.Embed(ref temp, passwd, bits, 0, 3); dst_path = args[i].Substring(0, args[i].Length - 4); dst_path += "\\b"; for (int j = 0; j < 2 - bits.ToString().Length; j++) { dst_path += "0"; } dst_path += bits.ToString() + ".jpg"; CJpegEncoderT.WriteFile(ref temp, dst_path); Console.WriteLine(dst_path + " wrote"); err = WaterMarkingT.Check(ref temp, passwd, bits, 0, 3); dst_files += dst_path + " "; } //Process exec = Process.Start("PSNR.exe", dst_files); } break; case "c": int check_count = int.Parse(Console.ReadLine()); BinaryWriter bw_csv = new BinaryWriter(File.Open(args[0]+".csv", FileMode.Create)); for (int i = 0; i < args.Length; i++) { int emb = int.Parse(args[i].Substring(args[i].Length - 6, 2)); cj_raw = new Cjpeg(args[i]); cbmp = new CBitmap(new Bitmap(args[i])); CJpegDecoderT.HuffmanDecode(ref cj_raw); err = WaterMarkingT.Check(ref cj_raw, passwd, emb, 0, 3); cbmp.CheckError(ref cj_raw, err, check_count); //string dst_name = args[i] + args[i].Substring(args[i].Length - 6, 2) + ".bmp"; string dst_name = args[i] + ".bmp"; bw_csv.Write("" + i + "," + CountError(err, check_count) + "\n"); cbmp.ToBitmap().Save(dst_name); Console.WriteLine(args[i] + " checked"); } bw_csv.Close(); Console.ReadLine(); break; } return; while (true) { Console.Write(">"); switch (Console.ReadLine()) { case "o": Console.WriteLine("enter filename"); path = Console.ReadLine(); if (path == "") { path = @"h:\lenna512.jpg"; Console.WriteLine("read \"h:\\lenna512.jpg\""); } try { cj = new Cjpeg(path); cbmp = new CBitmap(new Bitmap(path)); CJpegDecoderT.HuffmanDecode(ref cj); } catch { Console.WriteLine("read error"); } break; case "w": Console.WriteLine("enter filename"); dst_path = Console.ReadLine(); if (dst_path == "") { dst_path = @"h:\dst.jpg"; Console.WriteLine("write \"h:\\dst.jpg\""); } CJpegEncoderT.WriteFile(ref cj, dst_path); break; case "c": wm.Extract(embed_bits, offset, color); break; case "e": //wm.Embed(10); WaterMarkingT.Embed(ref cj, "aaaaa",embed_bits, offset, color); break; case "t": Cjpeg test = new Cjpeg(cj); cj = test; break; case "q": return; } } //cjd.HuffmanDecode(); ////wm.Embed(0); //wm.Extract(0); //wm.CheckError(ref cbmp); //cje.WriteFile(); //Application.EnableVisualStyles(); //Application.SetCompatibleTextRenderingDefault(false); //Application.Run(new MainForm(cbmp)); }
static void EmbedHash(ref Cjpeg cj, int[][][] temp, string passwd, int embed_bits, int offset, int color) { int bit_seek = 0; int array_seek = 0; byte[] hash_key; byte[] hash_value; SHA256 sha = SHA256.Create(); for (int k = 0; k < color; k++) { for (int i = 0; i < cj.cb.b_len; i++) { hash_key = GetHashKey(ref cj, passwd, k, i); hash_value = sha.ComputeHash(hash_key); for (int j = offset; j < (embed_bits + offset); j++) { if ((hash_value[array_seek] & (1 << (7 - bit_seek))) != 0) { cj.cb.data[k][i][j] = SetValue(ref cj, temp, k, i, j); } bit_seek++; if (bit_seek == 8) { array_seek++; bit_seek = 0; } } array_seek = 0; bit_seek = 0; } } }
static void Main(string[] args) { Cjpeg cj = null; try { cj = new Cjpeg(@"c:\88.jpg"); } catch { Console.WriteLine("file cannnot open."); return; } for (int i = 0; i<cj.dqt.num_color; i++) { for (int j = 0; j < 64; j++) { Console.Write("" + cj.dqt.table[i][j]+ ","); } Console.WriteLine(); } for (int i = 0; i < cj.sos.cbs.data_length; i++) { Console.Write("" + cj.sos.cbs.GetBit()); } Console.WriteLine("\n"); for (int i = 0; i < 2; i++) { for (int j = 0; j < 1; j++) { Console.WriteLine("" + i + "," + j + "sum_nodes:" + cj.dht.table[i, j].sum_nodes); Console.WriteLine("" + i + "," + j + "sum_reaves:" + cj.dht.table[i, j].sum_reaves); for (int k = 0; k < cj.dht.table[i, j].sum_nodes; k++) { if (cj.dht.table[i, j].nodes[k].is_reaf) { Console.Write("" + k + " "); } } Console.WriteLine(""); for (int k = 0; k < cj.dht.table[i, j].sum_nodes; k++) { Console.Write("" + k + " depth:" + cj.dht.table[i,j].nodes[k].depth + " child:" + cj.dht.table[i, j].nodes[k].child[0] + " " + cj.dht.table[i, j].nodes[k].child[1] + " "); if (cj.dht.table[i, j].nodes[k].is_reaf) { Console.WriteLine(cj.dht.table[i, j].nodes[k].value); } else { Console.WriteLine(); } } } Console.WriteLine(); } Console.Write("\n" + cj.sof.height + "," + cj.sof.width); }
public CJpegDecoder(ref Cjpeg cj_in) { cj = cj_in; }
public static int SearchEOBStart(ref Cjpeg cj, int color, int b_idx) { for (int i = 63; i > -1; i--) { if (cj.cb.data[color][b_idx][i] != 0) { return i+1; } } return 1; }
//量子化 static void Quantize(ref Cjpeg cj) { for (int i = 0; i < cj.cb.b_len; i++) { for (int k = 0; k < 3; k++) { for (int j = 0; j < 64; j++) { cj.cb.data[k][i][j] = (int)Math.Round((double)(cj.cb.data[k][i][j] / cj.dqt.table[cj.sof.t_sel[k]][j])); } } } }
public static void WriteFile(ref Cjpeg cj, string path) { byte[] soi = new byte[2]{ 0xff, 0xd8 }; byte[] eoi = { 0xff, 0xd9 }; BinaryWriter bw = new BinaryWriter(File.Open(path, FileMode.Create)); bw.Write(soi); cj.app0.WriteMarker(ref bw); cj.dqt.WriteMarker(ref bw); cj.sof.WriteMarker(ref bw); cj.dht.WriteMarker(ref bw); cj.sos.WriteMarker(ref bw); try { WriteImgData(ref cj, ref bw); } catch { Console.WriteLine("WriteImgData Erorr"); } bw.Write(eoi); bw.Close(); }
//埋込ビットが1の場合の動作 static int SetValue(ref Cjpeg cj, int[][][] temp, int color, int b_idx, int dct_idx) { Random rand = new Random(temp[color][b_idx][dct_idx]); if (cj.cb.data[color][b_idx][dct_idx] == 0) { //埋込先が0の場合、-1 か 1のどっちかにランダムにプロット if (cj.cb.data[color][b_idx][dct_idx] == 0) { if (rand.Next() % 2 == 0) { return 1; } else { return -1; } } else { return temp[color][b_idx][dct_idx]; } } if (cj.cb.data[color][b_idx][dct_idx]< -1) { return (cj.cb.data[color][b_idx][dct_idx] - 1); } if (1 < cj.cb.data[color][b_idx][dct_idx]) { return (cj.cb.data[color][b_idx][dct_idx] + 1); } return 0; }
static int[][][] GetCbTemp(ref Cjpeg cj) { int[][][] dst = new int[3][][]; for (int k = 0; k < 3; k++) { dst[k] = new int[cj.cb.b_len][]; for (int i = 0; i < cj.cb.b_len; i++) { dst[k][i] = new int[64]; } } for (int k = 0; k < 3; k++) { for (int i = 0; i < cj.cb.b_len; i++) { for (int j = 0; j < 64; j++) { dst[k][i][j] = cj.cb.data[k][i][j]; } } } return dst; }
//値を間引く static void ValueCombing(ref Cjpeg cj, int embed_bits, int offset, int color) { for (int k = 0; k < color; k++) { for (int i = 0; i < cj.cb.b_len; i++) { for (int j = offset; j < (embed_bits + offset); j++) { // -1<=value<=1 -> 0 if ((-1 <= cj.cb.data[k][i][j]) && (cj.cb.data[k][i][j] <= 1)) { cj.cb.data[k][i][j] = 0; } // 1 < value if (cj.cb.data[k][i][j] > 1) { cj.cb.data[k][i][j] -= (cj.cb.data[k][i][j] % 2); } // value < -1 if (cj.cb.data[k][i][j] < -1) { cj.cb.data[k][i][j] += (-cj.cb.data[k][i][j] % 2); } } } } }
//逆量子化 static void UnQuantize(ref Cjpeg cj) { for (int i = 0; i < cj.cb.b_len; i++) { for (int k = 0; k < 3; k++) { for (int j = 0; j < 64; j++) { cj.cb.data[k][i][j] *= cj.dqt.table[cj.sof.t_sel[k]][j]; } } } }
//public void Extract(int embed_bits, int offset, int color) //{ // int bit_seek = 0; // int array_seek = 0; // byte[] extract_data = new byte[8]; // UnDiffDC(); // for (int k = 0; k < color; k++) // { // for (int i = 0; i < cj.cb.b_len; i++) // { // for (int j = 0; j < 8; j++) // { // extract_data[j] = 0; // } // if (i == 37) // { // int aaa; // } // for (int j = offset; j < (offset + embed_bits); j++) // { // extract_data[array_seek] += (byte)(SeparateValue(k,i,j) << (7 - bit_seek)); // bit_seek++; // if (bit_seek > 7) // { // array_seek++; // bit_seek = 0; // } // } // GetHashBuf(k, i); // hash_value = sha.ComputeHash(hash_buf); // error[i] += (byte)CheckHash(i, embed_bits, extract_data, hash_value); // bit_seek = 0; // array_seek = 0; // } // } //} ////ハッシュ値を比較して、値が異なれば1を返す //public int CheckHash(int b_idx, int embed_bits, byte[] hashA, byte[] hashB) //{ // for (int i = 0; i < embed_bits; i++) // { // if ((hashA[(int)(i / 8)] & (byte)(1 << (7 - (i % 8)))) // != (hashB[(int)(i / 8)] & (byte)(1 << (7 - (i % 8))))) // { // //error[b_idx]++; // return 1; // } // } // return 0; //} ////透かし埋込済みDCT係数から値を取り出しつつ値を元に戻す //public int SeparateValue(int color, int b_idx, int dct_idx) //{ // int dst; // if ((-1 <= cj.cb.data[color][b_idx][dct_idx]) && (cj.cb.data[color][b_idx][dct_idx] <= 1)) // { // if (cj.cb.data[color][b_idx][dct_idx] == 0) // { // return 0; // } // else // { // cj.cb.data[color][b_idx][dct_idx] = 0; // return 1; // } // } // if (cj.cb.data[color][b_idx][dct_idx] > 1) // { // dst = (cj.cb.data[color][b_idx][dct_idx] % 2); // cj.cb.data[color][b_idx][dct_idx] -= dst; // return dst; // } // if (cj.cb.data[color][b_idx][dct_idx] < -1) // { // dst = (-cj.cb.data[color][b_idx][dct_idx] % 2); // cj.cb.data[color][b_idx][dct_idx] += dst; // return dst; // } // return 0; //} //public CBitmap CheckError() //{ // CBitmap dst = new CBitmap(cj.sof.width, cj.sof.height); // for (int i = 0; i < dst.width; i++) // { // for (int j = 0; j < dst.height; j++) // { // if (error[i] == 1) // { // dst.SetPixel(i * 8, (i * 8) + 7, j * 8, (j * 8) + 7, 255, 0, 0); // } // } // } // return dst; //} //void //儀式用関数群 //逆差分化 static void UnDiffDC(ref Cjpeg cj) { for (int i = 1; i < cj.cb.b_len; i++) { for (int j = 0; j < 3; j++) { cj.cb.data[j][i][0] += cj.cb.data[j][i - 1][0]; } } }
public CJpegEncoder(ref Cjpeg cjpeg, string path) { cj = cjpeg; bw = new BinaryWriter(File.Open(path, FileMode.Create)); cbw = new CBitWriter(ref bw); }
static byte[] GetHashKey(ref Cjpeg cj, string passwd, int color, int b_idx) { byte[] buf = new byte[71]; byte[] pass = StringToByte(passwd); byte[] dst; buf.Initialize(); for (int i = 0; i < 64; i++) { if (cj.cb.data[color][b_idx][i] > 0) { buf[i] = (byte)cj.cb.data[color][b_idx][i]; } } buf[64] = (byte)((cj.sof.width & 0xff00) >> 8); buf[65] = (byte)(cj.sof.width & 0xff); buf[66] = (byte)((cj.sof.height & 0xff00) >> 8); buf[67] = (byte)(cj.sof.height & 0xff); buf[68] = (byte)color; buf[69] = (byte)((b_idx & 0xff00) >> 8); buf[70] = (byte)(b_idx & 0xff); dst = new byte[buf.Length + pass.Length]; buf.CopyTo(dst, 0); pass.CopyTo(dst, buf.Length); return dst; }