C ++ How to create a raster file

I am trying to figure out how to create a raster file in C ++ VS. Currently, I took the file name and added the extension ".bmp" to create the file. I want to know how I can change the pixels of a file, turning it into different colors or patterns (i.e. Like a chessboard). This is my function that I have, and I believe that I have to send 3 different bytes at a time in order to set the pixel color.

void makeCheckerboardBMP(string fileName, int squaresize, int n) { ofstream ofs; ofs.open(fileName + ".bmp"); writeHeader(ofs, n, n); for(int row = 0; row < n; row++) { for(int col = 0; col < n; col++) { if(col % 2 == 0) { ofs << 0; ofs << 0; ofs << 0; } else { ofs << 255; ofs << 255; ofs << 255; } } } } void writeHeader(ostream& out, int width, int height){ if (width % 4 != 0) { cerr << "ERROR: There is a windows-imposed requirement on BMP that the width be a multiple of 4.\n"; cerr << "Your width does not meet this requirement, hence this will fail. You can fix this\n"; cerr << "by increasing the width to a multiple of 4." << endl; exit(1); } BITMAPFILEHEADER tWBFH; tWBFH.bfType = 0x4d42; tWBFH.bfSize = 14 + 40 + (width*height*3); tWBFH.bfReserved1 = 0; tWBFH.bfReserved2 = 0; tWBFH.bfOffBits = 14 + 40; BITMAPINFOHEADER tW2BH; memset(&tW2BH,0,40); tW2BH.biSize = 40; tW2BH.biWidth = width; tW2BH.biHeight = height; tW2BH.biPlanes = 1; tW2BH.biBitCount = 24; tW2BH.biCompression = 0; out.write((char*)(&tWBFH),14); out.write((char*)(&tW2BH),40); } 
+4
source share
3 answers

If your writeHeader correctly implemented, it is almost correct. You need to fix 2 problems:

  • You write one int for each color channel. Instead, it should be one byte. You need to pass literals to an unsigned char .
  • Scanning in bitmap images must be DWORD limited. After your inner loop over col you need to write extra bytes for the account if the size in bytes of the string is not a multiple of four.
+3
source

These are the two functions that I use for my code (one grayscale, one RGB preservation).

You can give you a clue what is going wrong. Note: they are implemented to work, not to be effective.

 void SaveBitmapToFile( BYTE* pBitmapBits, LONG lWidth, LONG lHeight,WORD wBitsPerPixel, LPCTSTR lpszFileName ) { RGBQUAD palette[256]; for(int i = 0; i < 256; ++i) { palette[i].rgbBlue = (byte)i; palette[i].rgbGreen = (byte)i; palette[i].rgbRed = (byte)i; } BITMAPINFOHEADER bmpInfoHeader = {0}; // Set the size bmpInfoHeader.biSize = sizeof(BITMAPINFOHEADER); // Bit count bmpInfoHeader.biBitCount = wBitsPerPixel; // Use all colors bmpInfoHeader.biClrImportant = 0; // Use as many colors according to bits per pixel bmpInfoHeader.biClrUsed = 0; // Store as un Compressed bmpInfoHeader.biCompression = BI_RGB; // Set the height in pixels bmpInfoHeader.biHeight = lHeight; // Width of the Image in pixels bmpInfoHeader.biWidth = lWidth; // Default number of planes bmpInfoHeader.biPlanes = 1; // Calculate the image size in bytes bmpInfoHeader.biSizeImage = lWidth* lHeight * (wBitsPerPixel/8); BITMAPFILEHEADER bfh = {0}; // This value should be values of BM letters ie 0x4D42 // 0x4D = M 0×42 = B storing in reverse order to match with endian bfh.bfType = 'B'+('M' << 8); // <<8 used to shift 'M' to end // Offset to the RGBQUAD bfh.bfOffBits = sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER) + sizeof(RGBQUAD) * 256; // Total size of image including size of headers bfh.bfSize = bfh.bfOffBits + bmpInfoHeader.biSizeImage; // Create the file in disk to write HANDLE hFile = CreateFile( lpszFileName,GENERIC_WRITE, 0,NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,NULL); if( !hFile ) // return if error opening file { return; } DWORD dwWritten = 0; // Write the File header WriteFile( hFile, &bfh, sizeof(bfh), &dwWritten , NULL ); // Write the bitmap info header WriteFile( hFile, &bmpInfoHeader, sizeof(bmpInfoHeader), &dwWritten, NULL ); // Write the palette WriteFile( hFile, &palette[0], sizeof(RGBQUAD) * 256, &dwWritten, NULL ); // Write the RGB Data if(lWidth%4 == 0) { WriteFile( hFile, pBitmapBits, bmpInfoHeader.biSizeImage, &dwWritten, NULL ); } else { char* empty = new char[ 4 - lWidth % 4]; for(int i = 0; i < lHeight; ++i) { WriteFile( hFile, &pBitmapBits[i * lWidth], lWidth, &dwWritten, NULL ); WriteFile( hFile, empty, 4 - lWidth % 4, &dwWritten, NULL ); } } // Close the file handle CloseHandle( hFile ); } void SaveBitmapToFileColor( BYTE* pBitmapBits, LONG lWidth, LONG lHeight,WORD wBitsPerPixel, LPCTSTR lpszFileName ) { BITMAPINFOHEADER bmpInfoHeader = {0}; // Set the size bmpInfoHeader.biSize = sizeof(BITMAPINFOHEADER); // Bit count bmpInfoHeader.biBitCount = wBitsPerPixel; // Use all colors bmpInfoHeader.biClrImportant = 0; // Use as many colors according to bits per pixel bmpInfoHeader.biClrUsed = 0; // Store as un Compressed bmpInfoHeader.biCompression = BI_RGB; // Set the height in pixels bmpInfoHeader.biHeight = lHeight; // Width of the Image in pixels bmpInfoHeader.biWidth = lWidth; // Default number of planes bmpInfoHeader.biPlanes = 1; // Calculate the image size in bytes bmpInfoHeader.biSizeImage = lWidth* lHeight * (wBitsPerPixel/8); BITMAPFILEHEADER bfh = {0}; // This value should be values of BM letters ie 0x4D42 // 0x4D = M 0×42 = B storing in reverse order to match with endian bfh.bfType = 'B'+('M' << 8); // <<8 used to shift 'M' to end // Offset to the RGBQUAD bfh.bfOffBits = sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER); // Total size of image including size of headers bfh.bfSize = bfh.bfOffBits + bmpInfoHeader.biSizeImage; // Create the file in disk to write HANDLE hFile = CreateFile( lpszFileName,GENERIC_WRITE, 0,NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,NULL); if( !hFile ) // return if error opening file { return; } DWORD dwWritten = 0; // Write the File header WriteFile( hFile, &bfh, sizeof(bfh), &dwWritten , NULL ); // Write the bitmap info header WriteFile( hFile, &bmpInfoHeader, sizeof(bmpInfoHeader), &dwWritten, NULL ); // Write the palette //WriteFile( hFile, &palette[0], sizeof(RGBQUAD) * 256, &dwWritten, NULL ); // Write the RGB Data if(lWidth%4 == 0) { WriteFile( hFile, pBitmapBits, bmpInfoHeader.biSizeImage, &dwWritten, NULL ); } else { char* empty = new char[ 4 - lWidth % 4]; for(int i = 0; i < lHeight; ++i) { WriteFile( hFile, &pBitmapBits[i * lWidth], lWidth, &dwWritten, NULL ); WriteFile( hFile, empty, 4 - lWidth % 4, &dwWritten, NULL ); } } // Close the file handle CloseHandle( hFile ); } 
+6
source

You need to force the output in binary format, not text, it is selected when opening the file / creating a stream and outputting all values ​​as bytes, not integers, this can be done in several ways, perhaps the easiest of which is writing chr(0) or chr(255) - you also need to run your file using the header section - there are a number of formats that make it enter too long in the answer here - some of them prefer as you like. In Wikipedia .

Basically, you should tell the receiving applications whose format you are using the number of rows, columns, and color preservation order.

+1
source

Source: https://habr.com/ru/post/1502512/


All Articles