2013-09-16 1 views
4

Я пытаюсь выяснить, как создать растровый файл в C++ VS. В настоящее время я взял имя файла и добавил расширение «.bmp» для создания файла. Я хочу знать, как я могу изменить пиксели файла, превратив его в разные цвета или шаблоны (т. Е. Как шахматная доска). Это моя функция, которую у меня есть, и я считаю, что мне приходится отправлять 3 разных байта за раз в чтобы установить цвет пикселя.C++ Как создать файл растрового изображения

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); 
} 
+1

(1) Вы закрыли поток? (2) Вы можете изменить размер, изменив заголовок (это свойство в заголовке). –

+0

@CommuSoft. Когда объект выходит из области действия, его деструктор вызывается. 'деструктор' потока 'вызывает 'close'. Так что да, поток закрывается. – IInspectable

+0

Да, я закрыл поток – user2557642

ответ

3

Учитывая, что ваш writeHeader правильно реализован, это почти правильно. Вам необходимо исправить 2 проблемы:

  1. Вы пишете один int на цветной канал. Вместо этого это должен быть один байт. Вам нужно наложить литералы на unsigned char.
  2. Сканирование в растровых изображениях должно быть DWORD -определено. После вашего внутреннего цикла над col вам нужно написать дополнительные байты для учетной записи, если размер в байтах строки не будет кратным четырем.
+0

Большое спасибо за совет !!! Замена int на unsigned char работает. Теперь следующая проблема, которая у меня есть, - это фактически размер шахматной доски. Это на самом деле очень мало по сравнению с растровым изображением, которое я хотел создать. – user2557642

1

Вам необходимо форсировать выход, который будет записан в двоичном формате, а не текст, это выбирается при открытии файла/создать поток и вывести все значения, как байты, а не целые числа, это может сделайте несколько способов, возможно, проще всего написать chr(0) или chr(255) - вам также нужно запустить свой файл с заголовком - есть несколько форматов, которые заставляют это слишком долго входить в ответ здесь - некоторые из них до тех пор, пока все не так. В Wikipedia есть хорошее резюме.

В основном вам необходимо сообщить получающим приложениям, формат которых вы используете, количество строк, столбцов и порядок сохранения цветов.

6

Это две функции, которые я использую для своего кода (одна шкала серого, одно сохранение RGB).

Можете дать вам подсказку, что происходит не так. Примечание: они выполняются, чтобы работать, а не быть эффективными.

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 i.e 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 i.e 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); 
} 
+0

Ваши реализации не работают надежно. В вашем расчете 'biSizeImage' не учитываются отсканированные строки. Для несжатых изображений RGB это лучше всего установить на 0. Ваш расчет 'bfOffBits' не учитывает требования к выравниванию. Вместо этого используйте 'offsetof (BITMAPINFO, bmiColors [256])'. Вы также демпинг действительно случайных байтов ('empty'). Есть больше проблем, и он еще раз показывает: не сворачивайте свои собственные. Используйте [Компонент обработки изображений Windows] (http://msdn.microsoft.com/en-us/library/windows/desktop/ee719902.aspx) - он существует по какой-либо причине. – IInspectable