2012-01-11 30 views
6

Tôi đang cố gắng viết (sử dụng libpng) hình ảnh màu xám 16 bit, trong đó mỗi điểm màu bằng tổng của tọa độ của nó. Đoạn mã sau sẽ tạo ra PNG 16 bit, nhưng thay vào đó tạo ra 8-bit như this. Tại sao?16 bit grayscale 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; 
} 

Trả lời

5

Hình ảnh được liên kết hiển thị dưới dạng "16 bit" trong "Thuộc tính" của Windows 7. Tôi đoán bạn chỉ nhìn thấy các ứng dụng khác nhau rơi xuống để chuyển đổi xuống 8-bit để hiển thị, mà (tôi đoán) là khá mong đợi vì hầu hết các thiết bị hiển thị không hỗ trợ 16 bit.

+0

Windows 7 hiển thị hai hình tam giác tô đầy. Đây phải là hình vuông cho hình ảnh và hình tam giác 16 bit cho 8 bit. – Yagg

+0

Ồ, bạn nói đúng. Tôi đọc hình ảnh với libpng một lần nữa và kiểm tra màu sắc của điểm. Họ nên như vậy. – Yagg

1

Xin lỗi vì đã phục hồi một chuỗi cũ, nhưng tôi đã nhận được ở đây sau khi googling về cách viết 16 ảnh màu xám. Tôi đã gặp phải các vấn đề tương tự và tôi nghĩ rằng sẽ hữu ích khi đăng cách tôi giải quyết vấn đề.

TL; DR:

a) Các byte phải được cung cấp cho các thư viện MSB đầu tiên, vì vậy nó hoạt động nếu bạn lật các dòng ở trên để này:

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

b) Để thực sự thấy giá trị 16 bit trên màn hình 8 bit, bất kỳ giá trị nào dưới 256 sẽ chỉ được cắt bớt thành màu đen. Thực tế, các giá trị là bội số của 256 nên được sử dụng để xem bất cứ điều gì cả. Mã color = x + y ở trên có thể không tạo ra các giá trị đủ sáng.

Làm thế nào tôi đã đến kết luận trên:

tôi bắt đầu với đoạn code trên, chỉ sử dụng 'x' như màu sắc, không phải là 'x + y'.

Mục đích là có một độ dốc mờ dần từ màu đen ở bên trái đến bất kỳ giá trị nào của x tối đa ở bên phải.

Tuy nhiên, thay vì có một độ dốc dài, tôi đã nhận được một số gradient hẹp thay thế. Điều này hét lên "WRONG ENDIANNESS!"

Tôi đã thử đảo ngược các bit, nhưng sau đó tôi có một hình ảnh màu đen. Đã cho tôi một thời gian để đầu mối, nhưng kể từ khi màn hình chỉ hiển thị trong 8 bit, ngay cả giá trị tối đa (trong trường hợp của tôi) 968 là quá tối. Bản đồ này đến 2 hoặc 3 trên màn hình 8 bit và thậm chí với gamma cao, tôi không thể thấy sự khác biệt.

Vì tôi biết X tối đa của tôi xấp xỉ 1000 và giá trị tối đa cho giá trị 16 bit là 65000 ish nên tôi đã sử dụng (x * 60) làm màu của mình. Điều đó đã tạo ra một kết quả rõ ràng.

Cảm ơn bài đăng gốc. Đó là một ví dụ tuyệt vời để bắt đầu.