ppm format that have magic code P3 - c

how i can read ppm image that have magic code P3. in c language?
this code reading ppm image that have magic code P3 but there a problem with loading method,this code enters into in infinite loop when reading the value of pixles?
/* This is for reading and Writing images file in PPM
Also example of making Negative images
- Use this file as an example of reading (loading) and writing (storing) images files.
- This program loads an PPM image and store a new image that is the negative of the original image.
*/
typedef struct pdata {
int red;
int green;
int blue;
} pdata;
typedef struct ppm {
int w;
int h;
int max;
pdata *pData;
} ppm;
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
//#define kernelW 3
//#define kernelH 3
//#define imageW 403
//#define imageH 332
char filename[256];
/*
This LoadPGM function is an updated version that will deal with
comments in file headers and do at least some basic checking if the
file can be opened or is the correct format. It does assume the file
is actually a valid length once the header has been read.
You are of course free to use your own file reading functions.
*/
void LoadPGM( char* filename, ppm* pPgm ) {
FILE* ifp;
int word;
int nRead = 0;
char readChars[256];
//open the file, check if successful
ifp = fopen( filename, "r" );
if (!ifp) {
printf("Error: Unable to open file %s.\n\n", filename);
exit(1);
}
//read headers from file
printf ("Reading PPM file: %s...\n", filename);
fscanf (ifp, "%s", readChars);
if (strcmp(readChars, "P3") == 0) {
//valid file type
//get a word from the file
fscanf (ifp, "%s", readChars);
while (readChars[0] == '#') {
//if a comment, get the rest of the line and a new word
fgets (readChars, 255, ifp);
fscanf (ifp, "%s", readChars);
}
//ok, comments are gone
//get width, height, color depth
sscanf (readChars, "%d", &pPgm->w);
fscanf (ifp, "%d", &pPgm->h);
fscanf (ifp, "%d", &pPgm->max);
// allocate some memory, note that on the HandyBoard you want to
// use constant memory and NOT use calloc/malloc
pPgm = (ppm *)malloc(sizeof(ppm));
pPgm->pData = (pdata*)malloc(pPgm->w *pPgm->h * sizeof(pPgm->pData));
fscanf(ifp, "%d" ,&word);
pPgm->pData[0].red = word;
printf (" %d \n", word);
for (nRead = 0; nRead < pPgm->w * pPgm->h; nRead++) {
fscanf(ifp, "%d" ,&word);
// printf (" %d \n",word);
pPgm->pData[nRead].red = word;
fscanf(ifp, "%d" ,&word);
pPgm->pData[nRead].green = word;
fscanf(ifp, "%d" ,&word);
pPgm->pData[nRead].blue = word;
}
printf ("Loaded PPM. Size: %dx%d, Greyscale: %d \n",
pPgm->w, pPgm->h, pPgm->max + 1);
}
else {
printf ("Error: Read file type %s. Format unsupported.\n\n", readChars);
exit(1);
}
fclose(ifp);
}
/* Simply saves the PGM file to a file whose name is in filename */
void WritePGM( char* filename, ppm* pPgm ) {
FILE* ofp;
int w, h, max;
int nWrite = 0;
int i,j;
strcat(filename, ".out.ppm");
ofp = fopen(filename, "w");
if (!ofp) {
printf("Error: Unable to open file %s.\n\n", filename);
exit(1);
}
printf ("Writing ouput PPM: %s\n\n", filename);
//write the header
fprintf( ofp, "P3\n" );
fprintf( ofp, "%d %d\n", pPgm->w, pPgm->h );
// printf("Done. Have a nice day...\n\n");
fprintf( ofp, "%d\n", pPgm->max );
//write the image data
for (i = 0; i < pPgm->h;i++) {
for (j = 0; j < pPgm->w; j++)
fprintf(ofp,"%d ",*(pPgm->pData + i * pPgm->w + j));
fprintf(ofp,"\n");
}
fclose(ofp);
}
int main(int argc, char * argv[]) {
ppm* image, *r1,*r2;
// char filename[256];
int val;
int errchk;
char f1[256];
//check if a filename was given, if not, ask for one
if (argc > 1) {
strcpy(filename, argv[1]);
}
else {
printf ("Enter filename: ");
scanf ("%s", filename);
}
//allocate memory for the pgm struct
image = (ppm *) malloc (sizeof(ppm));
//read the file
LoadPGM(filename, image);
int h,w;
w=image->w;
h=image->h;
int* pBuff1;
int* pBuff2;
int size;
int sum=0;
WritePGM(filename, image);
// end of the program
}

