Bodmer / JPEGDecoder

A JPEG decoder library
Other
220 stars 64 forks source link

Canvas to JPEG, then file upload to ESP32 SPIFFS fails to decode, Picojpeg error 19 #62

Closed frankcohen closed 3 years ago

frankcohen commented 3 years ago

Picojpeg is great. I found it embeded in Bodmer's JPEGDecoder https://github.com/Bodmer/JPEGDecoder/blob/master/src/picojpeg.h and used to display images on a 135x240 pixel OLED display.

I created a 10x10 pixel JPEG encoded image from a Javascript context using this code:

var mywide = video.videoWidth;
mywide = mywide / 6;
canvas.width = 135;
canvas.height = 240;

var image = canvas.getContext('2d').drawImage(video,0,0,10,10,0,0,10,10);
var base64png = canvas.toDataURL("image/jpeg", 1.0);
var dataURL = base64png.replace(/\s/g, '+').replace(/^data:image\/jpeg;base64,/, '');
var nobase = window.atob(dataURL);

var oAjaxReq = new XMLHttpRequest();
oAjaxReq.submittedData = nobase;

oAjaxReq.onreadystatechange = function() {
   console.log("Uploading image");
   console.log(oAjaxReq.responseText);
}

oAjaxReq.onload = function (oEvent)
{
   console.log("Uploaded");
}

oAjaxReq.open("post", "upload", true);

var bound = Date.now().toString(16);
var sBoundary = "----WebKitFormBoundary" + bound;

oAjaxReq.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + sBoundary );

var mydata = "--" + sBoundary + "\r\n";

mydata += "Content-Disposition: form-data; name=\"name\"; filename=\"" + "slice1.jpg" + "\"\r\n";
mydata += "Content-Type: image/png";
mydata += "\r\n";
mydata += "\r\n";

mydata += nobase;

mydata += "\r\n";

mydata += "--" + sBoundary + "--";
mydata += "\r\n";

oAjaxReq.send( mydata );

I am using FHessel's HTTPS Server on ESP32 to receive the form post from a Chrome browser.

https://github.com/fhessel/esp32_https_server

Here is my form post handler code for the server side:

void handle_upload(HTTPRequest * req, HTTPResponse * res)
{ 
  Serial.println("Handle_upload");

  HTTPBodyParser *parser;
  parser = new HTTPMultipartBodyParser(req);
  bool didwrite = false;

  Serial.println( "Handle_upload 2" );

  while(parser->nextField()) {

    Serial.println( "Handle_upload 3" );
    std::string name = parser->getFieldName();
    std::string filename = parser->getFieldFilename();
    std::string mimeType = parser->getFieldMimeType();
    Serial.printf("handleFormUpload: field name='%s', filename='%s', mimetype='%s'\n", name.c_str(), filename.c_str(), mimeType.c_str() );

    if ( ! (filename.rfind("/", 0) == 0) )
    {
      filename = "/" + filename;
    }

    Serial.print("handle_upload Name: "); 
    Serial.println(filename.c_str()  );

    fsUploadFile = LITTLEFS.open( filename.c_str(), "w");            // Open the file for writing in SPIFFS (create if it doesn't exist)

    size_t fileLength = 0;
    didwrite = true;

    while (!parser->endOfField()) {
      byte buf[512];
      size_t readLength = parser->read(buf, 512);
      fsUploadFile.write(buf, readLength);
      fileLength += readLength;
    }

    fsUploadFile.close();
    res->printf("<p>Saved %d bytes to %s</p>", (int)fileLength, filename.c_str() );
  }

  if (!didwrite) {
    res->println("<p>Did not write any file contents</p>");
  }

  delete parser;
  if(didwrite) 
   {                                    // If the file was successfully created
     res->setHeader("Location", "/success");
     res->setStatusCode(303);
   }
   else 
   {
     res->setStatusCode(500);
     res->setStatusText("Upload failed");
   }
 }

