//使用方法:
// BmpSafe.exe /file2bmp (input BMP) (input file to hide) [output file]
//BmpSafe.exe /bmp2file (data BMP) [output file]
using System;
using System.IO;
using System.Drawing;
public class Bitmap24Writer
{
 protected Bitmap bmp;
 protected int curX, curY, iRGB;
 protected uint bitsLeft, bitsTotal;
 protected byte r, g, b;
 public Bitmap24Writer(Bitmap bmp)
 {
  if (bmp.PixelFormat != System.Drawing.Imaging.PixelFormat.Format24bppRgb)
   throw new ArgumentException();
  // assign vars
  curX       = curY = iRGB = 0;
  this.bmp   = bmp;
  bitsLeft   = bitsTotal = (uint)bmp.Height * (uint)bmp.Width * 3;
 }
 public uint GetUnusedBitCount()
 {
  return bitsLeft;
 }
 public uint GetMaxBitStorageCount()
 {
  return bitsTotal;
 }
 public Bitmap GetBitmap()
 {
  return bmp;
 }
 public bool WriteByte(byte by)
 {
  if (bitsLeft < 8)
   return false;
  uint bits2Do = 8;
  for (; curX < bmp.Width; curX++)
  {
   if (curY >= bmp.Height)
    curY = 0;
   for (; curY < bmp.Height; curY++)
   {
    if (bits2Do == 0)
     return true;
    Color col = bmp.GetPixel(curX, curY);
    r = col.R;
    g = col.G;
    b = col.B;
    for ( ; ; )
    {
     byte curBit = (byte)(by & 1);
     switch( iRGB )
     {
      case 0:
       r = (byte)(r & 0xFE);
       r |= curBit;
       break;
      case 1:
       g = (byte)(g & 0xFE);
       g |= curBit;
       break;
      case 2:
       b = (byte)(b & 0xFE);
       b |= curBit;
       break;
     }
     --bits2Do;
     --bitsLeft;
     by >>= 1; 
     bmp.SetPixel(curX, curY, Color.FromArgb(r, g, b));
     if (iRGB == 2) 
     {
      iRGB = 0;
      break; 
     }
     iRGB++;
     if (bits2Do == 0)
      return true; 
    }
   }
  }
  return true; 
 }
}
public class Bitmap24Reader
{
 protected Bitmap bmp;
 protected int curX, curY, iRGB;
 protected uint bitsLeft, bitsTotal;
 public Bitmap24Reader(Bitmap bmp)
 {
  if (bmp.PixelFormat != System.Drawing.Imaging.PixelFormat.Format24bppRgb)
   throw new ArgumentException();
  curX       = curY = iRGB = 0;
  this.bmp   = bmp;
  bitsLeft   = bitsTotal = (uint)bmp.Height * (uint)bmp.Width * 3;
 }
 public uint GetUnusedBitCount()
 {
  return bitsLeft;
 }
 public uint GetMaxBitStorageCount()
 {
  return bitsTotal;
 }
 public Bitmap GetBitmap()
 {
  return bmp;
 }
 public bool ReadByte(out byte by)
 {
  by = 0;
  if (bitsLeft < 8)
   return false; 
  byte bit = 0;
  uint bits2Do = 8; 
  for (; curX < bmp.Width; curX++)
  {
   if (curY >= bmp.Height) 
    curY = 0;
   for (; curY < bmp.Height; curY++)
   {
    if (bits2Do == 0)
     return true; 
    Color col = bmp.GetPixel(curX, curY);
    for ( ; ; )
    {
     switch( iRGB )
     {
      case 0:
       bit = (byte)(col.R & 1);
       break;
      case 1:
       bit = (byte)(col.G & 1);
       break;
      case 2:
       bit = (byte)(col.B & 1);
       break;
     }
     --bits2Do; 
     --bitsLeft;
     by |= (byte)(bit << 7); 
     if (bits2Do != 0)
      by >>= 1; 
     if (iRGB == 2) 
     {
      iRGB = 0;
      break;
     }
     iRGB++;
     if (bits2Do == 0)
      return true;
    }
   }
  }
  return true; 
 }
}
public class BitmapWorks
{
 public static bool Data2Bmp(Fil