2

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/257104fa1b21d7b483c160ee8f3943bb

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.

Cross posted:

https://stackoverflow.com/questions/34341327/dojo-request-a-png-image-array-buffer-using-nodejs-and-return-the-image-to-the

https://geonet.esri.com/message/575847#575847

  • What do you need the image for? I examined your post and wanted to get a thumbnail of a map service through dojo/request, and then I found I can just use the REST address as image SRC. This might be enough for you as well... or not, and than I can only wish you good luck, and update for showing a good list of ways not leading to the solution, at least directly. – Pavel V. Jan 7 '16 at 14:39
  • @PavelV. Thanks for your reply. The client does not have access to the REST service url, it is behind the proxy. This is due to security on the REST services. I need to look at src code and see how people proxy images from rest endpoints with node. I admit this question needs a rewrite for clarity and I am trying to find the time! Cheers!! – Tom Jan 7 '16 at 16:16
  • I've managed to show a thumbnail of a proxied layer - so if you can find it on the proxy's REST API, it's easy. If something different (map layer containing the raster) is offered, then there might be some other way to workaround it, but I didn't try. Of course, there might be cases when dojo/request is the only option. – Pavel V. Jan 8 '16 at 12:42
  • @PavelV. can you explain what you mean by "proxy's REST API"? My node server is acting as the "proxy" and is requesting from ESRI ArcServer REST API. The request URL that works in a browser does not work when returned through a node route. Can you post some code? Thanks for your help. – Tom Jan 8 '16 at 17:35
  • I mean administering the proxy (not the original server) through the REST API, like myproxy.com/arcgis/rest/services/myservice/mapserver/info/…. In my case, I needed thumbnails only, and they were provided by the proxy. Sorry for false hopes; I don't know how to get real images provided by the REST API. I quickly checked few options I thought might work, but none seems viable. – Pavel V. Jan 12 '16 at 15:00
1

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

encoding: null

as an option on the request.

Answer: https://stackoverflow.com/questions/34341327/dojo-request-a-png-image-array-buffer-using-nodejs-and-return-the-image-to-the/36182182#36182182

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;

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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