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;
}
Related
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;
}
I'm trying to embed a file in an image by using the last 2 LSB's of each color in each pixel (last 3 in the case of blue), and whenever I encode/decode, text works fine, but any binary data like ELF files, random data, etc get all mixed up. Here's my steganography and desteganography function:
bool steganographize(int height, int width, unsigned long long filesize, unsigned char *file, RGBTRIPLE image[height][width], bmpstatus about)
{
int f = 0; //for char access
int i = 0;
int j = 0;
for (i = 0 ; i < height; i++)
{
if (f >= filesize)
{
goto finis;
}
for (j = 0 ; j < width; j++)
{
if (f >= filesize)
{
goto finis;
}
image[i][j].rgbtRed = ((image[i][j].rgbtRed & ~0x3) | ((file[f] & 0x60) >> 5));
image[i][j].rgbtGreen = ((image[i][j].rgbtGreen & ~0x3) | ((file[f] & 0x18) >> 3));
image[i][j].rgbtBlue = ((image[i][j].rgbtBlue & ~0x7) | ((file[f] & 0x7)));
f++;
}
}
finis:
if (f == (filesize))
{
printf("%d\n", i);
printf("%d\n", j);
print_status("Embedded file into BMP");
print_status("Inserting EOF");
image[i][j].rgbtRed = 0;
image[i][j].rgbtGreen = 92;
image[i][j].rgbtBlue = 183;
image[i][j + 1].rgbtRed = 12;
image[i][j + 1].rgbtGreen = 57;
image[i][j + 1].rgbtBlue = 237;
image[i + 1][j].rgbtRed = 91;
image[i + 1][j].rgbtGreen = 34;
image[i + 1][j].rgbtBlue = 45;
return true;
}
return false;
}
bool desteganographize(int height, int width, RGBTRIPLE image[height][width], bmpstatus about, FILE* output)
{
unsigned char* buffer = calloc(height * width * 3, sizeof(unsigned char));
int i = 0;
int j = 0;
int f = 0;
for (i = 0; i < height; i++)
{
for (j = 0; j < width; j++)
{
if (image[i][j].rgbtRed == 0 && image[i][j].rgbtGreen == 92 && image[i][j].rgbtBlue == 183) {
if (image[i][j + 1].rgbtRed == 12 && image[i][j + 1].rgbtGreen == 57 && image[i][j + 1].rgbtBlue == 237
&& image[i + 1][j].rgbtRed == 91 && image[i + 1][j].rgbtGreen == 34 && image[i + 1][j].rgbtBlue == 45) {
goto finis;
}
}
unsigned char c =
((image[i][j].rgbtRed & 0x3) << 5) |
((image[i][j].rgbtGreen & 0x3) << 3 ) |
(image[i][j].rgbtBlue & 0x7);
buffer[f] = c;
f++;
}
}
finis:
fwrite(buffer, sizeof(unsigned char), f, output);
printf("%d\n", i);
printf("%d\n", j);
fclose(output);
return true;
return false;
}
Here's the relevant parts of my main function, as well:
int main(int argc, char** argv) {
if (strstr(argv[1], encode) != NULL) {
FILE *bmp = fopen(bitmap, "rb");
bmpstatus *result = is_valid_bmp(bmp);
if (result == NULL)
{
print_error("Bad BMP. Maybe you specified the wrong file?");
}
//Get BMP into memory
char buffer[BUFFER_LEN];
sprintf(buffer, "Found BMP of Height %d and width %d", result->height, result->width);
print_status(buffer);
cleararr(buffer);
int width = result->width;
int height = result->height;
RGBTRIPLE(*image)
[width] = calloc(height, width * sizeof(RGBTRIPLE));
if (!scanimage(height, width, bmp, image, *result))
{
print_error("Error scanning BMP into memory. Probably not enough RAM.");
}
print_status("Scanned BMP into memory");
//Scan file into memory
unsigned long long filesize = file_size(fopen(filename, "rb"));
sprintf(buffer, "Found file with %llu kilobytes", filesize / 1024);
print_status(buffer);
cleararr(buffer);
if (filesize > ((unsigned long long)width * height * 3) / 8)
{
print_error("Bitmap not big enough to hold file");
}
unsigned char *file = calloc(filesize, sizeof(unsigned char));
printf("%llu\n", filesize);
if (!scan_file(file, filesize, fopen(filename, "rb")))
{
print_error("Error scanning file into memory");
}
print_status("Scanned file into memory");
if (!steganographize(height, width, filesize, file, image, *result))
{
print_error("Error embedding file into BMP");
}
//Output manipulated BMP
sprintf(buffer, "Outputting finished BMP to %s", output);
print_status(buffer);
outputimage(height, width, fopen(output, "wb"), image, *result);
cleararr(buffer);
free(result);
free(image);
free(file);
print_success("Finished!");
return 0;
}
if (strstr(argv[1], decode)) {
bmpstatus *result = is_valid_bmp(input);
if (result == NULL)
{
print_error("Bad BMP");
}
int height = result->height;
int width = result->width;
RGBTRIPLE(*image)
[width] = calloc(height, width * sizeof(RGBTRIPLE));
char buffer[BUFFER_LEN];
sprintf(buffer, "Found a BMP with height %d and width %d", height, width);
print_status(buffer);
cleararr(buffer);
if (!scanimage(height, width, input, image, *result))
{
print_error("Cannot scan BMP into memory. Not enough RAM, maybe?");
}
print_status("Scanned BMP into memory");
char tmpname[16] = "/tmp/tmp.XXXXXX";
mkstemp(tmpname);
print_status("Made temporary file");
FILE* finish = fopen(tmpname, "wb");
if (!desteganographize(height, width, image, *result, finish)) {
print_error("Could not extract file.");
}
free(result);
free(image);
return 0;
}
}
It isn't the most elegant way, but it seems like it gets the job done (at least for text). bmpstatus is a struct that has the height and width of the bmp, filesize has the size of the input data, and RGBTRIPLE is a struct with 3 elements, red green and blue. I've verified that these two work. scanimage gets the BMP and puts it into an RGBTRIPLE matrix, and scan_file takes a file pointer and scans the data into an unsigned char array. All of these work, so I'm assuming it's something with the steganography functions themselves.
It turned out that I was only reading 7 bits from each char, instead of 8. Once I put replaced 0x60 with 0xe0 and 0x3 with 0x7 in the red component, it worked.
I've been trying to write a program that resizes bitmap files, but cannot for the life of me figure out why my file size in the output file is off.
I tried resizing with another program and it resizes a file from 486 bytes to 1,9kb with a factor of 2, whereas my code results in a file of 3,5kb. Please have a look at my code and I hope someone can point me in the right direction as to what is making my file so bloated.
PS: The resulting file has the correct dimensions and also looks alright, its just the file size that's not scaling correctly...
#include <stdio.h>
#include <stdbool.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include "bmp.h"
bool is_valid_count(int argc);
bool is_valid_range(int fact);
bool is_valid_file_type(char *filename);
int main(int argc, char *argv[])
{
char *n = argv[1];
int resize_factor = atoi(n);
// validate
if (!is_valid_count(argc) ||
!is_valid_range(resize_factor) ||
!is_valid_file_type(argv[2]) ||
!is_valid_file_type(argv[3]))
{
printf("USAGE: run resize <resize-factor> <infile.bmp> <outfile.bmp>\n");
return 1;
}
// remember filenames
char *infile = argv[2];
char *outfile = argv[3];
// open input file
FILE *open_in_file = fopen(infile, "r");
if (open_in_file == NULL)
{
fprintf(stderr, "Could not open %s.\n", infile);
return 2;
}
// open output file
FILE *open_out_file = fopen(outfile, "w");
if (open_out_file == NULL)
{
fclose(open_in_file);
fprintf(stderr, "Could not create %s.\n", outfile);
return 3;
}
// read infile's BITMAPFILEHEADER
BITMAPFILEHEADER bitmap_file_header;
fread(&bitmap_file_header, sizeof(BITMAPFILEHEADER), 1, open_in_file);
// read infile's BITMAPINFOHEADER
BITMAPINFOHEADER bitmap_info_header;
fread(&bitmap_info_header, sizeof(BITMAPINFOHEADER), 1, open_in_file);
// ensure infile is (likely) a 24-bit uncompressed BMP 4.0
if (bitmap_file_header.bfType != 0x4d42 ||
bitmap_file_header.bfOffBits != 54 ||
bitmap_info_header.biSize != 40 ||
bitmap_info_header.biBitCount != 24 ||
bitmap_info_header.biCompression != 0)
{
fclose(open_out_file);
fclose(open_in_file);
fprintf(stderr, "Unsupported file format.\n");
return 4;
}
int padding_old = (4 - (bitmap_info_header.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
LONG old_biWidth = bitmap_info_header.biWidth;
// resize bitmap
bitmap_info_header.biHeight *= resize_factor;
bitmap_info_header.biWidth *= resize_factor;
int padding_new = (4 - (bitmap_info_header.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
bitmap_info_header.biSizeImage = ((sizeof(RGBTRIPLE) * bitmap_info_header.biWidth) + padding_new) * abs(bitmap_info_header.biHeight);
bitmap_file_header.bfSize = bitmap_info_header.biSizeImage + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
// write outfile's BITMAPFILEHEADER & BITMAPINFOHEADER
fwrite(&bitmap_file_header, sizeof(BITMAPFILEHEADER), 1, open_out_file);
fwrite(&bitmap_info_header, sizeof(BITMAPINFOHEADER), 1, open_out_file);
// iterate over infile's scanlines
for (int i = 0, biHeight = abs(bitmap_info_header.biHeight); i < biHeight; i++)
{
for (int j = 0; j < resize_factor; j++)
{
// iterate over pixels in scanline
for (int k = 0; k < old_biWidth; k++)
{
// temporary storage
RGBTRIPLE triple;
// read RGB triple from infile
fread(&triple, sizeof(RGBTRIPLE), 1, open_in_file);
for (int l = 0; l < resize_factor; l++)
{
// write RGB triple to outfile
fwrite(&triple, sizeof(RGBTRIPLE), 1, open_out_file);
}
}
// add padding
for (int m = 0; m < padding_new; m++)
{
fputc(0x00, open_out_file);
}
if (j < resize_factor - 1)
{
fseek(open_in_file, -(old_biWidth * (int)sizeof(RGBTRIPLE)), SEEK_CUR);
}
}
// skip over padding, if any
fseek(open_in_file, padding_old, SEEK_CUR);
}
fclose(open_in_file);
fclose(open_out_file);
// success
return 0;
}
bool is_valid_count(int argc)
{
if (argc != 4)
{
printf("Incorrect number of arguments provided. Must be 3!\n");
return false;
}
return true;
}
bool is_valid_range(int fact)
{
if (fact < 1 || fact > 100)
{
printf("Range is invalid.Resize-factor has to be between 1 and 100! Was: %i\n", fact);
return false;
}
return true;
}
bool is_valid_file_type(char *filename)
{
const char *dot = strrchr(filename, '.');
const char *extension = ".bmp";
if (strcmp(dot, extension) != 0)
{
printf("Filetype not recognized: %s!\n", dot);
return false;
}
return true;
}
//FILE *open_in_file = fopen(infile, "r");
FILE *open_in_file = fopen(infile, "rb");
//FILE *open_out_file = fopen(outfile, "w");
FILE *open_out_file = fopen(outfile, "wb");
//for (int i = 0, biHeight = abs(bitmap_info_header.biHeight); i < biHeight; i++)
for (int i = 0, biHeight = abs(bitmap_info_header.biHeight)/resize_factor; i < biHeight; i++)
UPDATE***********************
For reference I included the program I made for opening a PPM image - embedding a message into the image and then saving out a new image with the embedded text. With the function below I'm hoping to extra that message, (hidden in the LSB) and then converting it to text to display it. Thanks for the replies so far - I'm going to start testing them out and see if anything works.
I'm trying to write a function that extracts the LSB of an unsigned char value - puts them bits together to form an extracted message. I have the length of how many LSBs I need to extract from the file, but I'm having trouble with how to convert this into a message.
At first I extracted the first 8 bits into an int array - giving me something such as 00110000. Now I have an INT array with that value, and I need to convert it to a single char for the letter representation. However, I think I should be taking in all of the LSBs into an array that is messageLength * 7 and somehow converting that int array into the text. It would be giving me the binary represenation of the text before converting. Maybe theirs a way to convert a long string of 1's and 0's to text?
unsigned char * extBits(PPMImage *img, int messageLen, unsigned char * decMsg)
{
//int count = 2;
int embCount = 0;
int deM = messageLen * 7;
int count = 0;
unsigned char byte;
// int mask;
// unsigned char update;
// unsigned char flipOne = 0x01; //0x01
// unsigned char flipZero = 0xFE; //0x00
unsigned char dMsg[deM];
int byteArray[7];
int takeByte = 0;
unsigned char *extMsg;
char c;
for(int j = 0; j < 7; j++)
{
if(takeByte == 8)
{
//first letter extracted
takeByte = 0;
}
//byte = msgOne[j];
// byte = img->pixel[j];
//encMsg[j] = byte;
byte = img->pixel[j];
//printf("byte: %c\n", byte);
// printf("byte: %x\n", byte);
byte &= 1;
//printf("byte after: %x\n", byte);
dMsg[j] = byte;
byteArray[j] = byte;
data[j] = byteArray[j];
printf("dMsg:%x ", dMsg[j]);
// printf("pixel:%c \n", img->pixel[j]);
embCount++;
takeByte++;
}
/*
for(int r=0;r<7;r++)
{
printf("\n%d\n", byteArray[r]);
}
printf("count: %d", embCount);
printf("%s ", dMsg);
*/
return decMsg = dMsg;
}
embedding program*******
//////////////////////////////////////////////////////////////
/*
execute as ./emb -i <img2embed> -i <text file> -o <embedIMG>
*/
//////////////////////////////////////////////////////////////
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct {
int x, y;
unsigned char *pixel;
} PPMImage;
#define RGB_COMPONENT_COLOR 255
static PPMImage *readPPM(const char *filename)
{
FILE * fp;
PPMImage *img;
int rgb_comp_color;
int size = 0;
fp = fopen(filename, "a+");
fseek(fp, 0, SEEK_END);
size = ftell(fp);
fseek(fp, 0, SEEK_SET);
unsigned char *buff;
unsigned char stuff[16];
int c;
int x,y;
buff = (unsigned char*) malloc(sizeof(unsigned char)*size +1);
memset(buff, '\0', sizeof(unsigned char)*size+1);
fgets(stuff, sizeof(stuff), fp);
if (stuff[0] != 'P' || stuff[1] != '3') {
fprintf(stderr, "Invalid image format (must be 'P3')\n");
exit(1);
}
//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);
if (fscanf(fp, "%d %d", &img->x, &img->y) != 2) {
fprintf(stderr, "Invalid image size (error loading '%s')\n", filename);
exit(1);
}
if (fscanf(fp, "%d", &rgb_comp_color) != 1) {
fprintf(stderr, "Invalid rgb component (error loading '%s')\n", filename);
exit(1);
}
if (rgb_comp_color!= RGB_COMPONENT_COLOR) {
fprintf(stderr, "'%s' does not have 8-bits components\n",filename);
exit(1);
}
//printf("x: %d y: %d\n", img->x, img->y);
unsigned char buffer[1024];
memset(buffer,0,1024);
fgets(buffer,1024,fp);
fread(buff, 1, size, fp);
img->pixel = buff;
/*
for(int h = 0; h < 20; h++)
{
printf("%c", buff2[h]);
}
printf("%s", buff2);
*/
fclose(fp);
return img;
}
void writePPM(const char *filename, unsigned char * img, int x, int y)
{
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, "P3\n");
//comments
// fprintf(fp, "# Created by %s\n",CREATOR);
//image size
fprintf(fp, "%d %d\n",x,y);
// rgb component depth
fprintf(fp, "%d\n",RGB_COMPONENT_COLOR);
// pixel pixel
fwrite(img,1, strlen(img), fp);
fclose(fp);
}
//unsigned char * embBits(PPMImage *img, int messageLen, unsigned char*msgOne, unsigned char *encMsg)
int embBits(PPMImage *img, int messageLen, unsigned char*msgOne, int embLen)
{
//int count = 2;
int embCount = 0;
int count = 0;
unsigned char *eMsg;
unsigned char byte;
int mask;
unsigned char update;
unsigned char flipOne = 0x01; //0x01
unsigned char flipZero = 0xFE; //0x00
for(int j = 0; j < messageLen; j++)
{
byte = msgOne[j];
//encMsg[j] = byte;
for(int k=7; 0 < k; k--)
{
update = byte;
update = update & (1<<k);
//printf("pixel:%c\n", img->pixel[count]);
//printf("pixel+1:%c\n", img->pixel[count+1]);
// printf("pixel+2:%c\n", img->pixel[count+2]);
if(update == 0)
{
// if i see 1 |=
// if i see a 0 &=
//img->pixel[count] = img->pixel[count] &= flipZero;
img->pixel[count+2] &= flipZero;
}
else
{
//flip bit
//red
//check LSB and FLIP
// img->pixel[count] = img->pixel[count] |= flipOne;
img->pixel[count+2] |= flipOne;
}
//mask--;
//eMsg[count] = img->pixel[count];
//printf("count: %d\n", count);
count = count + 3;
}
// eMsg[j] = byte;
}
//return encMsg = eMsg;
//unsigned char *yes = "sucess";
/*
for(int a = 0; a < messageLen; a++)
{
printf("pixel: %c", img->pixel[a]);
printf("msg: %c\n", eMsg[a]);
// eMsg[a] = img->pixel[a];
}
*/
embCount = count;
return embLen = embCount;
}
int main(int argc, char **argv){
int messageLen;
int i = 0;
PPMImage *img;
int size = 0;
FILE * fp;
int testSize;
fp = fopen(argv[4], "a+");
fseek(fp, 0, SEEK_END);
size = ftell(fp);
fseek(fp, 0, SEEK_SET);
unsigned char *buff;
buff = (unsigned char*) malloc(sizeof(unsigned char)*size +1);
memset(buff, '\0', sizeof(unsigned char)*size+1);
fread(buff, 1, size, fp);
fclose(fp);
// printf("text encryption: %s\n", buff);
testSize = strlen(buff);
// printf("Size of text %d\n", testSize);
messageLen = strlen(buff);
img = readPPM(argv[2]);
/*
int testing = strlen(img->pixel);
for (int f=0;f<6;f++)
{
//f2 = 1
//f3 = 6
printf("%c", img->pixel[f]);
}
*/
// printf("%c \n", img->pixel[2]);
// printf("%c \n", img->pixel[5]);
printf("\n");
// unsigned char * encMsg;
int encMsg = 0;
encMsg = embBits(img, messageLen, buff, encMsg);
// printf("cipher msg:%s\n", img->pixel);
printf("message length: %d\n", messageLen);
// printf("cipher msg length: %d\n", encMsg);
writePPM(argv[6], img->pixel, img->x, img->y);
printf("Please press enter to complete\n");
getchar();
}
I don't know what you are doing specifically with your file and assigning each bit to a position in an array but you can print binary sequences stored in a unsigned int. Try using something like this...
#include <stdio.h>
int main() {
unsigned int arr[] = {00110110, 00111100, 10111011};
int i = sizeof(arr)/sizeof(arr[0]);
while(i-->0) {
printf("%c, ", arr[i]);
}
printf("\n");
}
You can use bit operations to gather these bits into a byte.
#include <stdio.h>
#define BYTE_LENGTH 8
#if 1
/* MSB is in data[0], LSB is in data[BYTE_LENGTH - 1] */
int arrayToChar(const int data[]) {
int c = 0;
int i;
for (i = 0; i < BYTE_LENGTH; i++) {
if (data[i]) c |= (1 << (BYTE_LENGTH - 1 - i));
}
return c;
}
#else
/* LSB is in data[0], MSB is in data[BYTE_LENGTH - 1] */
int arrayToChar(const int data[]) {
int c = 0;
int i;
for (i = 0; i < BYTE_LENGTH; i++) {
if (data[i]) c |= (1 << i);
}
return c;
}
#endif
int main(void) {
int data[8] = {0, 0, 1, 1, 0, 0, 0, 0};
int c = arrayToChar(data);
printf("%d %c\n", c, c);
return 0;
}
If you want to produce one byte from 7 bits, change BYTE_LENGTH to 7.
If you want to deal with long sequence of bits, apply arrayToChar repeatedly with changing the (address of) first element to be passed.