Simple test to hide Information …

Simple test to hide Information in Image (I) - Source code.
    - X.G. ZHANG

ATL CImage class is used in the following code, and it can only be built
in Windows environment, however the principle is quite simple. Some advance
technologies can be used actually, for example data encryption and decryption,
and information can be distributed to image more evenly.

Source code are as follows:

//=================================================================================================
//  Hide Information in Image, a simple test, no right reserved by X.G. ZHANG
//    Nanjing, China
//=================================================================================================

// File2Image.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "File2Image.h"
#include "math.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

#define SW_ENCRYPT


#define MAGIC_HEADER_SIZE                12              // 12 = 4 + 4 + 4,  -------  magic data (4), data_size(4), randome_seed (4)
#define MAGIC_DATA    0xF0
#define MAGIC_DATA_IN_IMAGE            1234567

#define MY_ABS(a)        ((a>0)?(a):(-a))

// turn a byte array to int, machine independent
#define INT_FROM_CHAR_ARRAY(iV,pByte)  do{\
                                                                                iV = \
                                                                                  (((int)(unsigned char)(pByte)[0]) +        \
                                                              (((int)(unsigned char)(pByte)[1]) << 8)  \
                                                                                  (((int)(unsigned char)(pByte)[2]) << 16) + \
                                                                                  (((int)(unsigned char)(pByte)[3]) << 24) );\
                                                            }while(0)

// turn an int to byte array, machine independent
#define CHAR_ARRAY_FROM_INT(pByte, iV)  do{\
                                                                    (pByte)[0] =  (byte)(iV & 0x000000FF);\
                                                                  (pByte)[1] = (byte)((iV & 0x0000FF00) >> 8);\
                                                                  (pByte)[2] = (byte)((iV & 0x00FF0000) >> 16);\
                                                                  (pByte)[3] = (byte)((iV & 0xFF0000) >> 24);\
                                                            }while(0)



#include "atlimage.h"
#include "math.h"


class CMagicHeader
{
public:
      CMagicHeader()
      {
            Init(0,0);
      }
      void Init(int data_size, int rand_seed)
      {
            m_magic_data = MAGIC_DATA_IN_IMAGE;
            m_actual_data_size = data_size;
            m_rand_seed = rand_seed;
      }
public:
      bool IsLegal()
      {
            return (MAGIC_DATA_IN_IMAGE == m_magic_data);
     
      }
      int  GetHeaderSize()
      {
            return 12;
      }

public:
      void ToByteArray(byte* bArray)
      {
            CHAR_ARRAY_FROM_INT(bArray,m_magic_data);
              CHAR_ARRAY_FROM_INT(bArray+4,m_actual_data_size);
            CHAR_ARRAY_FROM_INT(bArray+8,m_rand_seed);     
      }

      void FromByteArray(byte* bArray)
      {
            INT_FROM_CHAR_ARRAY(m_magic_data,bArray);
              INT_FROM_CHAR_ARRAY(m_actual_data_size,bArray+4);
            INT_FROM_CHAR_ARRAY(m_rand_seed,bArray);           
      }
protected:
      int m_magic_data;
      int m_actual_data_size;
      int m_rand_seed;
};

template <class T>
class CMemCleaner
{
protected:

      T*&            m_Ptr;

      BOOL      m_bIfArray;
     
      CMemCleaner(){}            //Disable this function
public:
     
      CMemCleaner(T*& pT,BOOL IfArray = FALSE):m_Ptr(pT)
               
            m_bIfArray = IfArray;
      }
     
      virtual ~CMemCleaner()
      {
            Reset();
      }
public:
      T*& operator ->()
      {
            return m_Ptr;
      }
public:
      //only for array
      T& operator [](int i)
      {
            return m_Ptr[i];
      }
protected:
     
      void      Reset()
      {
            if(m_Ptr)
            {
                  if(m_bIfArray)
                  {
                        delete []m_Ptr;
                  }
                  else
                  {
                        delete m_Ptr;                 
                  }
                 
                  m_Ptr = NULL;
            }
      }
};

