pythonexcelimageopenpyxlcell

Delete or update a specific image in Excel using Python


I'm just creating some automation program in Python where the results have to be saved in Excel file. The problem I encountered is to update those results, particularly images. I can't find a way to delete or update the image previously saved in a particular cell.

I know how to delete all the images but that's not what I need; the other images can't be deleted. I need to clear only one particular cell and then paste a different image. example here As a made up example, how can I clear completely cell C6 without touching the other cells; not just clearing the text what I know how to do?


Solution

  • If you want to do this with Python, Openpyxl can be used to read and delete the desired image(s) in the Sheet.
    There are other python modules that would also accomplish this, with Openpyxl it does not require Excel and can run on Windows and Linux.

    The exact implementation may depend on what is used to determine the image is the one to delete. In this example I am using the full cell text, however a partial match to the text or the cell co-ordinate may be sufficient.

    In the example, for the selected sheet we loop through the images to extract the cell co-ordinates for each image. Use the coords to find the cell text and then delete the image and clear the text.

    The code uses your example Sheet as the basis.
    ws._images is a Python List of the images in the Sheet. An image can be then deleted from the list by its index.
    Note the deletion in the code is followed by a 'break' since deleting an image in while looping the image list will affect the order so the example deletes for only one cell and exits. If more than one image is to be found and deleted, creating a list of the cells to delete and running the deletes from that would be better.
    Also note the images list ._images is a protected member.

    Example Code

    import openpyxl
    import string
    
    excelfile = 'imagefile.xlsx'
    wb = openpyxl.load_workbook(excelfile)
    ws = wb['Sheet1']
    
    ### Set the cell to clear image from
    cell_to_delete = 'C9'
    
    ### Check for images in Sheet
    for idx, image in enumerate(ws._images):
        row = image.anchor._from.row + 1
        col = string.ascii_uppercase[image.anchor._from.col]
        cell = ws[f'{col}{row}']
        print(f"Image in cell {cell.coordinate}. Cell text: '{cell.value}'")
        if cell.value.lower() == f"some text in {cell_to_delete}".lower():
    
            ### Delete image from cell
            del ws._images[idx]
    
            ### Clear contents from cell
            cell.value = None
    
            break
    
    wb.save(excelfile)
    

    The code relies on an accurate cell anchor for the image, i.e. if an image top left point is slightly in another cell then that cell will be considered the anchor point. For example with the image in cell C9 in your screenshot. If the image was slightly to the left and encroached on cell 'B9' then that would be the image anchor cell even though the majority of the image sits in cell 'C9'.

    Alternate implementation
    The code below is an alternate implementation. This update allows for multiple deletions;
    Deleting multiple images in the same cell
    Deleting image(s) in more than one cell.
    The list 'cell to delete' is used to determine which cells are to be cleared and all images in that cell will be removed.
    A List is generated with the indexes of the images to be deleted. The image deletion is then performed separately after the list generation.
    The cell contents is cleared as it is added to the image removal List.

    import openpyxl
    import string
    
    
    excelfile = 'imagefile.xlsx'
    wb = openpyxl.load_workbook(excelfile)
    ws = wb['Sheet1']
    
    ### Set the cell to clear image from
    cell_to_delete = ['G6', 'C9']
    
    img_idx_list = []
    ### Check for images in Sheet
    for idx, image in enumerate(ws._images):
        row = image.anchor._from.row + 1
        col = string.ascii_uppercase[image.anchor._from.col]
        cell = ws[f'{col}{row}']
        print(f"Image in cell {cell.coordinate}. Cell text: '{cell.value}'")
    
        ### Check if Image cell is in the 'cell_to_delete' list
        if cell.coordinate in cell_to_delete:
            img_idx_list.append(idx)
            cell.value = None  # Clear cell value if added to list
    
    ### Delete image(s) from cell
    for index in sorted(img_idx_list, reverse=True):  # Loop the List in reverse
        del ws._images[index]
    
    wb.save(excelfile)