ESP32 fetching an image and displaying to eink display

Hello, I'm trying to download an image with an HTTP request and send the image data to eink display. The eink display I'm using is Waveshare 7.5inch eink display. Each pixel in the display is represented by a single bit (1 for black and 0 for white). The display seems to expect unsigned char array where each element represents 8 pixels. I have been googling online and asking ChatGPT but I have not been able to figure out how to download the data correctly and send to the display. Can someone please help with this?

#include "DEV_Config.h"
#include "EPD.h"
#include "GUI_Paint.h"
#include "imagedata.h"
#include <stdlib.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <SPIFFS.h>

const char* ssid     = "";
const char* password = "";

const char* imageUrl = "https://fastly.picsum.photos/id/538/800/480.jpg?grayscale&hmac=z6A6OaRs-W_K6IOv7ghUPDw70SlLDtjilwctBN4FmqA";

// const int imageWidth = 800;
// const int imageHeight = 480;
// const size_t imageSize = imageWidth * imageHeight * 3; // Assuming RGB format
// unsigned char imageBuffer[imageSize];

void setup()
{
  Serial.begin(115200);

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("WiFi - Connecting......");
  }
  Serial.println("WiFi - Connected");

  if(!SPIFFS.begin()){
    Serial.println("An Error has occurred while mounting SPIFFS");
    return;
  }

  printf("EPD_7IN5_V2_test Demo\r\n");
  DEV_Module_Init();

  printf("e-Paper Init and Clear...\r\n");
  EPD_7IN5_V2_Init();
  EPD_7IN5_V2_Clear();
  DEV_Delay_ms(500);

  UBYTE *BlankImage;
  UWORD Imagesize = ((EPD_7IN5_V2_WIDTH % 8 == 0) ? (EPD_7IN5_V2_WIDTH / 8 ) : (EPD_7IN5_V2_WIDTH / 8 + 1)) * EPD_7IN5_V2_HEIGHT;
  if ((BlankImage = (UBYTE *)malloc(Imagesize)) == NULL) {
    printf("Failed to apply for black memory...\r\n");
    while (1);
  }
  printf("Paint_NewImage\r\n");
  Paint_NewImage(BlankImage, EPD_7IN5_V2_WIDTH, EPD_7IN5_V2_HEIGHT, 0, WHITE);

// #if 1   // show image for array   
//   printf("show image for array\r\n");
//   Paint_SelectImage(BlankImage);
//   Paint_Clear(WHITE);
//   Paint_DrawBitMap(testImage);
//   EPD_7IN5_V2_Display(BlankImage);
//   DEV_Delay_ms(1000);
// #endif

#if 1
  HTTPClient http;
  http.begin(imageUrl);
  int httpCode = http.GET();

  if (httpCode <= 0) {
    Serial.print("Failed to fetch the JPEG image, HTTP code: ");
    Serial.println(httpCode);
    return;
  }

  // Serial.printf(http.header("Content-Type"));
  String length = http.header("Content-Length");
  Serial.printf("length", length);
  WiFiClient* stream = http.getStreamPtr();

  File file = SPIFFS.open("/image.png", FILE_WRITE);
  while (http.connected() && stream->available()) {
    file.write(stream->read());
  }
  size_t fileSize = file.size();
  Serial.printf("file size", fileSize);
  file.read(BlankImage, fileSize);

  file.close();

  Paint_SelectImage(BlankImage);
  Paint_Clear(WHITE);
  Paint_DrawBitMap(BlankImage);
  EPD_7IN5_V2_Display(BlankImage);
  DEV_Delay_ms(1000);

  http.end();
#endif

  printf("Goto Sleep...\r\n");
  EPD_7IN5_V2_Sleep();
  free(BlankImage);
  BlankImage = NULL;
}

void loop()
{
}

It looks like the way the display library works is first you call Paint_SelectImage, then Paint_DrawBitMap, and then EPD_7IN5_V2_Display.

The image at the URL is a grayscale JPEG, not a black-and-white bit-per-pixel image. Properly converting to simple monochrome requires dithering. Some display libraries support JPEGs and other formats, usually with different functions. In that case, you can pass the bytes that comprise the JPEG and not care how it does the conversion (although you are stuck with whatever quality of conversion you get).

If the display driver does not support JPEGs, then you need to convert the image format yourself.

You can try to fill the BlankImage with simple fill patterns to see if applying them has the expected results. Then you know you've got that part working.

Some general notes about that code

  • httpCode is less than zero only for internal HTTPClient errors. Code values in the 400 and 500 range are legitimate HTTP errors that you will want to see, including the response bodies. You want to get HTTP_CODE_OK, which is 200.
  • With Serial.printf("length", length), printf expects a format string as the first argument, and so this will always only print that one word, "length". The variable length is a String, and not a number, so the easiest fix is probably
    Serial.println("length " + length);
  • A .png file is created in SPIFFS, but this is likely not a PNG
  • The file is filled with read and write one byte at a time, which is not efficient
  • You may need to flush the file after writing to update its size
  • fileSize is a size_t, a number, so to print it
    Serial.printf("file size %d\n", fileSize);
  • You need to reposition with file.seek(0) after writing it (and flushing) to read it back out. The file is also open with FILE_WRITE, and I forget if you can read it in that case. Maybe better to close and reopen. Then you don't have to flush and seek.
  • For a file.read, you can't trust that the fileSize is less than or equal to the BlankImage size. If it is bigger, you will write outside the buffer and bad things will happen. At the very least, you need to check.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.