makeImageRequest from stream

I can download PNG using makeImageRequest("https://serverl/png.png"...) but I'd like to not save any file on server.

I can generate PNG in server's memory, but how to return it? I've tried many things but always got 404.

  • There are 2 things:

    1. returning own error to ciq - it's impossible, always 404

    forums.garmin.com/.../makeimagerequest-ignores-error-returning-from-server

    2. returning image - it depends on your server/software

    - you can generate image file on server return redirect to this image (e.g. in header using location: image_url)

    - image as stream - you have to return CLEAR image, it can't be any additional byte, no header, nothing more than bytes from image

  • redirect to this image (e.g. in header using location: image_url)

    GOT it . 302 Redirect

    you have to return CLEAR image, it can't be any additional byte, no header, nothing more than bytes from image

    I used to successfully receive an image with makeImageRequest util I made a change to my api. Will try to find the modification culprit. THX

  • 1. returning own error to ciq - it's impossible, always 404

    I am using a cdn I don't know what is the error. https://img.niulasong.com/qr-image.png

    This image can be opened in a browser but always 404 with makeImageRequest 

    function downloadQR() as Void {
    // var qrToken = Application.Properties.getValue("CODE");
    // if (qrToken.equals("")) {
    // return;
    // }
    System.println("downloadQR");
    var ecLevel = "L";
    switch (Application.Properties.getValue("EC")) {
    case 0:
    ecLevel = "L";
    break;
    case 1:
    ecLevel = "M";
    break;
    case 2:
    ecLevel = "Q";
    break;
    case 3:
    ecLevel = "H";
    break;
    }
    var screenWidth = System.getDeviceSettings().screenWidth;

    System.println("strUrl:" + strUrl);

    var maxWidth =
    screenWidth * (System.getDeviceSettings().screenShape == 1 ? 0.707 : 1);
    Communications.makeImageRequest(
    strUrl,
    null,
    {
    :palette => [Graphics.COLOR_BLACK, Graphics.COLOR_WHITE],
    :maxWidth => maxWidth,
    :maxHeight => maxWidth,
    :dithering => Communications.IMAGE_DITHERING_NONE,
    :packingFormat => Communications.PACKING_FORMAT_PNG,
    },
    new Lang.Method(self, :onReceiveImage)
    );
    }

    function saveStorage(key, value as Object) {
    try {
    Application.Storage.setValue(key, value);
    } catch (e) {
    if (e instanceof Lang.StorageFullException) {
    storageFull = true;
    } else {
    throw e;
    }
    }
    }
    function onReceiveImage(code as Number, data as Object) as Void {
    System.println("data:" + data);
    System.println("code:" + code);

    if (code == 200) {
    System.println("data:" + data);
    if (data instanceof String && "N".equals(data)) {
    saveStorage("INVALID_TOKEN", true);
    WatchUi.requestUpdate();
    }
    //Remember to keep this order
    //Cuz if we invert them, some devices with ciq3.x have no BitmapReference
    //has operator is heavy!
    if (
    data instanceof Toybox.WatchUi.BitmapResource ||
    (Toybox.Graphics has :BitmapReference &&
    data instanceof Toybox.Graphics.BitmapReference)
    ) {
    saveStorage("CODE", data);
    Application.Storage.deleteValue("INVALID_TOKEN");
    WatchUi.requestUpdate();
    }
    } else {
    }
    }
    }
    Sorry for the terrible code display.
  • var strUrl = "https://img.niulasong.com/qr-image.png";
    ...
    
    Communications.makeImageRequest(
    strUrl,
    null,
    {
    :palette => [Graphics.COLOR_BLACK, Graphics.COLOR_WHITE],
    //:maxWidth => maxWidth, //with this system resize picture even it is smaller than max sizie
    //:maxHeight => maxWidth,//with this system resize picture even it is smaller than max sizie
    :dithering => Communications.IMAGE_DITHERING_FLOYD_STEINBERG, //IMAGE_DITHERING_NONE,
    //:packingFormat => Communications.PACKING_FORMAT_PNG,
    },
    new Lang.Method(self, :onReceiveImage)
    );

    but url is static so if 2 users will make req in the same time can be problem...

  • NO problem. It is merely a demo. I always get 404. I don't know why

  • The problem is that your server doesn't return png as stream (and ciq in case of any error returns always 404 when makeImageRequest is called - https://forums.garmin.com/developer/connect-iq/i/bug-reports/makeimagerequest-ignores-error-returning-from-server).

    call makeWebRequest with 

    and look into http traffic, there is html page, png is in body and should be stream

  • I have a similar issue. I am serving a png image dynamically generated in memory through https, and it looks like garmin's image server cannot access my server. I've installed apache http server and use a static png file to test. The API always returns 404 but my other device can access the URL perfectly. 

    I then moved my service to google cloud. Funny thing is with google's app engine URL, the makeImageRequest() still returns 404 but with google's cloud run URL, makeImageRequest() always succeeds. Same code, just 3 different URL hosted in different places:

    - my own server using dynamic DNS (duckdns.org) --> 404

    - google cloud: App Engine --> 404

    - google cloud: Cloud Run --> 200, always successful.

    This is really annoying because the URL is perfectly fine in a browser. 

  • Well I tried to create a new project in google cloud, and select us-central as the region. Now makeImageRequest() returns successfully every time. Guess there must be something wrong in garmin's backend service related to DNS so they cannot reach my original region (australia east). Something must be off in their server so some domains are not reachable.

  • Very strange. If there's a way then I would try to compare both the requests garmin makes and the responses those requests get. Compare the ones that fail with those that are successful. Maybe there's some difference you can see in the request/response headers...

  • Yeah at first I thought the same. I compared all the request/headers between working and non-working URL in the browser (they all work in the browser), and found that they are identical. Also by hosting in the google cloud I can see where the requests are coming from. There is no request at all in the 404 case. This implies garmin's service didn't even make the https request successfully.

    By switching to a different region (from australia to the US), the same piece of code works. I just re-deployed to a different serverless region. I can't think of any possible reason apart from the theory that they simply cannot resolve some of the domain names?

    Garmin also return 404 when using my own server running on an OrangePi at my home (in Australia), using duckdns.org service. Really weird.