javascriptc#asp.netfabricbmp

Incorrect format problem when converting a BMP image file from Base-64 to binary


I am trying to convert the Base-64 data contained in the "data" returned by toDataURL of a fabric.Canvas into a file with its corresponding extension (BMP). The result is a "The file is not in the correct format" error.

The steps I follow are the following.

  1. I get the dataURL variable from the fabric.Canvas with the toDataURL method.

    dataURL = canvas.toDataURL({ format: 'bmp', quality: 1.0 });

  2. I extract only the string that contains the "data".

    dataURLto64 = dataURL.substr(dataURL.lastIndexOf(',') + 1, dataURL.length - dataURL.lastIndexOf(',') - 1);

  3. The above is done on the client. On the server I needed to save the string in segments in a TXT text file. I have verified that the final content of the text file is identical to the original dataURLto64 (in Base-64).

  4. I extract the content of the text file.

    string strtextfile64 = File.ReadAllText([path]);
    
  5. I convert that string into a byte array with the method Convert.FromBase64String

byte[] fileBinary = null;

fileBinary = Convert.FromBase64String(strtextfile64);
        
File.WriteAllBytes([path], fileBinary);

I have verified that both, dataURLto64 and strtextfile64 have the same characters and the same number. To verify that the Base-64 string is correct, I have included the following verification on the server.

 int mod4 = strtextfile64.Length % 4;   

 if (mod4 > 0) {
    strtextfile64 += new string('=', 4 - mod4);
 }

It was not necessary to modify strtextfile64 because mod4 = 0.

I am attaching two text files in which the initial (client) and final (server) Base-64 strings are contained.

Inicial cliente Final servidor

Could someone tell me the reason why that Base-64 data converted to binary data does not comply with the original BMP format from the original BMP file created from the fabric.Canvas?

Edit to add the client code that I am using to transfer the image file to the server.

CLIENT

I make a send with Ajax that when it receives the response from the server with the file name data and the last position of the character sent, the sending is repeated as long as the last position does not exceed the length of the string.

async function exportarCanvasF1(nombrearchivo, start_) {       

let start = Number(start_);
        var chunkSize = 90000; // size of each chunk
        let start_limite = (start == 0 ? Number(start_) : 

Number(start_)) + chunkSize;      

 if (start_limite > dataURL.length) {
     start_limite = (start_limite - (start_limite -  dataURL.length - 1));
  }
 if (Number(start) + chunkSize > dataURL.length) {
    chunkSize = chunkSize - ((Number(start) + chunkSize) - dataURL.length) + 1;           }
            
  let dataURL_;
    
   if (Number(start) < dataURL.length) {           

   dataURL_ = dataURL.substr(start, chunkSize);
   dataURL_ = encodeURI(encodeURI(dataURL_));
               
   $.ajax({
                

   type: "POST",
   url: "Respuestaajax.aspx/Respuestaaj",
   contentType: "application/json; charset=utf-8",
   data: 

'{"parametro":"funcion","valor":"TroceadoFileBase64","tabla":"' + dataURL_ + '","campo":"' + nombrearchivo + '","criterio":"' + start_limite + '","v1":""}',
   dataType: "json",
   success: function (devolucion) {
     if (devolucion.d) {
       var d = JSON.parse(devolucion.d);
       exportarCanvasF1(d[0][1], d[1][1]);
           }
    },
     error: function (req, status, error) {
                    }
                });
     }
  else if (!Number(start) < dataURL.length) {
      dataURL_ = dataURL.substr(start, chunkSize);
      console.log("Length chunk: " + dataURL_.length);
      dataURL_ = encodeURI(encodeURI(dataURL_));
                
       $.ajax({
         type: "POST",
         url: "Respuestaajax.aspx/Respuestaaj",
         contentType: "application/json; charset=utf-8",
         data: '{"parametro":"funcion","valor":"TroceadoFileBase64","tabla":"' + dataURL_ + '","campo":"' + nombrearchivo + '","criterio":"' + start_limite + '","v1":""}',
         dataType: "json",
         success: function (devolucion) {
         if (devolucion.d) {
            var d = JSON.parse(devolucion.d);
                 $.ajax({
                  type: "POST",
                  url: "Respuestaajax.aspx/Respuestaaj",
                  contentType: "application/json; charset=utf-8",
                 data: '{"parametro":"funcion","valor":"TroceadoFileBase64_fin","tabla":"' + nombrearchivo + '","campo":"","criterio":"","v1":""}',
                 dataType: "json",
                 success: function (devolucion) {
                     if (devolucion.d) {
                                    }
                     },
                      error: function (req, status, error) {                                    
                                }
                            });
                        }
                    },
                    error: function (req, status, error) {
                     alert("No hubo respuesta desde el servidor. Prueba otra vez.");
                    }
                });
    
            }
        }

SERVER

The parameters "parameter", "value", "table", "field", "criterion" are used in a routine to supply a method on the server. The method performs the following.

 public string TroceadoFileBase64(string base64file, string nombrefile, string start)
        {
    string jsonDevolucion = "";
           
   string base64filedec = HttpUtility.UrlDecode(base64file);  
   string base64filedec1 = HttpUtility.UrlDecode(base64file);  
                                                                               
    byte[] b = null;
    System.Text.ASCIIEncoding codificador = new 
    System.Text.ASCIIEncoding();
    b = codificador.GetBytes(base64filedec1);

    CrearfiledesdeArray(b, nombrefile);

     string[,] devolucion = new string[2, 2]; // 2 bloques de 2 datos                
                devolucion[0,0] = "nombrefile";
                devolucion[0,1] = nombrefile;
                devolucion[1,0] = "start";
                devolucion[1,1] = start;
                
     jsonDevolucion = JsonConvert.SerializeObject(devolucion);

     return jsonDevolucion;
}
               
public string TroceadoFileBase64_fin(string nombrefile)
        {
               
                string strtextfile = File.ReadAllText((string)HttpContext.Current.Server.MapPath("~") + "google/archivoseditados/" + Left(nombrefile, nombrefile.Length - 4) + ".txt");

                int mod4 = strtextfile.Length % 4;
                if (mod4 > 0)
                {
                    strtextfile += new string('=', 4 - mod4);
                }

                byte[] b = null;

                b = Convert.FromBase64String(strtextfile);

                File.WriteAllBytes((string)HttpContext.Current.Server.MapPath("~") + "google/archivoseditados/" + nombrefile, b);

                return "Finalizado";
        }

public void CrearfiledesdeArray(Byte[] array, string nombrefile)
        {
                FileStream fs = new FileStream((string)HttpContext.Current.Server.MapPath("~") + "google/archivoseditados/" + Left(nombrefile, nombrefile.Length - 4) + ".txt", FileMode.Append);
                fs.Seek(0, SeekOrigin.End);
                fs.Write(array, 0, array.Length);
                fs.Flush();
                fs.Dispose();
          
        }
       

TroceadoFileBase64 method writes each chunk to the text file; the TroceadoFileBase64_fin method is called only at the end and extracts the text and converts it to binary.


Solution

  • The client code that has finally worked with the help of the colleagues who have responded is the following

    I get the dataURL variable from the fabric.Canvas with the toDataURL method. Now is with JPG file.

    dataURL = canvas.toDataURL({ format: 'jpg', quality: 1.0 });
    

    I extract only the string that contains the "data".

    dataURL = dataURL.split(',')[1];
    

    Function in the client.

    async function exportarCanvasF1(nombrearchivo, start_) {       
            
            let start = Number(start_);
                    var chunkSize = 30000; // size of each chunk
                    let start_limite = (start == 0 ? Number(start_) : 
            
            Number(start_)) + chunkSize;      
            
             if (start_limite > dataURL.length) {
                 start_limite = (start_limite - (start_limite -  dataURL.length - 1));
              }
             if (Number(start) + chunkSize > dataURL.length) {
                chunkSize = chunkSize - ((Number(start) + chunkSize) - dataURL.length) + 1;           }
                        
              let dataURL_;
                
               if (Number(start) < dataURL.length) {           
            
               dataURL_ = dataURL.substr(start, chunkSize);
               **dataURL_ = encodeURIComponent(dataURL_);**
                           
               $.ajax({               
            
               type: "POST",
               url: "Respuestaajax.aspx/Respuestaaj",
               contentType: "application/json; charset=utf-8",
               data: 
            
            '{"parametro":"funcion","valor":"TroceadoFileBase64","tabla":"' + dataURL_ + '","campo":"' + nombrearchivo + '","criterio":"' + start_limite + '","v1":""}',
               dataType: "json",
               success: function (devolucion) {
                 if (devolucion.d) {
                   var d = JSON.parse(devolucion.d);
                   exportarCanvasF1(d[0][1], d[1][1]);
                       }
                },
                 error: function (req, status, error) {
                                }
                            });
                 }
              else if (!Number(start) < dataURL.length) {
                  dataURL_ = dataURL.substr(start, chunkSize);
                  console.log("Length chunk: " + dataURL_.length);
                  dataURL_ = encodeURIComponent(dataURL_);
                            
                   $.ajax({
                     type: "POST",
                     url: "Respuestaajax.aspx/Respuestaaj",
                     contentType: "application/json; charset=utf-8",
                     data: 
                    '{"parametro":"funcion","valor":"TroceadoFileBase64","tabla":"' + 
                    dataURL_ + '","campo":"' + nombrearchivo + '","criterio":"' + 
                    start_limite + '","v1":""}',
                     dataType: "json",
                     success: function (devolucion) {
                     if (devolucion.d) {
                        var d = JSON.parse(devolucion.d);
                             $.ajax({
                              type: "POST",
                              url: "Respuestaajax.aspx/Respuestaaj",
                              contentType: "application/json; charset=utf-8",
                             data: '{"parametro":"funcion","valor":"TroceadoFileBase64_fin","tabla":"' + nombrearchivo + '","campo":"","criterio":"","v1":""}',
                             dataType: "json",
                             success: function (devolucion) {
                                 if (devolucion.d) {
                                                }
                                 },
                                  error: function (req, status, error) {                                    
                                            }
                                        });
                                    }
                                },
                                error: function (req, status, error) {
                                 alert("No hubo respuesta desde el servidor. Prueba otra vez.");
                                }
                            });
                
                        }
                    }
    

    And the server:

    public string TroceadoFileBase64(string base64file, string nombrefile, string start)
            {
        string jsonDevolucion = "";
               
      
       *tring base64filedec1 = HttpUtility.UrlDecode(base64file);  
                                                                                   
        byte[] b = null;
        System.Text.ASCIIEncoding codificador = new 
        System.Text.ASCIIEncoding();
        b = codificador.GetBytes(base64filedec1);
    
        CrearfiledesdeArray(b, nombrefile);
    
         string[,] devolucion = new string[2, 2]; // 2 bloques de 2 datos                
                    devolucion[0,0] = "nombrefile";
                    devolucion[0,1] = nombrefile;
                    devolucion[1,0] = "start";
                    devolucion[1,1] = start;
                    
         jsonDevolucion = JsonConvert.SerializeObject(devolucion);
    
         return jsonDevolucion;
    }
                   
    public string TroceadoFileBase64_fin(string nombrefile)
            {
                   
                    string strtextfile = File.ReadAllText((string)HttpContext.Current.Server.MapPath("~") + "google/archivoseditados/" + Left(nombrefile, nombrefile.Length - 4) + ".txt");
    
                    int mod4 = strtextfile.Length % 4;
                    if (mod4 > 0)
                    {
                        strtextfile += new string('=', 4 - mod4);
                    }
    
                    byte[] b = null;
    
                    b = Convert.FromBase64String(strtextfile);
    
                    File.WriteAllBytes((string)HttpContext.Current.Server.MapPath("~") + "google/archivoseditados/" + nombrefile, b);
    
                    return "Finalizado";
            }
    
    public void CrearfiledesdeArray(Byte[] array, string nombrefile)
            {
                    FileStream fs = new FileStream((string)HttpContext.Current.Server.MapPath("~") + "google/archivoseditados/" + Left(nombrefile, nombrefile.Length - 4) + ".txt", FileMode.Append);
                    fs.Seek(0, SeekOrigin.End);
                    fs.Write(array, 0, array.Length);
                    fs.Flush();
                    fs.Dispose();
              
            }
    

    Here you finally see the JPG image opened with the Paint program.

    Imagen JPG con ediciones realizadas previamente con fabric.Canvas

    I clarify that there are variables in the methods provided that belong to complementary routines in my project and that I have not exposed them so as not to extend the thread. They correspond to both the client and the server.