Inverting the Values of a PPM image - c

I am writing in C and I have to write code that will invert the RGB values for each pixel in an image. It's a simple process in that you take the max color value and subtract the actual RGB values. I have successfully read in the max color value, but when trying to invert the values, everything is returned as 0 and when written to a new file is not readable. Below is the code, any ideas?
Inverting the picture
int i,j;
for(i=0; i<myPic->rows;++i) {
//Moves up and down the columns reaching all Pixels
//Moves across left to right across all columns
for (j=0;j<myPic->cols;++j) {
//Inverstion requires the actual value to be subtracted from the max
myPic->pixels[i][j].red = myPic->colors - myPic->pixels[i][j].red;
myPic->pixels[i][j].green = myPic->colors - myPic->pixels[i][j].green;
myPic->pixels[i][j].blue = myPic->colors - myPic->pixels[i][j].blue;
}
}
return myPic;
}
Output of the image
fprintf(name,"P3\n%d %d\n%d\n",myPic->rows,myPic->cols,myPic->colors);
//The P3,rows,columns,and color values are all printed first
int i,j;
for(i=0; i< myPic->rows;++i) {
for(j=0; j<myPic->cols;++j) { //Each Pixel is printed one at a time
fprintf(name,"%d",myPic->pixels[i][j].red); //Red printed first
fprintf(name,"%d",myPic->pixels[i][j].green); //Green printed second
fprintf(name,"%d",myPic->pixels[i][j].blue); //Blue printed third
fprintf("\n");
}
}
}
Thanks for the help guys, this is what I'm using now and it works

When writing the pixel data, this line
myPic->pixels[i] = malloc(sizeof(Pixel) *myPic->cols);
overwrites the existing pointer, and makes it point to new (and more importantly, uninitialized) data.
Copy-paste programming (which you seem to have been doing) can work sometimes, but you have to take care to modify the copied code properly.
On an unrelated note, you don't print a newline after each line, so the resulting PPM file will actually not be correct.

#Joachim is correct. so do something like this:
int i,j;
for(i=0; i<myPic->rows;++i) {
Pixel[myPic->cols] temp = *myPic->pixels[i];
//Moves up and down the columns reaching all Pixels
myPic->pixels[i] = malloc(sizeof(Pixel) *myPic->cols);
//Moves across left to right across all columns
for (j=0;j<myPic->cols;++j) {
//Inverstion requires the actual value to be subtracted from the max
myPic->pixels[i][j].red = myPic->colors - temp[j].red;
myPic->pixels[i][j].green = myPic->colors - temp[j].green;
myPic->pixels[i][j].blue = myPic->colors - temp[j].blue;
}
}
return myPic;
}

Related

C - Eliminating Loop Stutter?

I am making a little game using getch and print, as a bit of a test for myself, and surprisingly it actually works quite well but i'm having a bit of an issue. I am printing all of the tiles using a loop and printf, and of course as the loop has to process a bit, everytime the character moves, it re-prints everything, which causes a bit of a stutter, due to the loop printing. What can I possibly do to combat this?
This is how the tiles are printed
void Game() {
int X = 0;
int Y = 0;
int PrintWall = 0;
do {
for (int i = 0; i < 80; i++) {
X = i;
PrintWall = 0;
for (int j = 0; j < 12; j++) {
if (X == WallX[j]) {
if (Y == WallY[j]) {
PrintWall = 1;
}
}
}
if (X == Player.XCoor && Y == NegativeToPositive(Player.YCoor)) {
printf("#");
}
else if (PrintWall == 1){
printf("#");
}
else {
printf(".");
}
}
Y++;
} while (Y != 22);
}
You may want to try building the full screen of data into a buffer first and THEN print it. Start with an array of characters as long as you need it to be:
char buffer[SIZE_X * SIZE_Y];
Then go through your loop above, but instead of using printf(), set the character at that location in the buffer to what you want it to be:
buffer[(SIZE_X * Y) + X] = /* '#', '#', or '.' as appropriate */
Then, once you are through the loop, you will print the whole buffer to the screen:
printf(buffer);
Just make sure you don't accidentally overwrite your null terminator with another character or you may get more text than you bargained for.
That is just a limitation of printing the whole "board" on every change. The only way to fix it is to only print what changes. Depending on your OS etc you may be able to print individual characters or lines instead of the whole board.
You could look at a library like curses to give character level control (there may be something better - don't know, I don't do this often enough to know ;-)
As other answers have said, printing in bigger pieces (like a whole buffer at a time) is better than printf for each individual character but you will still probably have the same issue but it is certainly worth a try.
Consider separating initialization and the game loop. Draw the game board as init and update everything in your do-while-loop.
You should limit the number of moving walls.
If a wall moves, you delete/replace the wall mark # at the old position, write out the mark on your interface at the new place and then change the mark's data in the arrays.
After that, you just check, if the new player position hits an obstacle. If no, delete/replace the current mark of the player with the default character and write the new position.
If the two players hit each other, you would need your old condition.

Can't get value from an array (c)

I'm reading a code from a ppm file and store the value of each pixel in p1, array of pixel, which is a struct of .red .green .blue (int). I managed to create a "Negative Filter" of the picture, however. I'm trying to get a black and white by taking the mean of red, green, and blue pixel.
I have pixel p1, pixel p2(negative filter) and int p3(b&w). However every action that have p3 = ...., will stop responding. such as
for (i = 0; i < WIDTH; i++) {
for (j = 0; j < HEIGHT; j++) {
p3[i][j] = ((p1[i][j].red + p1[i][j].green + p1[i][j].blue)/3);
}
}
or
for (i = 0; i < WIDTH; i++) {
for (j = 0; j < HEIGHT; j++) {
fprintf(pf3, "%d", p3[i][j]);
}
}
However when I change int p3[WIDTH][HEIGHT] to char p3[WIDTH][HEIGHT], the program runs but gives a wrong output. Both int and char, compiled successfully. Can someone help me? thanks.
EDIT:
What I'm hoping is I could create a .pgm black and white extension of picture from .ppm by inputting .ppm value to pixel p1[WIDTH][HEIGHT] in .red, .green, and .blue. Then calculate the mean of RGB and assign it in int p3 before being written in .pgm.
What I got when using int p3, it crashes when I run the .exe stopped working without giving any error.
When I use char p3, it run perfectly, but it gives all negative value for the mean of all the pixel. (This already being helped by putting unsigned infront of the char thanks to #egoteclair)
My new question would be why can't I use int instead of unsigned char?
Normal char size is 8-bit. The first bit will be used for the sign extension. In a 24 bit png file each color-field contains 8 bits.
24 / 3 = 8
So try to use unsigned char instead of char. This allows you to use the complete 8 bits of the char.

For loop stops for no reason

So I'm trying to make a program to read a ppm file and store it in memory, I've got everything working up to the colors, this function is giving me problems:
typedef struct{
int red, green, blue;
} COLOR;
COLOR * getNextColor(FILE *fd);
COLOR **getColors(FILE *fd, int width, int height){
printf("\nentered get colors");
COLOR **colors = malloc(sizeof(COLOR*)*height);
printf("\nallocated %d space height",height);
int i,j;
for(i = 0; i < height; i++, colors++){
*colors = malloc(sizeof(COLOR)*width);
printf("\nallocated %d space width",width);
for(j = 0; j < width; j++, *colors++){
printf("\nlooping through to get the colors for point (%d,%d)", j,i);
//*colors = getNextColor(fd);
}
*colors -= width;
printf("\nmoved the pointer for *colors back %d spaces",width);
}
colors -= height;
printf("\nmoved the pointer for colors back %d spaces",height);
return colors;
}
I'm passing in a file pointer that is currently pointing at the first digit of the first color, the width = 400 and height is 530. The output looks like this:
allocated 530 space height
allocated 400 space width
looping through to get the colors for point (0,0)
looping through to get the colors for point (1,0)
looping through to get the colors for point (2,0)
...
looping through to get the colors for point (398,0)
looping through to get the colors for point (399,0)
moved the pointer for *colors back 400 spaces
allocated 400 space width
looping through to get the colors for point (0,1)
looping through to get the colors for point (1,1)
...
looping through to get the colors for point (398,1)
looping through to get the colors for point (399,1)
moved the pointer for *colors back 400 spaces
allocated 400 space width
and pattern repeats this all the way up to
looping through to get the colors for point (399,36)
then crashes. Any ideas?
There is a problem with *colors++ that does not probably mean what you think it does. This is due to operator precedence, highest precedence has postfix increment/decrement operators and lower precedence has indirection. So *colors++ actually meanst *(colors)++ which doesn't make much sense. You probably meant (*colors)++

2D array and how to print the array in C

I am trying to print a 2D array that should look like this
*************
*
*
*************
like a frame, but I have hard time because it is not printing the stars instead it prints numbers and even those columns I specified with 42 ('*') are not showing. I don't know if the problem is the way I am printing the array. I hope someone can help me. Thank you!
here's my code: int i,j;
int star=42;
char starchar=(char)star;
//colMax=10;
int frame[rowMax][colMax];
for(row=0;row<rowMax;row++)
{
for(column=0;column<colMax;column++)
{
frame[0][column]=starchar;
frame[9][column]=starchar;
frame[row][9]=starchar;
printf("%d%d",row,column);
}
It is printing numbers because you are passing %d%d to the printf function, which stands for decimal number. Replace %d with %c to get the character representation. See the manual for printf, e.g. at http://www.cplusplus.com/reference/cstdio/printf/
Also, you have another problem which is you are passing values other than the ones you intend into printf. You are passing row and column, which are not the values at that location, but the numbers of the index. You want something like:
printf("%c",frame[row][column]);
As Paul Roub points out in comments, you are also doing some odd things with the way you are putting values into the array during your display loop, which is probably also going to confuse you if you develop this code further. First, you don't ever specify what is in the non-star parts of the array. Those should be set to something like the space character before, or at the same time, as adding stars. As written, the values will default to zero, which is unprintable null in ASCII, not space (which is 32).
Also, I assume you mean to be setting up the values first, and then displaying them. The way your loop works, it is setting the values as it draws them, in an interesting way that I would assume is not what you intend. Your example will currently end up showing what you expect, but usually I would expect you to fill in the values first and then display them later.
printf("%d%d",row,column); prints the row and column, not the value in frame[row][column].
#include <string.h>
#include <stdio.h>
int main(void) {
// Not clear if rowMax is the maximum index or the width. Assume maximum index.
size_t rowMax = 10;
size_t colMax = 5;
int star = '*';
// Much easier to use char array
char frame[rowMax + 1][colMax + 1]; // +1 the dimensions
// fill
memset(&frame[0], star, colMax + 1); // fill first row
for (size_t row = 1; row < rowMax; row++) {
memset(&frame[row], ' ', colMax); // fill with spaces
frame[row][colMax] = star;
}
memset(&frame[rowMax], star, colMax + 1); // fill last row
// print
for (size_t row = 0; row <= rowMax; row++) {
for (size_t col = 0; col <= colMax; col++) {
fputc(frame[row][col], stdout);
}
fputc('\n', stdout);
}
return 0;
}

Reading pixel data of a PPM file using C

I am trying to read pixel data from a PPM file. I have a function to read the header so I know it's pointing to the beginning of the pixel data. I tried using fgetc(file) but if the value is more than one digit it will not work. I also tried using an array and converting the array to an int or char but I have no way of knowing how many digits each value is. I'm also not sure if the values are separated by whitespace or not. Basically I need a way to extract the pixel data. (I'm using C.)
My code right now is:
char read_byte(FILE *ipt) {
int c, i=0, sum=0;
while (i<16) {
c=fgetc(ipt);
if((i%2)!=0 {
if(c&1) {
sum+=pow(2,i/2);
}
}
i++;
}
return (char)sum;
}
EDIT:
At first I thought the file was stored as the ASCII values, then I realized it's stored as binary. Right now I think I'm making it act like hex. I'm not sure if that's correct. I'm really stuck.
EDIT: changed my code a bit
char read_byte(FILE *ipt) {
int c, i=0, sum=0;
while(i<8) {
c = fgetc(ipt);
c=c&1;
sum+=c*pow(2,i);
i++;
}
return sum;
}
I print the sum as %c
Must you write this for an assignment, or is it for pleasure, or could you use someone else's code?
There is an Open Source solution.
"Netpbm is a package of graphics programs and a programming library. " which includes programs to read PPM at http://netpbm.sourceforge.net/doc/
Edit:
Have you got, or read the definition of the file format, e.g. http://netpbm.sourceforge.net/doc/ppm.html?
It looks like the data is either sequences of one byte RGB triples, or sequences of two byte RGB triples.
The program can detect which format is used from item 7 "The maximum color value (Maxval)". It says "If the Maxval is less than 256, it is 1 byte. Otherwise, it is 2 bytes."
So you code a function which reads one byte/component RGB data, then code another to read two byte/component RGB data.
The program can choose which to call once it has read the value of Maxval.
Edit {
According to the document at that link, the image data in a 'P6' ppm is binary.
So if MaxValue is <256, and hence the data for each colour component is one byte, then reading three bytes, with three calls of fgetc(fp) would return the binary value of one RGB pixel.
If the program has read the header, it has the values of width and height for the image data. So it could allocate an array for every row (width wide of RGB pixels), and an array of pointers to each allocated pixel row array. Then read the binary data into each row, and the program has something straightforward to operate on; a 2d array.
} end edit
My reading of your question suggests you already know how to read one byte data using fgetc.
Edit - it seems like this is irrelevant:
You can read two byte data by calling fgetc twice, and shifting and bit or-ing the data, e.g. (partly ignoring error checking):
int a = fgetc(fp);
int b = fgetc(fp);
if (a >= 0 && b >= 0) { // then all is okay
unsigned int twobyte = (a<<8) | b; // or (b<<8) | a; depending on byte order
// ...

Resources