Как вывести bmp файл с
Перейти к содержимому

Как вывести bmp файл с

  • автор:

Read and write BMP file in C

And a simple test. I feel this one is a little messy. I’m not so sure about the helper functions I’ve made.

#include #include // for EXIT_SUCCESS and EXIT_FAILURE #include "bmp.h" BMPImage *read_image(const char *filename, char **error); void write_image(const char *filename, BMPImage *image, char **error); FILE *_open_file(const char *filename, const char *mode); void _handle_error(char **error, FILE *fp, BMPImage *image); void _clean_up(FILE *fp, BMPImage *image, char **error); int main(void) < char *error = NULL; BMPImage *image = read_image("6x6_24bit.bmp", &error); write_image("copy.bmp", image, &error); BMPImage *crop_image = crop_bmp(image, 2, 3, 4, 2, &error); write_image("crop.bmp", crop_image, &error); bool is_valid = check_bmp_header(&crop_image->header, fopen("crop.bmp", "rb")); _clean_up(NULL, image, &error); _clean_up(NULL, crop_image, &error); return EXIT_SUCCESS; > BMPImage *read_image(const char *filename, char **error) < FILE *input_ptr = _open_file(filename, "rb"); BMPImage *image = read_bmp(input_ptr, error); if (*error != NULL) < _handle_error(error, input_ptr, image); >fclose(input_ptr); return image; > void write_image(const char *filename, BMPImage *image, char **error) < FILE *output_ptr = _open_file(filename, "wb"); if (!write_bmp(output_ptr, image, error)) < _handle_error(error, output_ptr, image); >fclose(output_ptr); > /* * Open file. In case of error, print message and exit. */ FILE *_open_file(const char *filename, const char *mode) < FILE *fp = fopen(filename, mode); if (fp == NULL) < fprintf(stderr, "Could not open file %s", filename); exit(EXIT_FAILURE); >return fp; > /* * Print error message and clean up resources. */ void _handle_error(char **error, FILE *fp, BMPImage *image) < fprintf(stderr, "ERROR: %s\n", *error); _clean_up(fp, image, error); exit(EXIT_FAILURE); >/* * Close file and release memory. */ void _clean_up(FILE *fp, BMPImage *image, char **error) < if (fp != NULL) < fclose(fp); >free_bmp(image); free(*error); > 

Считать bmp побайтно и пересохранить

Author24 — интернет-сервис помощи студентам

необходимо открыть bmp файл, считать заголовок(читаю оба в одну структуру)
считать растровый массив( с этим походу и есть беда)
произвести манипуляции с массивом(это пока опустим)
и сохранить результат в новый bmp (пока что просто перезаписать этот файл с другим именем)
пробую так
насколько я понял, беда с чтением растрового массива. как его правильно читать?

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
#include int openBMP(char* path); int saveBMP(char* path); #pragma pack(push, 2) struct BmpHeader { unsigned char b1, b2; // Символы BM (2 байта) unsigned long size; // Размер файла (4 байта) unsigned short notUse1; // (2 байта) unsigned short notUse2; // (2 байта) unsigned long massPos; // Местанахождение данных растрового массива (4 байта) unsigned long headerLength; // Длинна этого заголовка (4 байта) unsigned long width; // Ширина изображения (4 байта) unsigned long height; // Высота изображения (4 байта) unsigned short colorPlaneNumber; // Число цветовых плоскостей (2 байта) unsigned short bitPixel; // Бит/пиксель (2 байта) unsigned long compressMethod; // Метод сжатия (4 байта) unsigned long massLength; // Длинна массива с мусоро (4 байта) unsigned long massWidth; // Ширина массива с мусором (4 байта) unsigned long massHeight; // Высота массива с мусором (4 байта) unsigned long colorNumber; // Число цветов изображения (4 байта) unsigned long generalColorNumber; // Число основных цветов (4 байта) } bmpHeader; #pragma pack(pop) unsigned char** img; int main(void) { if (readBMP("D:\\1.bmp") == 0) { printf("bad path"); return 0; } if (saveBMP("D:\\_1.bmp") == 0) { printf("bad path"); return 0; } return 0; } int readBMP(char* path)  FILE* file; int i, j; file = fopen(path,"rb"); if(file == NULL) return 0; fread(&bmpHeader, sizeof(bmpHeader), 1, file); if (bmpHeader.b1 != 'B'  img = (unsigned char**)calloc(bmpHeader.width, sizeof(*img)); for(i = 0; i  bmpHeader.width; ++i) img[i] = (unsigned char*)calloc(bmpHeader.height, sizeof(*img[i])); for (i = 0; i  bmpHeader.width; i++) { for (j = 0; j  bmpHeader.height; j++) { fread(&img[i][j], sizeof(img[i][j]), 1, file); } } fclose(file); return 1; } int saveBMP(char* path) { FILE* file; int i, j; file = fopen(path,"wb"); if(file == NULL) return 0; fwrite(&bmpHeader, sizeof(bmpHeader), 1, file); for (i = 0; i  bmpHeader.width; i++) { for (j = 0; j  bmpHeader.height; j++) { fwrite(&img[i][j], sizeof(img[i][j]), 1, file); } } fclose(file); return 1; }

Read and write bmp files in c/c++

The BMP format, often referred to as the Windows Bitmap Format is in my opinion, one of the simplest ways to store image information in a computer. Even though it was originally defined by Microsoft for its operating systems, nowadays its usage is widespread and can be recognized by practically every major imaging software. For the same reason, there are lots of libraries and APIs to work with images stored in this format.
The purpose of this post is to provide some guidance for those programmers who can’t or don’t want to use a third party library to work with images in the BMP format (e.g. targeting embedded platforms, developing sensitive proprietary software or for learning purposes). And even though our working example will be presented in the c language, it can be easily ported to other languages if necessary.

If you’re here just for the code, here’s a somewhat stripped-down implementation of the functions to open and save BMP files. Be aware that for legibility no safety validations are being performed (e.g. check for NULL pointers, validate file operations, etc.) as they are left to the reader. You can download the source code “bmp.c” and the sample image “img.bmp” from this link

img

#include #include #include #define DATA_OFFSET_OFFSET 0x000A #define WIDTH_OFFSET 0x0012 #define HEIGHT_OFFSET 0x0016 #define BITS_PER_PIXEL_OFFSET 0x001C #define HEADER_SIZE 14 #define INFO_HEADER_SIZE 40 #define NO_COMPRESION 0 #define MAX_NUMBER_OF_COLORS 0 #define ALL_COLORS_REQUIRED 0 typedef unsigned int int32; typedef short int16; typedef unsigned char byte; void ReadImage(const char *fileName,byte **pixels, int32 *width, int32 *height, int32 *bytesPerPixel) < FILE *imageFile = fopen(fileName, "rb"); int32 dataOffset; fseek(imageFile, DATA_OFFSET_OFFSET, SEEK_SET); fread(&dataOffset, 4, 1, imageFile); fseek(imageFile, WIDTH_OFFSET, SEEK_SET); fread(width, 4, 1, imageFile); fseek(imageFile, HEIGHT_OFFSET, SEEK_SET); fread(height, 4, 1, imageFile); int16 bitsPerPixel; fseek(imageFile, BITS_PER_PIXEL_OFFSET, SEEK_SET); fread(&bitsPerPixel, 2, 1, imageFile); *bytesPerPixel = ((int32)bitsPerPixel) / 8; int paddedRowSize = (int)(4 * ceil((float)(*width) / 4.0f))*(*bytesPerPixel); int unpaddedRowSize = (*width)*(*bytesPerPixel); int totalSize = unpaddedRowSize*(*height); *pixels = (byte*)malloc(totalSize); int i = 0; byte *currentRowPointer = *pixels+((*height-1)*unpaddedRowSize); for (i = 0; i < *height; i++) < fseek(imageFile, dataOffset+(i*paddedRowSize), SEEK_SET); fread(currentRowPointer, 1, unpaddedRowSize, imageFile); currentRowPointer -= unpaddedRowSize; >fclose(imageFile); > void WriteImage(const char *fileName, byte *pixels, int32 width, int32 height,int32 bytesPerPixel) < FILE *outputFile = fopen(fileName, "wb"); //*****HEADER************// const char *BM = "BM"; fwrite(&BM[0], 1, 1, outputFile); fwrite(&BM[1], 1, 1, outputFile); int paddedRowSize = (int)(4 * ceil((float)width/4.0f))*bytesPerPixel; int32 fileSize = paddedRowSize*height + HEADER_SIZE + INFO_HEADER_SIZE; fwrite(&fileSize, 4, 1, outputFile); int32 reserved = 0x0000; fwrite(&reserved, 4, 1, outputFile); int32 dataOffset = HEADER_SIZE+INFO_HEADER_SIZE; fwrite(&dataOffset, 4, 1, outputFile); //*******INFO*HEADER******// int32 infoHeaderSize = INFO_HEADER_SIZE; fwrite(&infoHeaderSize, 4, 1, outputFile); fwrite(&width, 4, 1, outputFile); fwrite(&height, 4, 1, outputFile); int16 planes = 1; //always 1 fwrite(&planes, 2, 1, outputFile); int16 bitsPerPixel = bytesPerPixel * 8; fwrite(&bitsPerPixel, 2, 1, outputFile); //write compression int32 compression = NO_COMPRESION; fwrite(&compression, 4, 1, outputFile); write image size (in bytes) int32 imageSize = width*height*bytesPerPixel; fwrite(&imageSize, 4, 1, outputFile); int32 resolutionX = 11811; //300 dpi int32 resolutionY = 11811; //300 dpi fwrite(&resolutionX, 4, 1, outputFile); fwrite(&resolutionY, 4, 1, outputFile); int32 colorsUsed = MAX_NUMBER_OF_COLORS; fwrite(&colorsUsed, 4, 1, outputFile); int32 importantColors = ALL_COLORS_REQUIRED; fwrite(&importantColors, 4, 1, outputFile); int i = 0; int unpaddedRowSize = width*bytesPerPixel; for ( i = 0; i < height; i++) < int pixelOffset = ((height - i) - 1)*unpaddedRowSize; fwrite(&pixels[pixelOffset], 1, paddedRowSize, outputFile); >fclose(outputFile); > int main()

