0

soy nuevo por aquí, lo que pasa es que tengo que leer un archivo (una imagen) PPM mediante un programa de C++, estoy usando QT Creator y el programa lo creé usando CMAKE a partir de un archivo CMakeLists.txt. En el CMakeLists coloqué todas las carpetas que necesito al igual que los .h y.c que voy a utilizar, sin embargo, cuando intento leer desde el main la imagen, me saltan dos errores. Si estoy incluyendo el archivo de cabecera en el main.

Este es el archivo CMakeLists.txt


project(testc LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

set(testc_src
    "test/main.cpp"
    "include/ppm.h"
    "source/ppm.c"

)

add_executable(testc ${testc_src})
include_directories ( ./include)

El archivo de cabecera .h

 *
 * ppm.h
 *
 * Read and write PPM files.  Only works for "raw" format.
 *
 * AF970205
 *
 ****************************************************************/

#ifndef PPM_H
#define PPM_H

#include <sys/types.h>

#define u_char unsigned char

typedef struct Image //crea un nuevo tipo Image de tipo struct
{
  int width;
  int height;
  u_char *data;
} Image;//crea una variable imagen

Image *ImageCreate(int width, int height);
Image *ImageRead(const char *filename);
void   ImageWrite(Image *image, const char *filename);

int    ImageWidth(Image *image);
int    ImageHeight(Image *image);

void   ImageClear(Image *image, u_char red, u_char green, u_char blue);

void   ImageSetPixel(Image *image, int x, int y, int chan, u_char val);
u_char ImageGetPixel(Image *image, int x, int y, int chan);

#endif /* PPM_H */

El archivo .c

 *
 * ppm.c
 *
 * Read and write PPM files.  Only works for "raw" format.
 *
 * AF970205
 *
 ****************************************************************/


#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include "ppm.h"
#include <sys/types.h>

#define u_char unsigned char


/************************ private functions ****************************/

/* die gracelessly */

static void
die(char *message)
{
  fprintf(stderr, "ppm: %s\n", message);
  exit(1);
}


/* check a dimension (width or height) from the image file for reasonability */

static void
checkDimension(int dim)
{
  if (dim < 1 || dim > 4000) //si es muy grande o tiene valores negativos el archivo no abre
    die("file contained unreasonable width or height");
}


/* read a header: verify format and get width and height */

static void
readPPMHeader(FILE *fp, int *width, int *height)
{
  char ch;
  int  maxval;

  if (fscanf(fp, "P%c\n", &ch) != 1 || ch != '6') //si fscanf retorna un numero diferente de 1 entonces falla la función. Si el numero que acompaña a la P no es el 6 no es PPM
    die("file is not in ppm raw format; cannot read");

  /* skip comments */
  ch = getc(fp);
  while (ch == '#')
    {
      do {
        ch = getc(fp);
      } while (ch != '\n'); /* read to the end of the line Lee hasta que el dato sea \n*/
      ch = getc(fp);            /* Continua leyendo en la siguiente linea*/
    }

  if (!isdigit(ch)) die("cannot read header information from ppm file"); //Si lo que se lee no es un numero, entonces se generar un error

  ungetc(ch, fp);       /* put that digit back Se devuelve una posición para leer de nuevo el número*/

  /* read the width, height, and maximum value for a pixel */
  fscanf(fp, "%d%d%d\n", width, height, &maxval);

  if (maxval != 255) die("image is not true-color (24 bit); read failed");

  checkDimension(*width);
  checkDimension(*height);
}

/************************ exported functions ****************************/ //Funciones que vienen del .h

Image *
ImageCreate(int width, int height) //Crea la imagen, asigna o reserva espacios de memoria para crear la imagen
{
  Image *image = (Image *) malloc(sizeof(Image));

  if (!image) die("cannot allocate memory for new image");

  image->width  = width;
  image->height = height;
  image->data   = (u_char *) malloc(width * height * 3);

  if (!image->data) die("cannot allocate memory for new image");

  return image;
}


Image *
ImageRead(const char *filename)
{
  int width, height, num, size;
  u_char *p;

  Image *image = (Image *) malloc(sizeof(Image));
  FILE  *fp    = fopen(filename, "r");

  if (!image) die("cannot allocate memory for new image");
  if (!fp)    die("cannot open file for reading");

  readPPMHeader(fp, &width, &height);

  size          = width * height * 3;
  image->data   = (u_char *) malloc(size);
  image->width  = width;
  image->height = height;

  if (!image->data) die("cannot allocate memory for new image");

  num = fread((void *) image->data, 1, (size_t) size, fp);

  if (num != size) die("cannot read image data from file");

  fclose(fp);

  return image;
}


void ImageWrite(Image *image, const char *filename)
{
  int num;
  int size = image->width * image->height * 3;

  FILE *fp = fopen(filename, "w");

  if (!fp) die("cannot open file for writing");

  fprintf(fp, "P6\n%d %d\n%d\n", image->width, image->height, 255);

  num = fwrite((void *) image->data, 1, (size_t) size, fp);

  if (num != size) die("cannot write image data to file");

  fclose(fp);
}


int
ImageWidth(Image *image)
{
  return image->width;
}


int
ImageHeight(Image *image)
{
  return image->height;
}


void
ImageClear(Image *image, u_char red, u_char green, u_char blue)
{
  int i;
  int pix = image->width * image->height;

  u_char *data = image->data;

  for (i = 0; i < pix; i++)
    {
      *data++ = red;
      *data++ = green;
      *data++ = blue;
    }
}

void
ImageSetPixel(Image *image, int x, int y, int chan, u_char val)
{
  int offset = (y * image->width + x) * 3 + chan;

  image->data[offset] = val;
}


u_char
ImageGetPixel(Image *image, int x, int y, int chan)
{
  int offset = (y * image->width + x) * 3 + chan;

  return image->data[offset];
}

El programa principal main.cpp

#include "ppm.h"

using namespace std;

int main()
{
    Image *image;
    const char *filename="Data/uno.ppm";
    image = ImageRead(filename);
    cout << "Hello World!" << endl;
    system("pause");
    return 0;
}

Todos los archivos están en sus carpetas correspondientes pero cuando intento leer la imagen los errores que me aparecen son: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings] char *filename="Data/uno.ppm"; //const

