libpng -- error: No es un archivo PNG -- png_process_data()

Estoy intentando escribir un lector progresivo usando libpng. He intentado seguir el código de ejemplo.c proporcionado con la fuente libpng pero no funciona. yo también he mirado libpng doc. Que te indica que uses png_set_progressive_read_fn() en conexión con png_process_data(). Después de configurar las cosas como se especifica en la documentación. Cuando voy a iniciar el proceso de lectura del archivo png, aparece el siguiente error de libpng.

No es un archivo PNG

Repasar el código revela que cuando png_process_data() va a verificar la firma del archivo PNG, identifica que no es un archivo png. Este es un comportamiento muy peculiar ya que antes de llamar a mi función de lectura verifico que el archivo es un archivo PNG con el siguiente código.

int check_png_sig(const char * file_name)
{
  FILE *fp = fopen(file_name, "rb");
  if(!fp) {
    return (0);
  }
  enum HeaderSize {Size = 8}; 
  png_byte header[Size];
  fread(header, 1, Size, fp);
  int is_png = !png_sig_cmp(header, 0, Size);
  if (!is_png) {
    fclose(fp);
    return (0);
  }
  fclose(fp);
  return (1);
}

Cierro el FILE* y luego reabrir uno nuevo en mi función de lectura para no tener que decirle a libpng que ya he leído 8 bytes con png_set_sig_bytes(png_ptr, 8);. Mi función de lectura es la siguiente.

int read_png_file(const char * file_name)
{
  fprintf(stdout, "Reading PNG File %s\n", file_name);
  fflush(stdout);

  if (!png_ptr || !info_ptr) {
    return (0);
  }

  FILE *fp = fopen(file_name, "rb");
  if(!fp) {
    return (0);
  }

  png_init_io(png_ptr, fp);
  png_voidp user_chunkp = png_get_user_chunk_ptr(png_ptr);

  /*
   * Tell libpng to call read_chunk_callback if an unknown chunk is
   * encountered
   */
  png_set_read_user_chunk_fn(png_ptr, user_chunkp, read_chunk_callback);

  /*
   * Tell libpng to call read_row_callback if an known chunk is
   * encountered.
   */
  png_set_read_status_fn(png_ptr, read_row_callback);

  /*
   * Tell libpng to call the specified functions on info, rows, or
   * end.
   */
  png_set_progressive_read_fn(png_ptr, user_chunkp, info_callback,
    row_callback, end_callback);

  enum Size {DataSize = 8};
  unsigned char rawbuf[DataSize];
  int process = 1;
  if (setjmp(png_jmpbuf(png_ptr))) {
    free_png_resources();
    process = 0;
    return process;
  }

  /*
   * Check to see if libpng is confused
   */
  //png_set_sig_bytes(png_ptr, 8);

  while (process) {
    memset(rawbuf, 0, DataSize);
    png_process_data(png_ptr, info_ptr, rawbuf, DataSize);
  }

  fclose(fp);
  return (process);
}

También tengo una versión funcional de un lector no progresivo en (lector no progresivo). Funciona bien en mi archivo. Así que no es un problema con mi archivo.


CODIGO COMPLETO

#include <png.h>
#include <stdlib.h>

static png_structp png_ptr;
static png_infop info_ptr;
static png_bytep old_row = NULL;

/* Variable that loops untill data is read */
int run = 0;

//-------------------------------------------------------------------
// Callbacks
int read_chunk_callback(png_structp png_ptr, png_unknown_chunkp chunk)
{
  struct chunk
  {
    png_byte name[5];
    png_byte *data;
    png_size_t size;
  };

  return (0); /* did not recognize */
}

/*
 * This method will be called each time a row is read
 * and differs from the row_callback in that ...
 */
void read_row_callback(png_structp ptr, png_uint_32 row, int pass)
{
  fprintf(stderr, "read_row_callback\n");
}

int process_data(png_bytep buffer, png_uint_32 length)
{
  fprintf(stderr, "process_data\n");
  png_process_data(png_ptr, info_ptr, buffer, length);
  return 0;
}

void info_callback(png_structp png_ptr, png_infop info)
{
  fprintf(stderr, "info_callback\n");
  png_uint_32 width;
  png_uint_32 height;
  int         bit_depth;
  int         color_type;
  int         interlace_type;
  int         compression_type;
  int         filter_type;
  png_byte    channels;
  png_uint_32 rowbytes;
  png_bytep   signature;

  /*
   * This will get the information stored in the header
   * of the PNG file.
   */
  png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
    &interlace_type, &compression_type, &filter_type);

  /*
   * Get the rest of the header information.
   */
  channels = png_get_channels(png_ptr, info_ptr);
  /* This is subject to change with transformations */
  rowbytes = png_get_rowbytes(png_ptr, info_ptr);
  signature = png_get_signature(png_ptr, info_ptr);

  fprintf(stdout,
    "width: %u"
    "height: %u"
    "bit_depth: %d"
    "color_type: %d"
    "interlace_type: %d"
    "compression_type: %d"
    "filter_type: %d"
    "channles: %d"
    "rowbytes: %u"
    "signature: %s", (unsigned int)width, (unsigned int)height, bit_depth, color_type,
    interlace_type, compression_type, filter_type, channels,
    (unsigned int)rowbytes, signature);
}

void row_callback(png_structp png_ptr, png_bytep new_row, png_uint_32 row_num,
  int pass)
{
  fprintf(stderr, "row_callback\n");
  png_progressive_combine_row(png_ptr, old_row, new_row);
}

