How to use fgetc() in arduino ide

I am trying to read pgm image file from SD card but I do not know how to use fgetc() in correct way in Arduino ide.
Any advice please?

I commented the code that used in C, But I do not know how to use fgetc() in Arduino IDE.

And this is the original code in c:

read image


#include <SD.h>
//------------------------ read image PGM ---------------

typedef struct _PGMData {
    int row;
    int col;
    int max_gray;
    int **matrix;
} PGMData;

#define HI(num) (((num) & 0x0000FF00) << 8)
#define LO(num) ((num) & 0x000000FF)


int **allocate_dynamic_matrix(int row, int col)
{
    int **ret_val;
    int i;
 
    ret_val = (int **)malloc(sizeof(int *) * row);
    if (ret_val == NULL) {
        perror("memory allocation failure");
        exit(EXIT_FAILURE);
    }
 
    for (i = 0; i < row; ++i) {
        ret_val[i] = (int *)malloc(sizeof(int) * col);
        if (ret_val[i] == NULL) {
            perror("memory allocation failure");
            exit(EXIT_FAILURE);
        }
    }
 
    return ret_val;
}
 
void deallocate_dynamic_matrix(int **matrix, int row)
{
    int i;
 
    for (i = 0; i < row; ++i) {
        free(matrix[i]);
    }
    free(matrix);
}


void ignoreComments(File &fp)
{

    int ch;
    char line[100];
  /*  
    while ((ch = fgetc(fp)) != EOF && isspace(ch)) {
        ;
    }
 
    if (ch == '#') {
        fgets(line, sizeof(line), fp);
        SkipComments(fp);
    } else {
        fseek(fp, -1, SEEK_CUR);
    }
 */

while (fp.available() && isspace(ch) ){
   ch = fp.read();
}
     
if (ch == '#') {
// fgets(line, sizeof(line), fp);      
int bar=0;
int in_char;
while((in_char = fp.read()) >= 0){             
    line[bar++] = (char)in_char;
}
        ignoreComments(fp);
    } else {
       // fseek(fp, -1, SEEK_CUR);
         fp.seek(fp.position());   
    }


}
// reading image
PGMData* readPGM( PGMData *data)
{
    File pgmFile;
    char version[3];
    int i, j;
    int lo, hi;
    if (!SD.begin()) {
    Serial.println("Failed to mount card read pgm");
  }
   pgmFile = SD.open("/imag.pgm", FILE_READ);
  if (!pgmFile) {
    Serial.println("Opening file to read failed read pgm");
  }
   /* if (pgmFile == NULL) {
        perror("cannot open file to read");
        exit(EXIT_FAILURE);
    }*/
  /*  fgets(version, sizeof(version), pgmFile);
    if (strcmp(version, "P5")) {
        fprintf(stderr, "Wrong file type!\n");
        exit(EXIT_FAILURE);
    }
    */

    /*
    ignoreComments(pgmFile);
   // fscanf(pgmFile, "%d", &data->col);
    ignoreComments(pgmFile);
   // fscanf(pgmFile, "%d", &data->row);
    ignoreComments(pgmFile);
   // fscanf(pgmFile, "%d", &data->max_gray);
   */

   while (pgmFile.available()){
 
    ignoreComments(pgmFile);
   data->col = pgmFile.read();
    ignoreComments(pgmFile);
   data->row = pgmFile.read();
    ignoreComments(pgmFile);
   data->max_gray = pgmFile.read();  
}
    fgetc(pgmFile);   // here the error how to use it in correct way ?
    data->matrix = allocate_dynamic_matrix(data->row, data->col);
    if (data->max_gray > 255) {
        for (i = 0; i < data->row; ++i) {
            for (j = 0; j < data->col; ++j) {
                hi = pgmFile.read();    //fgetc(pgmFile);
                lo = pgmFile.read();   //fgetc(pgmFile);
                data->matrix[i][j] = (hi << 8) + lo;
            }
        }
    }
    else {
        for (i = 0; i < data->row; ++i) {
            for (j = 0; j < data->col; ++j) {
                lo = pgmFile.read();   //fgetc(pgmFile);
                data->matrix[i][j] = lo;
            }
        }
    }
 
  //  fclose(pgmFile);
    pgmFile.close();
    return data;
 
}
void setup() {
  // put your setup code here, to run once:
Serial.begin(115200);
  while (!Serial) 
 
    int w, h, bpp;
    PGMData im;
    readPGM( &im);
}

void loop() {
  // put your main code here, to run repeatedly:
}
'
type or paste code here

It's complaining about the type of the parameter pgmFile that you've passed to fgetc().

