File in binary form - c

I want to write data into the file in binary form.
I was trying using the mentioned below
FILE *fp = fopen("binaryoutput.rgb888", "ab+");
for(int m=0; m<height; m++)
{
for (int n=0; n< width; n++)
{
temp = (pOutputImg+m*3+n*3); // here pOutputImg & temp is a pointer to a unsigned char
fprintf(fp,"%u",*temp);
}
}
fclose(fp);
I am able to get data which is strored at pOutputImg but not in binary form.
Can anyone guide me the correct step..
Thanks in advance

Replace fprintf() with fwrite().
Ex:
fwrite(temp, sizeof(*temp), 1, fp);
The whole purpose of fprintf() is to format binary data as readable ascii ... the exact opposite of what you want. fwrite() is for directly writing binary data.

If this is a pixmap of rgb triplets, you can write the binary data with one line:
fwrite(pOutputImg, 3, height * width, fp);

Related

Saving an integer array to a file in C

I've been trying to write the contents of an integer array to a file in C. I've been using the code below to do so.
int etData [600];
int i;
int size = sizeof(char);
for (i=0; i<600; i++)
{
etData[i] = analog_et(5);
}
FILE *f = fopen("/home/root/Documents/KISS/Default User/Launch Code/data/data", "w");
fwrite(etData, size, sizeof(etData), f);
fclose(f);
analog_et is a function that returns an integer value from a sensor. Whenever I run this code, a mess of ASCII characters is written to the file. I believe this is to blame on the fact that I am passing fwrite an element size sizeof(char) - however, whenever I attempt to pass a value larger than one byte, nothing is written to the file, and fwrite fails to return a non-zero value.
I've looked for a function in stdio that would be better suited to this purpose but can't find one. Any suggestions on how to fix this issue? Thanks!
If you want a textual representation of your data (in that case the file can be opened with a text editor), you cannot user fwrite but you need to use fprintf. Latter does basically is the same thing as printf, but instead of being displayed, the data is written into a text file.
You probably want this:
...
FILE *f = fopen("/home/root/Documents/KISS/Default User/Launch Code/data/data", "w");
for (i=0; i<600; i++)
{
fprintf("%d\n", etData[i]);
}
...

Codification, write an integer in a file

I am doing a coding task in the C language, I go well until the part of reading the symbol and assign the corresponding code according to a table. I must concatenate several codes until they reach 32 bits in length, to accomplish this I must write them in a file.
This method of writing to file is giving me a lot of problems, I'm trying to do it with the fputc() function.
I can not change the declaration of the function because they request it for the homework.
I create a mask to be able to write the integer by bytes because they also suggest that the teachers of the course.
The program with that code works but when I see the file with a binary viewer it only prints zero.
Any idea of what I'm doing wrong?
Thanks!
void write_int(FILE* fp, unsigned int buffer, int nbytes){
if ( (nbytes <= sizeof(int)) && (nbytes>=0) ){
unsigned int aux;
int i;
for (i=4; i>(4-nbytes) ; i--){
aux = buffer & new_mask( ((i*8)-1),((i-1)*8));
fputc(aux,fp)
}
fputc('\n',fp);
}else{
printf("nbytes out of range");
}
}
fputc is used to write one ASCII-character into a file.
int fputc(int, FILE*) //this int is converted to unsigned before going to the file(your bits are probably being messed up here)
1- solution: Open this file in binary mode and write using fwrite
fp = fopen("filename", "wb+");
fwrite(buffer, 4, 1, fp);
*since integers on most computers have 32bits(4bytes) this should write your whole 32 bits at once in a binary file
2- solution: Assuming that you can't open the file in binary mode inside this function... you could simply write 4chars usgin fprintf.
int fprintf(FILE*, format, ....);
*note: it's hard to help more than this, because it's not clear what is nature of these symbols.
ex: binary stream, integer number, ascii, utf, etc

Unable to write shell history to a text file

I'm currently writing a shell with basic functions in C, operating through Unix. I'm having difficulty transferring an array of history commands to a text file.
History is stored as a pointer to an array, with a capacity of 20 as not to over-complicate things. I got the basis of the method online so I've tried to tailor it to my needs, however it just feeds a bunch of weird characters to the text file.
Does anyone know why this may be happening?/What I could do to fix it?
I'm also not sure if the for loop is necessary.
Thanks in advance!
char *history[2];
void save(char ** history)
{
FILE *f;
f = fopen("history.txt", "w+");
for(int i = 0; i < 20; i++)
{
fwrite (history, sizeof(history[i]), sizeof(history)/sizeof(history[i]), f);
}
fclose(f);
}
history
is a char **, which is a pointertype.
history[i]
is char*, so still a pointertype
sizeof(history)/sizeof(history[i])
always returns one, since all pointertypes shall have the same size.
So your write statement will print sizeof(< anypointer >) random characters.
Solution
for(int i = 0; i < 20; i++){
fwrite (history[i], sizeof(*history[i]), strlen(history[i]) + 1, f);
}
Notice: This will include the '\0' for each string.
Notice: This will write the internal state into the file, so you should consider to open it in binary-mode or to use:
fputs(history[i], f);
fputc('\n', f); /*or anything similar*/

Trying to read back binary data from a file, causing crash

thanks in advance for your help.
I'm trying to call a function which will read back date from the binary file I've just created of a sine wave. The file has already been opened in w+b in the main function. I want to copy the data to my buffer array, then print them out.
end_time is the total number of samples in the file. The samples have been written as floats. Code Blocks gives no errors, but the program crashes when it gets to this point and I'm not sure why.
void printwave(FILE *fp, int end_time)
{
int i;
float buffer[end_time];
fseek(fp, 0, SEEK_SET);
for(i=0; i==end_time; i++)
{
fread(buffer, sizeof(float), 1, fp);
printf("%d\t%.2f\n", i, buffer[i]);
}
}
Thanks for your help,
Andy.
The return value of fread() needs to be checked to make sure there is no error
For loops's condition should be i < end_time
It seems the file is being opened in write mode, but both reading and writing are done.
Return value of fseek needs to be checked as well. I am assuming that fp is a valid file pointer and its validity has already been checked when the file was opened.
Since you are reading each float and printing out, you may not need to store it in an array buffer.
As it is in your code, you read one element after the end of buffer. Because valid elements have indices from 0 to end_time - 1 so the immediate fix to your code is
while ((i < end_time) && (fread(buffer, sizeof(float), 1, fp) == 1))
{
printf("%d\t%.2f\n", i, buffer[i]);
i += 1;
}
Note: Don't try printf("%d\t%.2f\n", i, buffer[i++]); or similar because it's undefined behavior.

Problems converting tga files to black and white

