Изменение монохромного рисунка для растрового файла с использованием текущего цикла - PullRequest
0 голосов
/ 04 апреля 2019

Я пытаюсь изменить шаблон текущего файла растрового изображения, но у меня возникают проблемы с изменением моего вложенного цикла for, чтобы сделать это. Я пытаюсь получить растровый файл с 8 горизонтальными полосами, высотой 32 пикселя, чередующимися черным и белым. В настоящее время я получаю 64 вертикальные полосы, чередующиеся с черным и белым. Размеры растрового изображения составляют 256 на 256 пикселей.

Я запутался во вложенном цикле for в моем коде, который отвечает за сохранение белого цвета (0x0f) в моем многомерном массиве битов. Я заметил, что если я изменю белый цвет на черный (от 0x0f до 0x00), весь растровый файл станет черным. Ниже приведена часть кода, на которой я сконцентрировался для вывода шаблона, под которым у меня есть весь код.

// Build monochrome array of bits in image
    for (int i = 0; i < IMAGE_SIZE; i++) {
        for (int j = 0; j < IMAGE_SIZE / 8; j++) {
            bits[i][j] = 0x0f;
        }
    }
#include <iostream>
#include <fstream>
#include "windows.h"
using namespace std;
// The following defines the size of the square image in pixels.
#define IMAGE_SIZE 256
int main(int argc, char* argv[])
{

    BITMAPFILEHEADER bmfh;

    BITMAPINFOHEADER bmih;

    char colorTable[8] = { 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff };

    // The following defines the array which holds the image.  The row length 
    // (number of columns) is the height divided by 8, since there are 8 bits
    // in a byte.
    char bits[IMAGE_SIZE][IMAGE_SIZE / 8];

    // Define and open the output file. 
    ofstream bmpOut("foo.bmp", ios::out + ios::binary);
    if (!bmpOut) {
        cout << "...could not open file, ending.";
        return -1;
    }
    // Initialize the bit map file header with static values.
    bmfh.bfType = 0x4d42;
    bmfh.bfReserved1 = 0;
    bmfh.bfReserved2 = 0;
    bmfh.bfOffBits = sizeof(bmfh) + sizeof(bmih) + sizeof(colorTable);
    bmfh.bfSize = bmfh.bfOffBits + sizeof(bits);

    // Initialize the bit map information header with static values.
    bmih.biSize = 40;
    bmih.biWidth = IMAGE_SIZE;
    bmih.biHeight = IMAGE_SIZE;
    bmih.biPlanes = 1;
    bmih.biBitCount = 1;
    bmih.biCompression = 0;
    bmih.biSizeImage = 0;
    bmih.biXPelsPerMeter = 2835;  // magic number, see Wikipedia entry
    bmih.biYPelsPerMeter = 2835;
    bmih.biClrUsed = 0;
    bmih.biClrImportant = 0;

    // Build monochrome array of bits in image
    for (int i = 0; i < IMAGE_SIZE; i++) {
        for (int j = 0; j < IMAGE_SIZE / 8; j++) {
            bits[i][j] = 0x0f;
        }
    }

    // Write out the bit map.  
    char* workPtr;
    workPtr = (char*)&bmfh;
    bmpOut.write(workPtr, 14);
    workPtr = (char*)&bmih;
    bmpOut.write(workPtr, 40);
    workPtr = &colorTable[0];
    bmpOut.write(workPtr, 8);
    workPtr = &bits[0][0];
    bmpOut.write(workPtr, IMAGE_SIZE*IMAGE_SIZE / 8);
    bmpOut.close();

    // showing result
    system("mspaint foo.bmp");

    // Done.
    return 0;
}

1 Ответ

0 голосов
/ 04 апреля 2019

Вы неправильно заполняете свой массив битов.

Вы создаете 1-битное (монохромное) восходящее растровое изображение. Каждый отдельный бит в вашем массиве представляет отдельный пиксель, где бит 0 относится к первому цвету, а бит 1 относится ко второму цвету в вашей таблице цветов. И первая строка в растровом изображении - это строка последняя в массиве, а последняя строка в растровом изображении - это первая строка в массиве.

0x0F шестнадцатеричный код 00001111 двоичный. Вы устанавливаете каждый 8-битный char в своем массиве на 0x0f, поэтому вы создаете чередующийся шаблон из 4 0000 битов, за которыми следуют 4 1111 битов для каждой строки, например:

00001111 00001111 00001111 ... (for 29 more bytes)
00001111 00001111 00001111 ... (for 29 more bytes)
00001111 00001111 00001111 ... (for 29 more bytes)
... (for 253 more rows)

Для растрового изображения 256x256, которое создает 64 чередующихся вертикальных столбца шириной 4 пикселя каждый.

Чтобы получить желаемый эффект - 8 чередующихся горизонтальных полос, каждый из которых имеет высоту 32 пикселя, - необходимо установить для каждого бита в данной строке либо все 0, либо все 1, а затем вам нужно чередовать этот шаблон в группах по 32 полных ряда, например:

00000000 00000000 00000000 ... (for 29 more bytes)
00000000 00000000 00000000 ... (for 29 more bytes)
00000000 00000000 00000000 ... (for 29 more bytes)
... (for 29 more rows)

11111111 11111111 11111111 ... (for 29 more bytes)
11111111 11111111 11111111 ... (for 29 more bytes)
11111111 11111111 11111111 ... (for 29 more bytes)
... (for 29 more rows)

... (repeat the above 4 more times)

Попробуйте вместо этого что-нибудь еще:

// Build monochrome array of bits in image
bool isWhite = false;
for (int i = 0; i < IMAGE_SIZE; ) {
    char ch = isWhite ? 0xFF : 0x00;
    int row = (IMAGE_SIZE - 1) - i; // use row = i for a top-down bitmap ...

    for (int col = 0; col < (IMAGE_SIZE / 8); ++col) {
        bits[row][col] = ch;
    }

    // alternatively to the above loop:
    // memset(bits[row], isWhite ? 0xFF : 0x00, IMAGE_SIZE / 8);

    if ((++i % 32) == 0) isWhite = !isWhite;
}

Или:

// Build monochrome array of bits in image
bool isWhite = true;
for (int i = 0; i < IMAGE_SIZE; ++i) {
    if ((i % 32) == 0) isWhite = !isWhite;
    int row = (IMAGE_SIZE - 1) - i; // use row = i for a top-down bitmap ...

    char ch = isWhite ? 0xFF : 0x00;
    for (int col = 0; col < (IMAGE_SIZE / 8); ++col) {
        bits[row][col] = ch;
    }

    // alternatively to the above loop:
    // memset(bits[row], isWhite ? 0xFF : 0x00, IMAGE_SIZE / 8);
}

Или:

// Build monochrome array of bits in image
for (int i = 0; i < IMAGE_SIZE; ++i) {
    char ch = ((i % 64) < 32) ? 0x00 : 0xFF;
    int row = (IMAGE_SIZE - 1) - i; // use row = i for a top-down bitmap ...

    for (int col = 0; col < IMAGE_SIZE / 8; ++col) {
        bits[row][col] = ch;
    }

    // alternatively to the above loop:
    // memset(bits[row], ((i % 64) < 32) ? 0x00 : 0xFF, IMAGE_SIZE / 8);
}

При этом я бы предложил несколько дополнительных настроек для остальной части вашего кода:

#include <iostream>
#include <fstream>
#include <windows.h>
//#include <string.h> // if using memset() above...

// The following defines the size of the square image in pixels.
#define IMAGE_SIZE 256

// The following defines the size of each row in bytes.
#define BYTES_PER_ROW (IMAGE_SIZE / sizeof(BYTE))

int main()
{
    // Define and open the output file. 
    std::ofstream bmpOut("foo.bmp", std::ios::binary);
    if (!bmpOut)
    {
        std::cerr << "could not open file, ending.";
        return -1;
    }

    BITMAPFILEHEADER bmfh;
    BITMAPINFOHEADER bmih;
    RGBQUAD colorTable[2] = { {0x00,0x00,0x00,0x00}, {0xFF,0xFF,0xFF,0x00} };

    // The following defines the array which holds the image bits.  The row length 
    // (number of columns) is the height divided by 8, since there are 8 bits
    // in a byte.
    BYTE bits[IMAGE_SIZE][BYTES_PER_ROW];

    // Initialize the bitmap file header with static values.
    bmfh.bfType = 0x4d42;
    bmfh.bfReserved1 = 0;
    bmfh.bfReserved2 = 0;
    bmfh.bfOffBits = sizeof(bmfh) + sizeof(bmih) + sizeof(colorTable);
    bmfh.bfSize = bmfh.bfOffBits + sizeof(bits);

    // Initialize the bitmap information header with static values.
    bmih.biSize = sizeof(bmih);
    bmih.biWidth = IMAGE_SIZE;
    bmih.biHeight = IMAGE_SIZE; // positive for bottom-up, negative for top-down
    bmih.biPlanes = 1;
    bmih.biBitCount = 1;
    bmih.biCompression = BI_RGB;
    bmih.biSizeImage = 0;
    bmih.biXPelsPerMeter = 2835;  // magic number, see Wikipedia entry
    bmih.biYPelsPerMeter = 2835;
    bmih.biClrUsed = 0;
    bmih.biClrImportant = 0;

    // Build monochrome array of bits in image, see above...

    // Write out the bitmap.  
    bmpOut.write(reinterpret_cast<char*>(&bmfh), sizeof(bmfh));
    bmpOut.write(reinterpret_cast<char*>(&bmih), sizeof(bmih));
    bmpOut.write(reinterpret_cast<char*>(&colorTable), sizeof(colorTable));
    bmpOut.write(reinterpret_cast<char*>(&bits), sizeof(bits));

    if (!bmpOut)
    {
        std::cerr << "could not write file, ending.";
        return -1;
    }

    bmpOut.close();

    // showing result
    ShellExecuteA(NULL, NULL, "foo.bmp", NULL, NULL, SW_SHOW);

    // Done.
    return 0;
}
...