This line
malloc(pPgm->w *pPgm->h * sizeof(pPgm->pData))
allocates the wrong size. It allocates sizeof(pointer) while you need it sizeof(pdata), your own RGB struct.
Typically, one only needs RGB as 3 unsigned char, and had you used that the error would have been invisible, since pointers are usually 4 bytes long (and nowadays can even be longer). But since you made your values each an int, the structure uses 12 bytes in total. Somewhere after the first third has been read (give or take), your code starts overwriting other stuff in memory and you get toasted.

Related

How to read the content from the second line onwards on a .txt file on C

I need help to read the numbers of a .txt file and put them in an array. But only from the second line onwards. I'm stuck and don't know where to go from the code that i built.
Example of the .txt file:
10 20
45000000
48000000
56000000
#define MAX 50
int main (void){
FILE *file;
int primNum;
int secNum;
int listOfNumers[50];
int numberOfLines = MAX;
int i = 0;
file = fopen("file.txt", "rt");
if (file == NULL)
{
printf("Error\n");
return 1;
}
fscanf(file, "%d %d\n", &primNum, &secNum);
printf("\n1st Number: %d",primNum);
printf("\n2nd Number: %d",secNum);
printf("List of Numbers");
for(i=0;i<numberOfLines;i++){
//Count the number from the second line onwards
}
fclose(file);
return 0;
}
You just need a loop to keep reading ints from file and populate the listOfNumers array until reading an int fails.
Since you don't know how many ints there are in the file, you could also allocate the memory dynamically. Example:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
FILE* file = fopen("file.txt", "rt");
if(file == NULL) {
perror("file.txt");
return 1;
}
int primNum;
int secNum;
if(fscanf(file, "%d %d", &primNum, &secNum) != 2) {
fprintf(stderr, "failed reading primNum and secNum\n");
return 1;
}
unsigned numberOfLines = 0;
// allocate space for one `int`
int* listOfNumers = malloc((numberOfLines + 1) * sizeof *listOfNumers);
// the above could just be:
// int* listOfNumers = malloc(sizeof *listOfNumers);
while(fscanf(file, "%d", listOfNumers + numberOfLines) == 1) {
++numberOfLines;
// increase the allocated space by the sizeof 1 int
int* np = realloc(listOfNumers, (numberOfLines + 1) * sizeof *np);
if(np == NULL) break; // if allocating more space failed, break out
listOfNumers = np; // save the new pointer
}
fclose(file);
puts("List of Numbers:");
for(unsigned i = 0; i < numberOfLines; ++i) {
printf("%d\n", listOfNumers[i]);
}
free(listOfNumers); // free the dynamically allocated space
}
There are a few ways to approach this; if you know the size of the first line, you should be able to use fseek to move the position of the file than use getline to get each line of the file:
int fseek(FILE *stream, long offset, int whence);
The whence parameter can be:
SEEK_SET : the Beginning
SEEK_CUR : the current position
SEEK_END : the End
The other option would to encapsulate the entire file read in a while loop:
char *line = NULL;
size_t linecap = 0;
ssize_t linelen;
int counter = 0;
while((linelen = getline(&line, &linecap, file)) != -1){
if counter == 0{
sscanf(line, "%d %d\n", &primNum, &secNum);
}else{
//Process your line
}
counter++; //This would give you your total line length
}

Write bitstream to file in C

I'm currently trying to use a CMP decompressor: https://web.archive.org/web/20070113004119/http://rewiki.regengedanken.de:80/wiki/.CMP
It does in fact decompress the cmp, but it does not write it into a file.
So i tried myself.
int main(int argc, char** argv)
{
int length, dstLength;
unsigned char* fileInMem; //compressed data
unsigned char* dstFile; //decompressed data
if (argc < 2) {
fprintf(stderr, "give filename.cmp as parameter\n");
return 1;
}
printf("%s", argv[1]);
fileInMem = loadFile(argv[1], &length); //compressed data read
if (fileInMem == NULL) {
return 1;
}
dstFile = parseCmp(fileInMem, length, &dstLength); //decompress and assign data to dstFile
if (dstFile) {
/* Now we can save the file from dstFile, dstLength bytes */
printf("%d bytes depacked\n", dstLength);
for (int i = 0; i < 16; i++) {
dataArray[i] = fileInMem[i];
}
FILE *writer = fopen(argv[2], "r+");
//fputs(fileInMem, writer);
//fputs(dstFile, writer);
fclose(writer);
free(dstFile);
}
free(fileInMem);
return 0;
}
As you can see the decompressed data is a pointer to an unsigned char (according to the website a bitstream) and I tried fputs() from stdio.h, but the resulting file contains only 4 Bytes when viewed in a hex-editor.
If you need more information, please comment.
Thank you in advance.
Edit: This is what I was able to change thanks to your help, but when I open the file, it is still empty:
FILE* writer = fopen(argv[2], "wb");
fwrite(dstFile, 192, 192, writer);
192, because the length of the first decompressed Image is 192 Bytes large.
This is a common issue.
First, you need to open the output file writer for writing in binary mode ("wb").
FILE *writer = fopen(argv[2], "wb");
Second, you can't use fputs to write arbitrary data to a file, since it expects a string. Use fwrite instead: (assuming writer is the output file, dstFile the decompressed data and dstLength the amount of bytes to write)
fwrite(dstFile, 1, dstLength, writer);
If you examine the resulting file with an hex editor, you will see it is identical to the decompressed data.
Test-update
I wrote some test-code to see what is wrong, share your results so we can help you.
Add these functions to your code:
void printDataToScreen(unsigned char *dataptr, int datalen)
{
if (dataptr == NULL)
{
printf("[!] ERROR, NULL POINTER PROVIDED!\n");
return;
}
printf("> Dumping %d bytes of data into the terminal...\n", datalen);
for (int i = 0; i < datalen; i++)
{
if (i % 16 == 0)
printf("\n ");
printf("%02X ", dataptr[i]);
}
printf("\n\n");
}
void writeDataToFile(char *fileName, unsigned char *dataptr, int datalen)
{
FILE *file = fopen(fileName, "wb");
if (dataptr == NULL)
{
printf("[!] ERROR, NULL POINTER PROVIDED!\n");
return;
} else if (file == NULL)
{
printf("[!] ERROR WHILE OPENING FILE '%s'!\n", fileName);
return;
}
printf("> Writting %d bytes of data to '%s'...\n", datalen, fileName);
int writtenBytes = fwrite(dataptr, 1, datalen, file);
printf(" Done, %d bytes written!\n\n", writtenBytes);
fclose(file);
}
void runTest(char *fileName, unsigned char *dataptr, int datalen)
{
printf("Running tests... [0/2 done]\n");
printDataToScreen(dataptr, datalen);
printf("Running tests... [1/2 done]\n");
writeDataToFile(fileName, dataptr, datalen);
printf("Finished! [2/2 done]\n");
}
Call it like this:
runTest(argv[2], dstFile, dstLength);
Add the call to this place in your code (comment this code, also the line where you close writer):
FILE *writer = fopen(argv[2], "r+");
//fputs(fileInMem, writer);
//fputs(dstFile, writer);
Please share your results.

Read in the contents of a tab delimited text file and save into a single array in C

