6
$\begingroup$

In my recent question I asked How to embed an image into a string?
The suggested solution was

(* In[1]:= *) image = Import["https://wolfram.com/favicon.ico", "Image"];
(* In[2]:= *) str = ToString[image, StandardForm];

If I execute

(* In[3]:= *) CopyToClipboard[str];

and then paste it into a plain text editor (e.g. notepad on Windows) than I get a very long and verbose string:

\!\(\*GraphicsBox[TagBox[RasterBox[RawArray["Byte", List[List[List[0, 0, 0, 0], (* ... *) List[0, 0, 0, 0]]]], List[List[0, 16], List[16, 0]], List[0, 255], Rule[ColorFunction, RGBColor]], BoxForm`ImageTag["Byte", Rule[ColorSpace, "RGB"], Rule[Interleaving, True]], Rule[Selectable, False]], Rule[BaseStyle, "ImageGraphics"], Rule[ImageSizeRaw, List[16, 16]], Rule[PlotRange, List[List[0, 16], List[0, 16]]]]\)

But if I copy the image to the clipboard directly

(* In[4]:= *) CopyToClipboard[image];

and then paste it into a plain text editor than I get a compressed representation:

\!\(\*
GraphicsBox[
TagBox[RasterBox[CompressedData["
1:eJyNUgss1HEc/+9CKBIyz928OodzCOdxcU95njh5tIQbpvUgDrFKWtIDPaZk
tLTmIiJbWR6pbLVSlNSI0S0j4bS8tiZ9Oi1NFvluv99+n+++n31/3+/nYyxK
CIojEQSRrCy/gqLT2ElJ0elCBTngpItjRWvkD43fZz75v3ibne/1+uIF0ipK
iVviDPd37ADrBdyRdYz8zZYz9yozS3UhdyckeVPl+csq/+LnpR7hvqG4yUaZ
/AP9gf6uMgqtdZwgoY3ilFbtEqJ5gxaa+Zizp7CuVKK03B+K1OwBkgl+MM1m
RnjG6GQZo1tJD7V6HGkTwUMfK0Gw0gyZWvSJJ0r2GBP5Y6goBv054ai3scU5
goEhgosB3zjHpZyykL2pD0nMqadkZ9yj2qOSYOKBiRcaOf4oZ3CRqspAsaEH
oO8IaNFHe7lBZlLPMKMB7g7qPL+ktEStx0kgnTO1xEBwAHrpbIz7haNdKESN
JwtnTeho5nOByG2YJXQBQgdf6VvRHbsv/c+uoyPM4eeK4TA/TIYJgIJTmC6/
irbcFNzmuaEpKhgTp3fik54aBnU2fR7wFdAXz9DnI5S8NzLHc3MqZAejMFlx
Ed8bqyAryseL7d6otnBAX7wQI+SNaN3mJVnglSYeXfuAubuhTnGzfEcaqNI3
RWegN3pOijFYdAJIT4DU2Rk3FSwgUWOgS8UK/dpWaDicwZvnF0Ts55+nel/K
0bU9U2VocP1ZgLu8Hw/tgTxI4/0wEcDEoKMDWmy24Jy6BY4Tlrgm16fOjj9V
IT4kWqpFl4217EOoJx7RLdCqtwEfPe0AcTDAdsBLbTrynH3Tdhmz1TPN+I7F
nCCXv3SMiF9fS1DQTKZBomMwUUNoYZpCwwzVAF8IVYwquqAlu0B5Oe8UBsb4
FPPC48o8vDWvkC1Z9Spus8PrGLjLYf3ya6ey3VhHbnHESv5bHPVOYe0Ngkjf
Bdxs6aFy/2Q+bbX8mpScjCpRovZKNT8BKotUng==
"], {{0, 16}, {16, 0}}, {0, 255},
ColorFunction->RGBColor],
BoxForm`ImageTag["Byte", ColorSpace -> "RGB", Interleaving -> True],
Selectable->False],
BaseStyle->"ImageGraphics",
ImageSizeRaw->{16, 16},
PlotRange->{{0, 16}, {0, 16}}]\)

Both the long and compressed strings, if being pasted back to a Mathematica notebook, are automatically represented as the original image:

(* In[5]:= *) 

I am interested in

Question 1: How to get the compressed string programmatically, without using the clipboard?

The content of CompressedData["..."] looks like a result of the Compress function, and indeed it could be checked that

(* In[6]:= *) ToBoxes[image][[1, 1, 1]] === 
 Uncompress["
  1:eJyNUgss1HEc/+9CKBIyz928OodzCOdxcU95njh5tIQbpvUgDrFKWtIDPaZk
  tLTmIiJbWR6pbLVSlNSI0S0j4bS8tiZ9Oi1NFvluv99+n+++n31/3+/nYyxK
  CIojEQSRrCy/gqLT2ElJ0elCBTngpItjRWvkD43fZz75v3ibne/1+uIF0ipK
  iVviDPd37ADrBdyRdYz8zZYz9yozS3UhdyckeVPl+csq/+LnpR7hvqG4yUaZ
  /AP9gf6uMgqtdZwgoY3ilFbtEqJ5gxaa+Zizp7CuVKK03B+K1OwBkgl+MM1m
  RnjG6GQZo1tJD7V6HGkTwUMfK0Gw0gyZWvSJJ0r2GBP5Y6goBv054ai3scU5
  goEhgosB3zjHpZyykL2pD0nMqadkZ9yj2qOSYOKBiRcaOf4oZ3CRqspAsaEH
  oO8IaNFHe7lBZlLPMKMB7g7qPL+ktEStx0kgnTO1xEBwAHrpbIz7haNdKESN
  JwtnTeho5nOByG2YJXQBQgdf6VvRHbsv/c+uoyPM4eeK4TA/TIYJgIJTmC6/
  irbcFNzmuaEpKhgTp3fik54aBnU2fR7wFdAXz9DnI5S8NzLHc3MqZAejMFlx
  Ed8bqyAryseL7d6otnBAX7wQI+SNaN3mJVnglSYeXfuAubuhTnGzfEcaqNI3
  RWegN3pOijFYdAJIT4DU2Rk3FSwgUWOgS8UK/dpWaDicwZvnF0Ts55+nel/K
  0bU9U2VocP1ZgLu8Hw/tgTxI4/0wEcDEoKMDWmy24Jy6BY4Tlrgm16fOjj9V
  IT4kWqpFl4217EOoJx7RLdCqtwEfPe0AcTDAdsBLbTrynH3Tdhmz1TPN+I7F
  nCCXv3SMiF9fS1DQTKZBomMwUUNoYZpCwwzVAF8IVYwquqAlu0B5Oe8UBsb4
  FPPC48o8vDWvkC1Z9Spus8PrGLjLYf3ya6ey3VhHbnHESv5bHPVOYe0Ngkjf
  Bdxs6aFy/2Q+bbX8mpScjCpRovZKNT8BKotUng==
  "]
(* Out[6]= True *) 

Unfortunately, RawArray, CompressedData and BoxForm`ImageTag are all undocumented. It looks like RawArray represents (probably, optimized) internal representation of a multi-dimensional array, and CompressedData is equivalent to Uncompress (e.g. unless being held, it automatically evaluates to the object represented by the compressed string) except that CompressedData can be successfully interpreted as part of an input of the form \!\(\* ... \).

Question 2: Did I get their meaning right? Can they be useful in any other context?

Assuming I did it right, the closest result I was able to obtain to what I need is given by

(* In[7]:= *) toCompressedString[image_Image] :=
  "\!\(\*" <> ToString[
    ToBoxes[image] /.
     array_RawArray :> 
      With[{compressed = Compress[array]}, 
       CompressedData[compressed] /; True],
    InputForm] <> "\)";

(/; True is the Trott-Strzebonski trick that I learned trying to write this code).

Is there a more strightforward way to get this string?

$\endgroup$

1 Answer 1

4
$\begingroup$

If you look at the internal expression of the cell containing the image, you'll find that it also uses the compressed form. However, the usual trick of Cell@BoxData@ToBoxes... doesn't seem to work here, as that only gives us the RawArray representation. This gives us a hint at a possible way of retrieving the compressed representation without having to build it up ourselves.

In the following implementation, we create a new document with the image, flip the cell to show its expression (as if you had chosen Cell > Show Expression from the menu bar), copy its contents and then discard the notebook.

ClearAll@getCompressedString
getCompressedString[img_] := Module[{nb = CreateDocument[img, Visible -> False], str},
    SelectionMove[nb, Next, Cell];
    FrontEndTokenExecute[nb, "ToggleShowExpression"];
    str = First[FrontEndExecute[FrontEnd`ExportPacket[NotebookSelection[nb], "InputText"]]];
    NotebookClose@nb;
    First@StringCases[str, x : ("GraphicsBox" ~~ __) :> StringDrop[x, -2]]
]

If you now call getCompressedString on your image, you should get the string you want, which you can then pad with "\!\(\*" and "/)" to get back the image.

$\endgroup$
1

Your Answer

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

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