Error Reading Image Data in Custom HS8 Image Loader (C)

102 Views Asked by At

I'm developing a C program to process images in a custom HS8 format. My load_image function seems to have issues correctly reading the binary pixel data after an initial text-based debugging step. I'm encountering a Segmentation fault (core dumped) warning, as well as my rgb values of the pixels completely changing.

(.hs8 file format simplified):

An HS8 image has an ASCII text header:

HS8
width height

where:

  • HS8 — fixed code indicating HS8 format
  • width — integer number of columns
  • height — integer number of rows

The fields in the header are separated by one or more whitespace (space, tab, carriage return or newline) characters. The height field is followed by a single whitespace character. The image data follows the header. Each pixel is stored as three unsigned 8-bit values as binary data (not text). Pixels are stored from left to right in the first row, then left to right in the second row, and so on until the end of the image.

/* The RGB values of a pixel. */
struct Pixel
{
    uint8_t red;
    uint8_t green;
    uint8_t blue;
};

/* An image loaded from a file. */
struct Image
{
    int width;
    int height;
    struct Pixel *pixels;
};

/* Free a struct Image */
void free_image(struct Image *img)
{
    /* Free the pixel data */
    free(img->pixels);

    /* Free the image structure */
    free(img);
}

/* Opens and reads an image file, returning a pointer to a new struct Image.
 * On error, prints an error message and returns NULL. */
struct Image *load_image(const char *filename)
{
    /* Open the file for reading */
    FILE *f = fopen(filename, "r");
    if (f == NULL)
    {
        fprintf(stderr, "File %s could not be opened.\n", filename);
        return NULL;
    }

    /* Read the header */
    char fileType[3];
    int width, height;
    if (fscanf(f, "%3s %d %d", fileType, &width, &height) != 3 || strcmp(fileType, "HS8") != 0)
    {
        fprintf(stderr, "Invalid header in file %s.\n", filename);
        fclose(f);
        return NULL;
    }

    /* Allocate memory for the image structure */
    struct Image *img = malloc(sizeof(struct Image));
    if (img == NULL)
    {
        fprintf(stderr, "Memory allocation failed.\n");
        fclose(f);
        return NULL;
    }

    /* Set image width and height */
    img->width = width;
    img->height = height;

    /* Allocate memory for pixel data */
    img->pixels = malloc(sizeof(struct Pixel) * width * height);
    if (img->pixels == NULL)
    {
        fprintf(stderr, "Memory allocation failed.\n");
        fclose(f);
        free(img);
        return NULL;
    }

    /* Read pixel data */
    size_t pixels_read = 0;
    for (int i = 0; i < img->height; i++)
    {
        for (int j = 0; j < img->width; j++)
        {
            size_t bytes_read = fread(&(img->pixels[pixels_read]), sizeof(struct Pixel), 1, f);
            if (bytes_read != 1)
            {
                fprintf(stderr, "Failed to read pixel data.\n");
                fclose(f);
                free(img->pixels);
                free(img);
                return NULL;
            }
            pixels_read++;
        }
    }
    /* Close the file */
    fclose(f);

    return img;
}

int main(int argc, char *argv[])
{

    /* Check command-line arguments */
    if (argc != 3)
    {
        fprintf(stderr, "Usage: process INPUTFILE OUTPUTFILE\n");
        return 1;
    }

    /* Load the input image */
    struct Image *in_img = load_image(argv[1]);
    if (in_img == NULL)
    {
        return 1;
    }

    /* Save the output image */
    if (!save_image(out_img, argv[2]))
    {
        fprintf(stderr, "Saving image to %s failed.\n", argv[2]);
        free_image(in_img);
        free_image(out_img);
        return 1;
    }

    free_image(in_img);
    free_image(out_img);
    return 0;
}

Things I've Considered/Tried:

  • File Position: I'm accounting for the bytes consumed during text debugging by adjusting the fread count.

Can anyone help me identify why I'm unable to read the image data correctly? I'm using ubuntu 22.04.3 lts and x86 intel processor

1

There are 1 best solutions below

1
Mark Setchell On

If you need to read binary data (as you describe), you need to open the file in binary mode:

FILE *f = fopen(filename, "rb");

If you want to provide a "minimum, complete, verifiable solution" as required by StackOverflow, you need to provide a link to a valid HS8 file and its specification.


If you are relying on the size of your Pixel struct, you need to check and print its size and check it is not padded out to 32bits.


You don't appear to read the whitespace character after the header.