Skip to content

Instantly share code, notes, and snippets.

@skhaz
Last active April 9, 2021 12:23
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save skhaz/4e83e245f41560634be4 to your computer and use it in GitHub Desktop.
Save skhaz/4e83e245f41560634be4 to your computer and use it in GitHub Desktop.
Steganography
#include <QtDebug>
#include <QImage>
#include <QString>
#include <QBitArray>
#include <QByteArray>
#include <QFile>
#include <QCommandLineParser>
namespace {
enum { headerSize = 32 };
QByteArray bitArrayToByteArray(const QBitArray& bits) {
QByteArray bytes;
bytes.resize(bits.count() / 8);
bytes.fill(0);
for (int b = 0; b < bits.count(); ++b)
bytes[b / 8] = (bytes.at(b / 8) | ((bits[b] ? 1 : 0) << (b % 8)));
return bytes;
}
QBitArray byteArrayToBitarray(const QByteArray& bytes) {
QBitArray bits(bytes.count() * 8);
for (int i = 0; i < bytes.count(); ++i)
for (int b = 0; b < 8; ++b)
bits.setBit(i * 8 + b, bytes.at(i) & (1 << b));
return bits;
}
}
QByteArray read(const QString& filename) {
QBitArray bits(8);
QByteArray bytes;
bytes.reserve(headerSize);
int bytesToRead = 0;
QImage image;
if (image.load(filename)) {
for (int y = 0; y < image.height(); ++y) {
for (int x = 0; x < image.width(); ++x) {
QRgb pixel = image.pixel(x, y);
uint32_t index = 0;
bits[index++] = qRed(pixel) & 1 << 0x00;
bits[index++] = qGreen(pixel) & 1 << 0x00;
bits[index++] = qBlue(pixel) & 1 << 0x00;
bits[index++] = qAlpha(pixel) & 1 << 0x00;
bits[index++] = qRed(pixel) & 1 << 0x01;
bits[index++] = qGreen(pixel) & 1 << 0x01;
bits[index++] = qBlue(pixel) & 1 << 0x01;
bits[index++] = qAlpha(pixel) & 1 << 0x01;
bytes += bitArrayToByteArray(bits);
if (!bytesToRead && bytes.size() == headerSize) {
bool ok;
bytesToRead = bytes.toInt(&ok);
if (!ok)
return bytes;
bytes.clear();
bytes.reserve(bytesToRead);
}
if (bytes.size() == bytesToRead) {
return bytes;
}
}
}
}
return bytes;
}
bool write(const QString& in, const QString& out, const QByteArray& message){
QImage image;
if (!image.load(in))
return false;
QImage result = image.copy();
int size = message.size();
QByteArray bytes;
bytes.reserve(size + headerSize);
bytes += QString("%1").arg(size, headerSize, 10, QChar('0'));
bytes += message;
QBitArray bits = byteArrayToBitarray(bytes);
for (int index = 0, y = 0; y < image.height(); ++y) {
for (int x = 0; x < image.width(); ++x) {
if (index >= bits.count())
break;
QRgb pixel = image.pixel(x, y);
int red = qRed(pixel);
int green = qGreen(pixel);
int blue = qBlue(pixel);
int alpha = qAlpha(pixel);
red = bits[index + 0] ? red | (1 << 0x00) : red & ~(1 << 0x00);
green = bits[index + 1] ? green | (1 << 0x00) : green & ~(1 << 0x00);
blue = bits[index + 2] ? blue | (1 << 0x00) : blue & ~(1 << 0x00);
alpha = bits[index + 3] ? alpha | (1 << 0x00) : alpha & ~(1 << 0x00);
red = bits[index + 4] ? red | (1 << 0x01) : red & ~(1 << 0x01);
green = bits[index + 5] ? green | (1 << 0x01) : green & ~(1 << 0x01);
blue = bits[index + 6] ? blue | (1 << 0x01) : blue & ~(1 << 0x01);
alpha = bits[index + 7] ? alpha | (1 << 0x01) : alpha & ~(1 << 0x01);
result.setPixel(x, y, qRgba(red, green, blue, alpha));
index += 8;
}
}
return result.save(out);
}
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
QCoreApplication::setApplicationName("stenog");
QCoreApplication::setApplicationVersion("1.0");
const QCommandLineOption readOption("i", "The input image", "read");
const QCommandLineOption writeOption("o", "The output image", "write");
const QCommandLineOption messageOption("m", "The message", "message");
QCommandLineParser parser;
parser.setApplicationDescription("This tool can read and write a message onto a image using steganography");
parser.addHelpOption();
parser.addVersionOption();
parser.addOption(readOption);
parser.addOption(writeOption);
parser.addOption(messageOption);
parser.process(app);
if (parser.isSet(readOption) && !parser.isSet(writeOption)) {
const QString in_filename = parser.value(readOption);
auto result = qPrintable(read(in_filename));
fputs(result, stdout);
} else {
const QString out_filename = parser.value(writeOption);
const QString in_filename = parser.value(readOption);
const QString message = parser.value(messageOption);
write(in_filename, out_filename, message.toLocal8Bit());
}
return 0;
}
QT += core
CONFIG += c++11
CONFIG -= app_bundle
TARGET = stenog
TEMPLATE = app
SOURCES += \
main.cpp
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment