Простейшее чтение BMP-файла. Логика вынесена в класс.

This commit is contained in:
Евгений Титаренко 2024-04-01 13:58:08 +03:00
parent 5c69bc1034
commit 4af1f2f4a0
4 changed files with 133 additions and 21 deletions

View file

@ -3,4 +3,6 @@ project(image_test_cpp)
set(CMAKE_CXX_STANDARD 17)
add_executable(image_test_cpp main.cpp)
add_executable(image_test_cpp main.cpp
bmpimage.h
bmpimage.cpp)

68
bmpimage.cpp Normal file
View file

@ -0,0 +1,68 @@
#include "bmpimage.h"
BMPImage::BMPImage(BitmapFileHeader &fileHeader, BITMAPINFOHEADER &infoHeader, Pixel **pixelArray) {
this->fileHeader = fileHeader;
this->infoHeader = infoHeader;
this->pixelArray = pixelArray;
}
const uint32_t &BMPImage::width() const { return this->infoHeader.BitmapWidth; }
const uint32_t &BMPImage::height() const { return this->infoHeader.BitmapHeight; }
void BMPImage::write(const std::string &filename) {
{
std::ofstream ofs(filename, std::ios_base::binary);
ofs.write((char *) &this->fileHeader, sizeof(this->fileHeader));
ofs.write((char *) &this->infoHeader, sizeof(this->infoHeader));
uint32_t byteByRow = this->infoHeader.BitmapWidth * 3;
uint8_t padding = 4 - this->infoHeader.BitmapWidth % 4;
for (int i = 0; i < this->infoHeader.BitmapHeight; ++i) {
ofs.write((char *) pixelArray[i], byteByRow);
if (padding != 4) ofs.write(PADDING_ZEROES, padding); // Write padding
}
}
}
BMPImage readBMPImage(const std::string &filename) {
BitmapFileHeader bitmapFileHeader;
BITMAPINFOHEADER bitmapInfoHeader;
Pixel **pixelArray;
uint32_t DIB_Header_Size;
{
std::ifstream ifs(filename, std::ios_base::binary);
if (!ifs.good()) {
throw std::runtime_error("File read error");
}
ifs.seekg(0, std::ios::beg);
ifs.read((char *) &bitmapFileHeader, sizeof(bitmapFileHeader));
ifs.read((char *) &DIB_Header_Size, sizeof(DIB_Header_Size));
}
if (DIB_Header_Size != 40) {
throw std::runtime_error("Invalid header");
}
{
std::ifstream ifs(filename, std::ios_base::binary);
if (!ifs.good()) {
throw std::runtime_error("File read error");
}
ifs.seekg(14, std::ios::beg);
ifs.read((char *) &bitmapInfoHeader, sizeof(bitmapInfoHeader));
}
pixelArray = new Pixel *[bitmapInfoHeader.BitmapHeight];
{
std::ifstream ifs(filename, std::ios_base::binary);
if (!ifs.good()) {
throw std::runtime_error("File read error");
}
ifs.seekg(bitmapFileHeader.imageDataOffset, std::ios::beg);
uint32_t byteByRow = bitmapInfoHeader.BitmapWidth * 3;
uint8_t padding = 4 - bitmapInfoHeader.BitmapWidth % 4;
for (int i = 0; i < bitmapInfoHeader.BitmapHeight; ++i) {
pixelArray[i] = new Pixel[bitmapInfoHeader.BitmapWidth];
ifs.read((char *) pixelArray[i], byteByRow);
if (padding != 4) ifs.seekg(padding, std::ios_base::cur); // Skip padding
}
}
return {bitmapFileHeader, bitmapInfoHeader, pixelArray};
}

57
bmpimage.h Normal file
View file

@ -0,0 +1,57 @@
#pragma once
#include <cstdint>
#include <string>
#include <fstream>
const char PADDING_ZEROES[3] = {0, 0, 0};
#pragma pack(push, 1)
struct BitmapFileHeader {
char signature[2] = {0, 0};
uint32_t fileSize = 0;
uint16_t reserved1 = 0;
uint16_t reserved2 = 0;
uint32_t imageDataOffset = 0;
};
#pragma pack(pop)
#pragma pack(push, 1)
struct BITMAPINFOHEADER {
uint32_t HeaderSize = 0;
uint32_t BitmapWidth = 0;
uint32_t BitmapHeight = 0;
uint16_t ColorPlanes = 0;
uint16_t BitsPerPixel = 0;
uint32_t CompressionMethod = 0;
uint32_t ImageSize = 0;
int32_t HorizontalPixelPerMetre = 0;
int32_t VerticalPixelPerMetre = 0;
uint32_t NumberOfColors = 0;
uint32_t NumberOfImportantColors = 0;
};
#pragma pack(pop)
#pragma pack(push, 1)
struct Pixel {
uint8_t r = 0;
uint8_t g = 0;
uint8_t b = 0;
};
#pragma pack(pop)
class BMPImage {
BitmapFileHeader fileHeader;
BITMAPINFOHEADER infoHeader;
Pixel **pixelArray;
public:
BMPImage(BitmapFileHeader &fileHeader, BITMAPINFOHEADER &infoHeader, Pixel **pixelArray);
[[nodiscard]] const uint32_t &width() const;
[[nodiscard]] const uint32_t &height() const;
void write(const std::string &);
};
BMPImage readBMPImage(const std::string &filename);

View file

@ -1,27 +1,12 @@
#include <iostream>
#include <cstdint>
#include <filesystem>
#include <fstream>
#include "bmpimage.h"
struct BitmapFileHeader {
char signature[2] = {0, 0};
uint32_t fileSize = 0;
uint16_t reserved1 = 0;
uint16_t reserved2 = 0;
uint32_t imageDataOffset = 0;
};
const std::string FILENAME = "../elef.bmp";
const std::string FILENAME_OUT = "../elef_out.bmp";
const std::string FILENAME = "elef.bmp";
int main() {
BitmapFileHeader bitmapFileHeader;
{
std::ifstream ifs(FILENAME, std::ios_base::binary);
ifs.seekg(0, std::ios::beg);
ifs.read((char *) &bitmapFileHeader, 14);
}
std::cout << "Structure:\n" << "Signature: " << std::string(bitmapFileHeader.signature, 2) << "\nFile size: "
<< bitmapFileHeader.fileSize << "\nReserved 1: " << bitmapFileHeader.reserved1 << "\nReserved 2: "
<< bitmapFileHeader.reserved2 << "\nImage data offset: " << bitmapFileHeader.imageDataOffset << std::endl;
auto image = readBMPImage(FILENAME);
image.write(FILENAME_OUT);
return 0;
}