/**************************************************************************** ***************************Author: Agnit Sarkar****************************** **************************CopyRight: April 2009****************************** ********************* Email: agnitsarkar@yahoo.co.uk************************* ****************************************************************************/ #include "stegosaurus.h" StegoSaurus::StegoSaurus(QWidget *parent, Qt::WFlags flags) : QDialog(parent, flags) { ui.setupUi(this); bitsAvailable=0; sizeofData=0; inputFileSize=0; } StegoSaurus::~StegoSaurus() { } void StegoSaurus::on_btnDryImg_clicked() { static QString srcImgFileName="/home/"; srcImgFileName= QFileDialog::getOpenFileName(this, "Open Bitmap", srcImgFileName, "Bitmap Files(*.bmp)"); if(srcImgFileName.isEmpty()){ ui.lblDryImgDisplay->setText("

Drag Image Here

OR

Select it by browsing

(BMP Images only)

"); ui.lblDryImgDisplay->setPixmap(QPixmap(":/StegoSaurus/images/stegosaurus-256x256.png")); bitsAvailable=0; ui.txtDryImg->setText(""); ui.lblDryImgInfo->setText("No image Loaded"); return; } setDryImage(srcImgFileName); } void StegoSaurus::on_btnFiletoHide_clicked() { static QString srcFileName="/home/"; srcFileName= QFileDialog::getOpenFileName(this, "Open file to hide", srcFileName); if(srcFileName.isEmpty()){ inputFileSize=0; ui.txtFiletoHide->setText(""); ui.lblFiletoHideinfo->setText("No file loaded"); return; } //Get File information QFileInfo fi= QFileInfo(srcFileName); inputFileSize= fi.size(); ui.txtFiletoHide->setText(srcFileName); ui.lblFiletoHideinfo->setText(QString("Size=%L1 bytes").arg(inputFileSize)); } void StegoSaurus::resizeEvent(QResizeEvent * event) { //Set the label image if(ui.txtDryImg->text().isEmpty()) return; QPixmap pixmap(ui.txtDryImg->text()); pixmap= pixmap.scaledToHeight(ui.lblDryImgDisplay->height()); ui.lblDryImgDisplay->setPixmap(pixmap); QPixmap pixmap2(ui.txtWetImg->text()); pixmap2= pixmap2.scaledToHeight(ui.lblWetImgDisplay->height()); ui.lblWetImgDisplay->setPixmap(pixmap2); } void StegoSaurus::on_btnWetImg_clicked() { static QString srcImgFileName="/home/"; srcImgFileName= QFileDialog::getOpenFileName(this, "Open Bitmap", srcImgFileName, "Bitmap Files(*.bmp)"); if(srcImgFileName.isEmpty()){ ui.lblWetImgDisplay->setText("

Drag Image Here

OR

Select it by browsing

(BMP Images only)