virtual class IBitStream
{

public:
      virtual void EnumInit() = 0;
      virtual void EnumNext() = 0;
      virtual bool IsEnd() = 0;
      virtual byte GetCurrentBit() = 0;
      virtual void SetCurrentBit(byte b) = 0; // b=1, means to set current bit to 1, otherwise set current bit = 0;

public:
      virtual int  GetTotalBitNum() = 0;
};

//=================================================================================================
//  iterate order (byte number, bit number)
//                  (0,0) -( 0, 1) - (0,2) ... ( 0,7 ) ==> (1,0) - (1,1) - (1,2) - .. ( 1,7)
//                  ..................... (m_size-1, 0) - ( m_size -1, 1) ......... ( m_size -1, 7)
//    so, first bit ( 0,0), second bit ( 0.1) ... last bit ( m_size -1, 7)
//=================================================================================================
class CDataBitStream: IBitStream
{
public:
      CDataBitStream(byte* array, int size)
      {
            m_array = array;
            m_size = size;

              m_cur_bit_pos = 0;
      }

private:
    CDataBitStream()
    {
            printf("Disabled!\r\n");
    }

public:
      virtual void EnumInit()
      {
            m_cur_bit_pos = 0;
     
      }
      virtual void EnumNext()
      {
            m_cur_bit_pos ++;
     
      }
      virtual bool IsEnd()
      {
            if ( (m_cur_bit_pos >> 3) == m_size)    // 8 bit --> size = 1, 16 bit -> size = 2
            {
                  return TRUE;
            }
            else
            {
                  return FALSE;
            }
     
      }
      virtual int  GetTotalBitNum()
      {
                  return m_size << 3;
     
      }
     
public:     
      virtual byte GetCurrentBit()
      {
            int byte_pos = m_cur_bit_pos / 8;
            int bit_pos = m_cur_bit_pos % 8;
             
            byte b = m_array[byte_pos];

            b = (byte)(b << (7 - bit_pos ));
            return b >>  7;
     
      }


      virtual void SetCurrentBit(byte b)
      {
            int byte_pos = m_cur_bit_pos / 8;
            int bit_pos = m_cur_bit_pos % 8;

            //TRACE("byte_pos = %d, bit_pos = %d, old_value = %d ", byte_pos, bit_pos, m_array[byte_pos]);

            if( b == 1)
            {
                  m_array[byte_pos]  |= (byte)(0x01 << bit_pos);
           
            }
            else //
            {
                m_array[byte_pos]  &= (byte) \
                                                                        (byte)( 0xFF >> (8 - bit_pos)) |  \
                                                                  (byte)( 0xFF << (bit_pos +1 ))      \
                                                      );
            }
           
            //TRACE("new_value = %d \r\n",  m_array[byte_pos]);
      }


public:
      int GetBitNumWhenEncodeInIma ge(int image_width, int image_height)
      {
                int valid_pitch = image_width * 3;  //valid byte number in each "line"
            //-----------------------------------------------------------------------------------------
            for (int i = 1; i < 16; i = i * 2)
            {
                  if( i * valid_pitch * image_height >= (m_size * 8) )
                  {
                        break;
                  }
           
            }

            return (i < 9)? (i):0; // return 0, means too much information, cannot be hided, otherwise, i bits will be used for each bytes in bmp byte array

      }

public:
    virtual ~CDataBitStream()
    {
            // need do nothing
    }


#ifdef _WIN32
public:

    CImage*  CreateCompatiableImage()
    {
            int total_size = m_size + MAGIC_HEADER_SIZE;  // 4 for magic data, 4 for actual_useful_size, 4 for randome seed
            int root = (int)sqrt((double)total_size/3)+1;

            CImage* pImage = new CImage();
            pImage->CreateEx(root,-root,24,BI_RGB,NULL);  // use -root, means up-bottom bitmaps
   
            return pImage;
    }
