I have to read a .pgm file for an assignment and decode the least significant bit in every byte to get some hidden text. I have the reading and writing code from the professor but when I try to read the file color has an issue being written to. I think I know how to actually get the hidden text out but the I/O always gives me trouble.
Thanks in advance for your help.
It wouldnt let me add the .pgm so i ranamed it as .png, so if you download it make sure to rename it to .pgm
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef unsigned char uchar;
/****************************************/
/* Clear PGM (XV) comments. */
/****************************************/
void pgmCommentClear(FILE* disk) {
uchar ch;
fread(&ch, 1, 1, disk);
if (ch != '#') {
fseek(disk, -1, SEEK_CUR);
return;
}
do {
while (ch != '\n') fread(&ch, 1, 1, disk);
} while (ch == '#');
pgmCommentClear(disk);
}
/****************************************/
/* Read PGM formatted image (1D array). */
/****************************************/
uchar* PGM_FILE_READ_1D(char* FileName, int* Width, int* Height, int* color) {
int pmax;
char ch;
char type[3];
uchar* Image;
FILE* disk;
if ((disk = fopen(FileName, "rb")) == NULL) {
return NULL;
}
fscanf(disk, "%s", type);
if (!strcmp(type, "P6")) *color = 1;
else *color = 0;
fread(&ch, 1, 1, disk);
pgmCommentClear(disk);
fscanf(disk, "%d", Width);
fscanf(disk, "%d", Height);
fscanf(disk, "%d", &pmax);
fread(&ch, 1, 1, disk);
if (*color == 1) {
Image = (uchar*)calloc(*Height * *Width * 3, sizeof(uchar));
fread(Image, 1, (*Height * *Width * 3), disk);
}
else {
Image = (uchar*)calloc(*Height * *Width, sizeof(uchar));
fread(Image, 1, (*Height * *Width), disk);
}
fclose(disk);
return Image;
}
/****************************************/
/* Write PGM formatted image (1D array).*/
/****************************************/
void PGM_FILE_WRITE_1D(char* FileName, uchar* Image, int Width, int Height, int color) {
FILE* disk;
disk = fopen(FileName, "wb");
if (color == 1) fprintf(disk, "P6\n");
else fprintf(disk, "P5\n");
fprintf(disk, "%d %d\n", Width, Height);
fprintf(disk, "255\n");
if (color == 1) {
fwrite(Image, 1, (Height * Width * 3), disk);
}
else {
fwrite(Image, 1, (Height * Width), disk);
}
fclose(disk);
}
int main(int argc, char const* argv[]) {
// do command line args stuff for extra credit
//if (argv == 2) { }
// read the file
//int width = 876
//int height = 594
uchar* image = PGM_FILE_READ_1D("./hw10.pgm", 876, 594, 0);
printf("%c", *image);
}
Pretty cool assignment, Ron Marsh ;-)
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef unsigned char uchar;
/****************************************/
/* Clear PGM (XV) comments. */
/****************************************/
void pgmCommentClear(FILE* disk) {
uchar ch;
fread(&ch, 1, 1, disk);
if (ch != '#') {
fseek(disk, -1, SEEK_CUR);
return;
}
do {
while (ch != '\n') fread(&ch, 1, 1, disk);
} while (ch == '#');
pgmCommentClear(disk);
}
/****************************************/
/* Read PGM formatted image (1D array). */
/****************************************/
uchar* PGM_FILE_READ_1D(char* FileName, int* Width, int* Height, int* color) {
int pmax;
char ch;
char type[3];
uchar* Image;
FILE* disk;
if ((disk = fopen(FileName, "rb")) == NULL) {
return NULL;
}
fscanf(disk, "%s", type);
if (!strcmp(type, "P6")) *color = 1;
else *color = 0;
fread(&ch, 1, 1, disk);
pgmCommentClear(disk);
fscanf(disk, "%d", Width);
fscanf(disk, "%d", Height);
fscanf(disk, "%d", &pmax);
fread(&ch, 1, 1, disk);
if (*color == 1) {
Image = (uchar*)calloc(*Height * *Width * 3, sizeof(uchar));
fread(Image, 1, (*Height * *Width * 3), disk);
}
else {
Image = (uchar*)calloc(*Height * *Width, sizeof(uchar));
fread(Image, 1, (*Height * *Width), disk);
}
fclose(disk);
return Image;
}
/****************************************/
/* Write PGM formatted image (1D array).*/
/****************************************/
void PGM_FILE_WRITE_1D(char* FileName, uchar* Image, int Width, int Height, int color) {
FILE* disk;
disk = fopen(FileName, "wb");
if (color == 1) fprintf(disk, "P6\n");
else fprintf(disk, "P5\n");
fprintf(disk, "%d %d\n", Width, Height);
fprintf(disk, "255\n");
if (color == 1) {
fwrite(Image, 1, (Height * Width * 3), disk);
}
else {
fwrite(Image, 1, (Height * Width), disk);
}
fclose(disk);
}
int main(int argc, char const* argv[]) {
// do command line args stuff for extra credit
char newMsg[100] = "";
if (argc >= 2)
for (int i = 1; i < argc; i++) {
strcat(newMsg, argv[i]);
strcat(newMsg, " ");
}
else
strcat(newMsg, "Greetings from the other side");
strcat(newMsg, "\0");
int width, height, color;
// read the file
uchar* image = PGM_FILE_READ_1D("./hw10.pgm", &width, &height, &color);
printf("width = %d, height = %d, color = %d\n", width, height, color);
// Read encoded message
int size = width * height, bitCount = 8;
uchar hiddenChar = 0;
for (int i = 0; i < size; i++) {
//shift least-significant bit left `bitCount` times and overlay onto `hidden`
hiddenChar |= ((image[i] & 0x01) << --bitCount);
// After 8 bits we have the hidden byte
if (bitCount == 0) {
// If character is null terminator then we're done
if (hiddenChar == 0)
break;
// Print hidden character and reset
printf("%c", hiddenChar);
bitCount = 8;
hiddenChar = 0;
}
}
// Encode new message
int len = strlen(newMsg) + 1;
for (int i = 0; i < len; i++)
for (int j = 0; j < 8; j++)
if ( newMsg[i] & (0x01 << (7-j) ) )
image[i * 8 + j] |= 0x01;
else
image[i * 8 + j] &= 0xfe;
PGM_FILE_WRITE_1D("./hw10-out.pgm", image, width, height, color);
return 0;
}
In this programme I want to ask the user to enter the file path of the image, this takes place in the main function. However the open file takes place in another function.
To get the variable (location) to communicate between both functions, I declared it as a global variable, however, when the programme is executed no file path can be found.
Here is a snippet from the main function:
#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
char * scale = "8Xoi?;`. ";
int numScale;
char * location;
typedef struct
{
size_t width;
size_t height;
unsigned char * data;
} image;
unsigned char luminanceFromRGB(unsigned char r, unsigned char g, unsigned char b)
{
return (unsigned char) (0.2126 * r + 0.7152 * g + 0.0722 * b);
}
//Loads image and saves it to img as an image pointer.
long loadImage(image ** img, char * location)
{
FILE *f = fopen(location, "rb");
if (f == NULL)
{
puts("Opening failed...");
return 0;
}
unsigned char * result;
fseek(f, 0, SEEK_END);
long size = ftell(f);
fseek(f, 0, SEEK_SET);
result = (unsigned char *) malloc((size_t) size);
if (size != fread(result, sizeof(unsigned char), (size_t) size, f))
{
free(result);
puts("Reading failed...");
fclose(f);
return 0;
}
fclose (f);
if (size < 54)
{
free(result);
puts("Invalid file...");
return 0;
}
size_t pdOffset = result[10] | result[11] << 8 | result[12] << 16 | result[13] << 24;
unsigned long width = result[18] | result[19] << 8 | result[20] << 16 | result[21] << 24;
unsigned long height = result[22] | result[23] << 8 | result[24] << 16 | result[25] << 24;
unsigned long bpp = result[28] | result[29] << 8;
int noCompression = result[30] == 0 && result[31] == 0 && result[32] == 0 && result[33] == 0;
if (bpp != 24 || !noCompression || width < 1 || height < 1 || width > 64000 || height > 64000)
{
free(result);
puts("Unsupported BMP format, only 24 bits per pixel are supported...");
return 0;
}
int bytesPerPixel = (int) (bpp / 8);
size_t rowBytes = (width * bytesPerPixel + 3) / 4 * 4;
printf("Bytes per row: %zu\n", rowBytes);
size_t usedRowBytes = width * bytesPerPixel;
size_t imageBytes = rowBytes * height;
*img = malloc(sizeof(image));
(*img)->height = height;
(*img)->width = width;
size_t imgSize = width * height;
(*img)->data = (unsigned char *) malloc(imgSize);
printf("Offset: %zu\n", pdOffset);
unsigned char * ptr = (*img)->data;
unsigned char * srcPtr = &result[pdOffset];
for (size_t i = 0; i < imgSize; ++i)
{
unsigned char r = *srcPtr;
unsigned char g = *(srcPtr + 1);
unsigned char b = *(srcPtr + 2);
*ptr = luminanceFromRGB(r, g, b);
ptr++;
srcPtr += bytesPerPixel;
if (i % width == 0)
{
srcPtr += rowBytes - usedRowBytes;
}
}
free(result);
return size;
}
//Assigns a ASCII character (scale) depending on the images brightness
void sprintchar(char *dst, image *img) {
for (size_t y = img->height - 1; y > 0; --y) {
for (size_t x = 0; x < img->width; ++x) {
unsigned char c = *(img->data + x + img->width * y);
int rescaled = c * numScale / 256;
*dst++ = scale[numScale - rescaled];
}
*dst++ = '\n';
}
*dst++ = 0;
}
void release(image * img)
{
if (img)
{
if (img->data)
free(img->data);
free(img);
}
}
int main(int argc, char ** argv)
{
char filepath [99];
printf("Enter file path: \n");
scanf_s("%s", &filepath);
location = filepath;
if (argc != 2)
{
puts("Argument needed: filename.");
return 1;
}
puts(argv[1]);
setbuf(stdout, 0);
numScale = strlen(scale) - 1;
printf("ASCII Brightness Scale: %d\n", numScale);
image *img = NULL;
if (loadImage(&img, argv[1]))
{
printf("Image dimensions: %zux%zu\n", img->width, img->height);
//Prints ASCII characters in terminal
char buf[1000000]; // 1M should be enough
sprintchar(buf, img);
//printf("%s", buf); // or whatever
release(img);
}
return 0;
}
This C code converts a BMP image to a ASCII art. The output is displayed in the terminal.
However I want to modify the programme and save the outputted characters to a string variable. The problem being that img which outputs the characters is a image pointer.
#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
char * scale = "8Xoi?;`. ";
int numScale;
typedef struct
{
size_t width;
size_t height;
unsigned char * data;
} image;
unsigned char luminanceFromRGB(unsigned char r, unsigned char g, unsigned char b)
{
return (unsigned char) (0.2126 * r + 0.7152 * g + 0.0722 * b);
}
//Loads image and saves it to img as an image pointer.
long loadImage(image ** img, char * location)
{
FILE *f = fopen(location, "rb");
if (f == NULL)
{
puts("Opening failed...");
return 0;
}
unsigned char * result;
fseek(f, 0, SEEK_END);
long size = ftell(f);
fseek(f, 0, SEEK_SET);
result = (unsigned char *) malloc((size_t) size);
if (size != fread(result, sizeof(unsigned char), (size_t) size, f))
{
free(result);
puts("Reading failed...");
fclose(f);
return 0;
}
fclose (f);
if (size < 54)
{
free(result);
puts("Invalid file...");
return 0;
}
size_t pdOffset = result[10] | result[11] << 8 | result[12] << 16 | result[13] << 24;
unsigned long width = result[18] | result[19] << 8 | result[20] << 16 | result[21] << 24;
unsigned long height = result[22] | result[23] << 8 | result[24] << 16 | result[25] << 24;
unsigned long bpp = result[28] | result[29] << 8;
int noCompression = result[30] == 0 && result[31] == 0 && result[32] == 0 && result[33] == 0;
if (bpp != 24 || !noCompression || width < 1 || height < 1 || width > 64000 || height > 64000)
{
free(result);
puts("Unsupported BMP format, only 24 bits per pixel are supported...");
return 0;
}
int bytesPerPixel = (int) (bpp / 8);
size_t rowBytes = (width * bytesPerPixel + 3) / 4 * 4;
printf("Bytes per row: %zu\n", rowBytes);
size_t usedRowBytes = width * bytesPerPixel;
size_t imageBytes = rowBytes * height;
*img = malloc(sizeof(image));
(*img)->height = height;
(*img)->width = width;
size_t imgSize = width * height;
(*img)->data = (unsigned char *) malloc(imgSize);
printf("Offset: %zu\n", pdOffset);
unsigned char * ptr = (*img)->data;
unsigned char * srcPtr = &result[pdOffset];
for (size_t i = 0; i < imgSize; ++i)
{
unsigned char r = *srcPtr;
unsigned char g = *(srcPtr + 1);
unsigned char b = *(srcPtr + 2);
*ptr = luminanceFromRGB(r, g, b);
ptr++;
srcPtr += bytesPerPixel;
if (i % width == 0)
{
srcPtr += rowBytes - usedRowBytes;
}
}
free(result);
return size;
}
//Assigns a ASCII character (scale) depending on the images brightness
void printchar(image * img)
{
for (size_t y = img->height - 1; y > 0; --y)
{
for (size_t x = 0; x < img->width; ++x)
{
unsigned char c = *(img->data + x + img->width * y);
int rescaled = c * numScale / 256;
putchar(scale[numScale - rescaled]);
}
putchar('\n');
}
}
void release(image * img)
{
if (img)
{
if (img->data)
free(img->data);
free(img);
}
}
int main(int argc, char ** argv)
{
if (argc != 2)
{
puts("Argument needed: filename.");
return 1;
}
puts(argv[1]);
setbuf(stdout, 0);
numScale = strlen(scale) - 1;
printf("ASCII Brightness Scale: %d\n", numScale);
image *img = NULL;
if (loadImage(&img, argv[1]))
{
printf("Image dimensions: %zux%zu\n", img->width, img->height);
//Prints ASCII characters in terminal
printchar(img);
release(img);
}
return 0;
}
Change main() to
//printchar(img);
char buf[1000000]; // 1M should be enough
sprintchar(buf, img);
printf("%s", buf); // or whatever
and change/copy printchar() to
void sprintchar(char *dst, image *img) {
for (size_t y = img->height - 1; y > 0; --y) {
for (size_t x = 0; x < img->width; ++x) {
unsigned char c = *(img->data + x + img->width * y);
int rescaled = c * numScale / 256;
*dst++ = scale[numScale - rescaled];
}
*dst++ = '\n';
}
*dst = 0;
}
In the pset4 recover, I've successfully recovered 49 instead of 50 JPGs, and though they look ok, check50 tells me the images don't match:
:) recover.c exists.
:) recover.c compiles.
:) handles lack of forensic image
:( recovers 000.jpg correctly
recovered image does not match
:( recovers middle images correctly
recovered image does not match
:( recovers 049.jpg correctly
049.jpg not found
My code is:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef uint8_t BYTE;
// Declare a function
int find_start(FILE *ptr);
int find_jpeg(FILE *ptr);
int main(int argc, char *argv[])
{
// Accept only one command-line argument
if (argc != 2)
{
printf("Enter the name of the forensic image\n");
return 1;
}
char *name = argv[1];
FILE *pointer = fopen(name, "r");
// Inform the reader if the file can't be opened
if (pointer == NULL)
{
printf("File cannot be opened\n");
return 1;
}
int q = 0;
// Find the signature for the beginning of the first jpeg
int d1 = find_start(pointer);
// Loop
while (q < 50)
{
if (q == 0)
{
fseek(pointer, 508, SEEK_CUR);
}
int e = find_jpeg(pointer);
fseek(pointer, -(e + 512), SEEK_CUR);
BYTE array[e + 512];
fread(array, 1, e + 512, pointer);
// Transfer the jpeg from the array to a new file
char new_name[8];
int o = sprintf(new_name, "%i%i%i.jpg", q / 100, q / 10 - (q / 100) * 100, q - (q / 100) * 100 - (q / 10) * 10);
FILE *out = fopen(new_name, "w");
fwrite(array, 1, e + 512, out);
q++;
fclose(out);
}
// Close all files
fclose(pointer);
return 0;
}
// Define the function for finding the beginning of the first jpeg
int find_start(FILE *ptr)
{
BYTE i, j, k, l;
int x;
int *count = &x;
*count = 0;
do
{
do
{
do
{
do
{
i = fgetc(ptr);
*count = *count + 1;
}
while (i != 0xff);
j = fgetc(ptr);
}
while (j != 0xd8);
k = fgetc(ptr);
*count = *count + 1;
}
while (k != 0xff);
l = fgetc(ptr);
*count = *count + 1;
}
while (l < 224 || l > 240);
return x;
}
int find_jpeg(FILE *ptr)
{
BYTE i, j, k, l;
int x;
int *count = &x;
*count = 0;
do
{
i = fgetc(ptr);
j = fgetc(ptr);
k = fgetc(ptr);
l = fgetc(ptr);
fseek(ptr, 508, SEEK_CUR);
*count = *count + 1;
}
while (i != 0xff || j != 0xd8 || k != 0xff || l < 224 || l > 240);
int a = x * 512;
return a;
}
I know it's very long and not elegant, but what is the problem otherwise?
It works perfectly well for a 20-20 table but for anything else it crashes.
the file is in this link:http://www.csd.uoc.gr/~hy100/glid.txt.
I can not figure out what the problem is because when I put an 20-20 table it works and when
I give a 21-20 table it does the job perfectly fine but crashes before being able to return 0; .
#include <stdio.h>
#include <stdlib.h>
int height, length;
char **world, **new_world;
int load_world_from_file(char filename[]) {
int i, j;
char ch;
FILE *fp;
fp = fopen(filename, "r");
if (fp == NULL ) {
perror("Error while opening the file.\n");
exit(EXIT_FAILURE);
}
fscanf(fp, "%d %d", &height, &length);
printf("here:%d,%d\n", height, length);
/*dilosi dunamika tou pinaka kataxoriseis*/
/* declaration under the table entries */
world = (char **) malloc(sizeof(char *) * (height + 1));/*height + 1 ('\0')*/
for (i = 0; i < 2 * height; i++) {
/* height + height ('|') + 1 ('\0') */
world[i] = (char *) malloc(sizeof(char) * (length + length + 1));
}
/* height + 1 ('\0') */
new_world = (char **) malloc(sizeof(char *) * (height + 1));
for (i = 0; i < 2 * height; i++) {
/* height + height ('|') + 1 ('\0') */
new_world[i] = (char *) malloc(sizeof(char) * (length + length + 1));
}
printf("The contents of %s file are :\n", filename);
i = 0;
j = 0;
while ((ch = fgetc(fp)) != EOF) {
i++;
if (i = length + length + 1) {
j++;
i = 0;
}
world[j] = ch;
printf("%c", world[j]);
}
printf("\n");
for (i = 0; i < (((2 * length) + 2) * height) + 1; i++) {
printf("%c", world[i]);
}
fclose(fp);
return 0;
}
int main() {
char filename[30], filename2[30];
printf("Enter the name of file you want to open:\n");
scanf("%s", &filename);
load_world_from_file(filename);
return 0;
}
Your help is much appreciated.
IT