openpyxl 以绝对位置形式插入图片(实现在区域居中)

openpyxl 以绝对位置形式插入图片(实现在区域居中)

  • 1、为什么要使用绝对位置插入图片

1、为什么要使用绝对位置插入图片

我们在使用openpyxl的插入图片使用add_image方法,图片是左上角对齐,并不能居中居中。
import openpyxl

wb = openpyxl.Workbook()
ws = wb.active
ws.add_image('图片路径')

openpyxl 以绝对位置形式插入图片(实现在区域居中)_第1张图片

from openpyxl.drawing.image import Image
from openpyxl.drawing.xdr import XDRPoint2D, XDRPositiveSize2D
from openpyxl.drawing.spreadsheet_drawing import AbsoluteAnchor
from openpyxl.utils.units import pixels_to_EMU
from openpyxl.cell.cell import get_column_letter

class AddImage():

   def __init__(self):
        self.workbook = openpyxl.Workbook()
        self.worksheet = self.workbook.active
        
   def get_absolute(self, row, col):
        """
        获取单元格的右下方绝对位置(单位:像素),及单元格的宽高
        """
        x = 0
        y = 0
        # get_column_letter(int)把整数转换为Excel中的列索引
        col_letter = get_column_letter(col)
        # 获取每列的列宽
        width = self.worksheet.column_dimensions[col_letter].width
        # 计算第一列到目标列的总宽
        for i in range(col):
            col_letter = get_column_letter(i + 1)
            fcw = self.worksheet.column_dimensions[col_letter].width
            x += fcw
		# 如果Excel中高为默认值时,openpyxl却没有值为NoneValue,这一点我很奇怪。
        if not self.worksheet.row_dimensions[col].height:
            self.worksheet.row_dimensions[col].height = 13.5
            height = 13.5  # Excel默认列宽为13.5
        else:
            height = self.worksheet.row_dimensions[col].height
        # 计算第一行到目标行的总高
        for j in range(row):
            if not self.worksheet.row_dimensions[j + 1].height:
                self.worksheet.row_dimensions[j + 1].height = 13.5
                fch = 13.5
            else:
                fch = self.worksheet.row_dimensions[j + 1].height
            y += fch 
        # 把高单位转换为像素
        height = (height * 18) // 13.5  # 一个单元格高为13.5,像素为18
        # 把宽单位转换为像素
        width = (width * 72) // 9  # 一个单元格为宽为9,像素为72
        x = (x * 72) // 9
        y = (y * 18) // 13.5
        return x, y, width, height

    def inster_image(self, row, col, end_row, end_col, image_url, image_size=None):

        img = Image(image_url)
        if image_size:
            img.width, img.height = image_size
        w, h = img.width, img.height
        x1, y1, w1, h1 = self.get_absolute(row, col)
        x2, y2, w2, h2 = self.get_absolute(end_row, end_col)
        x = (x2 + x1 - w1 - h) // 2
        y = (y2 + y1 - h1 - w) // 2
        p2e = pixels_to_EMU  # openpylx自带的像素转EMU
        pos = XDRPoint2D(p2e(x), p2e(y))  # 设置绝对位置
        size = XDRPositiveSize2D(p2e(w), p2e(h))  # 图片大小
        img.anchor = AbsoluteAnchor(pos=pos, ext=size)
        self.worksheet.add_image(img)
        

if __name__ == '__main__':
	a = AddImage()
    img_path = os.path.join(settings.IMAGE_PATH, file_name)  # 注意我这是用Django
    a.inster_image(10, 10, 20 ,20, img_path, image_size=(86, 68))

openpyxl 以绝对位置形式插入图片(实现在区域居中)_第2张图片
上面的有一个问题,在缩放Excel时,图片是以绝对位置插入的,所以Excel一缩放,图片就不在区域中
openpyxl 以绝对位置形式插入图片(实现在区域居中)_第3张图片
没方法就又想到一个办法,用 OneCellAnchor(_from=marker, ext=size)

    def inster_image(self, start_row, start_col, hieght, image_url, image_size=None):

        img = Image(image_url)
        img.height, img.width = image_size
        col_letter = get_column_letter(start_col)
        width = self.worksheet.column_dimensions[col_letter].width
        c2e = cm_to_EMU
        p2e = pixels_to_EMU
        size = XDRPositiveSize2D(p2e(img.height), p2e(img.width))
        image_cell, mod = divmod(img.height, 20)
        image_cell = image_cell+1 if mod != 0 else image_cell
        if (hieght - image_cell) % 2 == 0:
            start = start_row + (hieght - image_cell) // 2
            rowOff = c2e((0.6 * 49.77) / 99)
        else:
            start = start_row + (hieght - image_cell) // 2 + 1
            # start = start_row + (hieght - image_cell) // 2
            rowOff = c2e((0.4 * 49.77) / 99)
        colOff = (c2e(width + 1) - c2e(img.width / 72 * 13)) / 9
        marker = AnchorMarker(col=start_col - 1, colOff=colOff, row=start - 1, rowOff=rowOff)
        img.anchor = OneCellAnchor(_from=marker, ext=size)
        self.worksheet.add_image(img)

你可能感兴趣的:(openpyxl 以绝对位置形式插入图片(实现在区域居中))