I've racked my brain (and others) trying to get this to work. I am pulling a photo via MS Graph API - this part works fine. I am able to receive the data (as bytes). However, I can't get the image to convert properly to be attached as a file and posted.
I have read several postings on SO and GH as well as having tried ~10 different npm packages and flavors(btoa, atob, etc...out of desperation), including the JS example from the Graph docs. No solution has worked. The npm packages all produce different outputs from one another and none of them match the output when I take the photo and upload to an online base64 converter. In addition, if I take the online conversion and place the output string directly into the code, it works.
Here is the current iteration of my code. Any help would be appreciated.
var optionsPhoto = {
url: "https://graph.microsoft.com/v1.0/me/photo/$value",
method: "GET",
headers: {
Authorization: "Bearer " + token
}
};
await request(optionsPhoto, function callback(error, response, body) {
if (!error && response.statusCode == 200) {
photoResponse.data = [
{
"@odata.type": "#microsoft.graph.fileAttachment",
contentBytes: body.split(",").toString("base64"),
contentLocation: "https://graph.microsoft.com/v1.0/me/photo/$value",
isinline: true,
Name: "mypic.jpg"
}
];
photoResponse.ContentType = response.headers["content-type"].toString();
photoResponse.Base64string = (
"data:" +
photoResponse.ContentType +
";base64," +
photoResponse.data[0].contentBytes
).toString();
} else {
console.log(error);
}
});
The .sendActivity
command takes the attachment only as seen below:
await dc.context.sendActivity({
attachments: [
{ contentType: photoResponse.ContentType, contentUrl: photoResponse.Base64string }
]
});
When you request the photo's /$value
, the response will simply be the image's raw binary. The request
client however treats the body as a utf8
based string by default.
In order to retrain the raw binary value, you need to explicitly tell request
that you don't want this to happen. This is done by setting encoding: null
. From the documentation:
encoding
- encoding to be used onsetEncoding
of response data. Ifnull
, thebody
is returned as aBuffer
. Anything else (including the default value ofundefined
) will be passed as the encoding parameter totoString()
(meaning this is effectivelyutf8
by default). (Note: if you expect binary data, you should setencoding: null
.)
The code would look something like this:
var optionsPhoto = {
url: "https://graph.microsoft.com/v1.0/me/photo/$value",
encoding: null, // Tells request this is a binary response
method: "GET",
headers: {
Authorization: "Bearer " + token
}
};
await request(optionsPhoto, function callback(error, response, body) {
if (!error && response.statusCode == 200) {
// Grab the content-type header for the data URI
const contentType = response.headers["content-type"];
// Encode the raw body as a base64 string
const base64Body = body.toString("base64");
// Construct a Data URI for the image
const base64DataUri = "data:" + contentType + ";base64," + base64Body;
// Assign your values to the photoResponse object
photoResponse.data = [
{
"@odata.type": "#microsoft.graph.fileAttachment",
contentBytes: base64Body,
contentLocation: optionsPhoto.url,
isinline: true,
Name: "mypic.jpg"
}
];
photoResponse.ContentType = contentType;
photoResponse.Base64string = base64DataUri;
} else {
console.log(error);
}
});