I have to write a program where I take user input for a PPM image and then mirror the image from left to right (basically flipping it over the y-axis). So if the image was <, the new image would now be >. This should not be a 180 degree rotation, as that would make the image upside down. It should still be the same, just reflected.
I have the code here that I used to input and output the PPM, but I don't know how to mirror it. I made a function that would theoretically be used for the mirror code, but I'm not sure if that's the best way to do it either. If you know a better place to put the code, be my guest.
I have researched this topic quite a bit, but was only able to find issues where people needed to rotate the image.
Here is what I have so far:
#include<stdio.h>
#include<stdlib.h> //for fopen()
typedef struct {
unsigned char red,green,blue;
} pixel_t; //struct for pixels
typedef struct {
int x, y;
pixel_t *data;
} PPMImage; //struct for creating the image
#define RGB_COMPONENT_COLOR 255
static PPMImage *readPPM(const char *filename)
{
char buff[16];
PPMImage *img;
FILE *fp;
int c, rgb_comp_color;
fp = fopen(filename, "rb");
if (!fp) {
fprintf(stderr, "Unable to open file '%s'\n", filename);
exit(1);} //opens the ppm and checks to make sure it can be opened
if (!fgets(buff, sizeof(buff), fp)) {
perror(filename);
exit(1);} //read the format of the image
if (buff[0] != 'P' || buff[1] != '6') {
fprintf(stderr, "Invalid image format (must be 'P6')\n");
exit(1);} //checks to see if the format is ppm
img = (PPMImage *)malloc(sizeof(PPMImage));
if (!img) {
fprintf(stderr, "Unable to allocate memory\n");
exit(1);} //allocates the memory needed to form the input image
c = getc(fp);
while (c == '#') {
while (getc(fp) != '\n') ;
c = getc(fp);
}//checks for comments
ungetc(c, fp);
if (fscanf(fp, "%d %d", &img->x, &img->y) != 2) {
fprintf(stderr, "Invalid image size (error loading '%s')\n", filename);
exit(1);} //reads the size of the image, height becomes img->y, and width becomes img->x
if (fscanf(fp, "%d", &rgb_comp_color) != 1) {
fprintf(stderr, "Invalid rgb component (error loading '%s')\n", filename);
exit(1);} //reads how much of each color there is
if (rgb_comp_color!= RGB_COMPONENT_COLOR) {
fprintf(stderr, "'%s' does not have 8-bits components\n", filename);
exit(1);} //makes sure the the component is 8 bits
while (fgetc(fp) != '\n') ;
img->data = (pixel_t*)malloc(img->x * img->y * sizeof(pixel_t));
if (!img) {
fprintf(stderr, "Unable to allocate memory\n");
exit(1);} //allocates the memory need for the pixel data
if (fread(img->data, 3 * img->x, img->y, fp) != img->y) {
fprintf(stderr, "Error loading image '%s'\n", filename);
exit(1);} //reads the pixel data
fclose(fp);
return img;
}
void writePPM(const char *filename, PPMImage *img)
{
FILE *fp;
fp = fopen(filename, "wb");
if (!fp) {
fprintf(stderr, "Unable to open file '%s'\n", filename);
exit(1);} //opens the file for output
//write the header file
//image format
fprintf(fp, "P6\n");
//image size
fprintf(fp, "%d %d\n",img->x,img->y);
// rgb component depth
fprintf(fp, "%d\n",RGB_COMPONENT_COLOR);
// pixel data
fwrite(img->data, 3 * img->x, img->y, fp);
fclose(fp);
}
void mirror(PPMImage *img)
{
//this is where I want to insert the code for mirroring the image
}
int main(int argc, char* argv[]){ //takes command line parameters
PPMImage *image;
char* filename = argv[1];
image = readPPM(filename);
mirror(image);
writePPM("OutputFile.ppm",image); //creates the output file
printf("Press Enter");
getchar();
}
Your mirror() function can work on the image one row at a time. For each row, take the left-most pixel in the row and swap its value with the value of the right-most pixel in the row. Then take the second-left-most pixel and swap its value with the second-right-most pixel, and so on, until the column-positions of the pixels you are swapping "meet in the middle". (Then move on to the next row and do the same thing to it, until you've done all the rows).
Note that if the image contains an odd number of columns, there will be one column in the center of the image that stays unmodified (since it forms the axis around which the mirroring occurs). With an even number of columns, all columns will be swapped.
To mirror image vertically you can use this function:
void mirrorVert(PPMImage *img)
{
int y;
int x;
const int middleX = img->x / 2;
pixel_t tmp;
pixel_t* p;
for (y = 0; y < img->y; ++y)
{
p = img->data + y * img->x;
for (x = 0; x < middleX; ++x)
{
// swap pixels
tmp = p[x];
p[x] = p[img->x - 1 - x];
p[img->x - 1 - x] = tmp;
}
}
}
And to mirror it horizontally:
void mirrorHoriz(PPMImage *img)
{
const int line_size = img->x * sizeof(pixel_t);
const int middle = img->y / 2;
int y;
// allocate swap buffer
pixel_t* buff = (pixel_t*)malloc(line_size);
pixel_t* top;
pixel_t* bottom;
for (y = 0; y < middle; ++y)
{
// swap lines from top and bottom
top = img->data + (y * img->x);
bottom = img->data + ((img->y - y - 1) * img->x);
memcpy(buff, top, line_size);
memcpy(top, bottom, line_size);
memcpy(bottom, buff, line_size);
}
}
Related
I'm having trouble writing a code that turns an RGB image (in this case a .ppm file) into an image in grayscale (.pgm output file).
The code:
int i;
typedef struct {
unsigned char r, g, b;
} rgb;
FILE *fd;
FILE *gr;
rgb *img;
unsigned width, height;
fd = fopen("rocks.ppm", "r");
fscanf(fd, "%d %d\n", &width, &height);
img = calloc(3, width * height);
fread(img, 3, width * height, fd);
unsigned char *gray;
double len = width * height;
gray = calloc(1, len);
for (i = 0; i < len; i++) {
gray[i] = img[i].r * 0.2126 + img[i].g * 0.7152 + img[i].b * 0.0722;
}
fclose(fd);
gr = fopen("rocks_gray.pgm", "w");
fprintf(gr, "P5\n%d %d\n255\n", width, height);
fwrite(gray, 1, len, gr);
fclose(gr);
When I compile and run the code the image file created comes out completely black, and I can't put my finger on the problem.
Any help would be deeply appreciated.
The problem is here: fscanf(fd, "%d %d\n", &width, &height);
The ppm file starts with P6 so the fscanf() fails to convert anything and returns 0, leaving width and height unchanged, hence uninitialized, causing the rest of the program to have undefined behavior.
You should change the fscanf() and check the return value.
More generally, you should always check for errors that may cause undefined behavior and report the problem with a meaningful error message.
Here is a modified version:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct {
unsigned char r, g, b;
} rgb;
int main() {
const char *input_file = "rocks.ppm";
FILE *fd = fopen(input_file, "rb");
if (fd == NULL) {
perror(input_file);
return 1;
}
unsigned width, height;
char newline[2];
// Accept binary pixmaps:
// P6 <whitespace> width <whitespace> height <whitespace> 255 <single space> <raster>
if (fscanf(fd, "P6 %u %u 255%1[ \t\r\n\v\f]", &width, &height, newline) != 3) {
fprintf(stderr, "%s: invalid source format\n", input_file);
fclose(fd);
return 1;
}
unsigned len = width * height;
rgb *img = calloc(len, 3);
if (img == NULL) {
fprintf(stderr, "cannot allocate memory for %u pixels\n", len);
fclose(fd);
return 1;
}
if (fread(img, 3, len, fd) != len) {
fprintf(stderr, "%s: cannot read %u pixels\n", input_file, len);
fclose(fd);
return 1;
}
fclose(fd);
unsigned char *gray = calloc(len, 1);
if (gray == NULL) {
fprintf(stderr, "cannot allocate memory for %u gray scales\n", len);
return 1;
}
for (unsigned i = 0; i < len; i++) {
// using non standard gray scale conversion
gray[i] = img[i].r * 0.2126 + img[i].g * 0.7152 + img[i].b * 0.0722;
}
const char *output_file = "rocks_gray.pgm";
FILE *gr = fopen(output_file, "wb");
if (gr == NULL) {
perror(output_file);
return 1;
}
fprintf(gr, "P5\n%u %u\n255\n", width, height);
fwrite(gray, 1, len, gr);
fclose(gr);
return 0;
}
I read two ppm images and I have a struct that stores all the informations (magic number, width, height, level of colors, and pixels). I read the pixels using fread, but the problem is that we have some test to run to see if our code is valid and can create a new ppm. One test must be not valid (not creating an image because the number of pixels is different from the size given), but my code create the image anyway, because in the fread the successful bytes read must be 83 (the condition to exit from the code is that if the number of bytes is different from the given size (width * height * 3) we return 1 and stop executing), but actually it reads 84 bytes, that is equal to the size, then it continue to execute the code, instead of blocking it, and I don't understand why. The error is after the read pixel comment.
P.s Because the code works giving two images, I give the same invalid image twice.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct image
{
char *magicNumber;
int width;
int height;
int level;
uint8_t *pixels;
};
int main(int argc, char *argv[])
{
struct image img1;
struct image img2;
struct image img3;
// Read files
FILE *file1 = fopen(argv[1], "r");
FILE *file2 = fopen(argv[2], "r");
// Check files
if (!file1 || !file2)
{
fprintf(stderr, "Error while opening the file.\n");
return 1;
}
// Alloc memory for pixels array
img1.magicNumber = (char *)malloc(3 * sizeof(char));
img2.magicNumber = (char *)malloc(3 * sizeof(char));
// Take magic number
fscanf(file1, "%s", img1.magicNumber);
fscanf(file2, "%s", img2.magicNumber);
// Check magic number
if (strcmp(img1.magicNumber, "P6") != 0 || strcmp(img2.magicNumber, "P6") != 0)
{
fprintf(stderr, "Invalid magic number.\n");
return 1;
}
// Take width
fscanf(file1, "%d", &img1.width);
fscanf(file2, "%d", &img2.width);
// Take height
fscanf(file1, "%d", &img1.height);
fscanf(file2, "%d", &img2.height);
// Check size
if (img1.width != img2.width || img1.height != img2.height)
{
fprintf(stderr, "Invalid Dimension.");
return 1;
}
// Take level
fscanf(file1, "%d", &img1.level);
fscanf(file2, "%d", &img2.level);
// Check level
if (img1.level != 255 || img2.level != 255)
{
fprintf(stderr, "Invalid Level.");
return 1;
}
// Alloc memory for pixels array
img1.pixels = (uint8_t *)malloc(img1.width * img1.height * 3 * sizeof(uint8_t));
img2.pixels = (uint8_t *)malloc(img2.width * img2.height * 3 * sizeof(uint8_t));
// Read pixels
size_t nrPixel1 = fread(img1.pixels, sizeof(uint8_t), img1.width * img1.height * 3, file1);
size_t nrPixel2 = fread(img2.pixels, sizeof(uint8_t), img2.width * img2.height * 3, file2);
// Check pixels read
if (nrPixel1 != img1.width * img1.height * 3 || nrPixel2 != img2.width * img2.height * 3)
{
fprintf(stderr, "Invalid pixels.");
return 1;
}
My program that is meant to read and display a PPM image is not printing the actual format or height or width of the image being read. It's probably a really basic mistake, but I've not been using C for very long.
EDIT: I've actually just noticed where I check the image format is valid, I'm checking whether it == 2, but it should be != 2 (correct me if I'm wrong) so it says my image format is invalid either way. I'll try run my code on another image.
If anyone can help that would be great.
Current output:
PPM FILE PROGRAM
Memory allocation successful
File format is correct
89~
Image size: 3680602 544108293
Desired output:
PPM FILE PROGRAM
Memory allocation successful
File format is correct
P3
Image size: 125 100
Code:
#include <stdio.h>
#include <stdlib.h>
#define MAX_HEIGHT 600
#define MAX_WIDTH 400
struct PPM {
char format[3]; //PPM format code
int height, width; //image pixel height and width
int max; //max rgb colour value
};
struct PPM_Pixel {
//Create variables to hold the rgb pixel values
int red;
int green;
int blue;
};
struct PPM *getPPM(FILE * file);
void showPPM(struct PPM * image);
int main( void ){
printf("PPM FILE PROGRAM \n");
FILE *file;
// get image file
// FILE *file;
file = fopen("aab(1).ppm", "r");
//if there is no file then return an error
if(file == NULL){
fprintf(stderr, "File does not exist\n");
return 0;
}
struct PPM *newPPM = getPPM(file);
showPPM(file);
fclose(file);
}
struct PPM *getPPM(FILE * file){
char buffer[3];
int c;
struct PPM *image = NULL;
if(NULL == (image = malloc(sizeof(struct PPM)))){
perror("memory allocation for PPM file failed\n");
exit(1);
}
else {
printf("Memory allocation succesful\n");
}
//read the image of the format
if(!fgets(buffer, sizeof(buffer), file)){
exit(1);
}
//checks the format of the ppm file is correct
if(buffer[0] != 'P' || buffer[1] != '3'){
fprintf(stderr, "Invalid image format! \n");
exit(1);
}else{
printf("File format is correct\n");
printf("%s\n", image->format);
}
//checks whether the next character is a comment and skips it
c = getc(file);
while(c == '#'){
while(getc(file) != '\n'){
c = getc(file);
}
}
//check the image size is valid
if(fscanf(file, "%d %d", &image->height, &image->width) == 2){
printf("Invalid imaze size\n");
exit(1);
}else{
printf("Image size: %d %d ", image->height, image->width);
}
return image;
}
void showPPM(struct PPM * image){
struct PPM_Pixel rgb_array[MAX_HEIGHT][MAX_WIDTH];
int i;
int j;
for(i = 0; i<MAX_HEIGHT; i++){
for(j = 0; j<MAX_WIDTH; j++){
struct PPM_Pixel newPPM_Pixel;
if(fscanf(image, "%d %d %d", &newPPM_Pixel.red, &newPPM_Pixel.green, &newPPM_Pixel.blue) == 3){
rgb_array[i][j] = newPPM_Pixel;
}
}
}
}
Apologies, I'm not sure how to change the output text to just text.
Although you forget to include the code of showPPM(), his prototype is
void showPPM(struct PPM * image);
and you are passing a FILE *:
FILE *file;
...
showPPM(file);
Trying to do basic Steganography on a PPM Image.
I have the basic algorithm completed. Read in the file, check the header starts with P6, get the image width and height, and the pixel data.
I need to have a total of four methods: ReadPPM, WritePPM, WriteMsg and ReadMsg.
I have the ReadImg and WriteImg methods down, but where I am stuck is with my WriteMsg method. This is basic steganography that just writes each bit of the string to the last bit in each byte. The first 8 bytes are suppose to contain the size of the string being hidden, then each byte after that starts the hidden message.
My idea was to create a massive array that holds the binary code for the size of the string, then the binary code of the string itself. I'm just trying to figure out how I would take that array and add it to each byte in the image.
Any help is much appreciated. Here is my current code:
#include<stdio.h>
#include<stdlib.h>
typedef struct {
unsigned char red,green,blue;
} PPMPixel;
typedef struct {
int x, y;
PPMPixel *data;
} PPMImage;
#define CREATOR "RPFELGUEIRAS"
#define RGB_COMPONENT_COLOR 255
static PPMImage *readPPM(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] != '6') {
fprintf(stderr, "Invalid image format (must be 'P6')\n");
exit(1);
}
//alloc memory form image
img = (PPMImage *)malloc(sizeof(PPMImage));
if (!img) {
fprintf(stderr, "Unable to allocate memory\n");
exit(1);
}
//check for comments
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);
}
//read rgb component
if (fscanf(fp, "%d", &rgb_comp_color) != 1) {
fprintf(stderr, "Invalid rgb component (error loading '%s')\n", filename);
exit(1);
}
//check rgb component depth
if (rgb_comp_color!= RGB_COMPONENT_COLOR) {
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(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, 3 * img->x, img->y, fp) != img->y) {
fprintf(stderr, "Error loading image '%s'\n", filename);
exit(1);
}
fclose(fp);
return img;
}
void writePPM(const char *filename, PPMImage *img)
{
FILE *fp;
//open file for output
fp = fopen(filename, "wb");
if (!fp) {
fprintf(stderr, "Unable to open file '%s'\n", filename);
exit(1);
}
//write the header file
//image format
fprintf(fp, "P6\n");
//comments
fprintf(fp, "# Created by %s\n",CREATOR);
//image size
fprintf(fp, "%d %d\n",img->x,img->y);
// rgb component depth
fprintf(fp, "%d\n",RGB_COMPONENT_COLOR);
// pixel data
fwrite(img->data, 3 * img->x, img->y, fp);
fclose(fp);
}
void writeMsg(PPMImage *img, char *s)
{
int i;
int len;
len = sizeof(s);
if (img)
{
j = 0;
for (i=0; i < img->x * img->y; i++)
{
while(j < 8)
{
if(len & 0x80)
{
img->data[i].red= img->data[i].red | 0x01;
}
else
{
img->data[i].red= img->data[i].red & 0xFE;
}
len=len << 1;
j++;
if (len & 0x80)
{
img->data[i].green= img->data[i].green | 0x01;
}
else
{
img->data[i].green= img->data[i].green & 0xFE;
}
len = len << 1;
j++;
if (len & 0x80)
{
img->data[i].blue= img->data[i].blue | 0x01;
}
else
{
img->data[i].blue= img->data[i].blue & 0xFE;
}
j++;
}
}
}
}
To extract just a single bit from a byte, do this:
bit(i) = byte >> i & 0x1
This shifts the byte's bits to the right i times, and then ands it with 0000 0001 (such that all bits except the lowest are zeroed, and the lowest bit is 0 for 0 and 1 for 1).
You can do similar for 16 bit short, 32 bit int, 64 bit long... And even for the chars of a string. You can use sizeof(char) to see how many bytes are in a char.
But of course you'll have more than one char (or long or int or...) to extra bits from. To decide which element to extra a bit from:
If you want the ith bit and elements are x bits wide, then get the i%x bit from element [i/x]
Now that you have this bit, to place it inside of a byte (or int or char or...), do:
steganographybyte = originalbyte&(~0x1) + bit
What this means is, you take the number ... 0000 0001, invert its bits so it's ... 1111 1110, and it with the original byte so all of its bits are preserved EXCEPT the lowest, then just add your bit in.
I need to read a PPM file and store it in an array written in C.
Can anybody help me out doing this?
Thanks a lot.
The following code shows how to read, change the pixel colour and write an image in
PPM format. I hope it helps.
#include<stdio.h>
#include<stdlib.h>
typedef struct {
unsigned char red,green,blue;
} PPMPixel;
typedef struct {
int x, y;
PPMPixel *data;
} PPMImage;
#define CREATOR "RPFELGUEIRAS"
#define RGB_COMPONENT_COLOR 255
static PPMImage *readPPM(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] != '6') {
fprintf(stderr, "Invalid image format (must be 'P6')\n");
exit(1);
}
//alloc memory form image
img = (PPMImage *)malloc(sizeof(PPMImage));
if (!img) {
fprintf(stderr, "Unable to allocate memory\n");
exit(1);
}
//check for comments
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);
}
//read rgb component
if (fscanf(fp, "%d", &rgb_comp_color) != 1) {
fprintf(stderr, "Invalid rgb component (error loading '%s')\n", filename);
exit(1);
}
//check rgb component depth
if (rgb_comp_color!= RGB_COMPONENT_COLOR) {
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(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, 3 * img->x, img->y, fp) != img->y) {
fprintf(stderr, "Error loading image '%s'\n", filename);
exit(1);
}
fclose(fp);
return img;
}
void writePPM(const char *filename, PPMImage *img)
{
FILE *fp;
//open file for output
fp = fopen(filename, "wb");
if (!fp) {
fprintf(stderr, "Unable to open file '%s'\n", filename);
exit(1);
}
//write the header file
//image format
fprintf(fp, "P6\n");
//comments
fprintf(fp, "# Created by %s\n",CREATOR);
//image size
fprintf(fp, "%d %d\n",img->x,img->y);
// rgb component depth
fprintf(fp, "%d\n",RGB_COMPONENT_COLOR);
// pixel data
fwrite(img->data, 3 * img->x, img->y, fp);
fclose(fp);
}
void changeColorPPM(PPMImage *img)
{
int i;
if(img){
for(i=0;i<img->x*img->y;i++){
img->data[i].red=RGB_COMPONENT_COLOR-img->data[i].red;
img->data[i].green=RGB_COMPONENT_COLOR-img->data[i].green;
img->data[i].blue=RGB_COMPONENT_COLOR-img->data[i].blue;
}
}
}
int main(){
PPMImage *image;
image = readPPM("can_bottom.ppm");
changeColorPPM(image);
writePPM("can_bottom2.ppm",image);
printf("Press any key...");
getchar();
}
Here is the
PPM specification.
The PPM file is built in 9 sections separated by white-spaces.
Open the file
read until the first white space and check you got P6. Then skip other white-spaces.
read until the next white space, convert your buffer to an integer width. Then skip other white-spaces
read until the next white space, convert your buffer to an integer height. Then skip other white-spaces
Allocate a 2D array of integers in the size of height*width
read the max-val
read line by line and fill the array