-1

I try to read a file from this code. I am trying to load images and store them into my program as strings, so I can later create the identical image with fprintf to a new file. I am not allowed to use some file duplication; I need to load the files in as a string and write them to a new file later. What I am attempting is to have a char array, and since one char is one byte the array is as long as the file size, and each element of the char array corresponds to one byte of the diamond block texture, and I want to also be able to write this string from the code to a new file, and have another diamond block that I can open with an image viewer.

#include <stdio.h>
#include <stdlib.h>

char Contents[468];

int main(int argc, char *argv[]) {
    char *WD = getenv("HOME");
    char Path[strlen(WD)+strlen("/Desktop/diamond_block.png")+1];
    sprintf(Path, "%s/Desktop/diamond_block.png", WD);
    FILE *File = fopen(Path, "r");
    fscanf(File, "%s", Contents);
    printf(Contents);
}

The result is just four letters, âPNG, and it is supposed to be hundreds of characters meaning the file is NOT being fully read. I suspect it is somehow being terminated early by some terminating character, but how can I solve my problem?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Try to use fgets. You cannot output on the video an image content using printf. The image is not a string it contains values that cannot be displayed. The C stops the printout of the string at the first 0 value. – Sir Jo Black Jun 29 '19 at 17:09
  • This `fscanf(File, "%s", Contents);` reads one word i.e upto white space from file not complete file content. Why don't you rotate loop ? – Achal Jun 29 '19 at 17:11
  • You may not consider images as string. They're not string. A better way to printout the content of an image file is to print its binary value as numbers. As I've already said the C stops printout of strings at the first occurence of a 0 value. – Sir Jo Black Jun 29 '19 at 17:13
  • I don't see loops in your code. The same consideration about strings is true also for the function fscanf. The functions reads byte till the first 0 value or '\n'. – Sir Jo Black Jun 29 '19 at 17:16
  • If you are using Linux you may try to execute the following command: `od -c diamond_block.png | more`. You will see the value of the file bytes. – Sir Jo Black Jun 29 '19 at 17:20
  • @SirJoBlack I want a way to store an image as a value in my code –  Jun 29 '19 at 17:21
  • @SirJoBlack When I execute od -c, there are a lot of big numbers at the beginning of each line, how can I disable that –  Jun 29 '19 at 17:24
  • What you see are the bytes represented as char if the byte values have a terminal output code, or by value if the code has no terminal output code. To have a shorter view (a fee bytes) you may use `od -c vpn.png | head -n 4` – Sir Jo Black Jun 29 '19 at 17:51
  • To understand what I said about your code you may see also: https://stackoverflow.com/questions/174531/how-to-read-the-content-of-a-file-to-a-string-in-c – Sir Jo Black Jun 29 '19 at 18:17
  • 1
    PNG files are binary files; they contain zero bytes, and zero bytes mark the end of a string. You're using the wrong primitives. You should look into `fread()` and `fwrite()`, though it would be possible to use `getc()` and `putc()` instead without impossible overhead (though the overhead is substantial for megabyte size images — at less than 100 KiB, the difference probably isn't material unless you're running this program all day every day). – Jonathan Leffler Jun 29 '19 at 18:51
  • As @JonathanLeffler indicates me, `fgets` is inappropriate, is better to use `fread`. As is used in an answer in in https://stackoverflow.com/questions/174531/how-to-read-the-content-of-a-file-to-a-string-in-c . – Sir Jo Black Jun 29 '19 at 19:29

1 Answers1

1

This is a very basic answer to your question. With the code below you may understand what's your issue. This code need a good review to intercept all the errors the used functions may return. By the way ... enjoy it!

The code loads the whole file fname into the char array imgMem. It compute the file dimension on the variable n, allocates the memory for the array imgMem (malloc) and then loads the whole file into imgMem (fread).

Then the code writes the first 30 bytes of the file in two format:

  • the hex value of the byte
  • the char value if the byte has a console representation (otherwise prints a .)

Here the code:

#include <unistd.h>
#include <stdio.h>
#include <malloc.h>

int main(void)
{
    const char * fname = "/home/sergio/Pictures/vpn.png";

    FILE * fptr;
    char * imgMem=NULL;
    long n;
    int i;

    fptr=fopen(fname, "r");

    //Determine the file dimension
    fseek(fptr,0,SEEK_END); n=ftell(fptr);

    //Set the file cursor to the beginning
    fseek(fptr,0,SEEK_SET);

    printf("The file is %lu byte long.\n\n",n);

    //Allocate n bytes to load the file
    imgMem = malloc((size_t)n);

    //Load the file
    fread(imgMem,(size_t)n,1,fptr);;

    for(i=0; i<30; i++) {
        printf("[%02X %c] ",
           (unsigned char)imgMem[i],
           (imgMem[i]>31 && imgMem[i]<127)?
               imgMem[i]:'.'
        );

        if ((i+1)%8==0)
            puts("");
    }

    puts("");

    free(imgMem);

    fclose(fptr);

    return 0;
}
Sir Jo Black
  • 2,024
  • 2
  • 15
  • 22
  • 1
    Since the data in a `.png` file is binary data (it contains null bytes, particularly near the start in the header, but usually some also appear in the main data section), so using `fgets()` is not appropriate. You can't tell how many bytes it read if there are null bytes in the data, and `fgets()` doesn't tell you. Using POSIX [`getline()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getline.html) would avoid that problem; it says how many bytes it read. – Jonathan Leffler Jun 29 '19 at 18:58
  • As @JonathanLeffler indicate me I edited the routine to use `fread` instead of `fgets`. – Sir Jo Black Jun 29 '19 at 19:39