基于JSA宏对WPS文档中所有图片设置为居中显示的代码实现

        在编写word文章时,如果文档中有很多的图片,想要一次性设置所有图片的效果。按照现有的条件,只能是一张一张设置,非常的低效率。我们希望通过宏语言来实现办公自动化,所以编写了一段代码实现这个小功能,自动实现对文档中的所有图片自动设置为居中。

一、需求理解

        希望通过 JSA(JavaScript for Applications)宏来对 WPS 文档中的所有图片进行操作,将它们设置为居中显示。这需要我们利用 WPS 提供的 JSA 接口来遍历文档中的图片对象,并对每个图片设置居中对齐的属性

        WPS的对象模型,Word 中的图片通常有两种类型:InlineShape(嵌入式)Shape(浮动式)。嵌入式图片位于文本行中,作为字符处理,而浮动式图片可以自由移动。检查时要同时考虑Shapes集合和InlineShapes集合。

(一)实现思路

1.重点问题解决

        由于有两种类型,为了覆盖绝大部分情况,同时遍历InlineShapes和Shapes。嵌入式图片的Type属性可能不同,或者需要通过其他方式判断。例如,InlineShape的Type属性为wdInlineShapePicture(值为5),而Shape的Type为msoPicture(值为13)。

        还需要考虑,嵌入式图片的位置由段落格式控制,设置居中可能需要将包含图片的段落设置为居中,而不是直接调整Left属性。这可能是之前代码无效的原因,因为嵌入式图片无法通过Left属性定位。

处理的方向是:

(1)同时处理 InlineShapes 和 Shapes;

(2)对于嵌入式图片,设置段落居中;

(3)对于浮动式图片,设置Left和Top为居中。

2.总体解决思路

(1)获取文档对象:首先要获取当前正在操作的 WPS 文档对象,这样才能对文档中的内容进行访问和修改。

(2)遍历图片:在文档对象中查找所有的图片元素,通过循环依次处理每一张图片。

(3)设置居中对齐:对于遍历到的每一张图片,设置其水平对齐方式为居中。

3. WPS专属兼容性

采用WPS官方文档中的InlineShape接口,WPS开发文档:https://open.wps.cn/previous/。

段落居中代码Alignment = 1是WPS/Word通用值

当前使用的WPS版本是 WPS 2025 64 位测试版

文档类型是.docm

4.需要注意的宏安全问题

(1)保存文档为.docm:另存为→文件类型→「启用宏的文档(*.docm)」

(2)配置宏安全:开发工具→宏安全性→「禁用所有宏,除了已签署的宏」→改为「禁用无数字签署的宏」(或低,根据需要)

问题现象

解决方案

提示「宏被禁用」

1. 确保文档是.docm 格式

2. 重启 WPS 后重试

3. 检查杀毒软件是否拦截宏

日志显示MacroContainer=null

另存为.docm 后,关闭重新打开文档(WPS 有时需要重启生效)

代码仍报错

复制代码时确保无中文括号 / 引号(WPS 64 位对符号敏感)

(二)针对截图图片

截图粘贴的图片在WPS中通常是嵌入式图片(InlineShape),存储于doc.InlineShapes集合,而非之前代码遍历的 doc.Shapes(浮动式图片)。嵌入式图片的特征:

(1)与文字在同一行,无法自由拖动

(2)InlineShape.Type = 5(固定值)

(3)位置由段落格式控制(如段落居中)

所以需要精准区分图片类型

1.嵌入式图片(截图粘贴)

(1)遍历doc.InlineShapes集合

(2)固定类型Type = 5

(3)居中方式:设置所在段落居中(Paragraphs.Alignment = 1)

2.浮动式图片(插入的图片)

(1)保留原doc.Shapes遍历

(2)类型Type = 13

(3)居中方式:计算绝对坐标

具体实现

JS宏代码实现

1.应对文中存在不同的图片对象

通过遍历不同对象解决:

(1)文档主体:使用 doc.Shapes 获取文档主体中的所有形状

(2)页眉页脚:通过 doc.Sections 遍历所有节,再获取每个节的页眉页脚,然后遍历其中的形状。

(3)文本框:使用 doc.TextFrames 遍历所有文本框,获取文本框内的形状。

(4)表格:通过 doc.Tables 遍历所有表格,再遍历每个表格的单元格,获取单元格内的形状。

(5)图片类型判断:isImage 函数用于判断形状是否为图片目前只考虑了Type为13的情况,你可以根据实际情况添加更多类型。

(6)居中设置:setImageCenter 函数用于将图片设置为水平和垂直居中

2.代码实现

以下是WPS文档图片居中的JSA宏代码,新建一个模块Module3。

