Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request: Get image from stream object (e.g. iostream, socket, HTTPClient, Serial, etc.) #191

Open
knyipab opened this issue Jan 24, 2020 · 1 comment

Comments

@knyipab
Copy link

knyipab commented Jan 24, 2020

Feature Request or Enhancement

Apart from the current supproted ways of getting image (gslc_GetImageFromFile, gslc_GetImageFromProg, gslc_GetImageFromRam and gslc_GetImageFromSD), it would be good to support getting image from stream object.

Additional context

The main motivation is that one of my projects needs to load image dynamically from my server over HTTPS. From the API currently supported, I could think of two way, either to load it into SD/disk or into PROGMEN/RAM. While I'm using ESP32/Arduino, SPIFFS has limited write life cycle (probably few tens of thousands times) and PROGMEN resources is very limited (a raw 320 * 240 image alreay take 300 KB). Storing all images beforehand is not a possible option due to the feature of the project.

I believe that loading image from stream class is an ultimate solution and also fit into different application scenarios: fetching image from server database over HTTP, transmitting image over serial ports or SPI (e.g. a CCTV project with GUI needed).

Implementation

function instead of stream object

Okay, passing a stream object is obviously not sufficient because guislice may need to re-render part or whole screen later but guislice can't reset the stream object. So instead of passing a stream object, I suggest passing a function that return a "renewed" stream pointer. The specification would be something like this (for linux, it could be iostream* instead of Stream*) :

typedef Stream* (*gslc_teImgRefResetStreamFunc)();
gslc_tsImgRef gslc_GetImageFromStream(gslc_teImgRefResetStreamFunc pImgStreamFunc, gslc_teImgRefFlags eFmt);

When guislice need to load render the image, it would expect pImgStreamFunc to return the "renewed" a stream object that is ready for read. An example of ImgStreamFunc over HTTP implementation on ESP32/Arduino would be the following (for linux, it could be socket instead of HTTPClient):

WiFiClientSecure* client;
HTTPClient https;

Stream* ImgResetStreamFunc() {
  https.end();
  https.begin(*client, "https://example.com/image.bmp");
  return https.GET() == HTTP_CODE_OK ? https.getStreamPtr() : NULL;
}

void begin() {
  /* ...... maybe some codes to init WiFi & set CA cert for WiFiClientSecure here ...... */
  gslc_tsImgRef m_Img = gslc_GetImageFromStream(ImgResetStreamFunc, GSLC_IMGREF_FMT_BMP24);
}

asynchronicity and other features

The idea is the possibility to support both (pseudo)asynchronous reseting the stream object and (pseudo)asynchronous loading of image. The reason is simple. Some stream objects may take time to be ready and some image may be large to load. Also, sometimes the function may failed to reset, e. . when https.GET() not equals to HTTP_CODE_OK. An additional parameter for option struct may be required:

struct gslc_teImgRefStreamOption {
  bool skipWhenNULL; 
    // skipWhenNULL=true:  gslc_Update() will skip this element and render next if the func returns NULL pointer and retry next time
    // skipWhenNULL=false: gslc_Update() will return immediately and won't render any following element until the func returns non-NULL
  unsigned long retryTimeout; // how long gslc_Update() retry calling the func until give up
  unsgiend long numLinesLoadEachTime; // number of lines of pixels to load into screen each time gslc_Update() called
}

skipWhenNULL == true && retryTimeout will effectively block the rendering of other element for retryTimeout milliseconds. In case the image is oversized or the stream is slow, numLinesLoadEachTime could prevent gslc_Update() from blocking the runtime for too long. This is useful for some project when multitasking is important. I know these feature would complicate guislice even more, but they could be really useful in production environment.

@ImpulseAdventure
Copy link
Owner

Hi @knyipab -- thank you very much for the detailed and thoroughly-considered feature request!

Supporting a stream-based image source does look useful for certain niche applications. However, I am anticipating that I wouldn't have as much opportunity to develop the feature as I would like at this time. If you are interested in developing the idea further and submitting a pull request, it may be something that we could pull into GUIslice if it looks like the implementation is relatively localized and doesn't impact compatibility (assuming a stream feature config flag was not enabled). Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants