You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

SQL Server Image列图片嵌入HTML转Word不显示问题求助

解决SQL Server Image列嵌入HTML转Word的图片显示问题

首先纠正你最开始的错误尝试:直接把Image列转成binary再转varchar完全不对,这样会丢失图片的二进制信息,所以你看到的都是重复的乱码前缀。正确的做法是把图片二进制数据转成Base64编码嵌入HTML,你后来找的Base64转换思路是对的,但Word对这种嵌入方式有兼容性坑,下面一步步帮你解决:

一、先搞定正确的Base64转换查询

你之前的单条查询可以改成批量生成每个员工的img标签,方便直接拼到HTML里:

SELECT 
    -- 可添加员工ID、姓名等字段,和图片标签一起输出
    EmployeeId,
    EmployeeName,
    '<img src="data:image/jpeg;base64,' + 
    CAST(N'' AS XML).value('xs:base64Binary(xs:hexBinary(sql:column("Photo")))', 'VARCHAR(MAX)') + 
    '" style="height:100px;width:100px;" />' AS EmployeePhoto
FROM hrm.hrm_rp_Employee_Image

划重点:如果你的图片是PNG格式,一定要把data:image/jpeg改成data:image/png,否则Word识别不了。

二、解决Word里的红叉问题

在线HTML能显示但Word里出红叉,核心原因是旧版Word(比如2007及更早)对data URI scheme的Base64图片支持很差,即使是新版Word,直接通过HTML转成的doc格式也可能解析异常。这里给你两个解决方案:

方案1:优化HTML模板适配Word

修改你C#代码里的HTML头部,添加Word专属的命名空间属性,开启图片支持:

strBody = @"<html xmlns:o='urn:schemas-microsoft-com:office:office' 
xmlns:w='urn:schemas-microsoft-com:office:word'
xmlns='http://www.w3.org/TR/REC-html40'>
<head><title>员工档案</title>
<!--[if gte mso 9]>
<xml>
<w:WordDocument>
<w:View>Print</w:View>
<w:Zoom>100</w:Zoom>
<w:DoNotOptimizeForBrowser/>
<w:AllowPNG/> <!-- 允许Word解析PNG图片 -->
</w:WordDocument>
</xml>
<![endif]-->
<!-- 你的原有样式代码保持不变 -->
</head>";

另外,把输出的文件后缀从.doc改成.docx,新版Word对docx格式的HTML兼容性更好。

方案2:改用Open XML SDK直接生成Word(推荐)

如果上面的方法还是不行,最靠谱的方式是绕过HTML转Word的环节,直接用Open XML SDK生成标准的docx文档,把图片二进制数据直接插入文档。这种方式完全没有兼容性问题,步骤如下:

  1. 先安装NuGet包:DocumentFormat.OpenXml
  2. 用下面的代码片段替换你原来的HtmlToWordDownload方法:
public static void GenerateEmployeeDocDownload(byte[] photoBytes, string employeeName, string FileName)
{
    using (var memoryStream = new MemoryStream())
    {
        // 创建docx文档
        using (WordprocessingDocument doc = WordprocessingDocument.Create(memoryStream, WordprocessingDocumentType.Document))
        {
            MainDocumentPart mainPart = doc.AddMainDocumentPart();
            mainPart.Document = new Document();
            Body body = mainPart.Document.AppendChild(new Body());

            // 添加员工姓名
            var namePara = body.AppendChild(new Paragraph());
            var nameRun = namePara.AppendChild(new Run());
            nameRun.AppendChild(new Text($"员工姓名:{employeeName}"));

            // 添加图片
            ImagePart imagePart = mainPart.AddImagePart(ImagePartType.Jpeg);
            using (Stream stream = imagePart.GetStream())
            {
                stream.Write(photoBytes, 0, photoBytes.Length);
            }

            // 设置图片大小(单位是EMU,914400≈1厘米)
            string imageId = mainPart.GetIdOfPart(imagePart);
            var drawing = new Drawing(
                new DW.Inline(
                    new DW.Extent() { Cx = 914400, Cy = 914400 },
                    new DW.EffectExtent() { LeftEdge = 0L, TopEdge = 0L, RightEdge = 0L, BottomEdge = 0L },
                    new DW.DocProperties() { Id = 1U, Name = "员工照片" },
                    new DW.NonVisualGraphicFrameDrawingProperties(new A.GraphicFrameLocks() { NoChangeAspect = true }),
                    new A.Graphic(
                        new A.GraphicData(
                            new PIC.Picture(
                                new PIC.NonVisualPictureProperties(
                                    new PIC.NonVisualDrawingProperties() { Id = 0U, Name = "员工照片.jpg" },
                                    new PIC.NonVisualPictureDrawingProperties()),
                                new PIC.BlipFill(
                                    new A.Blip() { Embed = imageId, CompressionState = A.BlipCompressionValues.Print },
                                    new A.Stretch(new A.FillRectangle())),
                                new PIC.ShapeProperties(
                                    new A.Transform2D(
                                        new A.Offset() { X = 0L, Y = 0L },
                                        new A.Extents() { Cx = 914400, Cy = 914400 }),
                                    new A.PresetGeometry(new A.AdjustValueList()) { Preset = A.ShapeTypeValues.Rectangle }))
                        ) { Uri = "http://schemas.openxmlformats.org/drawingml/2006/picture" }))
                ) { DistanceFromTop = 0U, DistanceFromBottom = 0U, DistanceFromLeft = 0U, DistanceFromRight = 0U });

            var photoRun = body.AppendChild(new Paragraph()).AppendChild(new Run());
            photoRun.AppendChild(drawing);
        }

        // 输出到浏览器下载
        memoryStream.Seek(0, SeekOrigin.Begin);
        HttpContext.Current.Response.Clear();
        HttpContext.Current.Response.ContentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
        HttpContext.Current.Response.AddHeader("Content-Disposition", $"attachment;filename={FileName}.docx");
        memoryStream.CopyTo(HttpContext.Current.Response.OutputStream);
        HttpContext.Current.Response.Flush();
        HttpContext.Current.ApplicationInstance.CompleteRequest();
    }
}

你只需要从数据库读取员工的Photo列(转成byte[])和其他信息,传入这个方法就行,生成的docx文档里图片肯定能正常显示。

最后检查一下

确保数据库里的Image列存储的是标准的图片格式(JPEG/PNG/BMP),如果是其他格式,记得在代码里调整ImagePartType对应的枚举值。


内容的提问来源于stack exchange,提问作者Prasanth Kumar Vinakota

火山引擎 最新活动