Выходные данные libpng не ожидаемые - PullRequest
0 голосов
/ 19 ноября 2018

Я пытаюсь понять основные функции libpng. Для этого я использовал этот фрагмент и адаптировал его к своему собственному примеру.

int x, y;

png_byte color_type = PNG_COLOR_TYPE_RGBA;
png_byte bit_depth = 16;

png_structp png_ptr;
png_infop info_ptr;

auto create_image(const int height, const int width) {
    png_byte **rows = new png_byte *[height];
    for (auto i = 0; i < height; i++)
        rows[i] = new png_byte[width * 4];

    return rows;
}

auto modify_image(const int height, const int width, png_byte **rows) {
    for (auto i = 0; i < height; i++) {
        for (auto j = 0; j < width; j++) {
            // Red channel
            rows[i][j * 4 + 0] = (j * 127.) / width;
            // Blue channel
            rows[i][j * 4 + 2] = (i * 127.) / height;
            // Alpha channel
            rows[i][j * 4 + 3] = 127;
        }
    }
}

void write(const std::string& filename, const int height, const int width, png_byte** rows)
{
    /* create file */
    FILE *fp = fopen(filename.c_str(), "wb");
    if (!fp)
        abort_("[write_png_file] File %s could not be opened for writing", filename);


    /* initialize stuff */
    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

    if (!png_ptr)
        abort_("[write_png_file] png_create_write_struct failed");

    info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr)
        abort_("[write_png_file] png_create_info_struct failed");

    if (setjmp(png_jmpbuf(png_ptr)))
        abort_("[write_png_file] Error during init_io");

    png_init_io(png_ptr, fp);

    /* write header */
    if (setjmp(png_jmpbuf(png_ptr)))
        abort_("[write_png_file] Error during writing header");

    png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

    png_write_info(png_ptr, info_ptr);

    /* write bytes */
    if (setjmp(png_jmpbuf(png_ptr)))
        abort_("[write_png_file] Error during writing bytes");

    png_write_image(png_ptr, rows);

    /* end write */
    if (setjmp(png_jmpbuf(png_ptr)))
        abort_("[write_png_file] Error during end of write");

    png_write_end(png_ptr, NULL);

    fclose(fp);
}

Хотя, когда я запускаю свой код:

void render(const int height, const int width, const std::string &filename) {
    png_byte **rows = create_image(height, width);
    modify_image(height, width, rows);
    write(filename, height, width, rows);
}

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

Test result

Кроме того, я заметил, что эти два прямоугольника растянуты: при попытке визуализации круга я обнаружил, что круг был искажен, и удвоение его ширины делает его настоящим кругом ...

Наконец, я видел, что во втором прямоугольнике последняя строка представляется случайными данными (что не относится к первому прямоугольнику).

Пожалуйста, предложите, если у вас есть идеи.

1 Ответ

0 голосов
/ 19 ноября 2018

Вы создаете изображение с глубиной 16 бит, но используете 1 байт на канал. Выходное изображение состоит из нечетных / четных строк исходного изображения, помещаемых в одну строку. В основном каждая строка правого прямоугольника вызвана переполнением буфера. Вам необходимо выделить буферы, которые в два раза больше, то есть width * 4 * 2, и заполнить старшие и младшие байты каждого канала отдельно.

...