Uploading images to Webflow Assets via API-Images are corrupted

Hi there,

We are utilizing the new Assets API to transfer images to Webflow Assets. Unfortunately, a significant portion of these images become corrupted. To address this issue, we experimented with cropping each image by one pixel and recalculating its hash value. However, this approach has not consistently resolved the problem.
unnamed
Below is an outline of our current process:

  1. generate a hash value for the image.

  2. Create Asset Metadata using the hash value.

  3. Generate an uploadUrl and uploadDetails.

  4. Upload the file to Amazon S3 using the provided uploadUrl and uploadDetails.

We are using JavaScript (See script below).
Example of a hosted image which is corrupted: https://uploads-ssl.webflow.com/65c4be4f1d5115237e04bb89/663279995e33fd0ac56dcf5e_1000_F_389364320_rI3KdOKNf0PqAlPDWrhAfUFfi3lk6Rvn.jpg
The original Picture:

We would appreciate any recommendations on how to refine this process to ensure that all images are correctly uploaded to Webflow Assets without corruption.

We do know the API documentation and follow instructions provided.

Thanks for your support!

The code:

//Creating hash value

async function convertUrlToBlob(url) {
    try {
      const response = await fetch(url);
      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }
      const originalBlob = await response.blob();
      const originalHash = await calculateHash(originalBlob);
      console.log('Original Blob:', originalBlob);
      console.log('Original Hash:', originalHash);

      const croppedBlob = await cropBlob(originalBlob);
      const croppedHash = await calculateHash(croppedBlob);
      console.log('Cropped Blob:', croppedBlob);
      console.log('Cropped Hash:', croppedHash);

      return originalBlob; //the images are mostly corrupted even with croppedBlob
    } catch (error) {
      console.error('Error in fetching and converting to blob:', error);
    }
  }
 
  async function cropBlob(blob) {
    return new Promise((resolve, reject) => {
      const img = new Image();
      img.onload = async () => {
        const canvas = document.createElement('canvas');
        canvas.width = img.width-1; // Cropping 1 pixel
        canvas.height = img.height-1; // Cropping 1 pixel
        const ctx = canvas.getContext('2d');
        ctx.drawImage(img, 0, 0, canvas.width, canvas.height, 0, 0, canvas.width, canvas.height);
        canvas.toBlob(async function(croppedBlob) {
          resolve(croppedBlob);
        });
      };
      img.onerror = reject;
      img.src = URL.createObjectURL(blob);
    });
  }

  async function calculateHash(blob) {
    return new Promise((resolve, reject) => {
      const reader1 = new FileReader();
      reader1.onloadend = function() {
        const arrayBuffer1 = reader1.result;
        const spark1 = new SparkMD5.ArrayBuffer();
        spark1.append(arrayBuffer1);
        const hash1 = spark1.end();
        resolve(hash1);
      };
      reader1.onerror = reject;
      reader1.readAsArrayBuffer(blob);
    });
  }



async function getFileAndHash() {
  const fileInput = "imageurl.jpg";
var segments = "";
 var fileNameValue="";
 var fileData;
var spark;
var fileHashValue="";

  if (!fileInput) {
    console.error('File input not found');
    return;
  } else{
segments = fileInput.split('/');
fileNameValue = segments[segments.length - 1];

}
  const blob = await convertUrlToBlob(fileInput);
  if (!blob) {
    console.error('Failed to convert URL to Blob');
    return;
  }
else{
console.log(blob);
}


  const reader = new FileReader();
  reader.onload = async function(e) {
    fileData = e.target.result;
    spark = new SparkMD5.ArrayBuffer();
    spark.append(fileData);
    fileHashValue = spark.end();
console.log("sending this hash "+ fileHashValue);

bubble_fn_hashIt({output1: fileNameValue, output2: fileHashValue, output3:fileInput})
   
};


  reader.readAsArrayBuffer(blob);


}

getFileAndHash();




//sending asset to webflow (Uploading it to amazon s3)


const {uploadDetails}= "uploadDetails";

const form=new FormData();
const uploadUrl= "uploadUrl";
var fileBlob;


axios({
    url: 'imageUrl.jpg',
    method: 'GET',
    responseType: 'blob', // This ensures response data is returned as a Blob
})
.then(response => {
    fileBlob = response.data;
    console.log('File Blob:', fileBlob);
Object.entries(uploadDetails).forEach(([field, value]) => {
      if (value === null) {
       
        return;
      }
      form.append(field, value);
 console.log("field and value"+field+" "+value);
    });    

form.append('file', fileBlob, "filename");

axios.post(uploadUrl, form, {
  headers: {
'Content-Type': 'multipart/form-data',
   
     
  }
})
.then(response => {
  console.log('Upload successful:', response);
})
.catch(error => {
  console.error('Upload error:', error);
});

  console.log("upload details"+uploadDetails);
console.log("uploadUrl"+uploadUrl);
console.log([...form.entries()]);
})

Hi @Giorgi_Nar - sorry you’re running up against this, and thanks for your detailed repro w/ code here!

We’ll take a look and update with findings next chance we get

1 Like