Y luego que "ImageRead" no está definida pero sí está definida:

error: undefined reference to `ImageRead(char*)'

¿Qué puedo hacer para leer la imagen? Gracias por su ayuda!!!

PD: El código nos lo entregaron de una página web y debemos arreglarlo, pero no encuentro por qué no funciona. Gracias de nuevo.

Edit 1: El código actual se encuentra actualizado según el comentario que colocó braver anteriormente. Se cambiaron todas las funciones que tenían char por const char sin embargo aún aparece el siguiente error: error: undefined reference to `ImageRead(char const*)'

  • Te falta agregar C a la lista de lenguajes del proyecto (`project(testc LANGUAGES CXX C)` ) para que CMake no ignore los archivos de C y los compile. La otra advertencia que te sale esta respondida en [esta pregunta](https://es.stackoverflow.com/questions/283444/error-iso-c-forbids-converting-a-string-constant-to-char-wpedantic). – braver Apr 06 '21 at 03:18
  • @braver Listo, añadí lo que dijiste al cmakelist. Agradezco tu ayuda; ya había leído la otra pregunta sin embargo, cuando coloco el const char me aparece este error `error: undefined reference to ImageRead(char const*)'` Ya cambié todos los char que aparecía en las funciones por const char en todos los archivos pero aún así no puede compilar. Voy a actualizar el código para que veas los cambios. ¿Dónde debería añadir el "const"? – Camilo Castro Apr 06 '21 at 22:59

1 Answers1

0

Te falto envolver el include en un extern "C" {}:

extern "C" {
#include "ppm.h"
}

using namespace std;

int main()
{
    Image *image;
    const char *filename="Data/uno.ppm";
    image = ImageRead(filename);
    cout << "Hello World!" << endl;
    system("pause");
    return 0;
}

Se necesita hacerlo al incluir encabezados de bibliotecas de C, porque el enlazador de C++ usa una convención de nombres diferente que en C (en C++ se "mutilan" para soportar la sobrecarga de funciones que en C no existe).

braver
  • 906
  • 1
  • 4
  • 13