The BMP file structure

The structure of a minimal BMP file looks like this:

Name Size Offset (Hex) Description/Notes
Bitmap File Header
BMP signature 2 bytes 0x00 The characters ‘B’ and ‘M’
File size 4 bytes 0x02 Size in bytes of the file including headers and pixel data
Reserved 4 bytes 0x06 Unused
Data offset 4 bytes 0x0A Offset in the file where the pixel data is stored
Bitmap Information Header
Size of the header 4 bytes 0x0E The header is fixed size: 40 bytes
Width 4 bytes 0x12 Width of the image in pixels
Height 4 bytes 0x16 Height of the image in pixels
Planes 2 bytes 0x1A Number of color planes (must be 1)
Bits per pixel 2 bytes 0x1C Number of bits per pixel
Compression 4 bytes 0x1E Compression method
Image size 4 bytes 0x22 Can be 0 if image is not compressed, otherwise is the size of the compressed image
Pixels per meter in X axis 4 bytes 0x26 Horizontal resolution in pixels per meter
Pixels per meter in Y axis 4 bytes 0x2A Vertical resolution in pixels per meter
Colors used 4 bytes 0x2E Number used colors
Important colors 4 bytes 0x32 Number of important color. Can be 0 If all colors are important
Color table Only if Bits per pixel
Data
Pixel data Variable Variable Stored bottom-up

As the table shows, there are mainly 3 parts:

  • Bitmap file header: provides information about the file itself.
  • Bitmap information header: contains the properties of the pixel data.
  • Data: the actual pixel data.

Most of the time you will be working with 24-bit RGB color or 8-bit grayscale images but it’s important to consider that in the case where the pixels are represented with less than 8 bits, a Color Table must be included in the bitmap information header. Other optional fields might be present in the file but for simplicity they are not covered in this post. For more information about this you can consult this Wikipedia article or this post by Nathan Liesch.

Reading a BMP file

To extract the pixel information you could decide to read every field from the header based on the table above. But in reality there are only 4 parts we’re interested in:

  • The data offset (so you know where the pixel data is)
  • Image height
  • Image width
  • Bits per pixel

This can be achieved with the regular fopen function by moving to the correct offset inside the file (using fseek):

 
#define DATA_OFFSET_OFFSET 0x000A #define WIDTH_OFFSET 0x0012 #define HEIGHT_OFFSET 0x0016 #define BITS_PER_PIXEL_OFFSET 0x001C FILE *imageFile = fopen(fileName, "rb"); int32 dataOffset; fseek(imageFile, DATA_OFFSET_OFFSET, SEEK_SET); fread(&dataOffset, 4, 1, imageFile); fseek(imageFile, WIDTH_OFFSET, SEEK_SET); fread(width, 4, 1, imageFile); fseek(imageFile, HEIGHT_OFFSET, SEEK_SET); fread(height, 4, 1, imageFile); int16 bitsPerPixel; fseek(imageFile, BITS_PER_PIXEL_OFFSET, SEEK_SET); fread(&bitsPerPixel, 2, 1, imageFile);