"); ui.lblWetImgDisplay->setPixmap(QPixmap(":/StegoSaurus/images/stegosaurus-256x256.png")); ui.lblWetImgInfo->setText("No image loaded"); ui.txtWetImg->setText(""); sizeofData=0; return; } setWetImage(srcImgFileName); } void StegoSaurus::setDryImage(const QString &srcImgFileName) { //Get file info dryImage= new QImage(srcImgFileName); unsigned int height= dryImage->height(); unsigned int width= dryImage->width(); int depth= dryImage->depth(); //Check the depth, and return if it is not 24-bit if(depth<24){ QMessageBox::information(this, "StegoSaurus", "Must be 24-bit bitmap."); ui.txtDryImg->setText(""); ui.lblDryImgInfo->setText("No image Loaded"); return; } //Set the label image QPixmap pixmap(srcImgFileName); pixmap= pixmap.scaledToHeight(ui.lblDryImgDisplay->height()); ui.lblDryImgDisplay->setPixmap(pixmap); bitsAvailable= height*width*3; ui.txtDryImg->setText(srcImgFileName); if(bitsAvailable){ ui.lblDryImgInfo->setText(QString("Height= %L1 Width=%L2 Free Space=%L3 bytes").arg(height) .arg(width).arg(bitsAvailable/8)); }else{ ui.lblDryImgInfo->setText("No room for data"); qApp->beep(); } } void StegoSaurus::setWetImage(const QString &srcImgFileName) { //Get file info wetImage= new QImage(srcImgFileName); unsigned int height= wetImage->height(); unsigned int width= wetImage->width(); int depth= wetImage->depth(); //Check the depth, and return if it is not 24-bit if(depth<24){ QMessageBox::information(this, "StegoSaurus", "Must be 24-bit bitmap."); ui.txtWetImg->setText(""); ui.lblWetImgInfo->setText("No image Loaded"); return; } //Set the label image QPixmap pixmap(srcImgFileName); pixmap= pixmap.scaledToHeight(ui.lblWetImgDisplay->height()); ui.lblWetImgDisplay->setPixmap(pixmap); //Read the size of the embeded data QFile imgFile(srcImgFileName); if (!imgFile.open(QIODevice::ReadOnly)){ QMessageBox::warning(this, "StegoSaurus", "Unable to open bitmap file."); return; } if(imgFile.seek(6)){ imgFile.read((char *)&sizeofData, 4); }else{ QMessageBox::warning(this, "StegoSaurus", "Unable to read bitmap file."); return; } ui.txtWetImg->setText(srcImgFileName); if(sizeofData){ ui.lblWetImgInfo->setText(QString("Height= %L1 Width=%L2 Probable Size of Data=%L3 bytes").arg(height) .arg(width).arg(sizeofData)); }else{ ui.lblWetImgInfo->setText("No data in image."); qApp->beep(); } } //The drag and drop methods void StegoSaurus::dragEnterEvent(QDragEnterEvent *event) { if(ui.tabWidget->currentIndex()==2)return; if (event->mimeData()->hasFormat("text/uri-list")){ QList urls = event->mimeData()->urls(); if (urls.isEmpty()) return; QString fileName = urls.first().toLocalFile(); //Check the extension if (fileName.isEmpty()||!fileName.endsWith(".bmp", Qt::CaseInsensitive)) return; event->acceptProposedAction(); } } void StegoSaurus::dropEvent(QDropEvent *event) { QList urls = event->mimeData()->urls(); if (urls.isEmpty()) return; QString fileName = urls.first().toLocalFile(); if (fileName.isEmpty()) return; switch(ui.tabWidget->currentIndex()){ case 0: setDryImage(fileName); break; case 1: setWetImage(fileName); break; default: break; } } //The hide methods void StegoSaurus::on_btnHide_clicked() { //Get the filenames QString imgFileName= ui.txtDryImg->text(); QString inputFileName= ui.txtFiletoHide->text(); //Check if both image file and data file has been selected if(imgFileName.isEmpty()||inputFileName.isEmpty()){ QMessageBox::information(this, "StegoSaurus", "Please select a bitmap image and a data file."); return; } //Now check if size of the data file is less than that of the space available if(inputFileSize*8>bitsAvailable){ QMessageBox::information(this, "StegoSaurus", "Not enough space available in image to hide the data."); return; } static QString targetImgName="/home/"; targetImgName= QFileDialog::getSaveFileName(this, "Save bitmap with data to", targetImgName, "Bitmap Files(*.bmp)"); if(targetImgName.isEmpty())return; //If an image file with the same name exists delete it and then copy, unless source and target are same if(imgFileName!=inputFileName){ QFile::remove(targetImgName); QFile::copy(imgFileName, targetImgName); } //Calculate the no. of padding bytes unsigned int width= dryImage->width(); unsigned int padding=0; if((width*3)%4==0) padding=0; unsigned int quotient= (width*3)/4; padding= 4*(quotient+1)- width*3; /////////////////////////////////Hide the data//////////////////////////////////////////// QFile inputFile(inputFileName); if (!inputFile.open(QIODevice::ReadOnly)){ QMessageBox::warning(this, "StegoSaurus", "Unable to open data file for reading."); return; } //Stamp the size of the data file to the reserved bytes of the image file QFile imgOutputFile(targetImgName); if (!imgOutputFile.open(QIODevice::ReadWrite)){ QMessageBox::warning(this, "StegoSaurus", "Unable to open bitmap file."); return; } if(imgOutputFile.seek(6)){ imgOutputFile.write((char *)&inputFileSize, 4); }else{ QMessageBox::warning(this, "StegoSaurus", "Unable to write to bitmap file."); return; } //Read the dataoffset of the bitmap unsigned int dataoffset=0; if(imgOutputFile.seek(10)){ imgOutputFile.read((char *)&dataoffset, 4); }else{ QMessageBox::warning(this, "StegoSaurus", "Unable to read bitmap file."); return; } //Move by dataoffset bytes if(!imgOutputFile.seek(dataoffset)){ QMessageBox::warning(this, "StegoSaurus", "Unable to read bitmap file."); return; } QProgressDialog progress("Embedding Data", "Cancel", 0, inputFileSize, this); progress.show(); unsigned int progresscount=0; unsigned int countBytes=0; while (!inputFile.atEnd()){ //Read a byte unsigned char dataByte=0; inputFile.getChar((char *)&dataByte); //Store each bit of the data byte in 1 byte of the image pixel //starting with the MSB for(int i=7; i>=0; i--){ //Get the bit at position i in the data byte unsigned char checkByte= 0x01; checkByte= checkByte<>i; unsigned char imageByte=0; //To ignore the padding bytes if(countBytes>=width*3){ countBytes= 0; //Advance the read pointer for(int j=0; jtext(); //Check image file has been selected if(imgFileName.isEmpty()){ QMessageBox::information(this, "StegoSaurus", "Please select a bitmap image."); return; } static QString targetFileName="/home/"; targetFileName= QFileDialog::getSaveFileName(this, "Save recovered data to", targetFileName, "All Files(*.*)"); if(targetFileName.isEmpty())return; //If a file with the same name exists delete it QFile::remove(targetFileName); //Calculate the no. of padding bytes unsigned int width= wetImage->width(); unsigned int padding=0; if((width*3)%4==0) padding=0; unsigned int quotient= (width*3)/4; padding= 4*(quotient+1)- width*3; /////////////////////////////////Recover the data//////////////////////////////////////////// QFile targetFile(targetFileName); if (!targetFile.open(QIODevice::WriteOnly)){ QMessageBox::warning(this, "StegoSaurus", "Unable to open data file."); return; } QFile imgInputFile(imgFileName); if (!imgInputFile.open(QIODevice::ReadOnly)){ QMessageBox::warning(this, "StegoSaurus", "Unable to open bitmap file."); return; } //Read the dataoffset of the bitmap unsigned int dataoffset=0; if(imgInputFile.seek(10)){ imgInputFile.read((char *)&dataoffset, 4); }else{ QMessageBox::warning(this, "StegoSaurus", "Unable to read bitmap file."); return; } //Move by dataoffset bytes if(!imgInputFile.seek(dataoffset)){ QMessageBox::warning(this, "StegoSaurus", "Unable to read bitmap file."); return; } QProgressDialog progress("Recovering Data", "Cancel", 0, sizeofData, this); progress.show(); unsigned int progresscount=0; unsigned int countBytes=0; //Iterate to recover targetFileSize bytes for(unsigned int byteNo= 0; byteNo< sizeofData; byteNo++){ //construct each byte unsigned char dataByte= 0x00; for(int bitNo=7; bitNo>=0; bitNo--){ unsigned char imageByte=0xFF; //To ignore the padding bytes if(countBytes>=width*3){ countBytes= 0; //Advance the read pointer for(int j=0; j