16 бит в оттенках серого png - PullRequest
       42

16 бит в оттенках серого png

9 голосов
/ 11 января 2012

Я пытаюсь написать (используя libpng) 16-битное изображение в градациях серого, где каждый цвет точки равен сумме его координат.Следующий код должен генерировать 16-битный PNG, но вместо этого выдает 8-битный как this .Почему?

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <png.h>

void save_png(FILE* fp, long int size)
{
    png_structp png_ptr = NULL;
    png_infop info_ptr = NULL;
    size_t x, y;
    png_bytepp row_pointers;

    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (png_ptr == NULL) {
        return ;
    }

    info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == NULL) {
        png_destroy_write_struct(&png_ptr, NULL);
        return ;
    }

     if (setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_write_struct(&png_ptr, &info_ptr);
        return ;
    }

    png_set_IHDR(png_ptr, info_ptr,
                 size, size, // width and height
                 16, // bit depth
                 PNG_COLOR_TYPE_GRAY, // color type
                 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);

    /* Initialize rows of PNG. */
    row_pointers = (png_bytepp)png_malloc(png_ptr,
        size*png_sizeof(png_bytep));

    for (int i=0; i<size; i++)
       row_pointers[i]=NULL;

    for (int i=0; i<size; i++)
       row_pointers[i]=png_malloc(png_ptr, size*2);

    //set row data
    for (y = 0; y < size; ++y) {
        png_bytep row = row_pointers[y];
        for (x = 0; x < size; ++x) {
                short color = x+y;
                *row++ = (png_byte)(color & 0xFF);
                *row++ = (png_byte)(color >> 8);
        }
    }

    /* Actually write the image data. */
    png_init_io(png_ptr, fp);
    png_set_rows(png_ptr, info_ptr, row_pointers);
    png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
    //png_write_image(png_ptr, row_pointers);

    /* Cleanup. */
    for (y = 0; y < size; y++) {
        png_free(png_ptr, row_pointers[y]);
    }
    png_free(png_ptr, row_pointers);
    png_destroy_write_struct(&png_ptr, &info_ptr);
}

int main()
{
  FILE* f;
  if((f=fopen("test.png", "wb"))!=NULL)
  {
    save_png(f, 257);

    fclose(f);
  }
  return 0;
}

Ответы [ 2 ]

5 голосов
/ 11 января 2012

Связанное изображение отображается как «16-разрядный» в «Свойствах» Windows 7.Я полагаю, вы просто видите, как различные приложения возвращаются к 8-битному преобразованию для отображения, что (я полагаю) вполне ожидаемо, поскольку большинство устройств отображения не поддерживают 16-битные.

3 голосов
/ 27 января 2017

Извините за воскрешение старого потока, но я попал сюда после поиска в Google, как писать 16-битные изображения в градациях серого. Я столкнулся с похожими проблемами и подумал, что было бы полезно опубликовать, как я решил проблему.

TL; DR:

a) Сначала байты должны быть переданы в библиотеку MSB, поэтому она работает, если перевернуть строки выше к этому:

*row++ = (png_byte)(color >> 8);
*row++ = (png_byte)(color & 0xFF);

b) Чтобы увидеть 16-битное значение на 8-битном экране, любые значения ниже 256 будут просто обрезаны до черного. Практически говоря, значения, которые кратны 256, должны использоваться, чтобы увидеть что-либо вообще. Приведенный выше код color = x + y, вероятно, не дал достаточно ярких значений.

Как я пришел к выводам выше:

Я начал с приведенного выше кода, используя в качестве цвета только «x», а не «x + y».

Намерение состояло в том, чтобы иметь градиент, который постепенно исчезал от черного слева до любого максимального значения x справа.

Однако вместо одного длинного градиента я получил несколько узких градиентов. Это кричало "НЕПРАВИЛЬНАЯ КОНЕЧНОСТЬ!"

Я попытался инвертировать биты, но затем я получил черное изображение. Мне потребовалось некоторое время, чтобы понять, но, поскольку экран отображается только в 8 битах, даже максимальное значение (в моем случае) 968 было слишком темным. Это соответствует 2 или 3 на 8-битном экране, и даже с высокой гаммой я не мог видеть разницу.

Так как я знал, что мой максимальный X был примерно 1000, и что максимальное значение для 16-битного значения составляет 65000 иш, поэтому я использовал (x * 60) в качестве моего цвета. Это закончилось тем, что дало видимый результат.

Спасибо за оригинальный пост. Это был отличный пример для начала.

...