Skip to content

Commit

Permalink
BMP strider calculater low range bug fixed, improved bmp image load/s…
Browse files Browse the repository at this point in the history
…ave, import image function
  • Loading branch information
0xMartin committed Feb 12, 2024
1 parent 9000cd0 commit 0469df5
Show file tree
Hide file tree
Showing 13 changed files with 186 additions and 26 deletions.
30 changes: 18 additions & 12 deletions BMPEditor/Base/bmpio.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#include "bmpio.h"

#include <fstream>
#include <iostream>
#include <QFile>
#include <QDebug>

#include "../Base/error.h"
Expand All @@ -20,8 +19,9 @@ int BMP_IO_loadBMPImage(const QString &path,
}

// soubor ze ktereho bude nacitan BMP obrazke (binarni cteni)
std::ifstream file(path.toStdString(), std::ios::binary | std::ios::in);
if (!file.is_open()) {
//std::ifstream file(path.toStdString(), std::ios::binary);
QFile file(path);
if (!file.open(QIODevice::ReadOnly)) {
return ERR_FILE_OPEN;
}
qDebug() << "BMP LOAD - file opened";
Expand Down Expand Up @@ -70,11 +70,11 @@ int BMP_IO_loadBMPImage(const QString &path,
qDebug() << "BMP LOAD - image pixel array allocated (" << pixArrSiz << ")";

// vypocet stride (musi byt dorovnany na 32b, posledni bity jsou 0)
uint16_t stride = BMP_IO_calculateStride(infoHeader.bitCount, infoHeader.width);
uint32_t stride = BMP_IO_calculateStride(infoHeader.bitCount, infoHeader.width);
qDebug() << "BMP LOAD - stride size: " << stride;

// nacteni vsech pixelu obrazku z data bufferu
file.seekg(fileHeader.offset);
file.seek(fileHeader.offset);
uint32_t index = 0;
uint32_t offset = 0;
RGBQUAD_t color;
Expand Down Expand Up @@ -138,8 +138,9 @@ int BMP_IO_saveBMPImage(const QString &path,
qDebug() << "BMP SAVE - header validated";

// ovevre soubor pro zapis dat
std::ofstream file(path.toStdString(), std::ios::binary);
if (!file.is_open()) {
//std::ofstream file(path.toStdString(), std::ios::binary);
QFile file(path);
if (!file.open(QIODevice::WriteOnly)) {
return ERR_FILE_OPEN;
}
qDebug() << "BMP SAVE - file opened";
Expand All @@ -159,7 +160,7 @@ int BMP_IO_saveBMPImage(const QString &path,
}

// vypocet stride
uint16_t stride = BMP_IO_calculateStride(infoHeader.bitCount, infoHeader.width);
uint32_t stride = BMP_IO_calculateStride(infoHeader.bitCount, infoHeader.width);
qDebug() << "BMP SAVE - stride size: " << stride;

// zapis dat obrazku (inverzni zpusob jak u cteni)
Expand Down Expand Up @@ -220,8 +221,13 @@ int BMP_IO_saveBMPImage(const QString &path,
delete[] buff;
qDebug() << "BMP image data writing done (" << infoHeader.width << "; " << infoHeader.height << ")";

// flush
file.flush();

// overeni zda data byli spravne zapsany
if (!file.good()) {
if (file.error() != QFile::NoError) {
qDebug() << "BMP write to file error:" << file.errorString();
file.close();
return ERR_FILE_WRITE;
}

Expand All @@ -230,9 +236,9 @@ int BMP_IO_saveBMPImage(const QString &path,
return STATUS_OK;
}

uint16_t BMP_IO_calculateStride(uint8_t bitCount, uint16_t width)
uint32_t BMP_IO_calculateStride(uint8_t bitCount, uint16_t width)
{
uint16_t stride = bitCount * width;
uint32_t stride = bitCount * width;
if (stride % 32 != 0)
stride = (stride | 31) + 1;
stride /= 8;
Expand Down
2 changes: 1 addition & 1 deletion BMPEditor/Base/bmpio.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,6 @@ extern int BMP_IO_saveBMPImage(const QString & path,
* @param width - Sirka obrazku v pixelech
* @return Velikost stride
*/
extern uint16_t BMP_IO_calculateStride(uint8_t bitCount, uint16_t width);
extern uint32_t BMP_IO_calculateStride(uint8_t bitCount, uint16_t width);

#endif // BMPIO_H
4 changes: 2 additions & 2 deletions BMPEditor/Base/formatter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ static int FORMATTER_formatToBMPWithPalette(Image *src, Image **dst, uint8_t bit
bmpOut->bitDepth = bitCount;

// vypocet stride
uint16_t stride = BMP_IO_calculateStride(bmpOut->bitDepth, bmpOut->width);
uint32_t stride = BMP_IO_calculateStride(bmpOut->bitDepth, bmpOut->width);

// number of colors
uint16_t paletteSize = 1 << bitCount;
Expand Down Expand Up @@ -150,7 +150,7 @@ int FORMATTER_formatToBMP24(Image *src, Image **dst)
bmp24->bitDepth = 24;

// vypocet stride
uint16_t stride = BMP_IO_calculateStride(bmp24->bitDepth, bmp24->width);
uint32_t stride = BMP_IO_calculateStride(bmp24->bitDepth, bmp24->width);

// incializace BMP file header
bmp24->bmpFileHeader.type = 0x4D42; // 'BM'
Expand Down
43 changes: 43 additions & 0 deletions BMPEditor/Base/image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include "error.h"
#include <filesystem>
#include <QDebug>
#include <QFile>
#include <QImageReader>

Image::Image() {
this->type = IMG_NONE;
Expand Down Expand Up @@ -41,6 +43,47 @@ QString Image::getName() const {
return QString::fromStdString(fileName);
}

int Image::importImage(const QString &filePath)
{
// overeni existence souboru
if (!QFile::exists(filePath)) {
qDebug() << "File not exists: " << filePath;
return ERR_FILE_OPEN;
}

// image reader
QImageReader reader(filePath);

// nacteni informaci o obrazku
QSize imageSize = reader.size();

// nastaveni vlastnosti obrazku
this->imgPath = filePath;
this->width = imageSize.width();
this->height = imageSize.height();
this->bitDepth = 24;

// nacteni obrazku do pameti
QImage image = reader.read();
if (image.isNull()) {
qDebug() << "IMAGE read error: " << reader.errorString();
return ERR_FILE_READ;
}

// konverze formatu na RGB (pokud tomu tak jeste neni)
if (image.format() != QImage::Format_RGB888) {
image = image.convertToFormat(QImage::Format_RGB888);
}

// kopirovani dat z QImage do Image
image = image.mirrored(false, true);
this->dataLen = this->width * this->height * 3;
this->pixels = new unsigned char[this->dataLen];
memcpy(this->pixels, image.constBits(), this->dataLen);

return STATUS_OK;
}

int Image::buildImagePreview()
{
if(this->imagePreview != NULL) {
Expand Down
7 changes: 7 additions & 0 deletions BMPEditor/Base/image.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,13 @@ class Image
*/
QString getName() const;

/**
* @brief Univerzalni metoda pro import libovolneho typu obrazku
* @param filePath - Cesta k obrazku
* @return Error code
*/
int importImage(const QString &filePath);

};

#endif // IMAGE_H
5 changes: 3 additions & 2 deletions BMPEditor/Editor/imageinfopanel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ void ImageInfoPanel::setImage(Image *img) {

// paleta barev
this->colorPaletteFrame->getLabel()->setText("Color Palette");
int colorsPerRow = std::floor((this->width() - 50) / 32);
if(bmp->bmpInfoHeader.bitCount <= 8 && bmp->bmpInfoHeader.bitCount > 0) {
int row = 0;
int col = 0;
Expand All @@ -113,12 +114,12 @@ void ImageInfoPanel::setImage(Image *img) {
colorFrame->setFrameShape(QFrame::Box);
colorFrame->setFrameShadow(QFrame::Plain);
colorFrame->setLineWidth(1);
colorFrame->setFixedSize(22, 22);
colorFrame->setFixedSize(24, 24);
colorFrame->setToolTip(QString("RGB(%1, %2, %3)").arg(color.red).arg(color.green).arg(color.blue));
colorFrame->setStyleSheet(QString("background-color: rgb(%1, %2, %3);").arg(color.red).arg(color.green).arg(color.blue));
colorPalette->addWidget(colorFrame, row, col);
col++;
if (col >= 7) {
if (col >= colorsPerRow) {
col = 0;
row++;
}
Expand Down
39 changes: 39 additions & 0 deletions BMPEditor/Image/bmpimage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,3 +155,42 @@ int BMPImage::isBMPImage(Image *img, int bitDepth) {
}
return STATUS_OK;
}

int BMPImage::importAsBMP24(const QString &path)
{
// nacteni obrazovych dat do rodicovske tridy
int errCode = Image::importImage(path);
if(errCode != STATUS_OK) {
return errCode;
}

// vypocet stride ve finalnim BMP obrazku
uint32_t stride = BMP_IO_calculateStride(24, this->width);

// nastaveni typu obrazku
this->type = IMG_BMP;

// file header
this->bmpFileHeader.type = 0x4D42;
this->bmpFileHeader.size = sizeof(BitMapFileHeader_t) + sizeof(BitMapInfoHeader_t) + (stride * this->height);
this->bmpFileHeader.reserved1 = this->bmpFileHeader.reserved2 = 0;
this->bmpFileHeader.offset = sizeof(BitMapFileHeader_t) + sizeof(BitMapInfoHeader_t);

// info header
this->bmpInfoHeader.size = sizeof(BitMapInfoHeader_t);
this->bmpInfoHeader.width = this->width;
this->bmpInfoHeader.height = this->height;
this->bmpInfoHeader.planes = 1;
this->bmpInfoHeader.bitCount = 24;
this->bmpInfoHeader.compression = 0x0;
this->bmpInfoHeader.imageSize = (stride * this->height);
this->bmpInfoHeader.xPixelsPerMeter = 0x0;
this->bmpInfoHeader.yPixelsPerMeter = 0x0;
this->bmpInfoHeader.colorsUsed = 0;
this->bmpInfoHeader.colorsImportant = 0;

// sestaveni nahledu
this->buildImagePreview();

return STATUS_OK;
}
9 changes: 9 additions & 0 deletions BMPEditor/Image/bmpimage.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@ class BMPImage : public Image

// overeni formatu abstraktniho Image
static int isBMPImage(Image *img, int bitDepth);

/**
* @brief Obrazek libovolneho formatu importuje do aplikace jak BMP24. Pro nacteni
* obrazku z jeneho formatu nez BMP je pouzita knihovna. Dale uz se pouziva vlastni
* implementace pro praci z BMP
* @param path - Cesta k obrazku
* @return Error code
*/
int importAsBMP24(const QString &path);
};

#endif // BMPIMAGE_H
2 changes: 1 addition & 1 deletion BMPEditor/Struct/bmpstruct.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ int BMP_STRUCT_validate(const BitMapFileHeader_t& fileHeader, const BitMapInfoHe
return ERR_INVALID_FILE_OFFSET;
}

// overeni platnost hlavicky BMP obrazku
// overeni platnost info hlavicky BMP obrazku
if (infoHeader.size != 40) {
return ERR_INVALID_BMP_HEADER_SIZ;
}
Expand Down
2 changes: 1 addition & 1 deletion BMPEditor/about.ui
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>&lt;h1&gt;BMP Editor&lt;/h1&gt;&lt;b&gt;Author:&lt;/b&gt; Martin Krčma&lt;br&gt;&lt;b&gt;Last Update:&lt;/b&gt; 9. 2. 2024&lt;br&gt;&lt;b&gt;Version:&lt;/b&gt; 0.1.0</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;h1 style=&quot; margin-top:18px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:xx-large; font-weight:700;&quot;&gt;BMP Editor&lt;/span&gt;&lt;/h1&gt;&lt;p&gt;&lt;span style=&quot; font-weight:700;&quot;&gt;Author:&lt;/span&gt; Martin Krčma&lt;br/&gt;&lt;span style=&quot; font-weight:700;&quot;&gt;Last Update:&lt;/span&gt; 12. 2. 2024&lt;br/&gt;&lt;span style=&quot; font-weight:700;&quot;&gt;Version:&lt;/span&gt; 0.2.0&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
Expand Down
49 changes: 44 additions & 5 deletions BMPEditor/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ void MainWindow::appActionActivation()
this->ui->actionSharpen->setEnabled(enabled);
this->ui->actionEdge_Detection->setEnabled(enabled);
this->ui->actionEmboss->setEnabled(enabled);
this->ui->actionApply_Custom_Kernel->setEnabled(enabled);
// transformace
this->ui->actionRotate_90_plus->setEnabled(enabled);
this->ui->actionRotate_90_minus->setEnabled(enabled);
Expand All @@ -239,6 +240,16 @@ void MainWindow::appActionActivation()
this->ui->actionRead_message->setEnabled(enabled);
}

void MainWindow::checkForHiddenMessage()
{
// overi zda se v nactenem obrazku nenachazi zprava
QString msg = "";
int errCode = STEGANOGRAPHY_readMessage(this->image->pixels, this->image->width, this->image->height, msg);
if(errCode == STATUS_OK) {
QMessageBox::information(this, tr("Hidden message"), tr("The image contains a hidden message!\n\nMessage: %1").arg(msg));
}
}

void MainWindow::imageChanged(const QString &message)
{
// obrazek byl zmenen nejaky zpusobem
Expand Down Expand Up @@ -298,11 +309,7 @@ void MainWindow::on_actionOpen_triggered()
QMessageBox::information(this, tr("Open Image"), tr("Image opened successfully!"));

// overi zda se v nactenem obrazku nenachazi zprava
QString msg = "";
int errCode = STEGANOGRAPHY_readMessage(this->image->pixels, this->image->width, this->image->height, msg);
if(errCode == STATUS_OK) {
QMessageBox::information(this, tr("Hidden message"), tr("The image contains a hidden message!\n\nMessage: %1").arg(msg));
}
this->checkForHiddenMessage();
}

}
Expand Down Expand Up @@ -653,3 +660,35 @@ void MainWindow::on_actionApply_Custom_Kernel_triggered()
}
}


void MainWindow::on_actionImport_as_BMP_24_triggered()
{
// app: import image
QString fileName = QFileDialog::getOpenFileName(this, tr("Import Image As BMP 24b"), QDir::homePath(), tr("Images (*.bmp *.jpg *.jpeg *.png *.gif *.tiff)"));
if (!fileName.isEmpty()) {

qDebug() << "Import file: " << fileName;
BMPImage *bmp = new BMPImage();
this->statusLabel->setText(tr("<b>Status:</b> Image importing ..."));

int errCode = bmp->importAsBMP24(fileName);
if(errCode != STATUS_OK) {

// nastala chyba pri importu souboru
QString errorStr;
getErrorCodeInfo(errCode, errorStr);
QMessageBox::critical(this, tr("Import Error"), tr("Failed to import BMP image. Error: %1").arg(errorStr));
this->statusLabel->setText(tr("<b>Status:</b> Failed to import image"));

} else {
// obrazek uspesne nacten => zobrazeni v editoru
this->setImage(bmp);
QMessageBox::information(this, tr("Import Image"), tr("Image imported successfully!"));

// overi zda se v nactenem obrazku nenachazi zprava
this->checkForHiddenMessage();
}

}
}

5 changes: 3 additions & 2 deletions BMPEditor/mainwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,9 @@ class MainWindow : public QMainWindow
KernelInputDialog kernelInputDialog;

void closeEvent(QCloseEvent *event);

void formatBMP(int bitCount);

void appActionActivation();
void checkForHiddenMessage();

private slots:
void imageChanged(const QString &message);
Expand Down Expand Up @@ -133,6 +132,8 @@ private slots:

void on_actionApply_Custom_Kernel_triggered();

void on_actionImport_as_BMP_24_triggered();

private:
Ui::MainWindow *ui;
QSplitter * splitter_horizontal;
Expand Down
Loading

0 comments on commit 0469df5

Please sign in to comment.