#endif

protected:
    byte*  m_array;
    int      m_size;

    int      m_cur_bit_pos; // start from 0                                            High --> | 7 | 6 | 5 | ...| 3 | 2 | 1 | 0 | <-- LOW  ( b7 b6 ... b0 )


private:
      // only for code backup
      virtual void SetCurrentBit_bad(byte b)
      {
            int byte_pos = m_cur_bit_pos / 8;
            int bit_pos = m_cur_bit_pos % 8;

            //TRACE("byte_pos = %d, bit_pos = %d, old_value = %d ", byte_pos, bit_pos, m_array[byte_pos]);
            m_array[byte_pos]  &= ( (byte)(b << bit_pos) |  (byte)(0xFF << (bit_pos +1)) | (byte)(0xFF >>( 8-bit_pos))          ) ;     

            //TRACE("new_value = %d \r\n",  m_array[byte_pos]);
      }
};

//==========================================================================================================================
//  The iterator order of Bit in bitmap is quite different from that of normal data
//    suppose ( x,y) means bit y in byte x, for example ( 3,2) means the second bit in byte 3 ( actually the forth byte)
//
//    ----->                  (0,0) - (1,0) - (2,0) ... ( m_width*3 -3,,0)
//    ----->                  (m_width*3,0)      ..........(2*m_width*3-3,0)
//              ...........
//    ----->                    ...........................(m_width*m_height*3-3, 0)        ## here, we have gotten every first bit in the bitmap array, we will try to get all second bits
//
//    ----->                  (0,1) - (1,1) ..............(m_width*-13, 1)
//                                      ...........................(m_width*m_height*3-3,1)          ## here, we have gotten every second bit in bitmap array,
//
//                          .......................................................
//
//    ----->                  (0,7) - (1,7) ...............(m_width*3-3, 7)
//                          ......................................................
//    ----->                  (m_width*(m_height-1)*3,7) ... (m_width*m_height*3-3,7)
//
//
//    Special words: This class doesn't support multi-thread, please constructor Stream instance for each thread
//    Also, no lock mechnism is supported.
//==========================================================================================================================
class CBitmapBitStream: IBitStream
{
public:
      // please use the two APIs to encode/decode information from Image
      boolean HideInformation(byte* bArray, int iArraySize)
      {
            CDataBitStream dbs(bArray,iArraySize);
            return HideInformation(&dbs);
      }