Once we have this information we can allocate enough memory to contain the pixel data, that is height x width x bytes per pixel (bits per pixel divided by 8).

At this point you might be tempted to just read the rest of the file starting from the data offset. If you do, you might notice that your image is upside-down and it has some extra pixels. Our example image would look like this:

weird

This is because the image is stored bottom-up and the rows contain padding bytes to make their size a multiple of 4. There are many ways of handling this situation. One option is to have a pointer to the last row of the (by now empty) pixel array, read a row from the file into that address (ignoring the padding bytes) and moving the pointer to the next row. The following code snippet illustrates this process:

//point to the last row of our pixel array (unpadded) byte *currentRowPointer = *pixels+((*height-1)*unpaddedRowSize); for (i = 0; i < *height; i++)

Now you have a pixel array to work with!

Writing BMP files

If you want other programs to be able to work with the a file you created, you need to adhere to the file’s structure specification. This is quite straightforward if you follow the table above. Look at the code sample for more details.

At this stage the key is to remember that rows must be padded to a multiple of 4 and stored bottom-up. To do this you can just reverse the process we used for reading the file:

 
for ( i = 0; i < height; i++) < //start writing from the beginning of last row in the pixel array int pixelOffset = ((height - i) - 1)*unpaddedRowSize; fwrite(&pixels[pixelOffset], 1, paddedRowSize, outputFile); >

And with that piece of code we covered the most basic operations. The provided source code was tested on Windows, Ubuntu and RHEL, but you might need to make some changes for other targets.

Notes for Windows users:
Make sure to open the output file in binary mode. Remember that in Windows line endings are represented with two characters (\n and \r). For this reason, if your file is open in text mode, every time you write the value 10 (0x0A, the \n character) an extra 13 will be added (0x0D, the \r character). These kind of errors are very difficult to debug without a Hex editor and lot of patience.

If you’re using Visual Studio you might experience problems with the fopen function. You can change it openf_s or add the _CRT_SECURE_NO_WARNINGS pre-processor definition as explained here.

You can use BITMAPFILEHEADER and BITMAPINFOHEADER to read/write the file header.

Notes for Linux users:
Since we’re using math.h remember to link your program with the -lm option (gcc and other compilers).

Вывод информации о *.bmp на чистом C++

Author24 — интернет-сервис помощи студентам

Dev-C++ это все компилировать не хочет (просто виснет), а VS 2008 выдает туеву хучу различных ошибок связанных с объявленными идентификаторами:

