2012-01-11 21 views
6

Sto provando a scrivere (usando libpng) un'immagine in scala di grigi a 16 bit dove ogni colore punto è uguale alla somma delle sue coordinate. Il seguente codice dovrebbe produrre un PNG a 16 bit, ma produce invece 8-bit come this. Perché?16 bit in scala di grigi 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; 
} 

risposta

5

L'immagine collegata all'immagine viene visualizzata come "16 bit" in "Proprietà" di Windows 7. Immagino tu stia vedendo le varie applicazioni tornare alla conversione fino a 8 bit per la visualizzazione, il che (presumo) è abbastanza prevedibile poiché la maggior parte dei dispositivi di visualizzazione non supporta 16 bit.

+0

Windows 7 mostra due triangoli pieni di sfumature. Questo dovrebbe essere un quadrato per immagine a 16 bit e triangolo per 8 bit. – Yagg

+0

Oh, hai ragione. Ho letto di nuovo l'immagine con libpng e ho testato i colori del punto. Loro come dovrebbero essere. – Yagg

1

Mi dispiace per la risurrezione di un thread precedente, ma sono arrivato qui dopo aver cercato su Google come scrivere immagini in scala di grigi a 16 bit. Ho avuto problemi simili e ho pensato che sarebbe stato utile postare come ho risolto il problema.

TL; DR:

a) I byte devono essere forniti alla biblioteca MSB prima, quindi funziona se lanciate le linee sopra a questo:

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

b) Per vedere effettivamente un valore a 16 bit su uno schermo a 8 bit, qualsiasi valore inferiore a 256 verrà semplicemente tagliato in nero. In pratica, i valori multipli di 256 devono essere usati per vedere qualcosa. Il codice colore = x + y sopra probabilmente non ha prodotto valori abbastanza luminosi.

Come ho avuto modo di le conclusioni di cui sopra:

Ho iniziato con il codice di cui sopra, utilizzando solo 'x' come il colore, non e 'x + y'.

L'intento era quello di avere un gradiente che sfumasse dal nero a sinistra a qualunque fosse il massimo x a destra.

Tuttavia, invece di avere un gradiente lungo, stavo ottenendo diverse sfumature strette. Questo ha gridato "ERRATA ENDANITÀ!"

Ho provato a invertire i bit, ma poi ho ottenuto un'immagine nera. Mi ci è voluto un po 'per capire, ma dato che lo schermo mostra solo 8 bit, anche il valore massimo di (nel mio caso) 968 era troppo scuro. Questo è mappato su 2 o 3 su uno schermo a 8 bit, e anche con l'alta gamma non ho potuto vedere la differenza.

Poiché sapevo che il mio max X era circa 1000, e che il valore massimo per un valore a 16 bit è 65000 ish, quindi ho usato (x * 60) come colore. Questo ha finito per produrre un risultato visibile.

Grazie per il post originale. È stato un ottimo esempio per iniziare.