2012-01-11 113 views
6

我想写(使用libpng)一个16位灰度图像,其中每个点的颜色等于其坐标的总和。下面的代码应该产生一个16位的PNG,但产生8位像this。为什么?16位灰度PNG

#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; 
} 

回答

5

链接的图像在Windows 7的“属性”中显示为“16位”。我想你只是看到各种应用程序回落到转换为8位显示,这(我猜)是相当期望的,因为大多数显示设备不支持16位。

+0

Windows 7显示两个渐变填充三角形。这应该是16位图像的正方形和8位的三角形。 – Yagg 2012-01-11 12:02:20

+0

哦,你是对的。我再次用libpng读取图像并测试点的颜色。他们应该如此。 – Yagg 2012-01-11 13:08:45

1

对不起复活旧的线程,但我在这里搜索后如何编写16位灰度图像。我遇到了类似的问题,我认为发布我如何解决问题会很有帮助。

TL; DR:

一)字节必须提供图书馆MSB第一,所以如果你翻车了上面这行它的工作原理:

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

二)要真正看到8位屏幕上的16位值,256以下的任何值将被简单地修剪为黑色。实际上,应该使用256倍数的值来查看任何内容。上面的color = x + y代码可能不会产生足够明亮的值。

我如何得到了上述结论:

我开始用上面的代码,只用“X”的颜色,而不是“X + Y”。

意图是有一个渐变,从左边的黑色渐变为右边的最大值x。

但是,我没有一个长渐变,而是得到了几个窄渐变。这个尖叫声“错误的ENDIANNESS!”

我尝试颠倒位,但后来我得到了一个黑色的图像。花了我一段时间才找到线索,但由于屏幕只显示8位,所以即使(在我的情况下)968的最大值太暗。这在8位屏幕上映射到2或3,甚至在高伽玛的情况下,我也看不出差异。

因为我知道我的最大X大约是1000,并且16位值的最大值是65000 ish,所以我用(x * 60)作为我的颜色。最终产生了可见的结果。

感谢您的原始文章。这是一个很好的例子,开始。