void end_callback(png_structp png_ptr, png_infop info)
{
  fprintf(stderr, "end_callback\n");
  run = 1;
}

/*
 * Error handler local to his translation unit
 * Used by png_create_read_struct function.
 */
void progressive_reader_error_fn(png_structp png_ptr, png_const_charp msg)
{
  fprintf(stderr, "error: %s\n", msg);
  fflush(stderr);
  longjmp(png_jmpbuf(png_ptr), 1);
  exit(0);
}

//-------------------------------------------------------------------

/*
 * Free PNG resources on close
 */
void free_png_resources() 
{
  png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
  png_ptr = NULL;
  info_ptr = NULL;

}

/*
 * All strings to this function must
 * be null terminated -- return 0 if
 * file is not in png format
 */
int check_png_sig(const char * file_name)
{
  FILE *fp = fopen(file_name, "rb");
  if(!fp) {
    return (0);
  }
  enum HeaderSize {Size = 8};
  png_byte header[Size];
  fread(header, 1, Size, fp);
  int is_png = !png_sig_cmp(header, 0, Size);
  if (!is_png) {
    fclose(fp);
    return (0);
  }
  fclose(fp);
  return (1);
}

/*
 * Create the png_structp and png_infop
 */
int create_png_structs()
{
  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
    progressive_reader_error_fn, NULL);
  if (!png_ptr) {
    return 0;
  }

  info_ptr = png_create_info_struct(png_ptr);
  if (!info_ptr) {
    png_destroy_read_struct(&png_ptr, NULL, NULL);
    return 0;
  }

  if (setjmp(png_jmpbuf(png_ptr))) {
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
    return 0;
  }

  return 1;
}

/*
 * This method does all the work
 */
int read_png_file(const char * file_name)
{
  fprintf(stdout, "Reading PNG File %s\n", file_name);
  fflush(stdout);

  if (!png_ptr || !info_ptr) {
    return (0);
  }

  FILE *fp = fopen(file_name, "rb");
  if(!fp) {
    return (0);
  }

  png_init_io(png_ptr, fp);
  png_voidp user_chunkp = png_get_user_chunk_ptr(png_ptr);

  /*
   * Tell libpng to call read_chunk_callback if an unknown chunk is
   * encountered
   */
  png_set_read_user_chunk_fn(png_ptr, user_chunkp, read_chunk_callback);

  /*
   * Tell libpng to call read_row_callback if an known chunk is
   * encountered.
   */
  png_set_read_status_fn(png_ptr, read_row_callback);

  /*
   * Tell libpng to call the specified functions on info, rows, or
   * end.
   */
  png_set_progressive_read_fn(png_ptr, user_chunkp, info_callback,
    row_callback, end_callback);

  enum Size {DataSize = 8};
  unsigned char rawbuf[DataSize];
  int process = 1;
  if (setjmp(png_jmpbuf(png_ptr))) {
    free_png_resources();
    process = 0;
    return process;
  }

  /*
   * Check to see if libpng is confused
   */
  //png_set_sig_bytes(png_ptr, 8);

  while (process) {
    memset(rawbuf, 0, DataSize);
    png_process_data(png_ptr, info_ptr, rawbuf, DataSize);
  }

  fclose(fp);
  return (process);
}

int main(int argc, char *argv[])
{
  if (check_png_sig("/home/matt6809/Downloads/png_image.png")) {
    if (create_png_structs()) {
      if (read_png_file("/home/matt6809/Downloads/png_image.png")) {
        fprintf(stderr, "SUCCESS!!!\n");
      }   
    }
  } 
  return 0;
}

Makefile

CC = /usr/bin/gcc
LD = /usr/bin/gcc
CFLAGS = -c -Wall -g
LDFLAGS = -lpng

SRC = $(wildcard *.c)
OBJ = $(SRC:%.c=%.o)

TARGET = progressive

all : $(TARGET)

$(TARGET) : $(OBJ)
        $(LD) $(LDFLAGS) $^ -o $(TARGET)

%.o : %.c
        $(CC) $(CFLAGS) -o $@ $<

clean :
        rm -rf *.o $(TARGET)

preguntado el 03 de mayo de 12 a las 20:05

1 Respuestas

Ha olvidado leer el contenido de su archivo.

Sustitución:

while (process) {
  memset(rawbuf, 0, DataSize);
  png_process_data(png_ptr, info_ptr, rawbuf, DataSize);
}

con

size_t read;
while ((read = fread(rawbuf, 1, DataSize, fp))) {
  png_process_data(png_ptr, info_ptr, rawbuf, read);
}

es suficiente para permitir que continúe la decodificación.

Me di cuenta de otra cosa: los segundos parámetros pasados ​​a png_set_read_user_chunk_fn() y png_set_progressive_read_fn() se supone que son valores arbitrarios que las funciones de devolución de llamada pueden obtener más tarde (a través de png_get_user_chunk_ptr() y png_get_progressive_ptr(), Respectivamente).

Estos se pueden establecer en los valores que desee (o en NULL si no los necesita), pero no debería llamar al png_get_*_ptr() funciona usted mismo para obtener un valor para pasar a png_set_*_fn(). (Creo que es inofensivo, ya que devolverán NULL para empezar, pero es confuso en el mejor de los casos).

Respondido 06 ago 13, 00:08

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.