But you haven't show the declaration of pgmFile

This is why it's important to post the entire sketch.

I update my question, can you help please?

You've now lost the error message!

Please don't change posts after there's replies - it means the thread will make no sense to anyone subsequently reading it.

Was there only the one error message, or also others?

Please post the full build output - in a new reply.

Now I'm trying to adapt c code that use files with Arduino ide, So I converted some functions that use with files. but I do not know how to use fgetc() in Arduino ide.

This is the error that I have:
cannot convert 'fs::File' to 'FILE* {aka __sFILE*}' for argument '1' to 'int fgetc(FILE*)'

Again:

Was there only the one error message, or also others?

Please post the full build output - using the <CODE/> button - in a new reply.

This is the output:

In function 'PGMData* readPGM(PGMData*)':
read_pgm_image_from_SD:155:18: error: cannot convert 'fs::File' to 'FILE* {aka __sFILE*}' for argument '1' to 'int fgetc(FILE*)'
     fgetc(pgmFile);
                  ^
Multiple libraries were found for "SD.h"
 Used: C:\Users\lab\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\SD
 Not used: C:\Program Files (x86)\Arduino\libraries\SD
exit status 1
cannot convert 'fs::File' to 'FILE* {aka __sFILE*}' for argument '1' to 'int fgetc(FILE*)'

It's telling you that fgetc() requires one parameter of type FILE*

In your code, you have:

That's File; not FILE*

I would suggest that you start with an Arduino example to see how file handling works with the Arduino library you are using, and work from there ...

This is all my code, I can't print the size of the image, the code inter in loop. The commented line represent the code in c , and it was work (as a c code without any problem). I convert some functions the deal with files to can work on Arduino but the problem I can't get the size of image. any help please?


#include <SD.h>
typedef struct _PGMData {
    int row;
    int col;
    int max_gray;
    int **matrix;
} PGMData;

#define HI(num) (((num) & 0x0000FF00) << 8)
#define LO(num) ((num) & 0x000000FF)


int **allocate_dynamic_matrix(int row, int col)
{
    int **ret_val;
    int i;
 
    ret_val = (int **)malloc(sizeof(int *) * row);
    if (ret_val == NULL) {
        perror("memory allocation failure");
        exit(EXIT_FAILURE);
    }
 
    for (i = 0; i < row; ++i) {
        ret_val[i] = (int *)malloc(sizeof(int) * col);
        if (ret_val[i] == NULL) {
            perror("memory allocation failure");
            exit(EXIT_FAILURE);
        }
    }
 
    return ret_val;
}
 
void deallocate_dynamic_matrix(int **matrix, int row)
{
    int i;
 
    for (i = 0; i < row; ++i) {
        free(matrix[i]);
    }
    free(matrix);
}
void SkipComments(File &fp)
{

    int ch;
    char line[100];
  /*  
    while ((ch = fgetc(fp)) != EOF && isspace(ch)) {
        ;
    }
 
    if (ch == '#') {
        fgets(line, sizeof(line), fp);
        SkipComments(fp);
    } else {
        fseek(fp, -1, SEEK_CUR);
    }
 */

while (fp.available() && isspace(ch) ){
 //  Serial.write(fin.read());
   ch = fp.read();
}
     
if (ch == '#') {
       // fgets(line, sizeof(line), fp);
      
int bar=0;
int in_char;
while((in_char = fp.read()) >= 0){             
    line[bar++] = (char)in_char;
}
        SkipComments(fp);
    } else {
       // fseek(fp, -1, SEEK_CUR);
         fp.seek(fp.position());   
    }


}
//for reading:*