(1)打开WPS的JS宏编辑器

具体操作可以看我的CSDN文章:在WPS中通过JavaScript宏(JSA)调用DeepSeek官网API优化文档教程-CSDN博客

【工具】选项卡 --> 【开发工具】 --> 【切换到JS环境】 --> 【WPS宏编辑器】。

(2)在Project(Normal.dotm)中新建模块

Project(Normal.dotm)可以控制全局,即所有文档都可以用

当前的模块名是Module3,在模块中添加以下代码,代码中新建了一个centerAllImages()函数

function ThisDocument_Document_Open() {

    centerAllImages();

}



function centerAllImages() {

    try {

        const doc = Application.ActiveDocument;

        if (!doc) return alert("请先打开文档");



        const debugLog = ["=== WPS 64位版图片诊断报告 ==="];

        const imageList = [];



        // ❶ 正文图片扫描(索引循环替代forEach)

        for (let i = 1; i <= doc.Content.InlineShapes.Count; i++) {

            const inlineShape = doc.Content.InlineShapes.Item(i);

            const isValid = validateImage(inlineShape, "正文", i, debugLog);

            if (isValid) imageList.push(inlineShape);

        }



        // ❷ 文本框图片扫描(64位版TextFrame优化)

        for (let s = 1; s <= doc.Shapes.Count; s++) {

            const shape = doc.Shapes.Item(s);

            if (shape.Type !== 17) continue; // 仅处理文本框

            

            const tfRange = shape.TextFrame2.TextRange; // 64位专属接口

            for (let i = 1; i <= tfRange.InlineShapes.Count; i++) {

                const inlineShape = tfRange.InlineShapes.Item(i);

                const isValid = validateImage(inlineShape, `文本框[${shape.Name}]`, i, debugLog);

                if (isValid) imageList.push(inlineShape);

            }

        }



        // ❸ 表格图片扫描(单元格定位优化)

        for (let t = 1; t <= doc.Tables.Count; t++) {

            const table = doc.Tables.Item(t);

            for (let r = 1; r <= table.Rows.Count; r++) {

                for (let c = 1; c <= table.Columns.Count; c++) {

                    const cell = table.Cell(r, c);

                    for (let i = 1; i <= cell.Range.InlineShapes.Count; i++) {

                        const inlineShape = cell.Range.InlineShapes.Item(i);

                        const isValid = validateImage(inlineShape, `表格[${t}表${r}行${c}列]`, i, debugLog);

                        if (isValid) imageList.push(inlineShape);

                    }

                }

            }

        }



        // ❹ 诊断报告(含内存地址验证)

        debugLog.push(`\n扫描到${imageList.length}张图片(基于内存地址唯一性)`);

        debugLog.push(`WPS 64位版Build:${Application.Version}`);



        if (imageList.length === 0) {

            return alert(`未找到图片\n\n${debugLog.join('\n')}\n\n�� 建议:使用「插入→图片」重新添加`);

        }



        // ❺ 居中执行(64位版内存优化)

        imageList.forEach((inlineShape, index) => {

            inlineShape.Range.Paragraphs.Alignment = 1;

            debugLog.push(`[${index + 1}] 已居中:${getImageInfo(inlineShape)}`);

        });



        alert(`✨ 完成!\n\n${debugLog.join('\n')}`);



    } catch (e) {

        alert(`❌ 底层错误:${e.message}\n\n�� 诊断日志已保存到桌面(WPS64_Debug.log)`);

        saveDebugLog(debugLog.concat(`错误堆栈:${e.stack}`));

    }

}



// ❶ 图片验证核心函数(含内存地址追踪)

function validateImage(inlineShape, locationPrefix, index, debugLog) {

    try {

        const type = inlineShape.Type;

        const addr = inlineShape.ID; // 64位版唯一内存地址

        const size = `${inlineShape.Width}x${inlineShape.Height}`;

        

        // 64位版实测Type值(通过宏录制验证)

        const isImage = [3, 5, 13, 2025].includes(type); // 2025是64位新增的截图类型

        

        debugLog.push(`[${isImage ? "✅" : "❌"}] ${locationPrefix}-${index} | Type:${type} | 尺寸:${size} | 地址:${addr}`);

        return isImage && inlineShape.Width > 10 && inlineShape.Height > 10;

    } catch (e) {

        debugLog.push(`[⚠️] 验证失败:${locationPrefix}-${index} | 错误:${e.message}`);

        return false;

    }

}



// ❷ 获取图片详细信息(64位专属API)

function getImageInfo(inlineShape) {

    return `Type:${inlineShape.Type}, 尺寸:${inlineShape.Width}x${inlineShape.Height}, 地址:${inlineShape.ID}`;

}