I am trying to read in the contents of a file using command line arguments to read the file and then store all contents of the file into a single array.
Keep in the mind, the file being read in is actually a matrix with the first row being an integer value designating the square size of the matrix and the following rows and columns being the matrix.
so far I have been able to dynamically allocate memory and then read the contents of the file using fgets. I am kind of stumped when it comes to storing the contents into a single array to access later. I tried using a double variable to hold the parsed contents of the 2nd while loop but when printed to the terminal it only gave me the last variable in the file.
I have attempted using strdup to make a copy of the string but am running into an error that says a value of type char cannot be stored in an entity of type char
here is my code.
If someone could help me, I would be very grateful.
#include<stdio.h>
#include<stdint.h>
#include<stdlib.h>
#include<string.h>
int main(int argc,char **argv){ //char **argv will be used to read the input file
int i,j,k,l,m,nn;
long size;
double mat;
char *buff;
char n[100];
char *file = argv[1];
long len =0;
int h =0;
FILE *output; // need to declare the output file
FILE *f =fopen(file, "rb+"); //utilize argv to read in file, will read file in as binary file to obtain ASCII
fseek(f, 0L, SEEK_END); //Want to determine the size of the file to create a buffer
size = ftell(f); //Will seek to the end of the file, declare that position as the size
rewind(f); //Will rewind to the beginning of the file
buff = (char *)malloc(size); //Declare the buffer size from fseek
//Will read in and print out the contents of the file using fgets and printf
while(fgets(buff,size - 1,f) != NULL){
printf( "%s\n", buff);
}
rewind(f);
while(fscanf(f, "%lf", &mat) ==1){
buff[h] = _strdup(n);
h++;
}
printf("matrix stored is %c\n",mat);
Here's an example:
/*
* EXAMPLE FILE:
* 3,3
* 1,2,3
* 4,5,6
* 7,8,9
*
* EXAMPLE OUTPUT:
* #/rows=3, #/columns=3
* 1.000000, 2.000000, 3.000000
* 4.000000, 5.000000, 6.000000
* 7.000000, 8.000000, 9.000000
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#define MAXLINE 100
#define DELIMITER ","
void print_matrix (int nrows, int ncols, double **mat) {
int i, j;
printf("#/rows=%d, #/columns=%d\n", nrows, ncols);
for (i=0; i < nrows; i++) {
for (j=0; j < ncols-1; j++) {
printf("%lf, ", mat[i][j]);
}
printf("%lf\n", mat[i][j]);
}
}
int main(int argc, char *argv[]) {
FILE *fp = NULL;
int iret = 1, n = 0, nrows, ncols;
double **mat, d;
char *s, line[MAXLINE], *endptr;
int i, j;
/* Read .csv filepath from cmd-line */
if (argc < 2) {
printf ("USAGE: app <fname>\n");
goto the_end;
}
/* Open file */
if (!(fp = fopen (argv[1], "r"))) {
printf ("File open(%s) failed: errno= %d\n",
argv[1], errno);
goto the_end;
}
/* Read matrix dimensions */
iret = fscanf(fp, "%d,%d", &ncols, &nrows);
if (iret != 2) {
printf ("Unable to read file dimensions, iret= %d, expected 2\n",
iret);
goto the_end;
}
/* Flush the extraneous newline left in the read buffer after fscanf()... */
fgetc(fp);
/* Allocate space for our matrix */
mat = (double **)malloc(sizeof(double *)*nrows);
if (!mat) {
printf ("Memory allocation error #matrix, errno=%d: exiting progam\n",
errno);
goto the_end;
}
for (i=0; i < nrows; i++) {
mat[i] = malloc(sizeof(double)*ncols);
if (!mat[i]) {
printf ("Memory allocation error #matrix[%d], errno=%d: exiting progam\n",
i, errno);
goto the_end;
}
}
/* Populate the matrix */
for (i=0; i < nrows; i++) {
++n;
s = fgets(line, MAXLINE, fp);
if (s == NULL) {
printf ("fgets read error, line %d, errno=%d: exiting program\n",
n, errno);
goto the_end;
}
s = strtok(line, DELIMITER);
for (j=0; j < ncols; j++) {
d = strtod(s, &endptr);
if (s == endptr) {
printf ("strtod(%s) conversion error, errno %d: exiting program\n",
s, errno);
goto the_end;
}
mat[i][j] = d;
s = strtok(NULL, DELIMITER);
}
}
/* Print the matrix */
print_matrix (nrows, ncols, mat);
/* Set "OK" status */
iret = 0;
the_end:
if (fp)
fclose(fp);
printf("Done: status=%d (%s)\n",
iret,
(iret == 0) ? "Status: OK" : "Status: FAIL");
return iret;
}

Read a file containing an array of long in C