PGMData* readPGM( PGMData *data)
{
    File pgmFile;
    char version[3];
    int i, j;
    int lo, hi;
    if (!SD.begin(BUILTIN_SDCARD)) {
    Serial.println("Failed to mount card read pgm");
  }
   pgmFile = SD.open("/image.pgm", FILE_READ);
  if (!pgmFile) {
    Serial.println("Opening file to read failed read pgm");
  }
   /* if (pgmFile == NULL) {
        perror("cannot open file to read");
        exit(EXIT_FAILURE);
    }*/
  /*  fgets(version, sizeof(version), pgmFile);
    if (strcmp(version, "P5")) {
        fprintf(stderr, "Wrong file type!\n");
        exit(EXIT_FAILURE);
    }
    */

    /*
    SkipComments(pgmFile);
   // fscanf(pgmFile, "%d", &data->col);
    SkipComments(pgmFile);
   // fscanf(pgmFile, "%d", &data->row);
    SkipComments(pgmFile);
   // fscanf(pgmFile, "%d", &data->max_gray);
   */

   while (pgmFile.available()){
 
    SkipComments(pgmFile);
   // fscanf(pgmFile, "%d", &data->col);
   data->col = pgmFile.read();
    SkipComments(pgmFile);
   // fscanf(pgmFile, "%d", &data->row);
   data->row = pgmFile.read();
    SkipComments(pgmFile);
   // fscanf(pgmFile, "%d", &data->max_gray);
   data->max_gray = pgmFile.read();
  
}
   /// fgetc(pgmFile);
    data->matrix = allocate_dynamic_matrix(data->row, data->col);
    if (data->max_gray > 255) {
        for (i = 0; i < data->row; ++i) {
            for (j = 0; j < data->col; ++j) {
                hi = pgmFile.read();    //fgetc(pgmFile);
                lo = pgmFile.read();   //fgetc(pgmFile);
                data->matrix[i][j] = (hi << 8) + lo;
            }
        }
    }
    else {
        for (i = 0; i < data->row; ++i) {
            for (j = 0; j < data->col; ++j) {
                lo = pgmFile.read();   //fgetc(pgmFile);
                data->matrix[i][j] = lo;
            }
        }
    }
 
    pgmFile.close();
    return data;
 
}

void setup() {
  // put your setup code here, to run once:
Serial.begin(115200);
  while (!Serial){}; 
    PGMData im;
    readPGM( &im);

   Serial.print("The size of image = ");
   Serial.println(im.col);
   Serial.println(im.row);   
}

void loop() {
  // put your main code here, to run repeatedly:

}

Hi @mercala_eng ,

is this related to your code?

https://stackoverflow.com/questions/32310874/how-to-blur-a-pgm-file

One thing seems to be obvious:

  • row and col are integer values
  • file.read() gets just one character/byte from the file

My suggestions:

  • I recommend to create a sketch that does only read row and col first. If this runs successfully you can add the rest step by step.
  • Concentrate on the first x data (10 < x < 80), read and print them via Serial
  • Analyse the structure (you should recognize where row and col of a known picture are coded
  • Make sure to correctly read row and col (right place in the file, correct conversion to int)

Good luck!

P.S.: The function fgets is defined as

The C library function **char *fgets(char str, int n, FILE stream) reads a line from the specified stream and stores it into the string pointed to by str . It stops when either (n-1) characters are read, the newline character is read, or the end-of-file is reached, whichever comes first

You can replace it by a routine using file.read() where you read data into a char array until newline has been read, end-of-file or the given limit of n characters has been reached.

The mentioned code in c, and I have the same code in c and work without any problem.
I converted some functions like fgetc() to file.read(). can you check it please if my conversion is correct or not?
And for this line (/// fgetc(pgmFile);) in PGMData* readPGM( PGMData *data)
How can I convert it to work correctly in arduino ide?
Please can you help?

The problem in this part in SkipComments():

while (fp.available() && isspace(ch) ){
       ch = fp.read();
    }

The original code in c was:

/*  
  while ((ch = fgetc(fp)) != EOF && isspace(ch)) {
            ;
   }
*/

If you google the functions in question you'll find what they do and can replace them either by the corresponding function for file reading or substitute them by a selfmade function.

E.g. for fgetc(), c++ you get a lot of links like this https://cplusplus.com/reference/cstdio/fgetc/

So instead of

  • ch = fgetc(pgmFile);
    you write
  • ch = pgmFile.read();

Both return the next character in the file and increment the "file position indicator" to point the next character in the file (if available).

Check the same for the other functions.

Unfortunately I will not have the time to solve your tasks ... but if you start as I suggested you may get an understanding what you have to do.

Good luck!

Just a hint. If you want other members to assist, it would be a good idea to provide a small pgm file or give a link to the one you use and a link to a description of the file structure. Otherwise you leave the work to get information to the others ...

A more accurate rewrite would look like this, I can't test it or even know if I've got the SD card thing right, but the original reads a character, checks to be sure it got one and if it is a space, ignores it.

  while ((ch = fp.read()) != EOF && isspace(ch) ){
       ; // ignore this space character
  }

Which makes me ask if you understood what nd how the original snippet functioned.

In less clever C:

  while (1) {
    ch = fp.read();
    if (ch == EOF) break;
    if (!isspace(ch)) break;
  }

The SD read() method probably has a return value meaning EOF. If not, there must be some kind of an available() method you could use before reading a character.

HTH

a7

1 Like

This is a link for pgm file format, I used lena.pgm

image file format

If any one can help I will be thankful!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.