I have been trying to make this program to convert a tga image for color into black and white. But i have no clue how to go about it. I am verry new to C and have yet to get the hang of the syntax and even proper usage of ubuntu.
I think my problem is somthing with tha tga files header cant be read. Because the result i get when trying this program on a tga file is an unopenable picture with no height. "height = 0".
Is there some good links for one to read up on C?
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct pixel {
uint8_t r, g, b, a;
};
static uint8_t *load_image(char *filename, int *sizex, int *sizey)
{
uint8_t *image;
char buf[512];
char *bufptr;
int ret;
FILE *fp = fopen(filename, "r");
bufptr = fgets(buf, 512, fp);
ret = fscanf(fp, "%d %d\n", sizex, sizey);
bufptr = fgets(buf, 512, fp);
image = malloc(*sizex * *sizey * 4);
int i;
uint8_t *ptr = image;
for (i=0; i<*sizex * *sizey; ++i) {
ret = fread(ptr, 1, 3, fp);
ptr += 4;
}
fclose(fp);
return image;
}
static int save_image(const char *filename, uint8_t *image, int sizex, int sizey)
{
FILE *fp = fopen(filename, "w");
fprintf(fp, "P6\n%d %d\n255\n", sizex, sizey);
int i;
uint8_t *ptr = image;
for (i=0; i<sizex * sizey; ++i) {
fwrite(ptr, 1, 3, fp);
ptr += 4;
}
fclose(fp);
return 1;
}
void convert_grayscale(uint8_t *input, uint8_t *output, int sizex, int sizey)
{
// Y = 0.299 * R + 0.587 * G + 0.114 * B
int i;
for (i = 0; i < sizex * sizey; ++i)
{
struct pixel *pin = (struct pixel*) &input[i*4];
struct pixel *pout = (struct pixel*) &output[i*4];
float luma = 0.299 * pin->r + 0.587 * pin->g + 0.114 * pin->b;
if (luma > 255)
luma = 255;
uint8_t intluma = (int) luma;
pout->r = intluma;
pout->g = intluma;
pout->b = intluma;
pout->a = 255;
}
}
int main()
{
uint8_t *inputimg, *outputimg;
int sizex, sizey;
inputimg = load_image("image.tga", &sizex, &sizey);
outputimg = malloc(sizex * sizey * 4);
convert_grayscale(inputimg, outputimg, sizex, sizey);
save_image("output.tga", outputimg, sizex, sizey);
}
(Personal note: A longer answer after reading Why Stackoverflow sucks. That should be Required Reading for everyone who gets Moderator privileges.)
The problem is your load_image code seems designed to read PPM (ASCII-based) images:
Each PPM image consists of the following:
1. A "magic number" for identifying the file type. A ppm image's magic number is the two characters "P6".
2. Whitespace (blanks, TABs, CRs, LFs).
3. A width, formatted as ASCII characters in decimal.
4. Whitespace.
5. A height, again in ASCII decimal.
6. Whitespace.
7. The maximum color value (Maxval), again in ASCII decimal. Must be less than 65536 and more than zero.
8. A single whitespace character (usually a newline).
9. A raster of Height rows [...]
-- your first fgets reads, then discards, the "magic number" line, followed by reading the width and height, and then discarding the "maxval" line.
It ought to work for PPM images (and you could rename this routine load_ppm_image) were it not for a single important issue: after all that ASCII stuff, you switch to fread, and so here is Warning #1.
Before opening your file, decide whether you are going to read exclusively ASCII text, or might need to read binary data.
The problem is that 'text mode' "w" converts certain characters when reading and writing into others. That's built-in behavior in all common C libraries; it attempts to fix the end-of-line characters mess that a previous generation of programmers left us with. Now, reading text files in text mode got a bit simpler, but reading binary data is impossible. You can't be sure you got exactly what was in the file.
Let's get on with Warning #2: not all file formats are the same.
The above routine works (mostly) for PPM images, but it will fail on TGA because its header is organized differently. The TGA header is described rather well here (a random pick of Google results).
The specification describes bytes, so first thing to do is change your fopen line to
FILE *fp = fopen(filename, "rb");
and, by the way, a good practice is to test if it was successful:
if (fp == NULL)
{
printf ("Opening the file '%s' failed\n", filename);
return NULL;
}
Then you can use fgetc or fread to read one or more bytes. Here comes Warning #3: use fread with care.
fread reads multiple bytes in the order in which they are stored into the file, and so you would think it may read an item such as width and height -- each a 2-byte integer value -- in one 'read' operation. But fread does not know the order of the bytes in your system (nor in the file itself), and so it could be it reads "lo-hi", as in the specification I pointed to, while in your computer the order of bytes in an integer is "hi-lo". To clarify: if the file contains this
80 00
and you read, then store, this with fread (&width,1,2, fp), these 2 bytes get stored into computer memory in that same order. The bytes are in Big-Endian order; the "large" byte is at the end. But if your computer happens to be a Little-Endian order system, you would not get the value 0x0080 = 128 but 0x8000 = 32768 instead!
The way to circumvent this is to read one byte at a time:
width = fgetc(fp) + (fgetc(fp)<<8);
will always read the data in the correct order: low first, then high. Only the sum gets stored (in the order for your system, but that's now irrelevant!).
With the above, I think I'm out of warnings. Using the TGA specifications as a guide, you can now open the file, read the header one byte at a time until you have all information that's needed, and continue to fread your raw image data into memory. You can safely use fread to read your image bytes three at a time because they will appear in the same order into memory as they were read (they are not integers or larger, so the "memory order" is not an issue).
A good approach to ensure you are reading the correct information is this:
Read one byte at a time, to prevent endianness issues.
Add a comment in your code detailing what it is
Print out the value
Check with the specifications if the value is allowed.
To get you started, after the fopen line (and the required check if it worked):
int idLength = fgetc(fp); /* length of id string after header */
printf ("id length: %u bytes\n", idLength);
int colorMapType = fgetc(fp); /* 0 = RGB */
printf ("color map type: %u\n", colorMapType);
if (colorMapType != 0)
{
printf ("unexpected color map type!\n");
return NULL;
}
int imageType = fgetc(fp); /* 0 = None, 1 = Indexed, 2 = RGB, 3 = Greyscale */
.. and so on. When the entire header has been read and you didn't encounter surprises, you are ready to set up things to read the actual image data. No changes needed there, your existing code should work just fine.
Post-edit: I see I used
int colorMapType = fgetc(fp);
where the 'color map type' is in fact a byte, not an integer. That is to allow a belt-and-suspenders approach. If you encounter the end of the file while you are reading the header, the code that fgetc returns is EOF. EOF cannot be stored into a char, because it is an integer value: 0xFFFFFFFF (more accurately: (int)-1). If you store it into a char, you cannot distinguish it from the perfectly okay value 0x000000FF (the value 255).
The belt-and-suspender approach is to check each and every single byte:
if (colorMapType == EOF)
{
printf ("encountered unexpected end of file!\n");
return NULL;
}
Overkill if you are working with a known file, and you know it's a valid TGA (you can view and edit it with bitmap editors), but if you ever plan to work on files of which you don't know if they are valid, you might need this.

Resources