The upload works, stores the file in the ESP32 SPIFFS file system (using LittleFS) and here are the file contents (printed out as ASCII character and Hex value):

 =A, ⸮=C3, ⸮=BF, ⸮=C3, ⸮=84, =0, )=29, =10, =1, =0, =1, =3, =2, =5, =1,  =9, =0, =0, =0, =0, =0, =0, =0, =0, =0, =1, =2, =3, =5, =4, =11, =6, =7, =12, =13, 1=31, ⸮=C2, ⸮=81, =14, !=21, "=22, #=23, 2=32, Q=51, ⸮=C2, ⸮=85, ⸮=C3, ⸮=81, ⸮=C3, ⸮=94, ⸮=C3, ⸮=BF, ⸮=C3, ⸮=84, =0, =19, =1, =1, =0, =3, =1, =1, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =3, =5, =7, =4, =6, ⸮=C3, ⸮=BF, ⸮=C3, ⸮=84, =0, -=2D, =11, =1, =0, =1, =3, =2, =3, =3, 
 =D, =0, =0, =0, =0, =0, =0, =0, =0, =0, =1, =2, =3, =11, =4, =12, =5, =15, !=21, 1=31, ⸮=C2, ⸮=A3, ⸮=C3, ⸮=93, =14, "=22, #=23, A=41, Q=51, S=53, T=54, a=61, s=73, ⸮=C2, ⸮=A1, ⸮=C2, ⸮=B1, ⸮=C2, ⸮=B3, ⸮=C3, ⸮=B0, ⸮=C3, ⸮=BF, ⸮=C3, ⸮=9A, =0, =C, =3, =1, =0, =2, =11, =3, =11, =0, ?=3F, =0, ⸮=C3, ⸮=A3, z=7A, ⸮=C3, ⸮=8D, ⸮=C3, ⸮=89, ⸮=C2, ⸮=99, ⸮=C2, ⸮=99, ⸮=C2, ⸮=8F, 4=34, ⸮=C3, ⸮=87, ⸮=C2, ⸮=BA, ⸮=C2, ⸮=A9, ⸮=C3, ⸮=9B, i=69, ⸮=C2, ⸮=9F, ⸮=C3, ⸮=97, ⸮=C3, ⸮=9B, =7F, =1B, ⸮=C3, ⸮=8B, >=3E, ⸮=C2, ⸮=89, ⸮=C3, ⸮=8E, q=71, 3=33, ⸮=C3, ⸮=AC, ⸮=C3, ⸮=8F, ⸮=C3, ⸮=A7, ⸮=C3, ⸮=BB, ⸮=C3, ⸮=97, ⸮=C3, ⸮=B3, k=6B, 
 =D, [=5B, ⸮=C3, ⸮=A6, ]=5D, u=75, \=5C, ⸮=C3, ⸮=A3, l=6C, ⸮=C3, ⸮=95, U=55, }=7D, S=53, =18, ⸮=C3, ⸮=8D, ⸮=C3, ⸮=BD, 1=31, =1A, =8, ⸮=C2, ⸮=89, ⸮=C3, ⸮=B5, ⸮=C2, ⸮=88, ⸮=C2, ⸮=87, ⸮=C2, ⸮=B0, ⸮=C3, ⸮=A1, Y=59, ⸮=C3, ⸮=B2, 
 =D, >=3E, {=7B, }=7D, /=2F, ⸮=C3, ⸮=AE, ⸮=C2, ⸮=B8, ⸮=C3, ⸮=8F, ⸮=C2, ⸮=B8, ⸮=C3, ⸮=AC, ⸮=C3, ⸮=A7, ⸮=C2, ⸮=8A, ⸮=C3, ⸮=AA, ⸮=C2, ⸮=A7, ⸮=C3, ⸮=A8, }=7D, ⸮=C2, ⸮=B4, ⸮=C3, ⸮=96, P=50, ⸮=C2, ⸮=8B, =15, @=40, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, -=2D, ⸮=C3, ⸮=A3, ⸮=C2, ⸮=98, ⸮=C3, ⸮=BC, g=67, =1E, 3=33, ;=3B, ~=7E, ;=3B, =15, ⸮=C3, ⸮=BC, *=2A, ⸮=C3, ⸮=BE, U=55, ⸮=C2, ⸮=A0, ⸮=C3, ⸮=B7, =1D, ⸮=C3, ⸮=AD, ⸮=C3, ⸮=AF, =11, m=6D, ⸮=C3, ⸮=8F, 8=38, ⸮=C2, ⸮=A7, ⸮=C3, ⸮=85, w=77, =1A, =7F, =5, -=2D, ⸮=C2, ⸮=92, ⸮=C3, ⸮=89, k=6B, r=72, ⸮=C3, ⸮=BA, ⸮=C3, ⸮=9B, ⸮=C3, ⸮=99, =1C, ⸮=C2, ⸮=8D, ⸮=C3, ⸮=BF, =0, h=68, ⸮=C3, ⸮=96, j=6A, ;=3B, }=7D, ⸮=C3, ⸮=AB, ⸮=C3, ⸮=9D, ⸮=C2, ⸮=BB, V=56, ⸮=C2, ⸮=BA, ⸮=C3, ⸮=BB, 6=36, m=6D, ⸮=C3, ⸮=98, ⸮=C2, ⸮=B7, ⸮=C3, ⸮=B2, ⸮=C3, ⸮=AC, [=5B, ⸮=C2, ⸮=B5, j=6A, ⸮=C2, ⸮=9E, ⸮=C2, ⸮=9B, V=56, ⸮=C2, ⸮=A8, ⸮=C2, ⸮=A3, ⸮=C3, ⸮=A1, ⸮=C2, ⸮=A2, ⸮=C2, ⸮=9D, ⸮=C3, ⸮=BA, z=7A, ⸮=C2, ⸮=AA, ⸮=C3, ⸮=9E, ⸮=C2, ⸮=A9, ⸮=C2, ⸮=99, ⸮=C2, ⸮=9E, ⸮=C3, ⸮=8B, V=56, ⸮=C2, ⸮=AD, ⸮=C3, ⸮=98, ⸮=C2, ⸮=B7, M=4D, ⸮=C2, ⸮=AB, T=54, ⸮=C3, ⸮=AD, ⸮=C2, ⸮=A2, ⸮=C2, ⸮=9C, ⸮=C3, ⸮=AD, ⸮=C2, ⸮=A7, 5=35, U=55, ⸮=C2, ⸮=8D, ⸮=C3, ⸮=95, M=4D, S=53, ⸮=C3, ⸮=96, ⸮=C2, ⸮=A9, ⸮=C2, ⸮=99, ⸮=C2, ⸮=9C, ⸮=C3, ⸮=8C, ⸮=C3, ⸮=8C, ⸮=C3, ⸮=B5, ⸮=C2, ⸮=99, ⸮=C3, ⸮=AD, ⸮=C3, ⸮=84, t=74, W=57, ⸮=C3, ⸮=9F, ⸮=C2, ⸮=BF, w=77, S=53, v=76, ⸮=C2, ⸮=BB, ⸮=C3, ⸮=B7, ⸮=C3, ⸮=AB, ⸮=C3, ⸮=9F, v=76, ⸮=C2, ⸮=BD, ⸮=C2, ⸮=BB, ⸮=C2, ⸮=AA, ⸮=C3, ⸮=9B, M=4D, 9=39, ⸮=C3, ⸮=9B, L=4C, Q=51, O=4F, ⸮=C2, ⸮=9B, D=44, S=53, L=4C, b=62, ⸮=C2, ⸮=9A, b=62, :=3A, D=44, g=67, =19, ⸮=C2, ⸮=9E, ⸮=C2, ⸮=B9, ⸮=C2, ⸮=96, 
 =A, D=44,  =20, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, =0, ⸮=C3, ⸮=BF, ⸮=C3, ⸮=99, [HTTPS:I] Request: GET /favicon.ico (FID=62)

Picojpeg rejects the file and throws error 19.

I tested Picojpeg using a jpeg file I created in Pixelmator for Mac and Picojpeg works fine. I use the same HTTPS Server code to upload the file contents. I use this HTML:

<form action=upload method=post enctype=multipart/form-data>
<input type=file name=name>
<input class=button type=submit value=Upload>
</form>

This uploads the Jpeg file correctly. And Picojpeg decodes the jpeg image correctly and with no error.

I'm not sure where to go next? Any help would be appreciated.

-Frank

Bodmer commented 3 years ago

Unfortunately I am unable to debug this for you. It appears the the data is not a valid JPEG file. The file should start with FF D8, hence the data is not being recognised as a valid JPEG file.

frankcohen commented 3 years ago

Thank you Bodmer, that helps in itself. I don't know anything about JPEG file formats. I'm going to focus on getting the canvas to give a valid jpeg image. -Frank