I am trying to get the data from an array of longs that I have just created but I got different data.
please see code below :
#include <string.h>
#include "readfile.h"
int main()
{
long wr_data [6] ;
wr_data[0] = 11;
wr_data[1] = 1100;
wr_data[2] = 1122323;
wr_data[3] = 11333;
wr_data[4] = 11434243;
wr_data[5] = 1166587;
writeFile(wr_data);
readFile();
return(0);
}
int readFile()
{
FILE *file;
long * data
printf("Error Reading File\n");;
/* Open file for both reading and writing */
file = fopen(fileName, "r");
if (file == NULL)
{
printf("Error Reading File\n");
return -1;
}
for (int i = 0; i < 5; i++)
{
fscanf(file, "%ld", &data[i] );
printf("data[%d]: %ld \n",i, data[i]);
}
fclose(file);
return 0;
}
int writeFile(long * data)
{
FILE *fp;
if (data != NULL)
{
if ((fp = fopen(fileName,"w")) == NULL)
return -1;
if (*data !=0 )
fwrite(data,sizeof(long),6,fp);
printf("Write data\n");
fclose(fp);
}
return 0;
}
the result I get is as follows :
Write data
data[0]: 140526045102081
data[1]: 47
data[2]: 197764
data[3]: 140526045102080
data[4]: 4096
I want to preserve the write function as it is as it comes from an existing code. I tried also the function fread but without success
fread(data, sizeof(long ), 6, file);
Thanks in advance for help.
It's working here. I made the following changes to your code:
//needed for malloc
#include <stdio.h>
//needed for output
#include <stdlib.h>
...
char *fileName = "so";
...
//allocate memory to store the values
long *data = (long *)malloc(sizeof(long)*6);
...
//read the stored longs
fread(data, sizeof(long ), 6, file);
int i;
for(i=0; i<6; i++)
printf("%ld\n", data[i]);
what do you think?
edit:
Well the main change was the memory allocation. When you want to store values of any kind, your program needs to be granted by the operating system a memory zone to store those values.
In this case we had two options, either create a staticly allocated array with a fixed size, or allocate the needed memory in a dynamic fashion with the malloc function or equivalent.
Don't forget, if you want to store something, first make sure you have a place for it to be stored (i.e. allocated memory). If you don't you will most likely get an error "Segmentation Fault" aka "SIGSEGV" which means that you tried to access memory that didn't belong to you.
Also, the "fscanf(file, "%ld", &data[i] );" will read "file" as text and will try to parse floats out of that same text. Since you're storing the longs as longs and not as text, this will not work, since you're writing and reading different things.
You are writing the binary content of the array to the file and afterwards try to interpret this as a long value which can obviously not work. If you want to store the numbers as text you must convert them to text before writing or print them to file by using the fprintf(FILE *, const char *, ...) function.
It is working as expected using the following code using a text file (you might want to change the filename). Otherwise you could just fwrite and fread the whole content, depending on your needs.
#include <stdio.h>
const char *filename = "yourfile";
int readFile()
{
FILE *file;
long data[6];
int i;
printf("Error Reading File\n");;
/* Open file for both reading and writing */
file = fopen(filename, "r");
if (file == NULL)
{
printf("Error Reading File\n");
return -1;
}
for (i = 0; i < 6; i++)
{
fscanf(file, "%ld", &data[i] );
printf("data[%d]: %ld \n",i, data[i]);
}
fclose(file);
return 0;
}
int writeFile(long * data)
{
FILE *fp;
int i;
if (data != NULL)
{
if ((fp = fopen(filename,"w")) == NULL)
return -1;
if (*data !=0 )
{
for(i = 0; i != 6; ++i)
fprintf(fp, "%ld ", data[i]);
}
printf("Write data\n");
fclose(fp);
}
return 0;
}
int main()
{
long wr_data [6] ;
wr_data[0] = 11;
wr_data[1] = 1100;
wr_data[2] = 1122323;
wr_data[3] = 11333;
wr_data[4] = 11434243;
wr_data[5] = 1166587;
writeFile(wr_data);
readFile();
return(0);
}

c, 2d char array and fopen

