7
$\begingroup$

Without GenerateHTTPResponse the import works as expected.

ba = ExportByteArray[Plot[x, {x, 0, 1}], "PNG"];
ImportByteArray[ba]

Mathematica graphics

However, when I use GenerateHTTPResponse

hr = GenerateHTTPResponse[ExportByteArray[Plot[x, {x, 0, 1}], "PNG"]];

then none of the following resolve to the image.

ImportByteArray@hr["BodyByteArray"]
ImportByteArray@*ByteArray@hr["BodyBytes"]
ImportByteArray[hr["Body"]]

What am I missing?

Note that this is for a web api and something other than Wolfram Language will be importing the ByteArray from the response. So I need to transport the bytes in the response such that any language can get the bytes and reconstruct the PNG image. I thought as a starting point that WL would be able to consume its own bytes within WL but I am obviously missing something.

$\endgroup$

1 Answer 1

9
$\begingroup$

One needs to be careful and construct the HTTPResponse properly before we ask GenerateHTTPRespone to produce the final thing so that it can be consumed by any HTTP client outside of WL world.

The following explicit MIME specification will solve the above problem.

res = HTTPResponse[
   ExportString[Plot[x, {x, 0, 1}], "PNG"],
   <|"ContentType" -> "image/png"|>
   ];
hr = GenerateHTTPResponse[res];
ImportByteArray@hr["BodyByteArray"]

enter image description here

Also as expected the following two ways will also produce the above image.

ImportString[hr["Body"], "PNG"]
ImportByteArray@ByteArray@hr["BodyBytes"]

Reason

The problem OP faced is just due to mime type getting messed up.

Note how the MIME type gets spoiled when we do:

GenerateHTTPResponse[
  ExportByteArray[Plot[x, {x, 0, 1}], "PNG"]]["ContentType"]

"text/plain;charset=utf-8"

WL will not deduce the correct content type "image/png" from the above code.

However the above behavior is probably natural as a byte array is just a collection of byte and possess no extra metadata about it's content type. Until one supply such metadata to a processor of the given byte array (e.g the process of creating a HTTP response from the given byte array), it is forced to predict the content type before it can process. In our case GenerateHTTPResponse predicts the content type to default "text/plain;charset=utf-8" and things gets messed up.

Using ExportForm

If one wants to skip explicitly forming the HTTPResponse there is a shorter way possible as pointed by @Kuba here. It uses the ExportForm function that can successfully infer the content type and form the HTTP response.

expr = Plot[x, {x, 0, 1}]]
GenerateHTTPResponse @ ExportForm[expr, "PNG"]
$\endgroup$
7
  • $\begingroup$ MIME types. It seems I have some studying ahead of me. Thanks. Will wait a bit to see what else turns up. (+1) $\endgroup$
    – Edmund
    Commented Nov 7, 2019 at 1:12
  • $\begingroup$ Thanks! Slowly MMA is at a stage where we can do some interesting web API stuffs. Glad to help. $\endgroup$ Commented Nov 7, 2019 at 1:17
  • $\begingroup$ @Edmund and PlatoManiac, the fastest way to get things right is GenerateHTTPResponse @ ExportForm[expr, "PNG"], it will set headers correctly. See related: 189803 $\endgroup$
    – Kuba
    Commented Nov 7, 2019 at 6:11
  • $\begingroup$ @Kuba Please add as an answer. ExportForm is a great find. $\endgroup$
    – Edmund
    Commented Nov 7, 2019 at 11:38
  • $\begingroup$ @Edmund I am fine with including it in the existing answer for the sake of clarity. $\endgroup$
    – Kuba
    Commented Nov 7, 2019 at 11:54

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.