I use a RAW Byte Data Partition in ESP32 Flash to access Pictures very fast. The bytes are aligned from left top corner linewise to bottom right Corner in 3 Bytes RGB Pixeldata.

So we have startaddress from first Picture Byte 0 in Flash with 100x100 Pixel, so we can transfer easy 100x100x3 Bytes after setWindow(x,y,100,100) on SPI to Draw the  image on Screen.

void transparentImage(uint32_t startpic, uint32_t startbackground, int x, int y, int width, int height, uint32_t tcolor) {
  tft.setWindow(x, y, x + width - 1, y + height - 1);

  
  char *buf = (char*)malloc(width * height * bitwidth);
  char *temp = (char*)malloc(width * 3);

  unsigned long offset = 0;
  for (int i = 0; i < height; i++) {
  //cut the Single Picture from Background fit to new Area drawed the Font
  unsigned long offsetbg = startbackground + ((y + i) * tftw * bitwidth ) + (x * bitwidth) ;
   memcpy(buf + (i * width * bitwidth), (uint8_t*)data + offsetbg, (width * bitwidth) );
  }
  for (int i = 0; i < height; i++) {
    offset = startpic + i * width * bitwidth;
    //copy the new Image with Transparent Color Black
    memcpy(temp, (uint8_t*)data + offset, (width * bitwidth) );
    for (int h = 0; h < width * 3; h = h + bitwidth)
    {
      uint32_t bp = temp[ h];
      bp = (bp << 8) | temp[h + 1];
      bp = (bp << 16) | temp[ h + 2];
//Compares cropped Background with new Picture and set Black Pixels to Background Pixel Color
      if (bp >= 0x111111 || y + i > 272) {
        buf[width * i * 3 + h] = temp[h];
        buf[width * i * 3 + h + 1] = temp[h + 1];
        buf[width * i * 3 + h + 2] = temp[h + 2];
      }
    }
  }
//Sebds New created Picture Bytes to Display Area

  vspi->beginTransaction(SPISettings(spiClk, MSBFIRST, SPI_MODE0));
  digitalWrite(vscp_cs, LOW); //pull SS slow to prep other end for transfer
  vspi->writeBytes((uint8_t*)buf, width * height  * bitwidth);
  digitalWrite(vscp_cs, HIGH); //pull ss high to signify end of data transfer
  vspi->endTransaction();
  free(buf);
  free(temp);
}