You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用C#更新Word(.doc)图片:如何检测衬于文字下方的图片

解决Word文档中“衬于文字下方”图片的替换问题

问题描述

我正在开发一款C#应用,用于遍历文件夹中的Word(.doc)文档,找到InlineShape(图片)后将其替换为新图片。程序对默认“嵌入型”环绕的图片处理正常,但遇到部分设置了“衬于文字下方”环绕方式的图片时无法处理,请问如何检测这类图片?

现有代码:

class Program
{
    Application wordApp;
    Document doc;
    string imagePath = @"\\Your\Folder\Path";
    string folderPath = @"\\Your\Folder\Path";
    List<InlineShape> InlineShapesToDelete;                                                                                                 

    public Program()
    {
        wordApp = new Application();
        InlineShapesToDelete = new List<InlineShape>();
    }// end of program construction
    public void Run()
    {
        try
        {
            if (Directory.Exists(folderPath))                                                                                          
            {
                string[] files = Directory.GetFiles(folderPath, "*.doc");                                                              
                foreach (string filePath in files)
                {
                    ProcessDocument(filePath);                                                                                        
                }
            }
            else
            {
                Console.WriteLine("Folder not found.");
            }
        }// end of outter try
        catch (Exception ex)
        {
            Console.WriteLine("Error: " + ex.Message);
        }// end of catch
        finally
        {
            CleanupApplication();                                                                                                                                                                                                     
        }// end of finally
    }// end of Run 
    private void ProcessDocument(string filePath)
    {
        Console.WriteLine($"\nProcessing File: {Path.GetFileName(filePath)}");
        try
        {
            doc = wordApp.Documents.Open(filePath);                                                                                    
            Console.WriteLine($"\tOpened File: {Path.GetFileName(filePath)}");
            InlineShapesToDelete.Clear();                                                                                                   

            foreach (Section section in doc.Sections)
            {
                ProcessSection(section, filePath);                                                                                      
            }

            if (InlineShapesToDelete.Count == 0)
            {
                Console.WriteLine($"\t\tNo Picture Found in doc {Path.GetFileName(filePath)}");
            }
            
            foreach (InlineShape shapeToDelete in InlineShapesToDelete)
            {   
                shapeToDelete.Delete();                                                                                                  
            }
            doc.Save();                                                                                                                  
            Console.WriteLine($"\t\t\tClosed File: {Path.GetFileName(filePath)}");
        }// end of inner try 
        catch (Exception ex)
        {
            Console.WriteLine($"Error: processing file {Path.GetFileName(filePath)}: {ex.Message}");
            
        }// end of catch
        finally
        {
            CleanupDocument();
        }// end of finally
    }// end of ProcessDocument
    private void ProcessSection(Section section, string filePath)
    {
        //bool replaced = false;
        int imageCount = 0;
        foreach (InlineShape shape in section.Range.InlineShapes)                                                                        
        {
            if (shape.Type == WdInlineShapeType.wdInlineShapePicture)                                                                     
            {
               
                shape.Select();
                InlineShapesToDelete.Add(shape);                                                                                         
                shape.Range.InlineShapes.AddPicture(imagePath);                                                                           
                imageCount++;
                Console.WriteLine($"\t\tImage \"{imageCount}\" Changed in file: {Path.GetFileName(filePath)}");
               // replaced = true; 
            }
        }
    }// end of ProcessSection
    
    private void CleanupDocument()
    {
        if (doc != null)
        {
            doc.Close();                                                                                                                
        }
    }// end of CleanupDocument
    private void CleanupApplication()
    {
        if (wordApp != null)
        {
            wordApp.Quit();                                                                                                              
            Marshal.ReleaseComObject(wordApp);                                                                                           
        }
    }// end of CleanupApplication

    static void Main(string[] args)
    {
        Program program = new Program();
        program.Run();
    }
}

核心原因

Word中,嵌入型图片属于InlineShape对象,而所有带有文字环绕属性的浮动图片(包括“衬于文字下方”)都归类为Shape对象,你的现有代码只遍历了InlineShapes集合,因此无法处理这类浮动图片。

解决建议

1. 新增Shape对象的处理逻辑

