我正在尝试使用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;
}
答案 0 :(得分:5)
链接到图像在Windows 7的“属性”中显示为“16位”。我猜你只是看到各种应用程序回落到显示器的8位转换,我猜这是非常期待的,因为大多数显示设备不支持16位。
答案 1 :(得分:3)
很抱歉复活旧线程,但谷歌搜索后如何编写16位灰度图像。我遇到了类似的问题,我认为发布我解决问题的方法会很有帮助。
TL; DR:
a)必须首先将字节提供给库MSB,因此如果您将上面的行翻到此处,它就可以工作:
*row++ = (png_byte)(color >> 8);
*row++ = (png_byte)(color & 0xFF);
b)要在8位屏幕上实际看到16位值,256以下的任何值都将被剪切为黑色。实际上,应该使用256的几倍的值来查看任何内容。上面的color = x + y代码可能没有产生足够亮的值。
我如何得出上述结论:
我从上面的代码开始,仅使用&#39; x&#39;作为颜色,而不是&#39; x + y&#39;。
目的是让渐变从左边的黑色渐变到右边的最大x。
然而,我没有使用一个长梯度,而是获得了几个狭窄的渐变。这尖叫着&#34; WRONG ENDIANNESS!&#34;
我尝试反转这些位,但后来我得到了一张黑色图像。我花了一段时间才知道,但由于屏幕只显示8位,即使最大值(在我的情况下)968也太暗了。这在8位屏幕上映射到2或3,即使是高伽玛,我也看不出差异。
因为我知道我的最大X大约是1000,并且16位值的最大值是65000 ish,所以我使用(x * 60)作为我的颜色。最终产生了可见的结果。
感谢原帖。这是开始的一个很好的例子。