Write PPM file header - c

I am trying to write a PPM file and am having trouble with the header specifically.
I have a function taking in a file pointer and header struct containing my header information.
void writeHeader(FILE* file, struct Header* header){
char space[] = " ";
char newLine[] = "\n";
fwrite(&header->magicNum[0], sizeof(char), 1, file);
fwrite(&header->magicNum[1], sizeof(char), 1, file);
fwrite(newLine, sizeof(char), 1, file);
fwrite(&(header->width), sizeof(int), 1, file);
fwrite(space, sizeof(char), 1, file);
fwrite(&header->height, sizeof(int), 1, file);
fwrite(newLine, sizeof(char), 1, file);
fwrite(&header->maxColor, sizeof(int), 1, file);
fwrite(newLine, sizeof(char), 1, file);
fwrite(space, sizeof(char), 1, file);
}
When I call this I end up only writing the first two values "P6" to file and then blanks after (or dots in hex editor). I have also tried removing the space and newline characters but I still don't get anything after P6. How can I write the rest of my header to file along with the necessary space and newline characters where needed?

As the PPM header is stored in ascii strings, I would say something like:
#include <stdio.h>
#include <string.h>
#define OUTFILE "file.ppm"
struct Header {
char magicNum[3];
int width;
int height;
int maxColor;
};
void writeHeader(FILE* file, struct Header* header)
{
fprintf(file, "%s\n", header->magicNum);
fprintf(file, "%d %d\n", header->width, header->height);
fprintf(file, "%d\n", header->maxColor);
}
int main()
{
struct Header header;
FILE *fp;
strcpy(header.magicNum, "P6");
header.width = 1920;
header.height = 1080;
header.maxColor = 255;
fp = fopen(OUTFILE, "w");
if (fp == NULL) {
perror(OUTFILE);
exit(1);
}
writeHeader(fp, &header);
// write the ppm data to the file
return 0;
}

If you look at the PPM header example here on Wikipedia, you will see that the width and height numbers are stored as ASCII text in the file (similar to how you correctly stored the number 6 in "P6" as text).
But in the code that follows, you appear to be writing actual integers (for width and height, etc) from memory to the file, which depends on your system's architecture and is not the same as writing the ASCII characters that represent the integers. Here I have annotated a hexdump from my system (with an "image" of width 5, height 4, maxColor 3), where my integers are stored across 4 bytes with the least-significant byte first:
(ch = character; sp = space)
ch ch ch --integer-- ch --integer-- ch --intege
P 6 \n |width:5--| sp |height:4-| \n |maxCol:
00000000 50 36 0a 05 00 00 00 20 04 00 00 00 0a 03 00 00 |P6..... ........|
00000010 00 0a 20 |.. |
3| \n sp
r- ch ch
So programmatically your code seems to work, but I don't think it is achieving what you intend.
This is probably what you want to end up with:
ch ch ch ch ch ch ch ch ch ch
P 6 \n 5 sp 4 \n 3 \n sp
00000000 50 36 0a 35 20 34 0a 33 0a 20 |P6.5 4.3. |

Related

Read PNG file with c

I want to read a PNG image file with C without any library. From PNG (Portable Network Graphics) Specification Version 1.0 any PNG file has a signature that distinguishes it from other image formats. The signature is the first 8 bytes of the image.
Some sources like the above RFC mentioned the signature as:
137 80 78 71 13 10 26 10 (decimal)
Or like Not able to read IHDR chunk of a PNG file mentioned the signature as:
89 50 4E 47 0D 0A 1A 0A (ASCii)
So, I write a simple code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SIZE (8)
int main(int argc, char **argv){
if(argc != 2) {
printf("Usage: %s <png file>\n", argv[0]);
return 1;
}
char *buf = (char *)malloc(MAX_SIZE);
if(!buf) {
fprintf(stderr, "Couldn't allocate memory\n");
return 1;
}
FILE *f = fopen(argv[1], "r");
if(!f) {
perror("fopen");
printf("Invalid file\n");
free(buf);
return 1;
}
int size = fread(buf, 1, MAX_SIZE, f);
printf(%c\n", buf[1]);
printf(%c\n", buf[2]);
printf(%c\n", buf[3]);
printf(%c\n", buf[4]);
printf(%c\n", buf[5]);
printf(%c\n", buf[6]);
printf(%c\n", buf[7]);
printf(%c\n", buf[8]);
fclose(f);
free(buf);
system("pause");
return 0;
}
When I print the bytes by printf, the output is not like the above.
This is what it shows:
ëPNG→►v#,
Can someone describe what happened and what can I do to modify it?
You need to print each value with the correct format specifier. Here we want numerical representations, not character ones.
From the documentation on printf:
%c writes a single character
%d converts a signed integer into decimal representation
%x converts an unsigned integer into hexadecimal representation
%02X prints a hexadecimal with a minimum width of two characters, padding with leading zeroes, using ABCDEF (instead of abcdef).
See also implicit conversions.
An example:
#include <stdio.h>
#define SIZE 8
int main(int argc, char **argv) {
unsigned char magic[SIZE];
FILE *file = fopen(argv[1], "rb");
if (!file || fread(magic, 1, SIZE, file) != SIZE) {
fprintf(stderr, "Failure to read file magic.\n");
return 1;
}
/* Decimal */
for (size_t i = 0; i < SIZE; i++)
printf("%d ", magic[i]);
printf("\n");
/* Hexadecimal */
for (size_t i = 0; i < SIZE; i++)
printf("%02X ", magic[i]);
printf("\n");
fclose(file);
}
Output:
137 80 78 71 13 10 26 10
89 50 4E 47 0D 0A 1A 0A

Problem when reading a binary file in C. The reading stops at the beginning when a binary value of 00 is found

When I open and read a text file it works. However, when I open and try to read a binary file it stops at the first byte equal to 00.
For example, I try to read a png file, with the below first line in hexdump:
00000000 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 |.PNG........IHDR|
But, I end up with a string that includes only these:
00000000 89 50 4e 47 0d 0a 1a 0a 0a |.PNG.....|
This is my code.
int main(int argc, char *argv[]) {
int num = 5;
char *filename;
char *myfile;
FILE *fp;
filename = argv[1];
if((fp = fopen(filename,"rb")) == NULL) {
printf("error open file\n");
exit(1);
}
myfile = (char *) malloc(num*sizeof(char));
if(myfile==NULL) {
printf("error memory\n");
exit(1);
}
int i=0;
while(!feof(fp)) {
fread(myfile+i,sizeof(char),1,fp);
if(i==num) {
myfile = (char *) realloc(myfile,sizeof(char)*(num*2));
if(myfile==NULL) {
printf("error memory\n");
exit(1);
}
num = num*2;
}
i++;
}
fclose(fp);
printf("%s\n",myfile);
return(0);
}
You're reading the entire file correctly. Instead, the problem lies here:
printf("%s\n",myfile);
printf doesn't know when your myfile string ends, and so assumes it's a cstring, which is terminated by the first null character.
You'd want to use fwrite instead:
fwrite(myfile, num, 1, stdout);
This isn't a complete working alternative, though -- from what I see in your code, num is likely to be higher unless your file's size is an exact power of two. You'd want to rewrite your program so that you know the exact size of the data you've read, and then replace num with that in fwrite.

Hex file reading in C, some data corrupted?

Iam having a problem with my school project. When i try to read in C program some hex data from a binary file i get some data filled with F's like this
00 64 61 56 03 00 00 00 09 00 00 00 73 00 00 00
6A 69 75 FFFFFFE8 FFFFFFD1 5B FFFFFF8C FFFFFF93 73 FFFFFFAF 19 FFFFFF87 FFFFFFC1 4D FFFFFFFD FFFFFF93
FFFFFFDF FFFFFFBE FFFFFFA0 09 FFFFFFBE FFFFFFD4 FFFFFFEB FFFFFFDE FFFFFFD3 FFFFFFF9 FFFFFFBD FFFFFFE6 FFFFFFFA FFFFFFAA 7E 29
FFFFFFD3 FFFFFFE2 13 FFFFFFA5 3F FFFFFFA0 3A FFFFFFB2 50 53 3B 12 FFFFFFA1 39 FFFFFFA6 FFFFFF82
FFFFFFF7
While the original file in hexdump looks like this:
0000000 6400 5661 0003 0000 0009 0000 0073 0000
0000010 696a e875 5bd1 938c af73 8719 4dc1 93fd
0000020 bedf 09a0 d4be deeb f9d3 e6bd aafa 297e
0000030 e2d3 a513 a03f b23a 5350 123b 39a1 82a6
0000040 00f7
Iam not quiet sure, why is this happening.
I tested it using this code:
int main()
{
char ch, file_name[25];
FILE *fp;
printf("Enter the name of file you wish to see\n");
fgets(file_name, sizeof(file_name), stdin);
file_name[strlen(file_name)-1] = 0x00;
fp = fopen(file_name,"rb"); // read binary mode
if( fp == NULL ) //error checking
{
perror("Error while opening the file.\n");
exit(EXIT_FAILURE);
}
printf("The contents of %s file are :\n", file_name);
int i;
while( ( ch = fgetc(fp) ) != EOF )
{
printf("%02X ",ch);
if( !(++i % 16) ) putc('\n', stdout);
}
fclose(fp);
putc('\n', stdout);
return 0;
}
You just tripped on the sign extension done by the processor when expanding a signed integer value to a larger integer type:
The type char is only one byte wide, while the printf() function expects int arguments (four bytes on your system). Since char is signed on your system, the other 24 bits are filled with copies of the sign bit, producing the FFFFFF pattern that you see in your output. Note that your output is correct, except for the FFFFFF-prefixes to all bytes that start with a hex digit greater or equal to 8.
You can avoid this by simply declaring ch as unsigned char. That will be zero extended to an int, and your output will be correct.
If you make ch an unsigned character you won't see the sign extension (the FFs).
It may not be a good idea to open a file as a binary file, and trying reading it by fgetc(), which deals with text files. Instead, you can use fread() to read binary files.
Here is my solution:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
int main()
{
char file_name[25];
puts("Enter the name of file you wish to see");
fgets(file_name, sizeof (file_name), stdin);
file_name[strlen(file_name) - 1] = '\0';
FILE *fp;
fp = fopen(file_name, "rb"); // read binary mode
if(!fp) //error checking
{
perror("fopen()");
exit(EXIT_FAILURE);
}
fseek (fp, 0, SEEK_END); // non-portable
long fSize = ftell(fp);
rewind(fp);
printf("The contents of %s file are :\n", file_name);
uint8_t *ch = malloc(fSize); // assuming CHAR_BIT == 8
fread(ch, 1, fSize, fp);
int i;
for(i = 0; i < fSize; i++)
{
printf("%.2x ", ch[i]);
if(!((i + 1) % 16))
putchar('\n');
}
fclose(fp);
putchar('\n');
return EXIT_SUCCESS;
}
This code has been tested on my machine, and its output is identical to that of hex dump. Feel free to ask me about the details.
make ch an unsigned char as it is treating the binary value as signed and the MSB as sign bit.

Reading a file 16 bytes at a time in C

I am trying to read a file parsed from a command line argument 16 bytes at a time. I am storing the bytes in an unsigned char array. I am then trying to print the elements in their HEX format and then, if they are printable characters, I am printing them and if not I am printing a dot "." I also would like to print the offset of the byte from the beggining of the file on each new line but I want to get the rest working before I start working on that. The problem I am having is the file I am reading from is not printing so I don't think I am doing it right. I started out using fread() but I think I may be needing to use fseek() but I am unsure. If anyone could point me in the right direction or tell me if I'm doing anything wrong I'd appreciate it.
Code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
FILE *fp;
int i, j;
unsigned char buffer[17];
fp = fopen(argv[1], "r");
while(!feof(fp))
{
while(fread(buffer, 16, 1, fp) !=0)
{
for(i=0; i < 16; i++)
{
printf("%X ", buffer[i]);
}
for(j = 0; j < 16; j++)
{
if(isprint(buffer[j]))
printf("%s", buffer[j]);
else
printf("." );
}
printf("\n");
}
}
fclose(fp);
return 0;
}
Expected output:
0001: 40 4F 28 37 0B B8 FF 9D 81 5E 2E 73 B5 CC 6A 70 #O(7.....^.s..jp
0010: 0F 30 9C 6E 7E F7 53 E0 C1 5E 9A 38 C5 02 F2 33 .0.n .S..^.8...3
EDIT: Fixed problem with suggestions. Was opening file in text mode instead of binary. Changed read mode to "rb" and code is working correctly now.
You need to open the file in binary mode, using fseek/ftell on a file in text mode gives erratic values.
So open the file with
fp = fopen(argv[1], "rb");
also good practice is to always check if a function succeeded by checking the return value, in this case if (fp != NULL) ...
Instead of reading 16 byte chunks read 1 byte 16 times, otherwise if the file length is not evenly dividable by 16 you miss the last bytes
if ( fp != NULL )
{
int read = 0;
while((read = fread(buffer, 1, 16, fp)) > 0)
{
for(i=0; i < read; i++)
{
...
}
fclose(fp);
}
IOW no need to for the outer while (feof(fp)) ...
in
printf("%s", buffer[j]);
you are not using the correct format specifier, buffer[j] is a character, not a string so write
printf("%c", buffer[j]);
EDIT: if you are not in some embedded environment with minimal stack reading 16 bytes at a time is not so effective, you can just as might read 2k or some bigger size to read faster.

why extra characters are appears in text file?

I have a file, such as the following (in hex).
1F 00 48 3A 18 00 00 00 53 00 70 00 6F 00 75 00
73 00 65 00 5F 00 61 00 7A 00 61 00 6D 00 00 00
I am trying to read the binary data from the file and output it as text. My current code is as follows:
#include<stdlib.h>
#include<stdio.h>
#include<iostream.h>
int main()
{
FILE *pFile, *tempFile;
pFile = fopen("C:\\wab files\\Admin.wab", "rb");
if(pFile == NULL)
{
fputs("file error", stderr);
exit(1);
}
tempFile = fopen("C:\\myfile.text","wb");
if(tempFile == NULL)
{
fputs("file not open", stderr);
exit(2);
}
int Contact_Id, Id_Size, Data_Info=0;
fread(&Contact_Id, 1, 4, pFile);
fread(&Id_Size, 1, 4, pFile);
Data_Info = Id_Size;
char* Main_buffer = (char*)malloc(Data_Info*sizeof(Data_Info));
fread(Main_buffer, 1, Id_Size, pFile);
const wchar_t* src = (unsigned short *) Main_buffer;
wcstombs ((char*) Main_buffer, src, Data_Info );
fwrite(Main_buffer, 1, Data_Info, tempFile);
free(Main_buffer);
return 0;
}
The output text file containts follow:
Spouse_azam _ a z a m
Why is _ a z a m shown in text file? I wants to write only Spouse_azam.
First of all this is wrong:
char* Main_buffer = (char*)malloc(Data_Info*sizeof(Data_Info));
It should be
char* Main_buffer = (char*)malloc(Data_Info*sizeof(char));
Second, you are using the same buffer (Main_buffer) for both source and destination. The result is that the first part of the buffer is overwritten with the converted string, but the rest of the buffer is left untouched. You have 24 bytes initially in the buffer (if you allocate correctly), and the first 11 are overwritten, but the other 13 are left there.
There are two options: use a second buffer for the multi-byte string, or use the return value of wcstombs to know how many bytes the result string has:
int bytes = wcstombs ((char*) Main_buffer, src, Data_Info );
fwrite(Main_buffer, 1, bytes, tempFile);

Resources