在现有代码基础上,添加对Shapes集合的遍历,筛选出符合条件的图片:

  • 用Shape.Type判断是否为图片(对应WdShapeType.wdShapePicture)
  • 用Shape.WrapFormat.Type判断环绕方式,“衬于文字下方”对应WdWrapType.wdWrapBehind

2. 修改后的完整代码片段

class Program
{
    Application wordApp;
    Document doc;
    string imagePath = @"\\Your\Folder\Path";
    string folderPath = @"\\Your\Folder\Path";
    List<InlineShape> InlineShapesToDelete;
    List<Shape> ShapesToDelete; // 新增存储浮动图片的列表

    public Program()
    {
        wordApp = new Application();
        InlineShapesToDelete = new List<InlineShape>();
        ShapesToDelete = new List<Shape>(); // 初始化列表
    }// end of program construction

    public void Run()
    {
        // 原Run方法逻辑不变,此处省略
    }// end of Run 

    private void ProcessDocument(string filePath)
    {
        Console.WriteLine($"\nProcessing File: {Path.GetFileName(filePath)}");
        try
        {
            doc = wordApp.Documents.Open(filePath);
            Console.WriteLine($"\tOpened File: {Path.GetFileName(filePath)}");
            InlineShapesToDelete.Clear();
            ShapesToDelete.Clear(); // 清空浮动图片列表

            foreach (Section section in doc.Sections)
            {
                ProcessSection(section, filePath);
                ProcessSectionShapes(section, filePath); // 新增处理浮动图片的方法调用
            }

            if (InlineShapesToDelete.Count == 0 && ShapesToDelete.Count == 0)
            {
                Console.WriteLine($"\t\tNo Picture Found in doc {Path.GetFileName(filePath)}");
            }
            
            // 删除嵌入型图片
            foreach (InlineShape shapeToDelete in InlineShapesToDelete)
            {   
                shapeToDelete.Delete();
            }
            // 删除浮动图片
            foreach (Shape shapeToDelete in ShapesToDelete)
            {
                shapeToDelete.Delete();
            }
            
            doc.Save();
            Console.WriteLine($"\t\t\tClosed File: {Path.GetFileName(filePath)}");
        }// end of inner try 
        catch (Exception ex)
        {
            Console.WriteLine($"Error: processing file {Path.GetFileName(filePath)}: {ex.Message}");
        }// end of catch
        finally
        {
            CleanupDocument();
        }// end of finally
    }// end of ProcessDocument

    // 原ProcessSection方法不变,此处省略

    // 新增处理浮动图片的方法
    private void ProcessSectionShapes(Section section, string filePath)
    {
        int imageCount = 0;
        foreach (Shape shape in section.Range.Shapes)
        {
            // 判断是否为图片且环绕方式为衬于文字下方
            if (shape.Type == WdShapeType.wdShapePicture && 
                shape.WrapFormat.Type == WdWrapType.wdWrapBehind)
            {
                // 保留原图片的位置、尺寸属性
                float left = shape.Left;
                float top = shape.Top;
                float width = shape.Width;
                float height = shape.Height;

                ShapesToDelete.Add(shape);
                // 在原位置插入新图片并设置相同环绕方式
                Shape newShape = section.Range.Shapes.AddPicture(
                    Filename: imagePath,
                    LinkToFile: false,
                    SaveWithDocument: true,
                    Left: left,
                    Top: top,
                    Width: width,
                    Height: height
                );
                newShape.WrapFormat.Type = WdWrapType.wdWrapBehind;
                
                imageCount++;
                Console.WriteLine($"\t\t浮动图片 \"{imageCount}\" Changed in file: {Path.GetFileName(filePath)}");
            }
        }
    }// end of ProcessSectionShapes

    // 原CleanupDocument、CleanupApplication、Main方法不变,此处省略
}

3. 注意事项

  • 不要在遍历Shapes或InlineShapes集合时直接删除对象,先存入列表再统一处理,避免集合遍历异常
  • 插入新图片时需保留原图片的位置、尺寸和环绕属性,保证文档布局一致性
  • 处理完COM对象后及时释放,避免内存泄漏

内容的提问来源于stack exchange,提问作者Maiz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 07:54:51