Search code examples
pythongoogle-drive-apigoogle-slides-api

Insert image to slides from drive using api in python


I am trying to insert images from google drive into an existing slides presentation but I get the error

Invalid requests[0].createImage: The provided image was not found

I have tried several ways to generate a link that would work (fig_url 2-8). Also, I manually set folder, slides file and image files permissions as "Anyone with this link can view". But still the only link that work is the online one (fig_url1).

Also, if there is a way to do it without running flow (opening the browser) it would be best.

def insert_figure_image_to_slides(user_login_dict, figure_url, page_id):
    presentation_id = user_login_dict["presentation_id"]
    jsonFile = user_login_dict["api_login_json"]
    scope = 'https://www.googleapis.com/auth/presentations'#, 'https://www.googleapis.com/auth/drive.file'
    seed(randint(page_id,101))
    id=randint(1, 100000)
    image_id = "Figure" + str(id)

    try:
        working_folder = os.getcwd()
        os.chdir("..")
        os.chdir(user_login_dict["certificates_folder"])
        credentials = service_account.ServiceAccountCredentials.from_json_keyfile_name(jsonFile, scopes=scope)
        os.chdir(working_folder)

        service = build('slides', 'v1', http=credentials.authorize(httplib2.Http()), cache_discovery=False)
        slides = service.presentations().get(presentationId=presentation_id,
                                         fields='slides').execute().get('slides')
        page_ids = []
        for slide in slides:
            page_ids.append(slide['objectId'])

        emu4M = {
            'magnitude': 4000000,
            'unit': 'EMU'
        }
        requests=[]
        requests.append({
            'createImage': {
                'objectId': image_id,
                'elementProperties': {
                    'pageObjectId': page_ids[page_id]
                },
                'url': figure_url
            }
        })

        body = {
        'requests': requests
    }
        response = service.presentations().batchUpdate(presentationId=presentation_id,
                                                   body=body).execute()
        create_image_response = response.get('replies')[0].get('createImage')

        print('Created image with ID: {0}'.format(
            create_image_response.get('objectId')))

    except:
        os.chdir(working_folder)
        print("Image insertion into presentation failed")


def export_figures_to_drive(user_login_dict, figure_name, figure_no):
    drive_folder_id = user_login_dict["drive_folder_id"]
    file_name = figure_name + ".png"
    scopes = (
        'https://www.googleapis.com/auth/drive',
        'https://www.googleapis.com/auth/presentations',
    )


    os.chdir("Output_files")
    output_dir = os.getcwd()
    os.chdir("..")

    try:
        working_folder = os.getcwd()
        os.chdir("..")
        os.chdir(user_login_dict["certificates_folder"])
        g_login = GoogleAuth(user_login_dict["drive_login_yaml"])
        g_login.LocalWebserverAuth()

        store = Storage(user_login_dict["drive_login_json"])
        flow = client.flow_from_clientsecrets(user_login_dict["drive_login_json"], scopes)

        os.chdir(working_folder)
        drive = GoogleDrive(g_login)
        file_list = drive.ListFile({'q': "'root' in parents and trashed=false"}).GetList()
        for file in file_list:
            if file['title'] == user_login_dict["result_file_name"]:
                folder_id = file.get('id')

        file_list = drive.ListFile({'q': "'%s' in parents and trashed=false" % folder_id}).GetList()
        for file1 in file_list:
            if file1['title'] == file_name:
                file1.Delete()

        os.chdir(output_dir)
        file_on_drive = drive.CreateFile({'parents': [{'id': drive_folder_id}]})
        file_on_drive.SetContentFile(file_name)
        file_on_drive.Upload()
        os.chdir(working_folder)
        print('Graph Export to drive complete - %s' % (file_name))
        metadata = file_on_drive.attr["metadata"]
        fig_url4 = metadata["alternateLink"]
        fig_url5 = metadata['selfLink']
        fig_url6 = metadata['webContentLink']
        fig_url7 = metadata['downloadUrl']
    except:
        os.chdir(working_folder)
        print("Error uploading file to drive")

    creds = tools.run_flow(flow, store) #opens browser identificaiton page
    HTTP = creds.authorize(httplib2.Http())
    DRIVE = discovery.build('drive', 'v3', http=HTTP)
    rsp = DRIVE.files().list(q="name='%s'" % file_name).execute().get('files')[0]

    fig_url1 = 'https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png'
    fig_url2 = "https://drive.google.com/uc?export=download&id=" + rsp["id"]
    fig_url3 = '%s&access_token=%s' % (DRIVE.files().get_media(fileId=rsp['id']).uri, creds.access_token)
    fig_url8="https://drive.google.com/file/d/1AmCmoc8Xrv706yJeWCmCuQw0HQkkYHpQ/view?usp=sharing"

    insert_figure_image_to_slides(user_login_dict=user_login_dict, figure_url=fig_url1, page_id=figure_no)

Solution

  • There are two things you need to do

    1. The documentation specifies that the image must be set as publicly accessible (you did this already)
    2. In addition, the link to the image that needs to be specified as the url is the webContentLink (file_on_drive.get('webContentLink'))

    The combination of both should enable you to insert the image into slides.