I was trying to open and read through a P5 .pgm (grayscale) file, then extract the least-significant-bit from each pixel. I tried to get the LSB of every pixel, so one bit bit per byte of the image.So it would take 8 image bytes/pixels to extract 1 byte of hidden text.Then, I would be able to get one byte of the hidden message and create a character. (using the ASCII values)
I also have to display the hidden message.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
//Clear PGM (XV) comments.
void pgmCommentClear(FILE *disk){
unsigned char 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).
unsigned char *PGM_FILE_READ_1D(char *FileName, int *Width, int *Height, int *color) {
int pmax;
char ch;
char type[3];
unsigned char *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 = (unsigned char *)calloc(*Height * *Width * 3, sizeof(unsigned char));
fread(Image, 1, (*Height * *Width * 3), disk);
} else {
Image = (unsigned char *)calloc(*Height * *Width, sizeof(unsigned char));
fread(Image, 1, (*Height * *Width), disk);
}
fclose(disk);
return Image;
}
//function to convert binary to decimal
int BinaryToDec(int array[]) {
int decimal=0;
int m=1;
for(int i=7; i>=0; i--){
decimal = array[i]*m;
m *= 2;
}
if(array[0] == 1) decimal *= -1;
printf("decimal: %d\n", decimal);
return decimal;
}
void DecToBinary(int dec){
int binary[8];
for(int i=0; i<=8; i ){
if(dec & (1 << i)) binary[i] = 1;
else binary[i] = 0;
}
printf("binaryform:");
for(int i=7; i>=0; i--){
printf("%d", binary[i]);
}
printf("\n");
}
int main(void){
char *fileName = "hw10.pgm";
int Width, Height, color;
unsigned char *Image;
Image = PGM_FILE_READ_1D(fileName, &Width, &Height, &color);
//int size = Width*Height;
int size = 50;
int array[8];
int xCount =0;
for(int i=0; i<size; i ){
int mask=1;
for(int k=0; k<8; k ){
array[k] = Image[i]&mask;
mask<<1;
}
printf("Image: %d\n", Image[i]);
DecToBinary(Image[i]);
BinaryToDec(array);
}
}
I have got this so far. To prevent going through too many pixels, it should stop after reading xxx
from the file. I am still confused about how to display the uncovered characters.
Image: 214
binaryform:11010110
decimal: 0
Image: 213
binaryform:11010101
decimal: -255
Image: 208
binaryform:11010000
decimal: 0
Image: 214
binaryform:11010110
decimal: 0
Image: 215
I have this as output(for the first few iterations,I didn't include all of them).
How would I extract the LSBs, group them and then find the hidden text? I am just stuck on what to do next and would appreciate any suggestions.
CodePudding user response:
- The lsb can be fetched using & 1
- the main for loop should just go over eight image bytes at a time
- the contents can use bit shifting to accumulate a byte
// We will have (at most) size/8 bytes in the final text
for(int i=0; i<size/8; i ){
// Process eight image bits in a row
int accum = 0;
for(int k=0; k<8; k ){
// Shift the current contents (multiply by 2)
// and add in the new bit. This will reconstruct
// a byte
accum = (accum << 1) (Image[i*8 k] & 1);
}
// the resulting byte is the next character of your hidden
// text
printf("%c", accum);
}
printf("\n");
CodePudding user response:
How would I extract the LSBs
Use the bitwise AND operator like
Image[i] & 1
How would I ... group them
Use a combination of bitwise shift and bitwise OR operators like
(LSB_a << 7) | (LSB_b << 6) | (LSB_c << 5) | ....
How would I ... then find the hidden text?
Simply print the resulting value as a character, e.g. using putchar
Below is a very simple example of one way to do it:
#include <stdio.h>
#include <assert.h>
int main(void)
{
unsigned char Image[] = {0x46, 0x51, 0x4a, 0x5c, 0x42, 0x10, 0xaa, 0xa1,
0xfe, 0x7b, 0x86, 0x18, 0x54, 0x2a, 0xa3, 0x60,
0x3c, 0x1d, 0x24, 0x9a, 0x06, 0x60, 0xa9, 0x75};
size_t sz = sizeof Image / sizeof Image[0];
assert(sz % 8 == 0);
for (size_t i = 0; i < sz; i = 8)
{
int res = (Image[i] & 1) << 7 |
(Image[i 1] & 1) << 6 |
(Image[i 2] & 1) << 5 |
(Image[i 3] & 1) << 4 |
(Image[i 4] & 1) << 3 |
(Image[i 5] & 1) << 2 |
(Image[i 6] & 1) << 1 |
(Image[i 7] & 1);
putchar(res);
}
return 0;
}
The output from this code is:
ABC
In the above example calculation of the result was done by explicit writing all 8 bitwise operations. That was done to keep the example simple. Should you prefer shorter code, it can be done in a loop like:
int res = 0;
for (int k=0; k<8; k)
{
res |= (Image[i k] & 1) << (7-k);
}