// ❸ 日志保存(64位版路径优化)

function saveDebugLog(logs) {

    const fso = new ActiveXObject("Scripting.FileSystemObject");

    const desktop = fso.GetAbsolutePathName("Desktop");

    const ts = fso.CreateTextFile(desktop + "\\WPS64_Debug.log", true);

    logs.forEach(line => ts.WriteLine(line.replace(/\u0000/g, ""))); // 过滤COM空字符

    ts.Close();

}    

添加代码之后的WPS宏编辑器界面效果:

代码中增加了ThisDocument_Document_Open()函数,用于调用centerAllImages()函数执行,如果centerAllImages()不能直接执行,就运行ThisDocument_Document_Open()。可以先在此页面上测试代码的运行效果。

执行结果是:

(二)代码解释

1. 事件触发

function ThisDocument_Document_Open() {

    centerAllImages();

}

功能:文档打开时自动运行centerAllImages函数(通过Document_Open事件触发)。

适用场景:每次打开文档时自动处理图片居中,无需手动运行宏。

2.核心函数:centerAllImages

(1)初始化与文档校验

const doc = Application.ActiveDocument;

if (!doc) return alert("请先打开文档");

const debugLog = ["=== WPS 64位版图片诊断报告 ==="];

const imageList = [];

作用:获取当前活动文档,初始化调试日志和图片列表。

关键变量:

debugLog:记录扫描过程中的详细信息(用于调试)。

imageList:存储所有识别到的图片对象。

(2)三阶段图片扫描

代码分三部分扫描文档中的图片,覆盖 正文、文本框、表格 三大场景:

❶ 正文图片扫描

for (let i = 1; i <= doc.Content.InlineShapes.Count; i++) {

    const inlineShape = doc.Content.InlineShapes.Item(i);

    const isValid = validateImage(inlineShape, "正文", i, debugLog);

    if (isValid) imageList.push(inlineShape);

}

对象:doc.Content.InlineShapes(正文内的嵌入式图片集合)。

遍历方式:索引循环(for...i++),兼容 WPS 的 COM 对象模型。

验证:调用validateImage函数判断是否为有效图片。

❷ 文本框图片扫描

for (let s = 1; s <= doc.Shapes.Count; s++) {

    const shape = doc.Shapes.Item(s);

    if (shape.Type !== 17) continue; // 仅处理文本框(Type=17)

    const tfRange = shape.TextFrame2.TextRange;

    for (let i = 1; i <= tfRange.InlineShapes.Count; i++) {

        const inlineShape = tfRange.InlineShapes.Item(i);

        const isValid = validateImage(inlineShape, `文本框[${shape.Name}]`, i, debugLog);

        if (isValid) imageList.push(inlineShape);

    }

}

对象:doc.Shapes(文档中的所有形状,过滤出文本框Type=17)。

嵌套扫描:进入文本框内部的TextFrame2.TextRange,扫描其中的嵌入式图片。

❸ 表格图片扫描

for (let t = 1; t <= doc.Tables.Count; t++) {

    const table = doc.Tables.Item(t);

    for (let r = 1; r <= table.Rows.Count; r++) {

        for (let c = 1; c <= table.Columns.Count; c++) {

            const cell = table.Cell(r, c);

            for (let i = 1; i <= cell.Range.InlineShapes.Count; i++) {

                const inlineShape = cell.Range.InlineShapes.Item(i);

                const isValid = validateImage(inlineShape, `表格[${t}表${r}行${c}列]`, i, debugLog);

                if (isValid) imageList.push(inlineShape);

            }

        }

    }

}

对象:doc.Tables(文档中的表格),逐层遍历行、列、单元格。

定位:记录图片所在的表格、行、列位置(如表格[1表2行3列])。

(4)图片验证核心:validateImage

function validateImage(inlineShape, locationPrefix, index, debugLog) {

    const type = inlineShape.Type;

    const isImage = [3, 5, 13, 2025].includes(type); // 关键:允许的图片Type值

    const size = `${inlineShape.Width}x${inlineShape.Height}`;

    debugLog.push(`[${isImage ? "✅" : "❌"}] ${locationPrefix}-${index} | Type:${type} | 尺寸:${size}`);

    return isImage && inlineShape.Width > 10 && inlineShape.Height > 10; // 过滤无效尺寸

}

Type 值列表:

  1. 3:公式 / 部分截图(需结合尺寸判断,用户自定义添加)。
  2. 5:嵌入式截图(常规粘贴的图片)。
  3. 13:浮动式图片(通过 “插入图片” 添加的图片)。

2025:WPS 64 位版新增的高 DPI 截图类型。

过滤条件:尺寸大于 10x10 像素(排除图标、占位符等小对象)。

(5)居中执行与结果反馈

imageList.forEach((inlineShape, index) => {

    inlineShape.Range.Paragraphs.Alignment = 1; // 1=居中

    debugLog.push(`[${index + 1}] 已居中:${getImageInfo(inlineShape)}`);

});

alert(`✨ 完成!\n\n${debugLog.join('\n')}`);

居中逻辑:通过设置图片所在段落的对齐方式为 “居中”(Alignment = 1)。

兼容性:嵌入式图片依赖段落格式居中,浮动图片需额外计算坐标(代码中未体现,可能需后续优化)。

3.辅助函数与细节

(1)错误处理与日志

catch (e) {

    alert(`❌ 底层错误:${e.message}`);

    saveDebugLog(debugLog.concat(`错误堆栈:${e.stack}`)); // 保存日志到桌面

}

function saveDebugLog(logs) {

    const fso = new ActiveXObject("Scripting.FileSystemObject");

    const desktop = fso.GetAbsolutePathName("Desktop");

    const ts = fso.CreateTextFile(desktop + "\\WPS64_Debug.log", true);

    logs.forEach(line => ts.WriteLine(line.replace(/\u0000/g, "")));

}

作用:捕获代码执行中的错误,生成详细日志(路径:桌面WPS64_Debug.log)。

用途:调试时通过日志分析未识别图片的原因(如 Type 值错误、尺寸过小)。

(2)图片信息获取

function getImageInfo(inlineShape) {

    return `Type:${inlineShape.Type}, 尺寸:${inlineShape.Width}x${inlineShape.Height}, 地址:${inlineShape.ID}`;

}

作用:记录图片的类型、尺寸和唯一标识(ID),用于调试定位。

4.代码特点与适用场景

(1)技术特点

兼容性:针对 WPS 64 位版设计,使用索引循环遍历 COM 对象(如InlineShapes.Item(i))。

全面性:覆盖正文、文本框、表格三大场景,支持多层嵌套图片。

调试性:详细的日志记录,方便排查 “未找到图片” 等问题(如 Type 值是否包含正确类型)。

(2)适用场景

图片来源:截图粘贴(嵌入式)、插入本地图片(浮动式)、文本框 / 表格内的图片。

格式要求:文档需保存为.docm(启用宏的格式),宏安全设置为 “低” 或允许运行。

5.可能的问题与优化

(1)Type 值问题

现状:代码中[3, 5, 13, 2025]是经验值,不同 WPS 版本的 Type 值可能不同(如旧版 Type=3 可能是公式,需结合尺寸和日志判断)。

优化:通过debugLog输出所有 Shape 的 Type 值,动态调整允许的 Type 列表。

(2)浮动图片居中

不足:当前代码通过段落居中处理嵌入式图片,浮动图片需额外计算坐标(如shape.Left = (页面宽度 - 图片宽度)/2)。

改进:添加对Shape(浮动图片)的单独处理逻辑,区分嵌入式和浮动式图片的居中方式。

6.使用建议

(1)调试步骤:

运行宏后查看桌面日志WPS64_Debug.log,确认图片的 Type 值是否在允许列表内。

若未找到图片,检查右键图片的 “文字环绕” 是否为 “嵌入型”(嵌入式图片)或 “浮于文字上方”(浮动式图片)。

(2)版本兼容:

若提示TextFrame2不存在,可能是 WPS 旧版,需改用TextFrame。

64 位版推荐使用Type=5(嵌入式截图)和Type=13(浮动图片),避免依赖 Type=3。

(3)安全设置:

保存文档为.docm,在 “开发工具→宏安全性” 中设置为 “禁用无数字签署的宏”(推荐)。

新建组件并添加到选项卡中

这个方式在我的另外一篇文章中已经讲解过了,具体的可以参照CSDN文章:在WPS中通过JavaScript宏(JSA)调用本地DeepSeek API优化文档教程:在WPS中通过JavaScript宏(JSA)调用本地DeepSeek API优化文档教程_wps调用api-CSDN博客

【文件】选项卡 --> 【选项】,之后如下图:

创建成功之后:

三、常见问题预判

问题现象

原因分析

解决方案

嵌入式图片未居中

段落格式被其他样式覆盖

手动右键图片 > 段落 > 居中,确认代码生效后排查样式冲突

浮动图片偏移

页边距计算错误

改为 shape.Left = doc.PageSetup.PageWidth / 2 - shape.Width / 2(更简洁)

日志显示无图片

图片被包裹在文本框 / 表格

新增文本框 / 表格内图片的递归查找(需进一步定制)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

搏博

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值