      boolean HideInformation(CDataBitStream * pSourceStream)
      {
            int iBitNum = pSourceStream->GetBitNumWhenEncodeInIma ge(m_width,m_height);

            if(iBitNum <=0 || iBitNum > 8)
            {
                  return FALSE;
            }

            for(this->EnumInit(),pSourceStream->EnumInit(); !pSourceStream->IsEnd();pSourceStream->EnumNext(),this->EnumNext())
            {
                  this->SetCurrentBit(pSourceStream->GetCurrentBit());                 
               
           
      }

      byte* ExtraceHideInformation() // Extract Hide information in the image
      {
            int iAll = m_width*3*m_height;

            byte* bArray = new byte[iAll];

            // allocated memory
            if(bArray)
            {
                  CDataBitStream dbs(bArray, iAll);

                  for(this->EnumInit(),dbs.EnumInit(); !dbs.IsEnd();dbs.EnumNext(),this->EnumNext())
                  {
                        dbs.SetCurrentBit(this->GetCurrentBit());                 
                           
            }

            return bArray;
     
      }



public:
      // please remember, this class will not de-allocate data
      CBitmapBitStream(byte* bmp_array, int pitch, int width, int height)
      {
            m_array = (byte*)bmp_array;
            m_pitch = pitch;
            m_height = height;
            m_width = width;

            m_x = m_y = m_bit_pos = 0;

            ASSERT( MY_ABS(pitch) == ( (width* 3 % 4 == 0) ? (width*3 ):((width* 3 /4+1) * 4)) );
     
      }

#ifdef _WIN32
      CBitmapBitStream(CImage* pImg)
      {
            byte* bmp_array = (byte*)pImg->GetBits();
            int pitch = pImg->GetPitch();
            int width = pImg->GetWidth();
            int height = pImg->GetHeight();

            m_array = (byte*)bmp_array;
            m_pitch = pitch;
            m_height = height;
            m_width = width;

            m_x = m_y = m_bit_pos = 0;

            ASSERT( MY_ABS(pitch) == ( (width* 3 % 4 == 0) ? (width*3 ):((width* 3 /4+1) * 4)) );
           
      }
#endif

private:
            CBitmapBitStream(){} // disable user directly create such an object

public:
      virtual void EnumInit()
      {
              m_x = m_y = m_bit_pos = 0;
     
      }
      virtual void EnumNext()
      {
            m_x ++;

            if( m_x == m_width * 3 ) // valid byte, padded byte will be clean by ATL Image lib automatically, so we will not use it
            {
                  m_x = 0;
                  m_y ++;

                  if( m_y == m_height) // that means we will iterate higher bit in bitmap array
                  {
                        m_y = 0;
                        m_bit_pos ++;
                 
                  }
            }
             
     
      }
      virtual bool IsEnd()
      {
            return ( m_bit_pos == 9);     
      }

      virtual int GetTotalBitNum()
      {
            return MY_ABS(m_width* 3 * m_height);
      }
     
public:     
      virtual byte GetCurrentBit()
      {
            byte b = *(m_array + m_y * m_pitch + m_x );
            return  (byte)(((byte)(b << (7-m_bit_pos))) >> 7);
     
      }
      virtual void SetCurrentBit(byte b) // bit is stored in the 0-th bit of "b"
      {
            byte* pB = m_array + m_y * m_pitch + m_x;
            //TRACE("m_x= %d, m_y = %d, m_bit_pos = %d data=%d ",m_x,m_y,m_bit_pos,*pB);
             
            if( b == 1)
            {
                  (*pB) |= (byte)(0x01 << m_bit_pos);
           
            }
            else //
            {
                  (*pB) &= (byte)\
                                ( (byte)( 0xFF >> (8 - m_bit_pos)) | \
                                  (byte)( 0xFF << (m_bit_pos +1)) \
                                );
            }
            //(*pB) &= ( (b << m_bit_pos) |  ((byte)(0xFF))<< (m_bit_pos +1) | (byte)(((byte)(0xFF)) >> (8-m_bit_pos))          ) ;     
            //TRACE(" new_data = %d\r\n", *pB);
     
      }

public:
    virtual ~CBitmapBitStream()
    {
   
    }
public:
    CMagicHeader*  RetrieveMagicHeaderInBit map()
    {
            int bit_num = GetTotalBitNum();
          byte data[12];
          if(bit_num < 12)
          {
                  return NULL;
          }

            CDataBitStream dbs((byte*)data,12);
         
          for(dbs.EnumInit(),EnumInit(); !this->IsEnd() && !dbs.IsEnd(); this->EnumNext(),dbs.EnumNext())
          {
                dbs.SetCurrentBit(this->GetCurrentBit());
          }

          CMagicHeader* pHeader = new CMagicHeader();
          pHeader->FromByteArray(data);

#ifndef SW_ENCRYPT
          //if(pHeader->IsLegal() == FALSE)
          //{
          //      delete pHeader;
          //    pHeader = NULL;
          //}
#endif
          // re-initialize iterator
          dbs.EnumInit();
          this->EnumInit();

          return pHeader;
         
    }


protected:
    byte*  m_array;
    int      m_pitch;    // usually m_pitch is a multiplication of 4, so it not always equal to (width * 4) for a 24 color bmp
    int      m_height;
    int      m_width;

    int      m_x,m_y;    // x,y is used to iterate bits in the bitmap array,
    int      m_bit_pos;
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值