0x00. 场景

日常使用Excel表格过程中,经常会遇到需要在单元格内插入图片的情形,比如证件照、身份证正反面等情况。为了美观且便于查看,WPS提供了“图片嵌入单元格”功能,可谓非常好用。

我开发小工具时使用Golang语言居多,处理Excel表格使用的是Excelize开源库,Excelize提供了自动适应单元格选项AutoFit(从字面意思看,似乎符合我们的需求),官方文档如下:

可选参数 AutoFit 用以指定是否使图形对象尺寸自动适合单元格,其默认值为 false。

通过翻看源码,AutoFit参数优先按单元格高度缩放图片,若图片高度小于单元格高度,则按单元格宽度缩放图片。

// drawingResize calculate the height and width after resizing.
func (f *File) drawingResize(sheet, cell string, width, height float64, opts *GraphicOptions) (w, h, c, r int, err error) {
	// 省略若干代码
    if float64(cellWidth) < width {
		asp := float64(cellWidth) / width
		width, height = float64(cellWidth), height*asp
	}
	if float64(cellHeight) < height {
		asp := float64(cellHeight) / height
		height, width = float64(cellHeight), width*asp
	}
    // 省略若干代码
}

实际使用下来,只适应了宽或高,效果跟预期不一致。

0x01. 魔改

既然我们已经定位到计算图片宽度的参数了,那剩下的只需要将图片的宽高按单元格的尺寸进行缩放,就能达到填满单元格的效果了。

  1. 新增GraphicOptions.Fill参数

  2. 修改drawingResize方法实现

    // drawingResize calculate the height and width after resizing.
    func (f *File) drawingResize(sheet, cell string, width, height float64, opts *GraphicOptions) (w, h, c, r int, err error) {
    	// 省略若干代码
        if opts.Fill {
            width, height = float64(cellWidth), float64(cellHeight)
        } else {
            if float64(cellWidth) < width {
                asp := float64(cellWidth) / width
                width, height = float64(cellWidth), height*asp
            }
            if float64(cellHeight) < height {
                asp := float64(cellHeight) / height
                height, width = float64(cellHeight), width*asp
            }
            width, height = width-float64(opts.OffsetX), height-float64(opts.OffsetY)
        }
        // 省略若干代码
    }
    
  3. 经过测试,符合预期。

0x02. 后续

所谓“魔改”,就是直接强行修改Excelize本地包源码,不方便项目托管和开发,也不方便依赖库的版本升级。

那么最好的方式就是让官方支持这个特性,所以我向官方仓库提交了Support filling images in cells #1923,经过旭日大佬的修改,现已合并进主分支了。

在以后的Excelize版本中,就可以直接使用AutoFitIgnoreAspect参数完成上述需求了。