c# NPOI 如何在指定单元格导入导出图片

 更新时间:2021年03月03日 08:27:06   作者:WeihanLi  
这篇文章主要介绍了c# NPOI 如何在指定单元格导入导出图片,帮助大家更好的理解和学习使用c#,感兴趣的朋友可以了解下

Intro

我维护了一个 NPOI 的扩展(WeihanLi.Npoi),主要用来导入导出 Excel 数据,最近有网友提出了导入 Excel 的时候解析图片的需求,于是就有了本文的探索

导入Excel 时解析图片

xls 和 xlsx 的 API 稍有不同,详细可以直接参考以下代码,实现代码如下:

public static Dictionary<CellPosition, IPictureData> GetPicturesAndPosition(this ISheet sheet)
{
  var dictionary = new Dictionary<CellPosition, IPictureData>();
  if (sheet.Workbook is HSSFWorkbook)
  {
    foreach (var shape in ((HSSFPatriarch)sheet.DrawingPatriarch).Children)
    {
      if (shape is HSSFPicture picture)
      {
        var position = new CellPosition(picture.ClientAnchor.Row1, picture.ClientAnchor.Col1);
        dictionary[position] = picture.PictureData;
      }
    }
  }
  else if (sheet.Workbook is XSSFWorkbook)
  {
    foreach (var shape in ((XSSFDrawing)sheet.DrawingPatriarch).GetShapes())
    {
      if (shape is XSSFPicture picture)
      {
        var position = new CellPosition(picture.ClientAnchor.Row1, picture.ClientAnchor.Col1);
        dictionary[position] = picture.PictureData;
      }
    }
  }
  return dictionary;
}

CellPosition 是一个自定义的结构体,表示当前单元格的位置,源码如下:

public readonly struct CellPosition : IEquatable<CellPosition>
{
  public CellPosition(int row, int col)
  {
    Row = row;
    Column = col;
  }

  public int Row { get; }
  public int Column { get; }

  public bool Equals(CellPosition other)
  {
    return Row == other.Row && Column == other.Column;
  }

  public override bool Equals(object? obj) => obj is CellPosition other && Equals(other);

  public override int GetHashCode() => $"{Row}_{Column}".GetHashCode();
}

根据上面的代码,我们就可以获取到获取到所有的图片以及图片的所在位置,这样根据单元格位置去找图片信息的时候就会很方便了

导出 Excel 时设置图片

实现代码如下:

public static bool TryAddPicture(this ISheet sheet, int row, int col, byte[] pictureBytes, PictureType pictureType = PictureType.PNG)
{
  if (sheet is null)
  {
    throw new ArgumentNullException(nameof(sheet));
  }

  try
  {
    var pictureIndex = sheet.Workbook.AddPicture(pictureBytes, pictureType);

    var clientAnchor = sheet.Workbook.GetCreationHelper().CreateClientAnchor();
    clientAnchor.Row1 = row;
    clientAnchor.Col1 = col;

    var picture = (sheet.DrawingPatriarch ?? sheet.CreateDrawingPatriarch())
      .CreatePicture(clientAnchor, pictureIndex);
    picture.Resize();
    return true;
  }
  catch (Exception e)
  {
    Debug.WriteLine(e);
  }

  return false;
}

通过上面的代码我们就可以在指定的单元格设置图片,目前没有支持单元格合并操作,有需要自己进行修改

WeihanLi.Npoi

WeihanLi.Npoi 在 1.15.0 版本中增加了图片导入导出的支持,使用示例可以参考下面的单元测试:

[Theory]
[ExcelFormatData]
public async Task ImageImportExportTest(ExcelFormat excelFormat)
{
  using var httpClient = new HttpClient();
  var imageBytes = await httpClient.GetByteArrayAsync("https://weihanli.xyz/assets/avator.jpg");
  var list = Enumerable.Range(1, 5)
    .Select(x => new ImageTest() { Id = x, Image = imageBytes })
    .ToList();
  var excelBytes = list.ToExcelBytes(excelFormat);
  var importResult = ExcelHelper.ToEntityList<ImageTest>(excelBytes, excelFormat);
  Assert.NotNull(importResult);
  Assert.Equal(list.Count, importResult.Count);
  for (var i = 0; i < list.Count; i++)
  {
    Assert.NotNull(importResult[i]);
    var result = importResult[i]!;
    Assert.Equal(list[i].Id, result.Id);
    Assert.NotNull(result.Image);
    Assert.True(list[i].Image.SequenceEqual(result.Image));
  }
}

private class ImageTest
{
  public int Id { get; set; }

  public byte[] Image { get; set; } = null!;
}

导入时会自动将 byte[] 类型的属性尝试获取对应的单元格位置的图片,如果在对应的位置找到了图片就能够读取到图片的字节数组信息映射到 model 里的字节数组属性

除此之外,还支持直接导入的时候将图片信息 Map 到 IPictureData 属性上,但是觉得还是字节数组更通用一些,如果对此感兴趣可以参考项目源码以及单元测试

More

感谢 @ZeguangZhang94 童鞋提出的需求和帮忙测试~

如果你也有类似的读取指定单元格的图片或者在指定单元格插入图片的需求,可以试一下上面的方法,希望对你有帮助,可以直接引用我的类库或者直接拷贝源码到自己的项目里使用

References

以上就是c# NPOI 如何在指定单元格导入导出图片的详细内容,更多关于NPOI 在指定单元格导入导出图片的资料请关注脚本之家其它相关文章!

相关文章

  • c# Task.Wait()与awaiat Task异常处理的区别说明

    c# Task.Wait()与awaiat Task异常处理的区别说明

    这篇文章主要介绍了c# Task.Wait()与awaiat Task异常处理的区别说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-06-06
  • C#数组初始化简析

    C#数组初始化简析

    C#数组与其它C系列语言有着很多的不同,以前接触的时候理解出现很大的偏差。尤其是对多维数组的认识,本文将详细介绍C#数组初始化,需要的朋友可以参考下
    2012-11-11
  • C# IQueryable<T>揭开表达式树的神秘面纱

    C# IQueryable<T>揭开表达式树的神秘面纱

    这篇文章主要介绍了C# IQueryable<T>表达式树,对IQueryable<T>感兴趣的同学,必须要仔细看一下
    2021-04-04
  • 关于Unity中RectTransform与transform的区别

    关于Unity中RectTransform与transform的区别

    这篇文章主要介绍了Unity中RectTransform与transform的区别,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-01-01
  • C#统计字符串的方法

    C#统计字符串的方法

    这篇文章主要为大家详细介绍了C#统计字符串的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-03-03
  • c#判断字符是否为中文的三种方法分享(正则表达式判断)

    c#判断字符是否为中文的三种方法分享(正则表达式判断)

    判断一个字符是不是汉字通常有三种方法,第一种用 ASCII 码判断,第二种用汉字的UNICODE编码范围判断,第三种用正则表达式判断,以下是具体方法
    2014-01-01
  • C#过滤DataTable中空数据和重复数据的示例代码

    C#过滤DataTable中空数据和重复数据的示例代码

    这篇文章主要给大家介绍了关于C#过滤DataTable中空数据和重复数据的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • C# 9使用foreach扩展的示例详解

    C# 9使用foreach扩展的示例详解

    在 C# 9 中,foreach 循环可以使用扩展方法。在本文中,我们将通过例子回顾 C# 9 中如何扩展 foreach 循环,感兴趣的小伙伴可以了解一下
    2023-01-01
  • C#串口接收程序的实现

    C#串口接收程序的实现

    本文主要介绍了C#串口接收程序的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05
  • 详解C#实现在Excel单元格中应用多种字体格式

    详解C#实现在Excel单元格中应用多种字体格式

    在Excel中,可对单元格中的字符串设置多种不同样式。本文,将以C#及VB.NET代码为例,介绍如何在Excel同一个单元格中应用多种字体样式,感兴趣的可以了解一下
    2022-05-05

最新评论