0
votes

I am following this guide:

https://cloud.google.com/appengine/docs/python/googlecloudstorageclient/app-engine-cloud-storage-sample

and it only specified how to upload text files, but I want to upload image instead. I got this image data from front end:

const contentType = 'image/png';

const b64toBlob = (b64Data, contentType='', sliceSize=512) => {
  const byteCharacters = atob(b64Data);
  const byteArrays = [];

  for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
    const slice = byteCharacters.slice(offset, offset + sliceSize);

    const byteNumbers = new Array(slice.length);
    for (let i = 0; i < slice.length; i++) {
      byteNumbers[i] = slice.charCodeAt(i);
    }

    const byteArray = new Uint8Array(byteNumbers);
    byteArrays.push(byteArray);
  }

  const blob = new Blob(byteArrays, {type: contentType});
  return blob;
}

image = b64toBlob(image, contentType);

//the above turns base64 into blobs

var data= new FormData();
data.append('image',image );
data.append('pointerlocation',pointerlocation);

 $.ajax({
    url: "/update",
    data: data,
    processData: false,
contentType: false,
    type: "POST",
   success: function(result) {   
    $("#testimg").attr({ "src": `data:image/png;base64,${image}` });

}
});

This is what I got right now in python

image=self.request.get('image')#gets image
pointerlocation=self.request.get('pointerlocation')#just location of where the image is on my website
upload_file(image,pointerlocation)

def upload_file(image,pointerlocation):
    bucket_name = os.environ.get(
            'mosaictest', app_identity.get_default_gcs_bucket_name())
    bucket = '/' + bucket_name
    filename = bucket + '/'+pointerlocation
    write_retry_params = cloudstorage.RetryParams(backoff_factor=1.1)
    with cloudstorage.open(
            filename, 'w', content_type='image/png',
            retry_params=write_retry_params) as cloudstorage_file:
    #pseudocode-----------------------------------
            cloudstorage_file.addfile(image)
            url=get public url of(filename)
    return url
#---------------------------------------------------

I have been stuck on this question for over 2 weeks because google apprently dropped support for python 2.7 and this is the only thing that even came close to working

https://cloud.google.com/storage/docs/reference/libraries

2

2 Answers

1
votes

this is how is how i solved it(literally 3 weeks of painful googling) copy and paste the function below(do not forget the contentype, you can set it to jpeg or whatever. Anyways this function turn base64 data into blob,which i named image blob.

const contentType = 'image/png';
const b64toBlob = (b64Data, contentType='', sliceSize=512) => {
  const byteCharacters = atob(b64Data);
  const byteArrays = [];

  for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
    const slice = byteCharacters.slice(offset, offset + sliceSize);

    const byteNumbers = new Array(slice.length);
    for (let i = 0; i < slice.length; i++) {
      byteNumbers[i] = slice.charCodeAt(i);
    }

    const byteArray = new Uint8Array(byteNumbers);
    byteArrays.push(byteArray);
  }

  const blob = new Blob(byteArrays, {type: contentType});
  return blob;
}

    if(image.substring(0,5)=='data:'){//this if statement determines if the image data is base 64 or not
      image=image.substr(image.indexOf(',') + 1);//strips off the data:/jpeg:base64 thing,so it is pure base64 data
    imageblob = b64toBlob(image, contentType);//converts image to blob
    }
var data= new FormData();//I created a form for the blob
data.append('image',imageblob );//add this blob to the form,you can add more if you want, 

now that the data is in a form, I send it to my backend via AJAX

$.ajax({
    url: "/update",//your handler
    data: data,//<-----this is the form that contains my data
    processData: false,//THESE TWO ARE VERY IMPORTANT!!!!
   contentType: false,//THESE TWO ARE VERY IMPORTANT!!!!
    type: "POST",
   success: function(result) {   
    alert('success!')
}
});

So now the blob is sent, i just get it using this(webbapp2)

class update(webapp2.RequestHandler):
 def post(self):
        image=str(self.request.get('image'))#turns image to string, it just works
        imageurl=upload_file(image,'test') #this second parameter is your file name, remember that two files cannot have the same name or something bad might happen
        self.response.write("success")
#just copy and paste this function. 
import cloudstorage
import os
def upload_file(image,filename):
    bucket_name = os.environ.get(
            'default', app_identity.get_default_gcs_bucket_name())
#i know you can change the bucket, but I have not gotten it to work, so default one it is
    bucket = '/' + bucket_name
    filename = bucket + '/'+filename
    write_retry_params = cloudstorage.RetryParams(backoff_factor=1.1)
    with cloudstorage.open(
            filename, 'w', content_type='image/png',
            retry_params=write_retry_params) as cloudstorage_file:
                cloudstorage_file.write(image)
    return 'https://storage.cloud.google.com{}'.format(filename)

you have to deploy your code in order to test it, to see if the image is in the database, you have to check the cloud storage yourself. just go to gcloud, open the 3 bars on top left corner, scroll down till you get to storage section, and then click on 'storage' in there, click browser and you should see 2 buckets.

You might think that this answer is excessive, but I didn't suffer 3 weeks just so another one can suffer the same fate again.

also if your image doesn't show up, start panicking.

0
votes

You can try uploading the images as blobs instead, as shown in the documentation, the following code will work for you:

def upload_blob(bucket_name, source_file_name, destination_blob_name):
    """Uploads a file to the bucket."""
    storage_client = storage.Client()
    bucket = storage_client.get_bucket(bucket_name)
    blob = bucket.blob(destination_blob_name)

    blob.upload_from_filename(source_file_name)

    print('File {} uploaded to {}.'.format(
        source_file_name,
        destination_blob_name))

You just need to provide the bucket name, the name of the source file and the name of the file that will be written to your bucket.