3
$\begingroup$

So, this is a problem that me and my friends are facing while doing a project for school.

Our idea is the following. Given a certain photo we want to be able to hide a message behind it. Our approach was the following.

We start by using the command Import to get the image to Mathematica. Then we use the command ImageData to extract the list that contains the pixels in the image.

Then, our approach was to identify a sequence which was not present in those digits. For example, there is no number that is of the form 0,1770... Then we could save the information in these types of numbers.

So, we generate these numbers and then, with the command ReplacePixelValue we were able to replace the pixels in the image. At this point we though that our work was done. But it happens that the information was not preserved with the Export of the coded image.

Our main questions are:

  1. Is it true, by any chance, that exporting a file do not preserve the information? And

  2. What would be the best approach to attain our goal?

Thank you som much for your attention. Have a nice day.

UPDATE

By using the ReplacePart in the list of pixels instead of ReplacePixelValue, I managed to obtain the correct list with the correct substitution of values. Although, when I ask for the image of this new list (by using the command Image) the values are edited. When I ask for a value that was substituted by me, the value is no longer there.

$\endgroup$
11
  • 1
    $\begingroup$ What format does the image have? If it's JPEG or another lossy format, the compression upon export will potentially alter the precise pixel values $\endgroup$
    – Lukas Lang
    Commented May 30, 2021 at 9:55
  • 1
    $\begingroup$ If you export to PNG, then you should be fine in that regard (i.e the pixel data that you export will be exactly the pixel data that you import again) $\endgroup$
    – Lukas Lang
    Commented May 30, 2021 at 9:59
  • 2
    $\begingroup$ You may find ResourceFunction["SteganographyInsert"] interesting. To see what it does, the WFR page lets you download the source notebook. $\endgroup$
    – flinty
    Commented May 30, 2021 at 10:12
  • 3
    $\begingroup$ What you're doing is called steganography. Look at Doing Spy Stuff with Mathematica and SteganographyInsert and SteganographyExtract. $\endgroup$
    – creidhne
    Commented May 30, 2021 at 10:13
  • 1
    $\begingroup$ Without seeing your code, it will be difficult to help you any further $\endgroup$
    – Lukas Lang
    Commented May 30, 2021 at 10:43

1 Answer 1

4
$\begingroup$

First, the problem with exporting. There are formats that are lossless and formats that will change the content. Lossless picture format are e.g.: BMP, PNG or RAW. On the other hand, e.g. JPEG will change the content.

Now how to hide some message in a picture? Here is a way to do this:

Idea: Change every pixel of the picture by 0 or 1 according to the message in binary form.

First convert the picture into an array of bytes and the message into a binary array. For convenience prepend the original message length in binary to the message array. Then add the message array to first part of the picture array with the same length. Then convert the message array back to a picture.

Here is the code that does this:

encode[pic_, message_] := Module[{len, d, dims, mess, df},
  d = ImageData[pic, "Byte"];
  dims = d // Dimensions;
  mess = IntegerDigits[ToCharacterCode[message], 2, 8] // Flatten;
  mess = Join[IntegerDigits[Length[mess], 2, 16], mess];
  df = Flatten[d];
  If[(len = Length[mess]) > Length[df], Print["Message too long"]; 
   Return[]];
  df[[;; len]] += mess;
  Image[ArrayReshape[df, dims]/255.]
  ]

decode[pic_, pic0_] := Module[{by, byc, len},
  byc = ImageData[pic, "Byte"] // Flatten;
  by = ImageData[pic0, "Byte"] // Flatten;
  mess = byc - by;
  len = FromDigits[mess[[;; 16]], 2];
  mess = mess[[17 ;; 17 + len]];
  FromCharacterCode@FromDigits[#, 2] & /@ Partition[mess, 8] // 
   StringJoin
  ]

We may test this using a picture from "ExampleData":

pic = ExampleData[{"TestImage", "House"}];
coded = encode[pic, "Hello World"];
decode[coded, pic]

(* "Hello World" *)

And there is little difference in the images:

pic
code

enter image description here

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.