简体   繁体   中英

Bitwise shifting in C++

Trying to hide data within a PPM Image using C++:

void PPMObject::hideData(string phrase)
{
    phrase += '\0';
    size_t size = phrase.size() * 8;
    bitset<8> binary_phrase (phrase.c_str()[0]);

    //We need 8 channels for each letter
    for (size_t index = 0; index < size; index += 3)
    {
        //convert red channel to bits
        bitset<8> r (this->m_Ptr[index]);
        if (r.at(7) != binary_phrase.at(index))
        {
            r.flip(7);
        }

        this->m_Ptr[index] = (char) r.to_ulong();

        //convert blue channel to bits and find LSB
        bitset<8> g (this->m_Ptr[index+1]);
        if (g.at(7) != binary_phrase.at(index+1))
        {
            g.flip(7);
        }

        this->m_Ptr[index+1] = (char) g.to_ulong();

        //convert green channel to bits and find LSB
        bitset<8> b (this->m_Ptr[index+2]);
        if (b.at(7) != binary_phrase.at(index+2))
        {
            b.flip(7);
        }

        this->m_Ptr[index+2] = (char) b.to_ulong();
    }
    //this->m_Ptr[index+1] = (r.to_ulong() & 0xFF);
}

Then extracting the data by reversing the above process:

string PPMObject::recoverData()
{
    size_t size = this->width * this->height * 3;
    string message("");
    //We need 8 channels for each letter
    for (size_t index = 0; index < size; index += 3)
    {
        //retreive our hidden data from the LSB in red channel
        bitset<8> r (this->m_Ptr[index]);
        message += r.to_string()[7];

        //retreive our hidden data from the LSB in green channel
        bitset<8> g (this->m_Ptr[index+1]);
        message += g.to_string()[7];

        //retreive our hidden data from the LSB in blue channel
        bitset<8> b (this->m_Ptr[index+2]);
        message += b.to_string()[7];
    }

    return message;
}

The above hide data function converts each channel (RGB) to binary. It then attempts to find the least significant bit and flips it if it does not match the nth bit of the phrase (starting at zero). It then assigns that new converted binary string back into the pointer as a casted char.

Is using the bitset library a "best practice" technique? I am all ears to a more straightforward, efficient technique. Perhaps, using bitwise maniuplations?

There are no logic errors or problems whatsoever with reading and writing the PPM Image. The pixel data is assigned to a char pointer: this->m_Ptr (above).

Here's some more compact code that does bit manipulation. It doesn't bounds check m_Ptr, but neither does your code.

#include <iostream>
#include <string>

using namespace std;

struct PPMObject
{
  void   hideData(const string &phrase);
  string recoverData(size_t size);

  char m_Ptr[256];
};

void PPMObject::hideData(const string &phrase) 
{
  size_t size = phrase.size();

  for (size_t p_index = 0, i_index = 0; p_index < size; ++p_index)
    for (int i = 0, bits = phrase[p_index]; i < 8; ++i, bits >>= 1, ++i_index)
    {
      m_Ptr[i_index] &= 0xFE;          // set lsb to 0
      m_Ptr[i_index] |= (bits & 0x1);  // set lsb to lsb of bits
    }
}

string PPMObject::recoverData(size_t size)
{
  string ret(size, ' ');

  for (size_t p_index = 0, i_index = 0; p_index < size; ++p_index)
  {
    int i, bits;

    for (i = 0, bits = 0; i < 8; ++i, ++i_index)
      bits |= ((m_Ptr[i_index] & 0x1) << i);

    ret[p_index] = (char) bits;
  }

  return ret;
}

int main()
{
  PPMObject p;

  p.hideData("Hello World!");    
  cout << p.recoverData(12) << endl;

  return 0;
}

Note that this code encodes from lsb to msb of each byte of the phrase.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM