Search code examples
python-3.xodooopenpyxl

How to store an Image of type PIL.Jpegimageplugin.Jpegimagefile into Odoo


I'm retrieving data from excel and one of the column is bunch of images mostly jpeg, I'm using openpyxl and openpyxl_image_loader to read excel and retrieve data

This is how I'm reading my data

def get_data_from_excel(file):
    data = defaultdict(list)  
    try:  
        wb = openpyxl.load_workbook(filename=BytesIO(base64.b64decode(file)))  
        ws = wb.active  
        image_loader = SheetImageLoader(ws)  
        # first row will be keys in dict  
        keys = [cell.value for cell in ws[1]]  
        i = 0
        for row in ws.iter_rows(min_row=2, max_col=ws.max_column, max_row=ws.max_row):  
            temp = {}  
            for key, cell in zip(keys, row):  
                if key == 'Photo':  
                    try:  
                        image = image_loader.get(cell.coordinate)  
                          
                        temp[key] = base64.b64decode(image.tobytes())
                        continue  
                    except Exception as e:  
                        print(e)  
                        temp[key] = False  
                        break           
                temp[key] = cell.value  
            data[i].append(temp)
            i+=1  
            
      
    except Exception as e:  
        raise ValidationError(_('Please upload a valid Excel file! ', e))  
    finally:  
        return data

trying to set the data into a field after getting the model through id

def set_photo(self, model, photo):  
    try:  
        model.image_1920 = photo   
    except Exception as e:  
        print(f'Error while setting photo for model {model}, error: {e}')

the error I get

This file could not be decoded as an image file. Please try with a different file.

I tried to use Pillow open() function and i get this exception

UnidentifiedImageError('cannot identify image file <_io.BytesIO object at 0x7f3ddcb0b2c0>')

More details about the image attributes

image_details

Using guess_mimetype

print(guess_mimetype(base64.b64decode(image.tobytes())))

OUTPUTs

application/octet-stream

I'd appreciate any help or explanation, thanks in advance


Solution

  • I managed to get it work, I had to change how I'm converting JpegImageFile to base64

    image = image_loader.get(cell.coordinate)
    buffer = BytesIO()
    image.save(buffer, format=image.format)
    image_bytes = buffer.getvalue()
    image_base64 = base64.b64encode(image_bytes)
    

    final code

    def get_data_from_excel(file):
        data = defaultdict(list)  
        try:  
            wb = openpyxl.load_workbook(filename=BytesIO(base64.b64decode(file)))  
            ws = wb.active  
            image_loader = SheetImageLoader(ws)  
            # first row will be keys in dict  
            keys = [cell.value for cell in ws[1]]  
            i = 0
            for row in ws.iter_rows(min_row=2, max_col=ws.max_column, max_row=ws.max_row):  
                temp = {}  
                for key, cell in zip(keys, row):  
                    if key == 'Photo':  
                        try:  
                            image = image_loader.get(cell.coordinate)  
                            buffer = BytesIO()  
                            image.save(buffer, format=image.format)  
                            image_bytes = buffer.getvalue()  
                            image_base64 = base64.b64encode(image_bytes)  
                              
                            temp[key] = image_base64
                            continue  
                        except Exception as e:  
                            print(e)  
                            temp[key] = False  
                            break           
                    temp[key] = cell.value  
                data[i].append(temp)
                i+=1  
                
          
        except Exception as e:  
            raise ValidationError(_('Please upload a valid Excel file! ', e))  
        finally:  
            return data
    

    not sure if this gonna help anyone but I'm leaving my answer here just in case