I'm trying to make a program that reads a file with list of names. The number of those names can vary, as well as the names lengths. I want to store them in an array of arrays of char, and read each row as a string to later open the file that corresponds to the name in question. But when I try to open the first one, I have an error opening file.
I'm totally out of ideas.
Help, please?
Here is the code relevant to this action:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
int glimps(char *fname);
int write_av(char *fname, int NumbFiles);
int clr(char *fname);
int readFile(char *fname, int i);
double *dalpha, *alpha, *Ln_t, *LnLnA, Conc;
long *time, *weights, *Lmax, Nmax;
char *av_file, **in_files, *antetka;
/****************************************************************************/
int main(int argc, char *farg[])
{
int i, NumbFiles, flag;
long row;
char *a1;
FILE *fp;
av_file = farg[1];
printf("av_file = %s\n",av_file);
NumbFiles = glimps(av_file);
in_files = (char **) malloc (sizeof(char *) * NumbFiles);
for (i=0 ; i<NumbFiles ; i++)
in_files[i] = (char *) malloc (sizeof(char) * 200);
Lmax = (long *) calloc((size_t) NumbFiles, sizeof(long));
if((in_files == NULL)||(Lmax==NULL)) printf("Грешка при read алок.\n, "), exit(-1);
if (flag = readFile(av_file, -1))
printf("Error in read av_file %s\n", av_file), exit(-1);
weights = (long *) calloc((size_t) Nmax, sizeof(long));
for(i = 0; i<Nmax; i++) weights = 0;
for(i = 0; i<NumbFiles; i++)
{
//if (flag = readFile(&(*in_files[i]), i))
if (flag = readFile(in_files[i], i))
printf("Error in in_files[%d], %s\n",i, &(*in_files[i])), exit(-1);
}
if (flag = write_av(av_file, NumbFiles))
printf("Error in write_av(%s)\n,", av_file), exit(-1);
exit(0);
}
/****************************************************************************/
int glimps(char *fname)
{
FILE *fp;
char buf[140];
int cnt=0;
fp = fopen (fname, "r");
while (fgets(buf,140,fp) )
{
cnt++;
}
fclose(fp);
return (cnt);
}
/****************************************************************************/
int readFile(char *fname, int k)
{
int cnt=0;
FILE *fp;
char buf[200], dummy[13];
printf("fname is %s\n", fname); getchar();
fp = fopen (fname, "r");
if(fp==(NULL)) return(-1);
if(!strcmp(fname,av_file) )
{
while (fgets(in_files[cnt++],200,fp) );
}
else
{
printf("read TUK!\n"); getchar();
fgets(buf,200,fp);
sscanf(buf,"%s %s %s %s %s %s %s %ld %s %s %lf\n",
dummy, dummy,dummy,dummy,dummy,dummy,dummy, &Lmax[k],
dummy, dummy, &Conc);
fgets(buf,200,fp);
sscanf(buf,"%s\n", antetka);
printf("read TUK!\n"); getchar();
while (fgets(buf,200,fp))
{
sscanf(buf,"%ld %lf %lf %s %lf %lf\n",
&time[cnt], &dalpha[cnt], &alpha[cnt], dummy, &Ln_t[cnt],
&LnLnA[cnt]);
weights[cnt++]++;
}
}
fclose(fp);
return (0);
}
...
Console Output:
> ./avr alpha_cubeL.C0.010
av_file = alpha_cubeL.C0.010
fname is alpha_cubeL.C0.010
fname is alpha_cubeL100C0.010
Error in read in_files[0], alpha_cubeL100C0.010
> ls alpha_cubeL100C0.010
alpha_cubeL100C0.010
What happens is that in the readFile function, you read the main file given as argument to make (from the content) several file names in in_files[i], but fgets reads lines including the CR or CRLF (ie the end of line character(s)). Thus later in the program, readFile fails as it tries to open filename + CR [LF].
You may just add a trim function near the top of your program, like
void trim(char *s) {
int i,l = strlen(s);
for (i=l-1 ; i>=0 && (s[i]==10 || s[i]==13) ; i--) s[i] = 0;
}
that removes CR and/or LF that end a string s, and then change the readFile function to trim the file names read in each line, like
while (fgets(in_files[cnt++],200,fp) ) {
trim(in_files[cnt-1]); // cnt-1, or do the cnt++ here (and not above...)
}
Then the files can be opened...
(this is probably not the only problem in this program, but this is a good start)

Resources