Last active
January 24, 2023 15:58
-
-
Save ziggi/e15a95b9feac8f59c7c1 to your computer and use it in GitHub Desktop.
bmp reader
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Если картинка без паддинга то linePadding == 0 . Но там и без этого вариант такой себе.