C:\Program Files\Microsoft Visual Studio 9.0\VC>cl new2.cpp Оптимизирующий 32-разрядный компилятор Microsoft (R) C/C++ версии 15.00.30729.01 для 80x86 (C) Корпорация Майкрософт (Microsoft Corporation). Все права защищены. new2.cpp C:\Program Files\Microsoft Visual Studio 9.0\VC\INCLUDE\xlocale(342) : warning C 4530: Использован обработчик исключений C++, но семантика уничтожения объектов н е включена. Задайте параметр /EHsc new2.cpp(41) : error C2059: синтаксическая ошибка: [ new2.cpp(52) : error C2062: тип "int" не требуется new2.cpp(72) : error C2051: значение выражения для варианта выбора не является к онстантой new2.cpp(76) : error C2051: значение выражения для варианта выбора не является к онстантой new2.cpp(80) : error C2051: значение выражения для варианта выбора не является к онстантой new2.cpp(84) : error C2051: значение выражения для варианта выбора не является к онстантой new2.cpp(88) : error C2051: значение выражения для варианта выбора не является к онстантой new2.cpp(90) : error C2065: OffBits: необъявленный идентификатор new2.cpp(90) : error C2668: pow: неоднозначный вызов перегруженной функции C:\Program Files\Microsoft Visual Studio 9.0\VC\INCLUDE\math.h(575): мож ет быть 'long double pow(long double,int)' C:\Program Files\Microsoft Visual Studio 9.0\VC\INCLUDE\math.h(527): или 'float pow(float,int)' C:\Program Files\Microsoft Visual Studio 9.0\VC\INCLUDE\math.h(489): или 'double pow(double,int)' при попытке сопоставить список аргументов '(int, int)' new2.cpp(92) : error C2065: OffBits: необъявленный идентификатор new2.cpp(95) : error C2051: значение выражения для варианта выбора не является к онстантой new2.cpp(100) : error C2051: значение выражения для варианта выбора не является константой new2.cpp(102) : error C2065: Width: необъявленный идентификатор new2.cpp(102) : error C2668: pow: неоднозначный вызов перегруженной функции C:\Program Files\Microsoft Visual Studio 9.0\VC\INCLUDE\math.h(575): мож ет быть 'long double pow(long double,int)' C:\Program Files\Microsoft Visual Studio 9.0\VC\INCLUDE\math.h(527): или 'float pow(float,int)' C:\Program Files\Microsoft Visual Studio 9.0\VC\INCLUDE\math.h(489): или 'double pow(double,int)' при попытке сопоставить список аргументов '(int, int)' new2.cpp(105) : error C2051: значение выражения для варианта выбора не является константой new2.cpp(107) : error C2065: Height: необъявленный идентификатор new2.cpp(107) : error C2668: pow: неоднозначный вызов перегруженной функции C:\Program Files\Microsoft Visual Studio 9.0\VC\INCLUDE\math.h(575): мож ет быть 'long double pow(long double,int)' C:\Program Files\Microsoft Visual Studio 9.0\VC\INCLUDE\math.h(527): или 'float pow(float,int)' C:\Program Files\Microsoft Visual Studio 9.0\VC\INCLUDE\math.h(489): или 'double pow(double,int)' при попытке сопоставить список аргументов '(int, int)' new2.cpp(110) : error C2051: значение выражения для варианта выбора не является константой new2.cpp(111) : error C2109: для индекса требуется массив или указатель new2.cpp(114) : error C2051: значение выражения для варианта выбора не является константой new2.cpp(115) : error C2065: biBitCount: необъявленный идентификатор new2.cpp(118) : error C2051: значение выражения для варианта выбора не является константой new2.cpp(119) : error C2065: biCompression: необъявленный идентификатор new2.cpp(122) : error C2051: значение выражения для варианта выбора не является константой new2.cpp(123) : error C2065: biSizeImage: необъявленный идентификатор new2.cpp(124) : error C2065: Size: необъявленный идентификатор new2.cpp(124) : error C2065: biSizeImage: необъявленный идентификатор new2.cpp(124) : error C2668: pow: неоднозначный вызов перегруженной функции C:\Program Files\Microsoft Visual Studio 9.0\VC\INCLUDE\math.h(575): мож ет быть 'long double pow(long double,int)' C:\Program Files\Microsoft Visual Studio 9.0\VC\INCLUDE\math.h(527): или 'float pow(float,int)' C:\Program Files\Microsoft Visual Studio 9.0\VC\INCLUDE\math.h(489): или 'double pow(double,int)' при попытке сопоставить список аргументов '(int, int)' new2.cpp(127) : error C2051: значение выражения для варианта выбора не является константой new2.cpp(128) : error C2065: biXPelsPerMeter: необъявленный идентификатор new2.cpp(131) : error C2051: значение выражения для варианта выбора не является константой new2.cpp(132) : error C2065: biYPelsPerMeter: необъявленный идентификатор new2.cpp(135) : error C2051: значение выражения для варианта выбора не является константой new2.cpp(136) : error C2065: biClrUsed: необъявленный идентификатор new2.cpp(139) : error C2051: значение выражения для варианта выбора не является константой new2.cpp(140) : error C2065: biClrImpotant: необъявленный идентификатор new2.cpp(145) : error C2065: Width: необъявленный идентификатор new2.cpp(146) : error C2065: Height: необъявленный идентификатор new2.cpp(148) : error C2057: требуется константное выражение new2.cpp(148) : error C2466: невозможно выделить память для массива постоянного нулевого размера new2.cpp(148) : error C2057: требуется константное выражение new2.cpp(148) : error C2466: невозможно выделить память для массива постоянного нулевого размера new2.cpp(148) : error C2087: pixels: отсутствует индекс new2.cpp(148) : error C2133: pixels: неизвестный размер new2.cpp(151) : error C2065: Size: необъявленный идентификатор new2.cpp(152) : error C2065: Width: необъявленный идентификатор new2.cpp(153) : error C2065: Height: необъявленный идентификатор

Хотя идентификаторы объявлены. В чем моя ошибка?

P.S. Программа до конца не доделана (есть лишние переменные, но на саму работу программы они повлиять не должны)

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *