title: How to convert jpeg byte stream into jpeg image and display on 1.8 inch TFT display
body: <p>i have esp32 having cam  and it is transmitting compressed jpeg stream.</p>
  
  <p>Device Name - TTGO T-Journal ESP32 Camera Development Board OV2640 SMA WiFi 3dbi Antenna 0.91 OLED Camera Board</p>
  
  <p>I have esp32 having  1.8inch tft screen and a SD card slot which act as receiver .</p>
  
  <p>Device name - ESP32 TS V1.2 MPU9250 1.8 Inch TFT Bluetooth Wifi MicroSD Card Slot Speakers Module</p>
  
  <p>On Chrome browser i get display of the jpeg images as a continuous image after image  ( video ).</p>
  
  <p>i can see the incoming compressed jpeg stream and i print it on serial monitor .
  But i need to decode/ decompress the jpeg stream at receiving end and paint pixel of TFT screen .</p>
  
  <p>Which steps i am missing ? Can anybody suggest code of jpeg image rendering on TFT screen ?</p>
  
  <p><a href="https://i.stack.imgur.com/QZAuF.png" rel="nofollow noreferrer">image1</a></p>
  
  <p><a href="https://i.stack.imgur.com/7rTHV.png" rel="nofollow noreferrer">image2</a></p>
  
  <p>sketch of transmitter -</p>
  
  <pre><code>#include "OV2640.h"
  #include &lt;WiFi.h&gt;
  #include &lt;WebServer.h&gt;
  #include &lt;WiFiClient.h&gt;
  
  #define ENABLE_OLED //if want use oled ,turn on thi macro
  
  #ifdef ENABLE_OLED
  #include "SSD1306.h"
  #define OLED_ADDRESS 0x3c
  #define I2C_SDA 14
  #define I2C_SCL 13
  SSD1306Wire display(OLED_ADDRESS, I2C_SDA, I2C_SCL, GEOMETRY_128_32);
  #endif
  
  OV2640 cam;
  WebServer server(80);
  
  IPAddress apIP = IPAddress(192, 168, 1, 1);
  
  void handle_jpg_stream(void)
  {
      WiFiClient client = server.client();
      String response = "HTTP/1.1 200 OK\r\n";
  response += "Content-Type: multipart/x-mixed-replace; boundary=frame\r\n\r\n";
  server.sendContent(response);
  
  while (1)
  {
      cam.run();
      if (!client.connected())
          break;
      response = "--frame\r\n";
      response += "Content-Type: image/jpeg\r\n\r\n";
      server.sendContent(response);
  
      client.write((char *)cam.getfb(), cam.getSize());
      server.sendContent("\r\n");
      if (!client.connected())
          break;
      }
  }
  
  void handle_jpg(void)
  {
      WiFiClient client = server.client();
  
      cam.run();
      if (!client.connected())
      {
          return;
      }
       String response = "HTTP/1.1 200 OK\r\n";
       response += "Content-disposition: inline; filename=capture.jpg\r\n";
      response += "Content-type: image/jpeg\r\n\r\n";
      server.sendContent(response);
      client.write((char *)cam.getfb(), cam.getSize());
  }
  
  void handleNotFound()
  {
      String message = "Server is running!\n\n";
      message += "URI: ";
      message += server.uri();
      message += "\nMethod: ";
      message += (server.method() == HTTP_GET) ? "GET" : "POST";
     message += "\nArguments: ";
     message += server.args();
     message += "\n";
     server.send(200, "text/plain", message);
  }
  
  void setup()
  {
      Serial.begin(115200);
      while (!Serial)
      {
          ;
       }
  camera_config_t camera_config;
  camera_config.ledc_channel = LEDC_CHANNEL_0;
  camera_config.ledc_timer = LEDC_TIMER_0;
  camera_config.pin_d0 = 17;
  camera_config.pin_d1 = 35;
  camera_config.pin_d2 = 34;
  camera_config.pin_d3 = 5;
  camera_config.pin_d4 = 39;
  camera_config.pin_d5 = 18;
  camera_config.pin_d6 = 36;
  camera_config.pin_d7 = 19;
  camera_config.pin_xclk = 27;
  camera_config.pin_pclk = 21;
  camera_config.pin_vsync = 22;
  camera_config.pin_href = 26;
  camera_config.pin_sscb_sda = 25;
  camera_config.pin_sscb_scl = 23;
  camera_config.pin_reset = 15;
  camera_config.xclk_freq_hz = 20000000;
  camera_config.pixel_format = CAMERA_PF_JPEG;
  camera_config.frame_size = CAMERA_FS_SVGA;
  
  cam.init(camera_config);
  
  WiFi.mode(WIFI_AP);
  WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
  bool result = WiFi.softAP("TTGO-CAMERA", "12345678", 1, 0);
  if (!result)
  {
      Serial.println("AP Config failed.");
      return;
  }
  else
  {
      Serial.println("AP Config Success.");
      Serial.print("AP MAC: ");
      Serial.println(WiFi.softAPmacAddress());
  }
  
  #ifdef ENABLE_OLED
  display.init();
  display.flipScreenVertically();
  display.setFont(ArialMT_Plain_16);
  display.setTextAlignment(TEXT_ALIGN_CENTER);
  display.drawString(128 / 2, 32 / 2, WiFi.softAPIP().toString());
  display.display();
  #endif
  
  server.on("/", HTTP_GET, handle_jpg_stream);
  server.on("/jpg", HTTP_GET, handle_jpg);
  server.onNotFound(handleNotFound);
  server.begin();
  }
  
  void loop()
  {
      server.handleClient();
  }
  </code></pre>
  
  <p>sketch of receiver -</p>
  
  <pre><code>#include &lt;WiFi.h&gt;
  #include "FS.h"
  #include "SD.h"
  #include "SPI.h"
  #include &lt;Adafruit_GFX.h&gt;    // Core graphics library
  #include &lt;Adafruit_ST7735.h&gt; // Hardware-specific library
  #include &lt;Adafruit_ImageReader.h&gt; // Image-reading functions
  //#include &lt;Adafruit_TFTLCD.h&gt; // Hardware-specific library
  #include &lt;SPI.h&gt;
  #include "WiFi.h"
  #include &lt;JPEGDecoder.h&gt;
  //#include &lt;FileIO.h&gt;
  
  
  
  
  // For the breakout, you can use any 2 or 3 pins
  // These pins will also work for the 1.8" TFT shield
  #define TFT_CS 16
  #define TFT_RST 9  // you can also connect this to the Arduino reset
                    // in which case, set this #define pin to -1!
  #define TFT_DC 17
  
  // Option 2: use any pins but a little slower!
  #define TFT_SCLK 5   // set these to be whatever pins you like!
  #define TFT_MOSI 23   // set these to be whatever pins you like!
  #define PIN_NUM_MISO 2
  #define PIN_NUM_MOSI 15
  #define PIN_NUM_CLK  14
  #define PIN_NUM_CS   13
  
  
  
  Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK,     TFT_RST);
  
  String text="";
  
  
  const char* ssid     = "TTGO-CAMERA";
  const char* password = "12345678";
  const char* host     = "192.168.1.1";
  const char* url      = "/";
  
  IPAddress local_IP(192, 168, 1, 3);
  IPAddress gateway(192, 168, 1, 1);
  IPAddress subnet(255, 255, 255, 0);
  IPAddress primaryDNS(8, 8, 8, 8); //optional
  IPAddress secondaryDNS(8, 8, 4, 4); //optional
  
  //PImage logo;
  
  
  #define BUFFPIXEL 20
    int      bmpWidth, bmpHeight;   // W+H in pixels
    uint8_t  bmpDepth;              // Bit depth (currently must be 24)
    uint32_t bmpImageoffset;        // Start of image data in file
    uint32_t rowSize;               // Not always = bmpWidth; may have     padding
    uint8_t  sdbuffer[3*BUFFPIXEL]; // pixel buffer (R+G+B per pixel)
    uint8_t  buffidx = sizeof(sdbuffer); // Current position in sdbuffer
    boolean  goodBmp = false;       // Set to true on valid header parse
    boolean  flip    = true;        // BMP is stored bottom-to-top
    int      w, h, row, col;
    uint8_t  r, g, b;               // pixel color for tft
    File     bmpFile; File     bmpFile1;
    uint32_t pos = 0, startTime ;
    uint8_t xx=0; uint16_t yy=0; int ww=0; int hh=0;
    int bmpfilepos;
  
  //How to use -
  //tft.fillScreen(ST7735_BLACK);
  //testdrawtext(2,3,ST7735_GREEN,text);
  
  
  
  void testdrawtext( int leftoffset , int topoffset , uint16_t color ,  String text ) {
    tft.setCursor(leftoffset, topoffset);  // (offset from left margin , offset from top margin. )
    tft.setTextColor(color);
    tft.setTextWrap(true);
    tft.setTextSize(1);
    tft.print(text  ); 
      }
  
  
  
  
  void jpegbytesdisplay()
  {
   // Create a buffer for the packet
      char dataBuff[240];
  
      delay(5000);
  
    Serial.print("connecting to ");
    Serial.println(host);
  
    // Use WiFiClient class to create TCP connections
    WiFiClient client;
    const int httpPort = 80;
    int cnt=0;
  
    if (!client.connect(host, httpPort)) {
      Serial.println("connection failed");
      return;
    }
  
    Serial.print("Requesting URL: ");
    Serial.println(url);
  
    // This will send the request to the cam server
    client.print(String("GET ") + url + " HTTP/1.1\r\n" +
             "Host: " + host + "\r\n" +
             "Connection: close\r\n\r\n");
    unsigned long timeout = millis();
  
  
  
    while (client.available() == 0) 
    {
      if (millis() - timeout &gt; 5000) 
      {
        Serial.println("&gt;&gt;&gt; Client Timeout !");
        client.stop();
        return;
      }
    }
  
  
     int max_y=200;
     int ypos =200;
     int max_x=0 ;
     int xpos =0;
  
    // Read all the lines of the reply from server and print them to Serial
  
    ImageReturnCode stat;
    while (client.available()) 
    {
      //================================
     // String line = client.readStringUntil('\r');
     // Serial.print(line);
  
  
      //================================
      //bytes put into char[len] databuffer.
      size_t len=client.available();
      unsigned char buf[len];
      client.readBytes(buf, len);
  
      Serial.println("------------------------");
      Serial.println(len);
      //Serial.write(buf);
  
       //================================
       // bufffer to tft screen pixel rendering
  
        int col=0;     
    int buffidx =0;
    cnt++;
  
      tft.fillScreen(ST7735_BLACK);
      tft.startWrite();
      tft.setAddrWindow(0, 0, 500, 500);
  
  
  String fname="/image2" + String(cnt) + ".jpg";
  File myFile = SD.open(fname, FILE_WRITE);
  myFile.write(buf,len);
  myFile.close();  
  
       for (col=0; col&lt;len; col++) 
         { 
            Serial.print(buf[col]);
         }
      Serial.println();
      Serial.println("------------------------");
  
  
        // For each pixel...
       for (col=0; col&lt;len; col++) 
       { 
           if (buffidx &gt;= sizeof(buf)) 
                {  
            buffidx = 0; // Set index to beginning
                  break;
          }
  
  
          b = buf[buffidx++]; //          [B]
          g = buf[buffidx++]; //     [G]
          r = buf[buffidx++]; //   [R]
  
  
  
          tft.pushColor(tft.color565(r,g,b));   
                               // Display pixel on tft screen one after another.
  
  
  
     } // end pixel loop.
  
      //================================
  
     delay(1000);
      tft.endWrite();    
    }
  
      }
  
  
  
  
  
  
  
   void setupNormal()
  {
  
  
     Serial.begin(115200);
  
  
     // Use this initializer if you're using a 1.8" TFT
    tft.initR(INITR_BLACKTAB);   // initialize a ST7735S chip, black tab
  
    Serial.println("Initialized");
  
  
    if (!WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS)) {
      Serial.println("STA Failed to configure");
    }
  
    Serial.print("Connecting to ");
    Serial.println(ssid);
  
    WiFi.begin(ssid, password);
  
    while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
    }
  
  
    tft.fillScreen(ST7735_BLACK);
  
  }
  
  
  void setup()
  {
  
      setupNormal();
      jpegbytesdisplay();
  
  
        }
  
  
  
  void loop()
  {
  
  
  
    }
  </code></pre>