2014-10-01 8 views
0

Я пытаюсь записать 16-битное изображение RGB, используя libpng, где каждый точечный цвет поступает из экземпляра ввода «массив». Следующий код работает, но дает 8-битный код.Создание 16-битного изображения с помощью libpng

template<typename T> void savePNG(Array2<Vec3<T> > *arrayImg, const std::string filename){ 

    /* create file */ 
    FILE *fp = fopen(filename.c_str(), "wb"); 
    if (!fp){ 
     std::runtime_error("[write_png_file] File could not be opened for writing"); 
     return; 
    } 


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

    if (!png_ptr){ 
     std::runtime_error("[write_png_file] png_create_write_struct failed"); 
     return; 
    } 

    png_infop info_ptr = png_create_info_struct(png_ptr); 
    if (!info_ptr){ 
     std::runtime_error("[write_png_file] png_create_info_struct failed"); 
     return; 
    } 

    if (setjmp(png_jmpbuf(png_ptr))){ 
     std::runtime_error("[write_png_file] Error during init_io"); 
     return; 
    } 

    png_init_io(png_ptr, fp); 


    /* write header */ 
    if (setjmp(png_jmpbuf(png_ptr))){ 
     std::runtime_error("[write_png_file] Error during writing header"); 
     return; 
    } 

    png_set_IHDR(png_ptr, info_ptr, 
      (png_uint_32) arrayImg->dimension[0], (png_uint_32) arrayImg->dimension[1], 
      (png_byte) 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, 
      PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); 

    png_write_info(png_ptr, info_ptr); 


    /* write bytes */ 
    if (setjmp(png_jmpbuf(png_ptr))){ 
     std::runtime_error("[write_png_file] Error during writing bytes"); 
     return; 
    } 

    /* Initialize rows of PNG. */ 
    png_bytepp row_pointers = (png_bytepp) malloc (sizeof(png_bytep)*arrayImg->dimension[1]); 
    for (size_t y = 0; y < arrayImg->dimension[1]; ++y) { 
     row_pointers[y] = (png_bytep) malloc (png_get_rowbytes(png_ptr,info_ptr)); 
     for (size_t x = 0; x < arrayImg->dimension[0]; ++x) { 
      for (size_t k = 0; k < 3; k++) { 
       row_pointers[y][x*3+k] = (uint8_t) (clamp((*arrayImg)[y][x][k],T(0.0),T(1.0))*T(255)); 
      } 
     } 
    } 

    /* Writes PNG. */ 
    png_write_image(png_ptr, (png_bytepp) row_pointers); 


    /* end write */ 
    if (setjmp(png_jmpbuf(png_ptr))){ 
     std::runtime_error("[write_png_file] Error during end of write"); 
     return; 
    } 

    png_write_end(png_ptr, NULL); 

    /* cleanup heap allocation */ 
    for (size_t y=0; y<arrayImg->dimension[1]; y++){ 
     free(row_pointers[y]); 
    } 
    free(row_pointers); 

    fclose(fp); 
} 

Следующий код должен содержать 16-битную версию. Она производит изображение, которое имеет правильные размеры, но данные все смещены влево:

template<typename T> void savePNG(Array2<Vec3<T> > *arrayImg, const std::string filename){ 

    /* create file */ 
    FILE *fp = fopen(filename.c_str(), "wb"); 
    if (!fp){ 
     std::runtime_error("[write_png_file] File could not be opened for writing"); 
     return; 
    } 


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

    if (!png_ptr){ 
     std::runtime_error("[write_png_file] png_create_write_struct failed"); 
     return; 
    } 

    png_infop info_ptr = png_create_info_struct(png_ptr); 
    if (!info_ptr){ 
     std::runtime_error("[write_png_file] png_create_info_struct failed"); 
     return; 
    } 

    if (setjmp(png_jmpbuf(png_ptr))){ 
     std::runtime_error("[write_png_file] Error during init_io"); 
     return; 
    } 

    png_init_io(png_ptr, fp); 


    /* write header */ 
    if (setjmp(png_jmpbuf(png_ptr))){ 
     std::runtime_error("[write_png_file] Error during writing header"); 
     return; 
    } 

    png_set_IHDR(png_ptr, info_ptr, 
      (png_uint_32) arrayImg->dimension[0], (png_uint_32) arrayImg->dimension[1], 
      (png_byte) 16, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, 
      PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); 

    png_write_info(png_ptr, info_ptr); 


    /* write bytes */ 
    if (setjmp(png_jmpbuf(png_ptr))){ 
     std::runtime_error("[write_png_file] Error during writing bytes"); 
     return; 
    } 

    /* Initialize rows of PNG. */ 
    png_bytepp row_pointers = (png_bytepp) malloc (sizeof(png_bytep)*arrayImg->dimension[1]); 
    for (size_t y = 0; y < arrayImg->dimension[1]; ++y) { 
     row_pointers[y] = (png_bytep) malloc (png_get_rowbytes(png_ptr,info_ptr)); 
     for (size_t x = 0; x < arrayImg->dimension[0]; ++x) { 
      for (size_t k = 0; k < 3; k++) { 
       row_pointers[y][x*3+k] = (uint16_t) (clamp((*arrayImg)[y][x][k],T(0.0),T(1.0))*T(65535)); 
      } 
     } 
    } 

    /* Writes PNG. */ 
    png_write_image(png_ptr, (png_bytepp) row_pointers); 


    /* end write */ 
    if (setjmp(png_jmpbuf(png_ptr))){ 
     std::runtime_error("[write_png_file] Error during end of write"); 
     return; 
    } 

    png_write_end(png_ptr, NULL); 

    /* cleanup heap allocation */ 
    for (size_t y=0; y<arrayImg->dimension[1]; y++){ 
     free(row_pointers[y]); 
    } 
    free(row_pointers); 

    fclose(fp); 
} 

Мое понимание проблемы заключается в том, что данные в настоящее время получения усечены из-за png_byte, png_bytep и/или типов png_bytepp , Как я могу записать 16-битные данные в два 8 бит?

+0

_ «Что я делаю неправильно?» _ Это слишком расплывчато, [тщательно продумайте] (http://stackoverflow.com/help/mcve)! –

+1

Определить * «не работает» *. –

ответ

0

Если кто-либо сталкивается с такой проблемой. Вот несколько вариантов:

  • Try читать API ...
  • Используйте функцию void png_save_uint_16 (png_bytep buf, unsigned int i);
0

Ваш "к" подсчитывает байты, и у вас есть 6 байт на пиксель, а не 3.

петля

for (size_t k = 0; k < 3; k++) { 
    row_pointers[y][x*3+k] = (uint16_t)clamp(...); 
} 

должно быть что-то вроде

for (size_t k = 0; k < 6; k+=2) { 
    png_save_uint_16(row_pointers[y][x*6+k],(unsigned int)clamp(...); 
} 

Это будет толкать два байта в то время (результат вашего «зажим()» операции) в буфер при row_pointers [у].

+0

Именно это я и понял. – Rufus