|
|
|
#include "hide.h"
|
|
|
|
|
|
|
|
void hide_lsb(string picture_path, string file_path, string output_path, byte forced_lsb) {
|
|
|
|
|
|
|
|
u32 width, height, size;
|
|
|
|
u32 lsb; // nombre de bits occupes par channnel
|
|
|
|
u32 w_index = 1; // nombre de groupes de bits écrits
|
|
|
|
|
|
|
|
picture image = 0;
|
|
|
|
byte *to_hide = 0; // donnees a dissimuler
|
|
|
|
byte write_buffer = 0; // buffer d'ecriture
|
|
|
|
byte buffer_fill = 0; // remplissage du buffer
|
|
|
|
|
|
|
|
FILE *fp;
|
|
|
|
|
|
|
|
EXIT_ON_TRUE(lodepng_decode32_file(&image, &width, &height, picture_path), LODEPNG_ERROR);
|
|
|
|
|
|
|
|
EXIT_ON_FALSE(fp = fopen(file_path, "r"), SYSTEM_CALL_FAIL);
|
|
|
|
EXIT_ON_TRUE(fseek(fp, 0L, SEEK_END), SYSTEM_CALL_FAIL);
|
|
|
|
size = (u32) ftell(fp);
|
|
|
|
rewind(fp);
|
|
|
|
|
|
|
|
EXIT_ON_FALSE(to_hide = malloc((size + 5) * sizeof(byte)), SYSTEM_CALL_FAIL);
|
|
|
|
fread(to_hide + EMBEDDED_HEADER_SIZE, size, 1, fp);
|
|
|
|
|
|
|
|
if (fclose(fp)) exit(3);
|
|
|
|
|
|
|
|
if ((lsb = (size * 8 + HEADER_SIZE_BITS) / (width * height * 3 - 1) +
|
|
|
|
((size * 8 + HEADER_SIZE_BITS) % (width * height * 3 - 1) != 0)) > 7)
|
|
|
|
exit(DATA_DOESNT_FIT);
|
|
|
|
//printf("%d\n", lsb);
|
|
|
|
|
|
|
|
lsb = (forced_lsb && forced_lsb >= lsb) ? forced_lsb : lsb;
|
|
|
|
|
|
|
|
// premiere partie header (3 bits)
|
|
|
|
image[0] = (byte) ((image[0] & 0xf8) | lsb);
|
|
|
|
u32 mask = gen_mask(lsb);
|
|
|
|
|
|
|
|
// deuxieme partie header (32 bits)
|
|
|
|
for (u32 i = 0, m = 0xff000000; i < LEN_HEADER_SIZE; ++i, m >>= 8)
|
|
|
|
to_hide[i] = (byte) ((size & m) >> ((3 - i) * 2 * 4));
|
|
|
|
|
|
|
|
// octet reserve
|
|
|
|
to_hide[LEN_HEADER_SIZE] = 0;
|
|
|
|
|
|
|
|
// parcours des donnees a stocker octet par octet
|
|
|
|
for (u32 i = 0; i < size + EMBEDDED_HEADER_SIZE; ++i) {
|
|
|
|
// parcours octet courant bit a bit
|
|
|
|
// incrementation indice j
|
|
|
|
// deplacement masque mk
|
|
|
|
for (u32 j = 0, mk = 0x80; j < 8; ++j, mk >>= 1) {
|
|
|
|
// on decale le contenu du buffer pour liberer le dernier bit
|
|
|
|
// on ecrit le bit courant dans le buffer
|
|
|
|
write_buffer = (byte) (write_buffer << 1u | (byte) (to_hide[i] & mk) >> (8u - j - 1u));
|
|
|
|
buffer_fill++; // on incremente le nombre d'elements dans le buffer
|
|
|
|
if (buffer_fill == lsb) { // si on a assez de donnees dans le buffer pour ecrire un canal de pixel
|
|
|
|
// formule pour retrouver le canal en evitant les alpha
|
|
|
|
// on insere les donnees du buffer dans l'image
|
|
|
|
image[w_index + w_index / 3] = (byte) ((image[w_index + w_index / 3] & mask) |
|
|
|
|
(write_buffer & (~mask)));
|
|
|
|
w_index++; // on indique qu'un element de plus a ete ecrit
|
|
|
|
buffer_fill = 0; // on indique que le buffer est vide (c'est un mensonge)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (buffer_fill) { // si le buffer n'est pas vide en fin d'execution on l'ecrit dans l'image
|
|
|
|
image[w_index + w_index / 3] =
|
|
|
|
(byte) ((image[w_index + w_index / 3] & mask) | (write_buffer << (lsb - buffer_fill) & ~mask));
|
|
|
|
w_index++;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (u32 i = w_index + w_index / 3; i < width * height * 4; ++i) { // remplissage du reste de l'image avec du bruit
|
|
|
|
if (i % 4 == 3) continue; // on skip le canal alpha
|
|
|
|
image[i] = (byte) ((image[i] & mask) | ((byte) rand() & (~mask)));
|
|
|
|
}
|
|
|
|
|
|
|
|
EXIT_ON_TRUE(lodepng_encode32_file(output_path, image, width, height), LODEPNG_ERROR);
|
|
|
|
|
|
|
|
free(to_hide);
|
|
|
|
free(image);
|
|
|
|
}
|