P6
650 652
255
P6 indicates that it is a PPM image. The next two fields are the width and height of the image. The last field gives the maximum pixel value. At the end of the header is a \n and then the binary pixel data. The image is in color so there are three bytes (red, green, blue). The goal of my readPPM function is to return the pixel data in a one-dimensional array of unsigned chars, plus the width and height of the image. The goal of my writePPM function (I haven't done anything for that function yet) is to write the PPM format image to an empty file from the given information returned from my readPPM function. I'm still not sure how to make this program work so I don't store the 650 in width and 652 in height. I'll worry about that once I can actually read and write the text files.
Update: I've successfully stored the header (P6, 650, 652, and 255)) in their right variables (I know because I tried printing their values and they came out right). My output is shown below. I was wondering what those nonsense characters below the maximum were. Are those the binary pixel data? If so, then I just need to write my writePPM function.
Output:
PSix: P6
Width: 650
Height: 652
maximum: 255
?ɡ?Ƞ?ɢ?ˤ?ɢ?Ş?ĝ?Ǡ?ʤ?ɣ?ɡ?ɡ?ǟ?Ĝ?ŝ?Ƞ?ȡ?ʣ?ʣ?ȡ?Ŝ?Ŝ?Ȟ?ʠ?̤?ƞ?Ơ?ʤ?ʦ?ʦ?ɧ?Ƥ?ǥ?Ȧ?ɩ?ʪ?ʫ?ʫ?ʪ?ʨ?ɤ?Ǡ?ʢ?̤?ȡ?ȡ?ʥ?ɥ?ʧ?Ģ?ǥ?Ƥ?Ģ? ????Ƥ????ǥ?ʨ?ɧ?ʨ?ɧ?ɧ?ͨ?ϧ?ʟ?ˠ?Х?Φ?ͥ?ˣ?ǟ??Ơ?ʦ?ɥ?Ġ????????????? ?????ħ?Ũ???????©?Ǯ?????????????Ǩ?˭?ū?????????????????????????鴢紣㴢ⳡ?ܴᷟ?⺡㻢Ḥ?ݳ?۱?ܲ?۱?خ??ٯ?֮?ѫ?Ъ?̨?մ?յ?Ǫ?̲?ٿ?һ????ư?ɳ?ɳ?ɱ?ɱ?˰?ˮ?ɪ?Ȧ?ͫ?ֵ?ұ?Ť?¡?ʩ?Ӳ?Ϯ?ͫ?ϭ?ѯ?ѯ?Ϭ?̭?˰?Ͷ?͵?˳?ʱ?Ǯ?ȯ?ε?ӷ?ϳ?̯?ɬ?̫?ͬ?ͭ?˪?ΰ?ͮ?ί?Ӵ?Ӷ?ϲ?ˮ?ɬ?ʭ?Ѵ?ҵ?г?ϲ?ˮ?ȫ?ɬ?ǩ?ϱ?в?˭?ʬ?˭?̭?ί?ͮ?ͮ?ͮ?ί?ˬ?ȩ?ʫ?ͮ?ղ?ү?Ӳ?ֵ?Ҵ?ѳ?ϲ?ˮ?ȭ?˰?ˮ?ˮ?ͯ?̮?̬?ͯ?ˮ?̱?˲?ȯ?ƭ?Ư?Ů?®?¯?????????????????????????????????????¨?é?é?ū?¨???????????????????????????????ī?ī?ī?Ŭ?Ŭ?ī?ū?ū?é???????ĭ?Ů?®???????????©??????????ȫ?ȫ?Ȫ?ɫ?̭?̭?˭?ʬ?ɫ?ʬ?ʮ?˯?˯?˯?˯?Ȭ?Ȫ?ɫ?̮?ͯ?ϱ?ѳ?ӵ?Ѵ?б?ϰ?ϭ?ά?Ѯ?Ա?Ӱ?Э?Ϭ?ү?ү?Э?ά?ѯ?ױ?ӭ?ϩ?ͧ?ϧ?ѩ?Ԭ?ذ?խ?ѩ?Ϧ?Ϧ?Ч?ҩ?ҩ?ҩ?ת?ث??خ?ׯ?֮?կ?կ?Ԭ?խ?ج?ج?ܬ?߰?㳩䴨峨ݫ?٧?ެ?䲧峨䲧䲧Ⱗ䲩붮?ﺲ국굯???????걦뱥ﶥ???????????????????????????????????????±????ð?????????????????????????????????????????????????æ?ũ?ç?é?Ī?ë???????£?Ʀ?Ʀ?ƥ?Ť?Ť?ƥ?ɧ?ʨ?ͫ?ά?ʩ?Ť?â?ţ?Ǩ?ť?Ƨ?ˬ?ɭ?¦???????????????????????????????ç???????????????????????????????????????????????????????????????????????????????????????????????????????????????????ñ?°?ñ??????????î????????????????????????鲯豮汭尬䯫汭곮췱洫ᱧద嵫緭䴪᯦᯦䲩洫鴬鴬鴬국국贩춬??????뵩괪???????????겱⪭????겳???뵫贩贩趫긭긭긭跩綨깫컭궩糦뵩뷩켨컪鸧綨浧絬鷮鷰峬洫???긭跩긭캱캳깲綯㳩ᱧ㳧嵩㵨᳦᳤ⴥ乩缬轭轭缬ߴ?۰?ߴ?幬
main.cc
int main() {
char fileName[50] = "binary_pixels.txt";
int width = 0; // width of the image
int height = 0; // heigt of the image
int size = 128; // size of the array
// read the PPM file and store its contents inside an array and return
// the pointer to that array to pixelArray
unsigned char* pixelArray[size] = readPPM(fileName, &width, &height);
// print the contents of the array
for (int i = 0; i < 128; i++) {
printf("%s\n", pixelArray[i]);
} // end of for loop
} // end of main
readPPM.cc
unsigned char readPPM(const char* fileName, char* pSix, int* width,
int* height, int* maximum) {
// open the file to read just the header reading
FILE* fr = fopen(fileName, "r");
// formatted read of header
fscanf(fr, "%s", pSix);
// check to see if it's a PPM image file
if (strncmp(pSix, "p6" , 10) != 0) {
printf("They are not the same\n");
} else {
printf("They are the same\n");
}
// read the rest of header
fscanf(fr, "%d\n %d\n", width, height);
fscanf(fr, "%d\n", maximum);
// check to see if they were stored properly
printf("PSix: %s\n", pSix);
printf("Width: %d\n", *width);
printf("Height: %d\n", *height);
printf("maximum: %d\n", *maximum);
// allocate array for pixels
unsigned char* pixels = new unsigned char[width * height];
// unformatted read of binary pixel data
while (fread(pixels, sizeof(pixel), 128, fr)) {
printf("%s", pixels);
} // end of for loop
// close file
fclose(fr);
// return the array
return pixels;
} // end of readPPM
//struct to hold a pixel.
struct rgb
{
char r;
char g;
char b;
};
//struct to hold the image and its info.
struct image
{
char p;
int format;
int width;
int height;
int intensity;
//struct rgb **rgb;
unsigned char *pixels;
};
int main(void)
{
struct image m;
FILE *fp = //fopen(...);
fscanf(fp, "%c%d\n", &m.p, &m.format);
fscanf(fp, "%d %d\n", &m.width, &m.height);
fscanf(fp, "%d\n", &m.intensity);
printf("%c%d\n", m.p, m.format);
printf("%d %d\n", m.width, m.height);
printf("%d\n", m.intensity);
//allocate array to hold the pixels
m.pixel = (unsigned char*)malloc(m.width*m.heigth*3*sizeof(unsigned char));
//read pixels into m.pixel
return 0;
}
You are not reading the char into the correct location. pixels is already a pointer to chars so you should pass it as is to fscanf:
fscanf(fr, "%c", pixels)
Of course there are other issues but I this should let you pass this road block.
Related
I would like to fwrite() then fread() the following struct ** whose memory has been allocated dynamically.
This struct is declared as following :
typedef struct {
int num;
char type;
Entity entity;
}Cell;
I declare a map of cell as following :
typedef struct {
char name[MAX_STRING];
int width;
int height;
Cell** map;
}Maze;
I allocate the map's memory as following :
maze.map = (Cell **)malloc( width*sizeof( Cell* ));
for (int x = 0; x < width; x++ )
{
maze.map[x] = (Cell *)malloc(sizeof( Cell )*height);
}
The thing is is i can't fwrite()/fread() my struct like this because once I would like to fread() the struct, I would not be able to allocate the proper memory space.
So i decided to write the height and width first then allocate the memory then read the map.
But I can't find how to write or read my map properly.
I tried :
for (int x = 0; x < maze.width; ++x) {
for (int y = 0; y < maze.height; ++y) {
fwrite(&maze.map[x][y], sizeof(Cell), 1, file);
}
}
But it doesn't work, otherwise i don't know how should I write/read my map.
Everything i tried doesn't give me back the map i wrote or it just crash saying me : Process finished with exit code -1073741819 (0xC0000005)
Here are the two writing and readin fuction :
void SaveMaze(Maze maze){
FILE *file;
char file_name[MAX_STRING];
strcpy(file_name, maze.name);
strcat(file_name,".save");
file = fopen(file_name, "w");
if(file == NULL)
{
perror("Error Fopen : ");
return ;
}
fwrite(maze.name,sizeof(maze.name), 1, file);
fwrite(&maze.height,sizeof(maze.height), 1, file);
fwrite(&maze.width,sizeof(maze.width), 1, file);
for (int x = 0; x < maze.width; ++x) {
fwrite(&maze.map[x], sizeof(Cell), maze.height, file);
}
// Close the file
fclose(file);
}
Maze LoadMaze(char * name){
FILE *file;
Maze maze;
char file_name[MAX_STRING];
strcpy(file_name, name);
strcat(file_name,".save");
file = fopen(file_name, "r");
if(file == NULL) {
perror("Error Fopen : ");
return maze;
}
fread(maze.name,sizeof(maze.name), 1, file);
fread(&maze.height,sizeof(maze.height), 1, file);
fread(&maze.width,sizeof(maze.width), 1, file);
maze.map = (Cell **)malloc( maze.width*sizeof( Cell* ));
for (int x = 0; x < maze.width; x++ )
{
maze.map[x] = (Cell *)malloc(sizeof( Cell )*maze.height);
}
for (int x = 0; x < maze.width; ++x) {
fread(&maze.map[x], sizeof(Cell), maze.height, file);
}
printf("%c",maze.map[0][0].num);
fclose (file);
return maze;
}
int main() {
int choice;
int width,height;
char name[MAX_STRING],file_name[MAX_STRING];
Maze maze;
do{
printf("1. Generate a new Maze\n");
printf("2. Load an existing maze\n");
printf("3. Play\n");
printf("4. Exit\n");
scanf("%d",&choice);
fflush(stdin);
if(choice == 1){
do {
printf("What is the width of your maze (Odd number only)\n");
scanf("%d", &width);
fflush(stdin);
} while (width%2 == 0);
do {
printf("What is the height of your maze (Odd number only)\n");
scanf("%d", &height);
fflush(stdin);
} while (height%2 == 0);
printf("What is the name of the maze\n");
fgets(name,sizeof(name),stdin);
// Remove the \n from the name
name[strcspn(name, "\n")] = 0;
fflush(stdin);
maze = CreateMaze(width,height,name);
InitialyzeMaze(&maze);
BuildMaze(&maze);
fflush(stdin);
SaveMaze(maze);
}else if(choice == 2){
//system("clear");
//system("ls *.{save}");
printf("What is the name of the maze you want to load ?\n");
fgets(file_name,sizeof(file_name),stdin);
// Remove the \n from the filename
file_name[strcspn(file_name, "\n")] = 0;
fflush(stdin);
maze = LoadMaze(file_name);
}else if(choice == 3){
Play(&maze);
}
}while(choice != 4);
}
You're mixing text data and binary data in your data file.
When you write the name, height, and width:
fprintf(file,"%s",maze.name);
fwrite(&maze.height,sizeof(maze.height), 1, file);
fwrite(&maze.width,sizeof(maze.width), 1, file);
This outputs a series of characters for the name (let's say "my_maze") followed immediately by sizeof(int) bytes for the height and sizeof(int) bytes for the width.
So that's 7 bytes for the name, 4 bytes for height (assuming an int is 4 bytes), and 4 bytes for width.
Now when you read back:
fscanf(file,"%s",maze.name);
fread(&maze.height,sizeof(maze.height), 1, file);
fread(&maze.width,sizeof(maze.width), 1, file);
The %s format specifier to fscanf reads characters until it encounters whitespace. The first 7 characters get read in correctly but right after that is binary data for height so where does it stop reading? The result is that you most likely read more bytes than you indented to and now the rest of your reads are not in the correct place.
You can fix this by doing away with fprintf and fscanf by writing the entire name field with fwrite:
fwrite(maze.name,sizeof(maze.name), 1, file);
And reading it with fread:
fread(maze.name,sizeof(maze.name), 1, file);
You also have a problem here:
fwrite(&maze.map[x], sizeof(Cell), maze.height, file);
And here:
fread(&maze.map[x], sizeof(Cell), maze.height, file);
&maze.map[x] is not the address of the memory you allocated but the address of the pointer it points to. So rather than reading/writing the memory set aside for each row of cells you're reading/writing the memory used for the row of pointers for each cell. You end up reading/writing past the end of allocated memory when you do this.
Get rid of the address-of operator here to pass in the pointer to the actual memory you're reading/writing:
fwrite(maze.map[x], sizeof(Cell), maze.height, file);
...
fread(maze.map[x], sizeof(Cell), maze.height, file);
Since the elements in each maze item (maze.map[X]) are continuous, and are pre-allocated, you can write each 'maze' item with a single fwrite call:
for (int x = 0; x < maze.width; ++x) {
fwrite(&maze.map[x], sizeof(Cell), maze.height, file);
}
Taking this route, you can use fread instead of fwrite to read the elements.
Side Note: Usually better to use calloc(count, sizeof(...)), instead of malloc(count*sizeof) - it will initialize the allocated memory to zeros.
The program i am creating a steganography program that hides a secret message inside a .ppm image by changing random red pixel values to ascii characters.
The program is based on code that is on stackoverflow for reading and writing ppm images (read PPM file and store it in an array; coded with C), all other code is my own work. I have completed all the necessary functions to do this such as writing,reading,encoding and decoding the files but i am struggling to grasp the fwrite function.
Currently when the program encodes an image it takes in the .ppm converts it to its rgb values in a struct. Then it hides the secret message by editing the red values to ascii characters. The issue arises when it comes to "printing" the image to a file. When the program has completed the image produced is around 90% of what it should be printing. Example show below:
Example of the unfinished image
I have checked it is storing all the values are being stored correctly by printing all the rgb values and it is. (used the showPPM method). Is there not enough memory to write the image? is the image to large for the write function? these are my guesses.
Any information on how i should go about changing the writePPM function so that i correctly print 100% of the image to the file would be great.
Here is the code below:
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<time.h>
typedef struct {
unsigned char red,green,blue;
} PPMPixel;
typedef struct {
int x, y;
PPMPixel *data;
} PPMImage;
void writePPM(PPMImage *img);
static PPMImage *getPPM(const char *filename)
{
char buff[16];
PPMImage *img;
FILE *fp;
int c, rgb_comp_color;
//open PPM file for reading
fp = fopen(filename, "rb");
if (!fp) {
fprintf(stderr, "Unable to open file '%s'\n", filename);
exit(1);
}
//read image format
if (!fgets(buff, sizeof(buff), fp)) {
perror(filename);
exit(1);
}
//check the image format
if (buff[0] != 'P' || buff[1] != '3') {
fprintf(stderr, "Invalid image format (must be 'P3')\n");
exit(1);
}else{
printf("P3\n");
}
//alloc memory form image
img = (PPMImage *)malloc(sizeof(PPMImage));
if (!img) {
fprintf(stderr, "Unable to allocate memory\n");
exit(1);
}
c = getc(fp);
while (c == '#') {
while (getc(fp) != '\n') ;
c = getc(fp);
}
ungetc(c, fp);
//read image size information
if (fscanf(fp, "%d %d", &img->x, &img->y) != 2) {
fprintf(stderr, "Invalid image size (error loading '%s')\n", filename);
exit(1);
}else{
printf("Height: %d\n",img->x);
printf("Width: %d\n",img->y);
}
//read rgb component
if (fscanf(fp, "%d", &rgb_comp_color) != 1) {
fprintf(stderr, "Invalid rgb component (error loading '%s')\n", filename);
exit(1);
}else{
printf("%d\n",rgb_comp_color );
}
//check rgb component depth
if (rgb_comp_color!= 255) {
fprintf(stderr, "'%s' does not have 8-bits components\n", filename);
exit(1);
}
while (fgetc(fp) != '\n') ;
//memory allocation for pixel data
img->data = (PPMPixel*)malloc(24*img->x * img->y * sizeof(PPMPixel));
if (!img) {
fprintf(stderr, "Unable to allocate memory\n");
exit(1);
}
//read pixel data from file
if (fread(img->data, 10*img->x, img->y, fp) != img->y) {
fprintf(stderr, "Error loading image '%s'\n", filename);
exit(1);
}
fclose(fp);
return img;
}
struct PPMImage * encode(char * text, PPMImage * img)
{
//convert secret message to ascii code
int i,ascii,height,width;
int total = 0;
int rolling = 0;
int original = 0;
time_t t;
srand((unsigned) time(&t));
height=img->y;
width=img->x;
for(i = 0; text[i]; i++){
ascii = text[i];
//create random number between 0 and max the width
total = total + rand() % width;
original = total;
//printf("Random Number: %d\n",total);
if(total >= width){
rolling = rolling + 1;
total = total - width;
}
//printf("Before R: %d \n",img->data[0].red );
img->x=rolling;
img->y=total;
printf("X: %d ",rolling );
printf("Y: %d ",total );
//set img position
//at position random we set the red bit equal to ascii number
printf("Old R: %d ",img->data[i].red );
img->data[i].red=ascii;
printf("New R: %d\n ",img->data[i].red );
}
//take img then print it out
//setting the img values again for printing
img->x=width;
img->y=height;
writePPM(img);
}
void writePPM(PPMImage *img)
{
FILE *fp;
//open file to be written
fp = fopen("encoded.ppm", "wb");
if (!fp) {
fprintf(stderr, "Unable to open file \n");
exit(1);
}
//image format
fprintf(fp, "P3\n");
//comments
//need to store comments to be outputted
fprintf(fp, "# Created by Sean \n");
//image size
fprintf(fp,"%d %d\n",img->x,img->y);
// rgb component depth
fprintf(fp, "%d\n",255);
//write pixels currently not fully working
fwrite(img->data, sizeof(img->data), 3*img->y*img->x, fp);
//close file stream
fclose(fp);
}
void showPPM(PPMImage *img)
{
int i;
if(img){
for(i=-1;i<img->x*img->y;i++){
printf("Number: %d\n",i);
printf("R: %d ",img->data[i].red );
printf("G: %d ",img->data[i].green );
printf("B: %d\n ",img->data[i].blue );
}
}
}
char * decode(PPMImage * i1,PPMImage * i2){
//compare difference in number of bits in red pixels
//if there is a different then take the red pixel value from the encrypted image
//then translate it from ascii to chars then print.
printf("Decoding......\n");
int i;
for(i=-1;i<i1->x*i1->y;i++){
if(i1->data[i].red != i2->data[i].red){
printf("%c",i1->data[i].red );
}
}
//to be able to test and finish this need to write code for encoding
}
int main(int argc, char *argv[]){
//input statements
if(argc == 3){
PPMImage *image;
image = getPPM(argv[2]);
//uncomment the showPPM to display all rgb values in the encoded files
//showPPM(image);
if(argv[1] = "e"){
printf("Please enter your secret message to be encoded estimated max characters: %d\n",image->y);
//need to add user input
encode("test output!",image);
}
}else if(argc == 4){
PPMImage *i1;
PPMImage *i2;
i1 = getPPM(argv[2]);
i2 = getPPM(argv[3]);
if(argv[1] = "d"){
decode(i1,i2);
}
}else{
printf("Wrong arguments");
}
}
The problem is actually in the code for reading in the PPM, which you have modified in a way that appears to work, but actually doesn't because the file format is different to what you think it is.
The code that you linked to is for reading PPM files in the "raw" format. These files start with the "P6" code. In these files, each RGB value is stored as either 1 or 2 bytes (depending on whether the RGB component depth is less than 256). So, if the max value is 255, it's 1 bytes per value, so the file size is width * height * 3.
However, you have modified the code to read "plain" PPM files, which start with the "P3" code, by checking for P3 and reading in more data. These files don't store the RGB values as raw binary data, but as ASCII text specifying the value in decimal format, separated by whitespace. So for example if you had the value 93 in raw format, it would just be 1 byte with a value of 93, but in the "plain" format it would be 3 (or more) bytes: one or more bytes with the ASCII value for a space (or tab), then the ASCII value for "9" (which is 57) then the ASCII value for "3" (which is 51). It's impossible to calculate the size of the file based on the width and height because the whitespace can be variable, and each value could be represented between 1 and 3 digits.
Despite the fact that you are not parsing the data as ASCII-encoded text, your PPM-reading code seems to work because you are just reading in a chunk of data, (optionally) modifying a few random bytes and then writing it out again either totally or mostly unchanged.
So, your possible solutions are:
Change the getPPM code back to what it was and use an actual P6 file.
Write a PPM reader that parses the data properly as ASCII text containing whitespace-separated decimal numbers (you can write out as either P3 or P6).
More info: PPM Format Specification
I'm trying to use the libsndfile library to read/write information between audio files.
I've managed to read the original file, write a copy of it with "watermark" values.
All I'm trying to do now is print any index where the value is not 0.
However, when I call my printBuffer() function, it's returning all 0s even though when on debug mode, I can see that the values in buffer are not zero/changing each iteration.
Am I calling the buffer array incorrectly?
I'm still new to C so if you have any suggestions they would be greatly appreciated.
Thank you.
Code:
#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
#include <stdlib.h>
#include <sndfile.h>
#include <time.h>
#define MAX_CHANNEL 2
#define BUF_SIZE 1024
int numItems(int frames, int channels);
void printInfo(int frames, int channels, int sampleRate);
void watermark(double *buffer, int count, int channels);
void watermark2(double *buffer, int count);
void readFile(int fileNumber);
void printBuffer(double *buffer, size_t count);
int main(void)
{
int chosenFile, answer;
printf("Please select the file you want to read\n");
printf("1. File1\n");
printf("2. File2\n");
printf("3. File3\n");
printf("4. File4\n");
printf("5. File5\n");
scanf("%d", &chosenFile);
processFile(chosenFile);
/*
Put boolean here to check whether to process the original file or the new one
*/
printf("Would you like to read the new file?\n");
printf("1. Yes\n");
printf("2. No\n");
scanf("%d", &answer);
if (answer == 1)
{
readFile(chosenFile);
}
}
int processFile(int fileNumber)
{
/*READING FILE*/
static double buffer[BUF_SIZE];
SF_INFO info;
SNDFILE *infile,*outfile;
int readCount, i;
/*
Put boolean here to check whether it should read the original files, or the new output files
*/
char *Files[] = { "File1.wav", "File2.wav", "File3.wav"
, "File4.wav", "DFile5.wav" };
char *Files2[] = { "File1Output.wav", "File2Output.wav", "File3Output.wav"
, "File4Output.wav", "File5Output.wav" };
char *inputFile = Files[fileNumber - 1];
if (!(infile = sf_open(inputFile, SFM_READ, &info)))
{
printf("Not able to open input file %s.\n", inputFile);
puts(sf_strerror(NULL));
return 1;
};
printf("You have opened: %s\n", Files[fileNumber - 1]);
printInfo( info.frames, info.channels, info.samplerate);
int num = numItems(info.frames, info.channels);
printf("Buffer(frames*channels): %d \n", num);
/*WRITING FILE*/
char *outputFile = Files2[fileNumber - 1];
printf("Your file has been saved in the following location: %s\n", outputFile);
if (!(outfile = sf_open(outputFile, SFM_WRITE, &info)))
{
printf("Not able to open output file %s.\n", outputFile);
puts(sf_strerror(NULL));
return 1;
};
/*
Actual buffer size is numItems, somehow can't declare buffer as buffer[numItems]
BUF_SIZE is set to 1024, which means that it reads the data in chunks of 1024 frames
it will keep writing in 1024 chuncks until all numItems have been written (numItems/BUF_SIZE)
Needs to be on a while loop otherwise it will only write the first 1024 frames of the file
*/
while ((readCount = sf_read_double(infile, buffer, BUF_SIZE)))
{
watermark(buffer, readCount, info.channels);
sf_write_double(outfile, buffer, readCount);
};
for (i = 0; i < sizeof(buffer) / sizeof *buffer; i++)
{
printBuffer(buffer, sizeof(buffer)/sizeof *buffer);
}
/*
Can only close SF_open once both reading/writing has been done
if you close infile after the read, it's not able to copy the audio
data from infile to write into outfile
*/
sf_close(infile);
sf_close(outfile);
return;
}
void readFile(int fileNumber)
{
SF_INFO info;
SNDFILE *infile;
char *Files[] = { "File1Output.wav", "File2Output.wav", "File3Output.wav"
, "File4Output.wav", "File5Output.wav" };
char *inputFile = Files[fileNumber - 1];
infile = sf_open(inputFile, SFM_READ, &info);
printf("You have opened: %s\n", Files[fileNumber - 1]);
printInfo(info.frames, info.channels, info.samplerate);
sf_close(infile);
return;
}
int numItems(int frames, int channels)
{
int numItems = frames * channels;
return numItems;
}
void printInfo(int frames, int channels, int sampleRate)
{
printf("Number of Frames = %d\n", frames);
printf("Number of Channels = %d\n", channels);
printf("Sample Rate = %d\n", sampleRate);
}
void watermark(double *buffer, int count, int channels)
{
double value[MAX_CHANNEL] = { 0.0, 0.0 };
int i, j;
if (channels > 1)
{
/*
Sets j to be the first channel and while i is less than 1024/5, i += channels
buffer[3] value is multiplied by 0, and set to 0
this mutes that particular index value or frame
this keeps going until i>=1024/5 and then the next channel is chosen where j = 2
buffer[4] value is multiplied by 0 and set to 0
this keeps going until i>=1024/5 where it calls back to the while loop in processFile
*/
for (j = 0; j < channels; j++)
{
for (i = j; i < count / 5; i += channels)
{
buffer[i] *= value[j];
}
}
}
else
{
/*
If audio file has 1 channel, buffer[i] is set to 0 for all values < 1024/5 frames
and it goes back to normal until the next 1024 frames where the first 1024/5 frames.
*/
for (i = 0; i < count / 5; i++)
{
buffer[i] *= value[0];
}
}
return;
}
void printBuffer(double *buffer, size_t count)
{
int i;
for (i = 0; i < count; i++)
{
if (i != 0)
printf("%d\n", buffer[i]);
}
}
/*
- *DONE* - Need to create function that will read the newly outputted file
- Find where the watermarks have been left on the audio
- Compare buffer[] values between original file and new outputted file
*/
while ((readCount = sf_read_double(infile, buffer, BUF_SIZE)))
{
watermark(buffer, readCount, info.channels);
sf_write_double(outfile, buffer, readCount);
};
Here, you use the buffer again and again to read some data, watermark it and write it out.Only once you are done, you print the last remaining data out of the buffer:
for (i = 0; i < sizeof(buffer) / sizeof *buffer; i++)
{
printBuffer(buffer, sizeof(buffer)/sizeof *buffer);
}
So, with
#define MAX_CHANNEL 2
#define BUF_SIZE 1024
and a wave file with 16 bit 44100 stereo, you will only see the last 5.8ms of sound data, which probably is almost silence, if you have normal audio like music or some high quality recorded voice with almost no noise.
Additionally: Depending on the last block read, you see the tail of the file, and then some part prior to the tail, like you see the last 3.2ms and then the 2.6ms prior to that, which was not overwritten in the last read call.
/edit: Ok, probably I got the numbers wrong, data type is double and so on, but the conceptual error is the same.
/edit 2: Looking at Jonathan Leffler's comment, I see there are even more errors ... - I recommend switching on ALL compiler warnings, and try to understand (and fix) them.
I have to open/read a file which is an ascii art file (image)
and requires me to return the width and height of the image to the main routine and then requires me to pass the picture data back via a pointer. Here is the function prototype that I MUST use:
unsigned char *foo(char *filename, int *width, int *height)
Inside of foo, I must use a dynamic array of chars
to store tha image data. I need to use fread() to read
that data. I must also account for the carriage return at the end of each line.
Once I have opened and read the data, pass it back to the main routine. The main routine must then create a dynamic 2D array to store the image, copy the 1D array
into the 2D array, and display the image on the screen.
Image File Name: data.txt
My Code:
#include <stdio.h>
#include <stdlib.h>
void readDimension(FILE *inFile, int *width, int *height)
{
int i;
for (i = 0; i < 2; i++)
{
if (i == 0)
{
fscanf(inFile, "%d", width);
}
if (i == 1)
{
fscanf(inFile, "%d", height);
}
}
}
unsigned char *foo(char *filename, int *width, int *height)
{
FILE *inFile = fopen(filename, "rb");
readDimension(inFile, width, height);
unsigned char *ret = malloc(*width * *height);
fread(ret, 1, *width * *height, inFile);
fclose(inFile);
return ret;
}
int main(int argc, char** argv)
{
FILE *inFile;
int width, height;
unsigned char art;
if (argc == 1)
{
printf("Please specify a file name.\n");
}
else if (argc == 2)
{
inFile = fopen(argv[1], "rb");
if (inFile != NULL)
{
fclose(inFile);
art = foo(argv[1], &width, &height);
int n = sizeof(art);
printf("Data in Array: \\%c \n", art);
printf("Size of Array: %d \n", n);
}
else
{
printf("Error: File Not Found %s", argv[1]);
}
}
printf("Width: %d\n", width); // Testing
printf("Height: %d\n", height); // Testing
}
The problem is that you are trying to get the size of art, which is a pointer. It has fixed size. Size should be computed as width*height:
printf("Size of Array: %d x %d (%d)\n", width, height, width*height);
You declared art as an unsigned char, but you are assigning it a pointer to unsigned char. This is incorrect: art should be declared with an asterisk.
You are also printing a single character %c while passing an array art. This is not going to print anything of interest. If you wish to print the first character, print art[0]. If you wish to print the entire picture, make a pair of nested loops that iterate over the width and height, print each character, and print '\n' after each line.
Here are a few additional notes:
You should not read the entire file in one go with fread, because it would introduce \ns into the data. Instead, you should read the file line by line.
You can read width and height in the same function that reads the data
You do not need a loop to read two integers. You can do it in a single line, like this: fscanf(inFile, "%d %d", width, height);
I'm writing a program that takes in two duplicate PNM P6 files, puts the memory of the first file into a buffer, creates a yellow diagonal line over that, and writes the result to the second file. When I run it, the output file is corrupted and can't be displayed. I noticed when looking at the output that it's missing the three lines that should be at the top:
P6
1786 1344
255
I don't know how to programmatically ensure that those lines stay in the code -- I can't figure out why they're even being overwritten in the first place.
When I manually add those lines to the output, the file is no longer corrupted. However, no yellow diagonal line appears. Is this part of the same issue, or is there something else I should look into fixing?
My code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
unsigned char red, green, blue;
} iPixel;
typedef struct
{
int x, y;
iPixel *data;
} Image;
Image *
ReadImage(char *filename)
{
FILE *f = fopen(filename, "rb");
Image *img = NULL;
char magicNum[128];
int width, height, maxval;
if (f == NULL)
{
fprintf(stderr, "Unable to open file %s\n", filename);
return NULL;
}
fscanf(f, "%s\n%d %d\n%d\n", magicNum, &width, &height, &maxval);
/*
printf("Magic num = %s width = %d, height = %d, maxval = %d\n",
magicNum, width, height, maxval)
;
*/
if (strcmp(magicNum, "P6") != 0)
{
fprintf(stderr, "Unable to read from file %s, because it is not a PNM file of type P6\n", filename);
return NULL;
}
img = (Image *) malloc(sizeof(Image));
img -> x = width;
img -> y = height;
img -> data = (iPixel*) malloc(img -> x * img -> y * sizeof(iPixel));
fread(img -> data, sizeof(iPixel), width*height, f);
fclose(f);
return img;
}
void WriteImage(Image *img, char *filename)
{
FILE *f = fopen(filename, "wb");
fwrite(img->data, sizeof(iPixel), img-> x * img-> y, f);
fclose(f);
}
Image *
YellowDiagonal(Image *input)
{
int i, j;
for (i = 0; i < input->x; i++)
{
for (j=0; j < input->y; j++)
{
if (i==j)
{
input->data[i].red=255;
input->data[i].green=255;
input->data[i].blue=0;
}
}
}
return input;
}
int main(int argc, char *argv[])
{
if (argc != 3)
{
fprintf(stderr, "Usage: ./3A_c.c <input image file> <output image file>\n");
exit(EXIT_FAILURE);
}
Image *img;
img = ReadImage(argv[1]);
fprintf(stderr, "Read.\n");
YellowDiagonal(img);
fprintf(stderr, "Diagonal line.\n");
WriteImage(img, argv[2]);
fprintf(stderr, "Write.\n");
}
Be careful to write exactly the same format you are reading. The PNM format is well defined, and you are reading it correctly. However, in the writing routine there were a couple of mistakes:
opening a file with "w" or "wb" truncates it to 0 bytes;
best practice is always to check if fopen succeeds;
reading actual ASCII data can be done with fscanf, binary data with fread. Similarly, writing ASCII should be done with fprintf and only binary data again with fwrite.
If you want to make sure you write the same data as you read in before, you need to save it somewhere. The maxval variable is read, but not saved, and so I cannot write it back. However, it is not a huge problem because the rest of your code assumes the image is R8G8B8 anyway, and so maxval should always be 255.
Here is an adjusted WriteImage that works.
void WriteImage(Image *img, char *filename)
{
FILE *f = fopen(filename, "wb");
if (f == NULL)
{
printf ("Unable to open '%s' for writing!\n", filename);
/* better would be: "return -1" to indicate an error, 0 otherwise */
return;
}
fprintf (f, "P6\n");
fprintf (f, "%d %d\n", img->x, img->y);
/* actually you need to write 'maxval' here */
fprintf (f, "%d\n", 255);
fwrite(img->data, sizeof(iPixel), img->x * img->y, f);
fclose(f);
}
With the above out of the way, you can now see your 'diagonal line' is not correct! I'm not going to fix that (I suppose not being able to see what happened stopped you in your tracks), but here are a few pointers just to guide you:
no need to return an Image * if you are changing data in situ anyway
no need to check every single pixel
check the coordinates of what pixels are changed ...