Saltar al contenido

Necesita ayuda para leer archivos JPEG usando libjpeg

Posteriormente a consultar expertos en el tema, programadores de deferentes ramas y profesores hemos dado con la solución al problema y la plasmamos en este post.

Solución:

Aquí hay una muestra para leer una imagen jpeg:

/***************************************************
    To read a jpg image file and download
    it as a texture map for openGL
    Derived from Tom Lane's example.c
    -- Obtain & install jpeg stuff from web 
    (jpeglib.h, jerror.h jmore.h, jconfig.h,jpeg.lib)
****************************************************/
#include     
#include 
//================================
GLuint LoadJPEG(char* FileName)
//================================

  unsigned long x, y;
  unsigned int texture_id;
  unsigned long data_size;     // length of the file
  int channels;               //  3 =>RGB   4 =>RGBA 
  unsigned int type;  
  unsigned char * rowptr[1];    // pointer to an array
  unsigned char * jdata;        // data for the image
  struct jpeg_decompress_struct info; //for our jpeg info
  struct jpeg_error_mgr err;          //the error handler

  FILE* file = fopen(FileName, "rb");  //open the file

  info.err = jpeg_std_error(& err);     
  jpeg_create_decompress(& info);   //fills info structure

  //if the jpeg file doesn't load
  if(!file) 
     fprintf(stderr, "Error reading JPEG file %s!", FileName);
     return 0;
  

  jpeg_stdio_src(&info, file);    
  jpeg_read_header(&info, TRUE);   // read jpeg file header

  jpeg_start_decompress(&info);    // decompress the file

  //set width and height
  x = info.output_width;
  y = info.output_height;
  channels = info.num_components;
  type = GL_RGB;
  if(channels == 4) type = GL_RGBA;

  data_size = x * y * 3;

  //--------------------------------------------
  // read scanlines one at a time & put bytes 
  //    in jdata[] array. Assumes an RGB image
  //--------------------------------------------
  jdata = (unsigned char *)malloc(data_size);
  while (info.output_scanline < info.output_height) // loop
  
    // Enable jpeg_read_scanlines() to fill our jdata array
    rowptr[0] = (unsigned char *)jdata +  // secret to method
            3* info.output_width * info.output_scanline; 

    jpeg_read_scanlines(&info, rowptr, 1);
  
  //---------------------------------------------------

  jpeg_finish_decompress(&info);   //finish decompressing

  //----- create OpenGL tex map (omit if not needed) --------
  glGenTextures(1,&texture_id);
  glBindTexture(GL_TEXTURE_2D, texture_id);
  gluBuild2DMipmaps(GL_TEXTURE_2D,3,x,y,GL_RGB,GL_UNSIGNED_BYTE,jdata);

  jpeg_destroy_decompress(&info);
  fclose(file);                    //close the file
  free(jdata);

  return texture_id;    // for OpenGL tex maps

La función jpeg_read_scanlines recibe un array de punteros (no el puntero directo de píxeles como imageData->pixels). Así que primero deberíamos crear un JSAMPARRAY:

int buffer_height = 1;
JSAMPARRAY buffer = (JSAMPARRAY)malloc(sizeof(JSAMPROW) * buffer_height);
buffer[0] = (JSAMPROW)malloc(sizeof(JSAMPLE) * row_stride);

En su código ha creado un "búfer" con "cinfo.mem->alloc_sarray" pero nunca lo usa. El paso final es pasar el "búfer" como argumento de jpeg_read_scanlines:

while (cinfo.output_scanline < cinfo.output_height) 
  jpeg_read_scanlines(&cinfo, buffer, 1);
  memcpy(imageData->pixels+counter, buffer[0], row_stride);
  counter += row_stride;

Vea que estamos usando "imageData->pixels+counter", no solo "imageData->pixels" como en su código. De esta manera, escribimos cada fila tras otra en el fragmento de memoria completo "imageData->pixels".

Como dijo dacap, está esperando un JSAMPARRAY. Dicho esto, puede escribir directamente en su imageData->pixels array si desea. Solo necesitas hacer algo como esto:

// Allocate imageData->pixels to be the correct size, start decompress and all
// that jazz, like you did in your code. Skip allocating buffer though.
// ...

JSAMPROW output_data;
unsigned int scanline_len = cinfo.output_width * cinfo.output_components;

unsigned int scanline_count = 0;
while (cinfo.output_scanline < cinfo.output_height)

    output_data = (imageData->pixels + (scanline_count * scanline_len));
    jpeg_read_scanlines(&cinfo, &output_data, 1);
    scanline_count++;

A continuación, puede omitir la asignación de búfer por completo. Usar memcpy funciona bien, pero ¿por qué hacer la copia adicional si no es necesario?

Sección de Reseñas y Valoraciones

Nos encantaría que puedieras dar difusión a este enunciado si lograste el éxito.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *