11

I want to upload an image on Google Cloud Storage from a python script. This is my code:

from oauth2client.service_account import ServiceAccountCredentials
from googleapiclient import discovery

scopes = ['https://www.googleapis.com/auth/devstorage.full_control']
credentials = ServiceAccountCredentials.from_json_keyfile_name('serviceAccount.json', scop
es)
service = discovery.build('storage','v1',credentials = credentials)

body = {'name':'my_image.jpg'}

req = service.objects().insert(
   bucket='my_bucket', body=body,
   media_body=googleapiclient.http.MediaIoBaseUpload(
      gcs_image, 'application/octet-stream'))

resp = req.execute()

if gcs_image = open('img.jpg', 'r') the code works and correctly save my image on Cloud Storage. How can I directly upload a bytes image? (for example from an OpenCV/Numpy array: gcs_image = cv2.imread('img.jpg'))

Davide Biraghi
  • 626
  • 1
  • 7
  • 17
  • Is your issue on the python upload side or on the server side? – jtlz2 Apr 04 '18 at 09:58
  • I know this is javascript, but: https://github.com/GoogleCloudPlatform/google-cloud-node/issues/2334 – jtlz2 Apr 04 '18 at 10:02
  • Also https://stackoverflow.com/a/37102815/1021819 – jtlz2 Apr 04 '18 at 10:05
  • https://www.quora.com/How-do-I-upload-a-file-to-Google-Cloud-Storage-using-Python; https://cloud.google.com/storage/docs/boto-plugin#setup-python; https://cloud.google.com/python/getting-started/using-cloud-storage#uploading_to_cloud_storage – jtlz2 Apr 04 '18 at 10:08

4 Answers4

17

In my case, I wanted to upload a PDF document to Cloud Storage from bytes.

When I tried the below, it created a text file with my byte string in it.

blob.upload_from_string(bytedata)

In order to create an actual PDF file using the byte string I had to do:

blob.upload_from_string(bytedata, content_type='application/pdf')

My byte data was b64encoded, so I also had b64decode it first.

Melissa Guo
  • 948
  • 9
  • 32
9

If you want to upload your image from file.

import os
from google.cloud import storage

def upload_file_to_gcs(bucket_name, local_path, local_file_name, target_key):
    try:
        client = storage.Client()
        bucket = client.bucket(bucket_name)
        full_file_path = os.path.join(local_path, local_file_name)
        bucket.blob(target_key).upload_from_filename(full_file_path)
        return bucket.blob(target_key).public_url

    except Exception as e:
        print(e)

    return None

but if you want to upload bytes directly:

import os
from google.cloud import storage

def upload_data_to_gcs(bucket_name, data, target_key):
    try:
        client = storage.Client()
        bucket = client.bucket(bucket_name)
        bucket.blob(target_key).upload_from_string(data)
        return bucket.blob(target_key).public_url

    except Exception as e:
        print(e)

    return None

note that target_key is prefix and the name of the uploaded file.

Ramtin M. Seraj
  • 686
  • 7
  • 17
1

MediaIoBaseUpload expects an io.Base-like object and raises following error:

  'numpy.ndarray' object has no attribute 'seek'

upon receiving a ndarray object. To solve it I am using TemporaryFile and numpy.ndarray().tofile()

from oauth2client.service_account import ServiceAccountCredentials
from googleapiclient import discovery
import googleapiclient
import numpy as np
import cv2
from tempfile import TemporaryFile


scopes = ['https://www.googleapis.com/auth/devstorage.full_control']
credentials = ServiceAccountCredentials.from_json_keyfile_name('serviceAccount.json', scopes)
service = discovery.build('storage','v1',credentials = credentials)

body = {'name':'my_image.jpg'}
with TemporaryFile() as gcs_image:
    cv2.imread('img.jpg').tofile(gcs_image)
    req = service.objects().insert(
       bucket='my_bucket’, body=body,
       media_body=googleapiclient.http.MediaIoBaseUpload(
          gcs_image, 'application/octet-stream'))

    resp = req.execute()

Be aware that googleapiclient is non-idiomatic and maintenance only(it’s not developed anymore). I would recommend using idiomatic one.

A.Queue
  • 1,549
  • 6
  • 21
  • I have a similar situation. I am using `OpenCV` processing image which is in `ndarray`. I want to now store this processed image on cloud as an image `.jpg` file. Can you give any suggestions? To solve this Please – Santhosh Apr 03 '18 at 14:07
  • Can you help me? @A.Queue – Santhosh Apr 04 '18 at 09:35
  • Sorry for not answering. Could you create a new question to follow SO rules? Feel free to mention me there in the comments. – A.Queue Apr 04 '18 at 10:29
  • 1
    I have asked so many question that SO has asked me only to answer. I can't ask anymore questions until I get more reputation – Santhosh Apr 04 '18 at 10:45
  • Can you guide me to a location online where I can find a solution for this at least? @A.Queue – Santhosh Apr 04 '18 at 11:30
  • https://stackoverflow.com/questions/49651351/upload-ndarrayimage-in-opencv-on-to-google-cloud-storage-as-a-jpg-or-png @A.Queue Posted question from a friends account – Santhosh Apr 04 '18 at 12:44
  • [link](https://stackoverflow.com/questions/49671827/upload-an-image-from-cloud-function-python-to-google-cloud-storage) @A.Queue – Santhosh Apr 05 '18 at 11:59
1

Here is how to directly upload a PIL Image from memory:

from google.cloud import storage
import io
from PIL import Image

# Define variables
bucket_name = XXXXX
destination_blob_filename = XXXXX

# Configure bucket and blob
client = storage.Client()
bucket = client.bucket(bucket_name)

im = Image.open("test.jpg")
bs = io.BytesIO()
im.save(bs, "jpeg")
blob.upload_from_string(bs.getvalue(), content_type="image/jpeg")

In addition to that, here is how to download blobfiles directly to memory as PIL Images:

blob = bucket.blob(destination_blob_filename)
downloaded_im_data = blob.download_as_bytes()
downloaded_im = Image.open(io.BytesIO(downloaded_im_data))
tnwei
  • 860
  • 7
  • 15