iTextSharp从SQL DataReader/数据表获取图片集合并插入PDF单元格的实现
实现全量图片读取并填充单元格的修正方案
原实现的问题根源
你当前代码仅能读取单张图片,核心原因有两个:
- 对SqlDataReader仅执行了1次
Read()操作,该对象是向前只读的游标结构,每调用一次Read()才会向下移动一行,单次调用只能拿到结果集第一条记录的二进制图片数据 - 代码采用字符串拼接方式生成SQL语句,存在SQL注入风险,且手动关闭资源的写法容易出现异常导致资源泄漏
方案选型说明
对比SqlDataReader和DataTable两种读取方式,优先选择SqlDataReader逐行遍历的实现:这种方式是流式读取二进制图片数据,不需要一次性把所有图片字节全部加载到内存,批量图片场景下内存占用更低,不需要额外转换为DataTable的额外开销。
修正后可直接运行的VB.NET代码
' 提前初始化要放所有图片的单元格,先放入已有的单张主图 Dim imageByte As Byte() = CType(row.Cells(11).Value, Byte()) Dim myImage As iTextSharp.text.Image Using ms As New MemoryStream(imageByte, 0, imageByte.Length) myImage = iTextSharp.text.Image.GetInstance(ms) ' 可选:统一缩放图片适配单元格宽度,避免撑破表格 myImage.ScaleToFit(120, 120) End Using Dim cellimg As New PdfPCell() cellimg.AddElement(myImage) ' 用Using自动释放数据库相关资源,避免异常时连接泄漏 Using connessione As New SqlConnection(stringa_database) connessione.Open() ' 改成参数化查询,替代原来的字符串拼接,杜绝SQL注入 Using comando As New SqlCommand("SELECT u.immagine From immagini_aggiuntive u INNER JOIN note q ON q.id = u.id_nota where id_nota = @IdNota", connessione) comando.Parameters.AddWithValue("@IdNota", id) Using lettura As SqlDataReader = comando.ExecuteReader() ' 循环遍历结果集所有行,不再单次Read()退出 While lettura.Read() ' 跳过空值的图片字段 If Not IsDBNull(lettura.GetValue(1)) Then Dim imageByte2 As Byte() = CType(lettura.GetValue(1), Byte()) Using ms2 As New MemoryStream(imageByte2, 0, imageByte2.Length) Dim myImage2 As iTextSharp.text.Image = iTextSharp.text.Image.GetInstance(ms2) ' 可选:和主图保持一致的缩放尺寸 myImage2.ScaleToFit(120, 120) ' 逐张把附加图片加入同一个单元格,AddElement支持多次调用 cellimg.AddElement(myImage2) End Using End If End While End Using End Using End Using ' 最后把填充完所有图片的单元格加入PDF表格 pdfTable.AddCell(cellimg)
关键注意点
PdfPCell的AddElement方法支持多次调用,加入的图片会在单元格内从上到下自动流式排列,不需要手动调整坐标- 遍历SqlDataReader时要判断图片字段是否为DBNull,避免空值导致类型转换报错
- 生成的图片实例建议根据单元格实际宽度做适配缩放,否则大尺寸图片会直接撑破PDF表格的固定列宽
- 所有数据库连接、阅读器、内存流都用Using块包裹,会在代码块执行完后自动释放资源,不需要手动写
Close()方法,异常场景下也不会出现资源泄漏
内容的提问来源于stack exchange,提问作者bernox
相关产品推荐
相关产品推荐

