Skip to content

Instantly share code, notes, and snippets.

@ziggi
Last active January 24, 2023 15:58
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ziggi/e15a95b9feac8f59c7c1 to your computer and use it in GitHub Desktop.
Save ziggi/e15a95b9feac8f59c7c1 to your computer and use it in GitHub Desktop.
bmp reader
#include <iostream>
#include <fstream>
#include "main.h"
int main(int argc, char *argv[])
{
if (argc < 2) {
std::cout << "Usage: " << argv[0] << " file_name" << std::endl;
return 0;
}
char *fileName = argv[1];
// открываем файл
std::ifstream fileStream(fileName, std::ifstream::binary);
if (!fileStream) {
std::cout << "Error opening file '" << fileName << "'." << std::endl;
return 0;
}
// заголовк изображения
BITMAPFILEHEADER fileHeader;
read(fileStream, fileHeader.bfType, sizeof(fileHeader.bfType));
read(fileStream, fileHeader.bfSize, sizeof(fileHeader.bfSize));
read(fileStream, fileHeader.bfReserved1, sizeof(fileHeader.bfReserved1));
read(fileStream, fileHeader.bfReserved2, sizeof(fileHeader.bfReserved2));
read(fileStream, fileHeader.bfOffBits, sizeof(fileHeader.bfOffBits));
if (fileHeader.bfType != 0x4D42) {
std::cout << "Error: '" << fileName << "' is not BMP file." << std::endl;
return 0;
}
// информация изображения
BITMAPINFOHEADER fileInfoHeader;
read(fileStream, fileInfoHeader.biSize, sizeof(fileInfoHeader.biSize));
// bmp core
if (fileInfoHeader.biSize >= 12) {
read(fileStream, fileInfoHeader.biWidth, sizeof(fileInfoHeader.biWidth));
read(fileStream, fileInfoHeader.biHeight, sizeof(fileInfoHeader.biHeight));
read(fileStream, fileInfoHeader.biPlanes, sizeof(fileInfoHeader.biPlanes));
read(fileStream, fileInfoHeader.biBitCount, sizeof(fileInfoHeader.biBitCount));
}
// получаем информацию о битности
int colorsCount = fileInfoHeader.biBitCount >> 3;
if (colorsCount < 3) {
colorsCount = 3;
}
int bitsOnColor = fileInfoHeader.biBitCount / colorsCount;
int maskValue = (1 << bitsOnColor) - 1;
// bmp v1
if (fileInfoHeader.biSize >= 40) {
read(fileStream, fileInfoHeader.biCompression, sizeof(fileInfoHeader.biCompression));
read(fileStream, fileInfoHeader.biSizeImage, sizeof(fileInfoHeader.biSizeImage));
read(fileStream, fileInfoHeader.biXPelsPerMeter, sizeof(fileInfoHeader.biXPelsPerMeter));
read(fileStream, fileInfoHeader.biYPelsPerMeter, sizeof(fileInfoHeader.biYPelsPerMeter));
read(fileStream, fileInfoHeader.biClrUsed, sizeof(fileInfoHeader.biClrUsed));
read(fileStream, fileInfoHeader.biClrImportant, sizeof(fileInfoHeader.biClrImportant));
}
// bmp v2
fileInfoHeader.biRedMask = 0;
fileInfoHeader.biGreenMask = 0;
fileInfoHeader.biBlueMask = 0;
if (fileInfoHeader.biSize >= 52) {
read(fileStream, fileInfoHeader.biRedMask, sizeof(fileInfoHeader.biRedMask));
read(fileStream, fileInfoHeader.biGreenMask, sizeof(fileInfoHeader.biGreenMask));
read(fileStream, fileInfoHeader.biBlueMask, sizeof(fileInfoHeader.biBlueMask));
}
// если маска не задана, то ставим маску по умолчанию
if (fileInfoHeader.biRedMask == 0 || fileInfoHeader.biGreenMask == 0 || fileInfoHeader.biBlueMask == 0) {
fileInfoHeader.biRedMask = maskValue << (bitsOnColor * 2);
fileInfoHeader.biGreenMask = maskValue << bitsOnColor;
fileInfoHeader.biBlueMask = maskValue;
}
// bmp v3
if (fileInfoHeader.biSize >= 56) {
read(fileStream, fileInfoHeader.biAlphaMask, sizeof(fileInfoHeader.biAlphaMask));
} else {
fileInfoHeader.biAlphaMask = maskValue << (bitsOnColor * 3);
}
// bmp v4
if (fileInfoHeader.biSize >= 108) {
read(fileStream, fileInfoHeader.biCSType, sizeof(fileInfoHeader.biCSType));
read(fileStream, fileInfoHeader.biEndpoints, sizeof(fileInfoHeader.biEndpoints));
read(fileStream, fileInfoHeader.biGammaRed, sizeof(fileInfoHeader.biGammaRed));
read(fileStream, fileInfoHeader.biGammaGreen, sizeof(fileInfoHeader.biGammaGreen));
read(fileStream, fileInfoHeader.biGammaBlue, sizeof(fileInfoHeader.biGammaBlue));
}
// bmp v5
if (fileInfoHeader.biSize >= 124) {
read(fileStream, fileInfoHeader.biIntent, sizeof(fileInfoHeader.biIntent));
read(fileStream, fileInfoHeader.biProfileData, sizeof(fileInfoHeader.biProfileData));
read(fileStream, fileInfoHeader.biProfileSize, sizeof(fileInfoHeader.biProfileSize));
read(fileStream, fileInfoHeader.biReserved, sizeof(fileInfoHeader.biReserved));
}
// проверка на поддерку этой версии формата
if (fileInfoHeader.biSize != 12 && fileInfoHeader.biSize != 40 && fileInfoHeader.biSize != 52 &&
fileInfoHeader.biSize != 56 && fileInfoHeader.biSize != 108 && fileInfoHeader.biSize != 124) {
std::cout << "Error: Unsupported BMP format." << std::endl;
return 0;
}
if (fileInfoHeader.biBitCount != 16 && fileInfoHeader.biBitCount != 24 && fileInfoHeader.biBitCount != 32) {
std::cout << "Error: Unsupported BMP bit count." << std::endl;
return 0;
}
if (fileInfoHeader.biCompression != 0 && fileInfoHeader.biCompression != 3) {
std::cout << "Error: Unsupported BMP compression." << std::endl;
return 0;
}
// rgb info
RGBQUAD **rgbInfo = new RGBQUAD*[fileInfoHeader.biHeight];
for (unsigned int i = 0; i < fileInfoHeader.biHeight; i++) {
rgbInfo[i] = new RGBQUAD[fileInfoHeader.biWidth];
}
// определение размера отступа в конце каждой строки
int linePadding = ((fileInfoHeader.biWidth * (fileInfoHeader.biBitCount / 8)) % 4) & 3;
// чтение
unsigned int bufer;
for (unsigned int i = 0; i < fileInfoHeader.biHeight; i++) {
for (unsigned int j = 0; j < fileInfoHeader.biWidth; j++) {
read(fileStream, bufer, fileInfoHeader.biBitCount / 8);
rgbInfo[i][j].rgbRed = bitextract(bufer, fileInfoHeader.biRedMask);
rgbInfo[i][j].rgbGreen = bitextract(bufer, fileInfoHeader.biGreenMask);
rgbInfo[i][j].rgbBlue = bitextract(bufer, fileInfoHeader.biBlueMask);
rgbInfo[i][j].rgbReserved = bitextract(bufer, fileInfoHeader.biAlphaMask);
}
fileStream.seekg(linePadding, std::ios_base::cur);
}
// вывод
for (unsigned int i = 0; i < fileInfoHeader.biHeight; i++) {
for (unsigned int j = 0; j < fileInfoHeader.biWidth; j++) {
std::cout << std::hex
<< +rgbInfo[i][j].rgbRed << " "
<< +rgbInfo[i][j].rgbGreen << " "
<< +rgbInfo[i][j].rgbBlue << " "
<< +rgbInfo[i][j].rgbReserved
<< std::endl;
}
std::cout << std::endl;
}
return 1;
}
unsigned char bitextract(const unsigned int byte, const unsigned int mask) {
if (mask == 0) {
return 0;
}
// определение количества нулевых бит справа от маски
int
maskBufer = mask,
maskPadding = 0;
while (!(maskBufer & 1)) {
maskBufer >>= 1;
maskPadding++;
}
// применение маски и смещение
return (byte & mask) >> maskPadding;
}
#ifndef MAIN_H_INCLUDED
#define MAIN_H_INCLUDED
// CIEXYZTRIPLE stuff
typedef int FXPT2DOT30;
typedef struct {
FXPT2DOT30 ciexyzX;
FXPT2DOT30 ciexyzY;
FXPT2DOT30 ciexyzZ;
} CIEXYZ;
typedef struct {
CIEXYZ ciexyzRed;
CIEXYZ ciexyzGreen;
CIEXYZ ciexyzBlue;
} CIEXYZTRIPLE;
// bitmap file header
typedef struct {
unsigned short bfType;
unsigned int bfSize;
unsigned short bfReserved1;
unsigned short bfReserved2;
unsigned int bfOffBits;
} BITMAPFILEHEADER;
// bitmap info header
typedef struct {
unsigned int biSize;
unsigned int biWidth;
unsigned int biHeight;
unsigned short biPlanes;
unsigned short biBitCount;
unsigned int biCompression;
unsigned int biSizeImage;
unsigned int biXPelsPerMeter;
unsigned int biYPelsPerMeter;
unsigned int biClrUsed;
unsigned int biClrImportant;
unsigned int biRedMask;
unsigned int biGreenMask;
unsigned int biBlueMask;
unsigned int biAlphaMask;
unsigned int biCSType;
CIEXYZTRIPLE biEndpoints;
unsigned int biGammaRed;
unsigned int biGammaGreen;
unsigned int biGammaBlue;
unsigned int biIntent;
unsigned int biProfileData;
unsigned int biProfileSize;
unsigned int biReserved;
} BITMAPINFOHEADER;
// rgb quad
typedef struct {
unsigned char rgbBlue;
unsigned char rgbGreen;
unsigned char rgbRed;
unsigned char rgbReserved;
} RGBQUAD;
// read bytes
template <typename Type>
void read(std::ifstream &fp, Type &result, std::size_t size) {
fp.read(reinterpret_cast<char*>(&result), size);
}
// bit extract
unsigned char bitextract(const unsigned int byte, const unsigned int mask);
#endif // MAIN_H_INCLUDEDs
@rubot813
Copy link

rubot813 commented Dec 8, 2020

	fileStream.seekg(linePadding, std::ios_base::cur);

Забавно. Что будешь делать если картинка без паддинга?
malloc/new нужного тебе размера (linePadding * height).

Если картинка без паддинга то linePadding == 0 . Но там и без этого вариант такой себе.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment