request a png image using NodeJS and dojo/request from an ArcGIS Server REST feed, and return the image to the client

8908
4
Jump to solution
12-17-2015 10:12 AM
TomGiles2
New Contributor II

I am attempting to request a png image using NodeJS and dojo/request from an ArcGIS Server REST feed, and return the image to the client.

I need nodeJS to add a token to the request as a query parameter as my services are secured and I want to control their security through node and not on the resource server (ArcGIS Server 10.3). Without nodeJS in the picture, the png loads in the browser. This is an (open) example of a call returning a png image, using their standard REST feed:

https://sampleserver6.arcgisonline.com/arcgis/rest/services/911CallsHotspot/MapServer/1/images/25710...

I am using dojo/request to access this resource. It seems the png image is coming back to node fine, however when I res.send() back to the client, I get a 'not an image' in Fiddler. I can see the PNG header, and the IHDR and IEND in the hexview, however it is apparent that the encoding (? or other) is not the same as when the resource is returned directly from the ArcServer. When the png is received on the client returned from node, the content-length is a little less than when the same png comes directly from the ArcServer. (Node is attempting, by its default, to use Transfer-Encoding: Chunked. I set content-length to the length of the response, so it sends at one time, which I believe is the behaviour the client is expecting.)

ESRI (ArcGIS Server) have a new sample stub out which does exactly what I want to do, however they are using esri/request (built on dojo/request) client side, and leverage Blob library to create the correct response for the client.

https://developers.arcgis.com/javascript/jssamples/data_requestArrayBuffer.html

We can see they use handleAs: "arrayBuffer", which I have tried on dojo/request and it seems to make no difference to the content of the returned png. When they receive the response, they make a new Blob and then read it as data URL with FileReader (which I have a node side implementation of) and directly use that result as the png.

I have tried ad-nausuem to replicate this, but it seems that node does not have a reliable Blob library (I have tried "Blob" with no luck) and I read that in node you are supposed to use Buffers instead. No matter what I pass to fileReader, I get the error "Cannot read as File" (I have tried all fileReader methods). The fileReader library: https://www.npmjs.com/package/filereader

ESRI code:

esriRequest(url, {handleAs: "arrayBuffer"}).then(function(response) { reader.readAsDataURL(new Blob([response], { type: "image/png" })); //reader.result is png ready to use client side });

My attempts:

//tried handleAs: "arrayBuffer"

//tried npm Blob library

request(url, {handleAs: "arrayBuffer"}).then(function(response) { var reader = new FileReader(); reader.addEventListener("loadend", function() { res.setHeader('Content-Type', 'image/png'); res.setHeader('Content-Length', reader.result.length); res.send(reader.result); }); reader.readAsDataURL(new Blob([response], { type: "image/png" })); });

I am using node package filereader and Blob, with no luck creating a blob to pass to fileReader. If nodeJS uses Buffers instead of Blob, given that the content returned by the service appears to be an ArrayBuffer png, how do I pass that back to the client, through node?

I have also attempted to use ArrayBuffer to Buffer methods (through Uint8Array) however once I have the png in buffer form I can never read it.

In short, I just want to proxy the png from its source to the client, adding a token query parameter.

Comments welcome to improve the question.

originally posted here:

http://stackoverflow.com/questions/34341327/dojo-request-a-png-image-array-buffer-using-nodejs-and-r...

0 Kudos
1 Solution

Accepted Solutions
TomGiles2
New Contributor II

Answered by Dietah on stackoverflow: To get the image in base64 I needed to include

encoding: null 

as an option on the request.

Answer: http://stackoverflow.com/questions/34341327/dojo-request-a-png-image-array-buffer-using-nodejs-and-r...

I was looking to do a similar action but didn't found any answer. After some trial and error I seem to have figured it out.

In your request options add the option encoding: null, this will get the image in a base64 format from the original source.

request({ url: yoururl, method: 'GET', encoding: null }, function (error, response, body) { if (!error && response.statusCode === 200) { res.send(response.statusCode, body); } else { res.send(response.statusCode, body.toString('utf8')); } }); 

Then in my client I did a GET on my own url which gives you the base64 string. For your image on the client you can set the source to data:image/PNG;base64,{result}

var result = getBase64FromMyUrl(); var src = 'data:image/PNG;base64,' + result;

View solution in original post

4 Replies
TomGiles2
New Contributor II

the fact that there is no word wrap applied to my copy+paste leaves me shaking my head.

0 Kudos
TimothyHales
Esri Notable Contributor

The reason there was no word wrap was because the text you pasted was part of a table, so you brought over the table container as well. I have removed the table and the text wraps a little better now.

TomGiles2
New Contributor II

Thanks, I didn't catch that. I must have copied a table tag from stackoverflow somehow while c+p.

Cheers

0 Kudos
TomGiles2
New Contributor II

Answered by Dietah on stackoverflow: To get the image in base64 I needed to include

encoding: null 

as an option on the request.

Answer: http://stackoverflow.com/questions/34341327/dojo-request-a-png-image-array-buffer-using-nodejs-and-r...

I was looking to do a similar action but didn't found any answer. After some trial and error I seem to have figured it out.

In your request options add the option encoding: null, this will get the image in a base64 format from the original source.

request({ url: yoururl, method: 'GET', encoding: null }, function (error, response, body) { if (!error && response.statusCode === 200) { res.send(response.statusCode, body); } else { res.send(response.statusCode, body.toString('utf8')); } }); 

Then in my client I did a GET on my own url which gives you the base64 string. For your image on the client you can set the source to data:image/PNG;base64,{result}

var result = getBase64FromMyUrl(); var src = 'data:image/PNG;base64,' + result;