转换插件

将文档转换为 45 种目标格式

Converter 插件将 Doconut 转变为文档转换服务。它提供公共 DocumentConverter 门面的引擎,并且(可选)提供一个带有自身 HTTP 合约的即插即用小部件,使您可以从 C#、从该小部件或从自行编写的前端进行文档转换。

安装包

安装最新的稳定版 Converter 插件:

bash
dotnet add package Doconut.NETStandard.Converter

要将插件固定到当前的 26.8.0 版本,请单独指定版本号:

bash
dotnet add package Doconut.NETStandard.Converter --version 26.8.0

保持 Converter 包的版本与 Doconut.NETStandard 相同。包 ID 为 Doconut.NETStandard.Converter;.26.8.0 只出现在下载的 .nupkg 文件名中。

注册插件

没有 AddConverter() 方法——Doconut 的插件模型是统一的。每个插件,包括 Converter,都是通过相同方式注册的:在 AddDoconut() 中调用 AddPlugin<TPlugin>()。ConverterPlugin 随其自己的 NuGet 包 Doconut.NETStandard.Converter 提供,安装在基础查看器包旁边。

csharp
builder.Services.AddDoconut(options =>
{
    options.LicensePath = "Doconut.Viewer.lic";
    options.AddPlugin<Doconut.Plugins.Converter.ConverterPlugin>();
});

如果缺少许可证、使用旧的 TRIAL 文件,或使用未授予 Converter 功能的非临时许可证,此调用将在启动时抛出异常——在 AddDoconut() 内部抛出的 InvalidOperationException,在应用处理请求之前。接受临时的 Demo/NFR 注册;在其日历到期后,转换仍可使用,但输出会带有水印。没有静默的免费层。请参阅 许可证设置 了解许可证的加载方式。

从 C# 转换

每次转换都会返回一个定位在 0 的可寻址 MemoryStream,可立即读取或复制。随时从依赖注入中解析 DocumentConverter——它本质上是无状态的,因此单个实例可以安全地在请求之间复用。

viewer.Converter.GetConverter() 在此不存在。转换不再通过 viewer 实例访问:请注入 Doconut.DocumentConverter。

csharp
// Inject DocumentConverter; its constructor is internal, so never `new` it.
Stream pdf = await converter.ConvertAsync("contract.docx", ConversionTarget.Pdf, ct: ct);
csharp
// sourceExtension includes the leading dot. password is null unless the document is protected.
Stream png = await converter.ConvertAsync(upload, ".xlsx", ConversionTarget.Png, password: null, ct: ct);
csharp
Stream html = await converter.WordToHtmlAsync("report.docx", ct);
csharp
Stream docx = await converter.HtmlToWordAsync(html, ConversionTarget.Docx, ct);

有两个容易出错的细节:流重载中的 sourceExtension 必须包含前导点(例如 ".xlsx",而不是 "xlsx")——转换器会将其与格式目录匹配,缺少点的扩展名将无法解析。并且尽管名称中含有 WordToHtmlAsync,它返回的是 Task<Stream>,而不是 Task<string>——您会得到 HTML 文档(图像以 Base64 嵌入)作为流,这与其他所有转换结果相同。

目标格式

ConversionTarget(命名空间 Doconut.Configs.Conversion)包含 45 个成员:

text
Pdf, Docx, Doc, Html, Xlsx, Pptx, Png, Jpeg, Csv, Tiff, Bmp, Gif, Svg, Xml,
Txt, Xls, Jp2, Rtf, Odt, Ods, Odp, Epub, Xps, Webp, Msg, Eml, Emlx, Mhtml,
Xlsm, Xlsb, Ppt, Docm, Dot, Dotx, Dotm, Vsdx, Vssx, Vstx, Vsdm, Vssm, Vstm,
Vdx, Vsx, Vtx, Ico

此枚举覆盖了所有源族。之前的库为每个族提供了单独的 *ConfigConverter 类型——WordConfigConverter、ExcelConfigConverter 等——每个都有自己的嵌套 EnTargetFormat 枚举,以及用于输入的 SourceFormatConverter 枚举。所有这些都已移除;请参阅 迁移指南。

并非每种源格式都能转换为每种目标格式——插件将每个源的格式族(Word、Excel、PowerPoint、PDF、CAD、图像、电子邮件、图表、项目/任务、PSD、网页文档)映射到其固定的允许目标集合。不要将此枚举硬编码为 UI 的目标列表:?convert=open 会返回刚上传文件的实际 allowedTargets,应以此来驱动选择器。

Drop-in 小部件

小部件的 ?convert=open|run|download 端点默认是可选且未启用 —— 默认安全。请在服务器端启用它们,并同时进行插件注册:

csharp
builder.Services.AddDoconut(options =>
{
    options.LicensePath = "Doconut.Viewer.lic";
    options.AddPlugin<Doconut.Plugins.Converter.ConverterPlugin>();
    options.AddConverterWidget(widget =>
    {
        widget.MaxUploadMb = 25;
    });
});
html
<div id="doconut-convert"></div>
<script src="/doconut-res/js/doconutConverter.js"></script>
<script>
  Doconut.convert('#doconut-convert', { basePath: '/doconut', resPath: '/doconut-res', maxUploadMb: 25 });
</script>

如果未调用 AddConverterWidget(),这三个 ?convert= 端点会返回 404 —— 但 JS 文件本身仍会被提供(它是一个普通的嵌入式静态资源;只有它所调用的端点受到限制)。AddConverterWidget() 仍然需要注册 Converter 插件并拥有授予 Converter 的许可证 —— 它本身并不授予转换权限。

自定义小部件

传递给 Doconut.convert(selector, options) 的初始化选项:

选项类型默认值备注
basePathstring/doconut?convert= 端点的基础路径;必须与实际挂载 UseDoconut() 的 ASP.NET 分支相匹配(通常通过 MiddlewarePath 协调)
resPathstring/doconut-res为保持与其他 Doconut 小部件的配置一致性而接受;转换小部件目前并未基于它构建任何 URL
maxUploadMbnumber25仅在客户端进行预检查 —— 在上传前拒绝超出大小的文件。服务器会独立强制其自身上限,若超出则返回 413
licenseUrlstring | nullnull设置后,会将结果页面的水印提示转换为指向该 URL 的链接
labelsobject{}覆盖小部件的英文默认字符串的任意子集(拖拽文字、按钮、aria-live 通知、错误信息)

回调函数:

回调触发时机负载
onReady()小部件已渲染其空闲/拖拽界面—
onSourceLoaded({ token, pages, sourceExt, allowedTargets })?convert=open 成功时源会话令牌、页数、源扩展名(不含前导点)、允许的目标列表
onConverted({ downloadToken, resultToken, resultPages, downloadName, watermarked, target })?convert=run 成功时与运行响应相同的字段,外加请求的 target
onDownload({ downloadName, downloadToken })用户点击下载链接时与浏览器的原生下载同时触发 —— 不会拦截或替代它
onError({ phase, message })打开或运行请求失败时phase 为 'open' 或 'run';message 为已清理的服务器错误信息(或上传大小预检查的客户端信息)

Doconut.convert() 返回小部件实例本身 —— 保存该实例以编程方式控制小部件:

javascript
const conv = Doconut.convert('#doconut-convert', { basePath: '/doconut' });
conv.reset();         // back to the idle/drop screen; does not re-fire onReady
conv.loadFile(file);  // starts the flow with a File object; no-op unless currently idle
conv.destroy();       // removes listeners, empties the mount; the instance is unusable after this

构建自己的前端

小部件只是此 HTTP 合约的客户端 —— 直接基于它构建自己的前端以获得不同的用户体验。所有三个路由都位于挂载 UseDoconut() 的 ASP.NET 分支下(通常是 /doconut):

路由用途成功响应
POST ?convert=open (multipart, field file)上传并打开源文档以进行预览200 — { token, pages, sourceExt, allowedTargets }
POST ?token=<token>&convert=run&target=<ext>将已存储的源转换为 target200 — { downloadToken, resultToken, resultPages, downloadName, watermarked }
GET ?convert=download&token=<downloadToken>流式传输已转换的文件200 — file bytes, Content-Disposition: attachment, Cache-Control: no-store

上传的源字节会在服务器端存储,具有 30 分钟的 TTL;一旦该时间窗口过去,run 将返回 404,文件必须重新打开。转换后的结果也保存在同一存储中 —— 转换完成后,downloadToken 将获得新的 30 分钟有效期 —— 而 resultToken 是普通的查看器会话令牌,其生命周期遵循查看器的会话缓存,独立于存储。

open 响应中的 sourceExt 不带前导点(例如 "docx")—— 与 DocumentConverter.ConvertAsync 的 sourceExtension 参数要求带点的约定相反。

失败模式(按路由分组):

路由状态码何时响应体
any404小部件未启用(从未调用 AddConverterWidget())—— 在任何三个路由分发前即检查仅状态码
any405HTTP 方法错误(open/run 需要 POST;download 需要 GET)仅状态码
open413上传的文件超过 MaxUploadMb{ "error": "File is too large." }
open400没有 multipart 正文、没有文件,或源扩展名无法转换{ "error": "..." }
run400令牌格式错误(不是 GUID),或 target 无法解析为 ConversionTarget{ "error": "Invalid token." } / { "error": "Unknown target format." }
run400target 不在源的 allowedTargets 列表中{ "error": "That target format is not available for this file." }
run404已存储的上传已过期(30 分钟 TTL)或令牌从未打开{ "error": "Upload expired — please re-open the file." }
open, run500内部处理失败{ "error": "<sanitized message>" } — 与其他 Doconut 错误路径相同的清理方式;永不泄露内部引擎名称
download400令牌格式错误(不是 GUID)仅状态码
download404未知或已过期的下载令牌仅状态码

资源所有权

转换器返回一个可寻址的 MemoryStream,其位置为零。调用方拥有该流,并应在复制或返回其内容后进行释放。DocumentConverter 服务本身是无状态的,并通过依赖注入解析;不要手动构造或释放该服务。

对于网页小部件,上传和下载的缓存各自拥有独立的 30 分钟 TTL。查看器的 resultToken 则遵循查看器会话的生命周期。关闭查看器结果不会删除仍然有效的下载缓存,重置浏览器小部件也不会延长任一 TTL。

故障排除

症状检查
解析 DocumentConverter 失败ConverterPlugin 注册发生在 AddDoconut() 内部
应用程序在启动期间失败加载的许可证授予 Converter
流转换提示格式不受支持sourceExtension 包含前导点
小部件 JavaScript 加载成功,但请求返回 404AddConverterWidget() 未被调用
小部件请求使用了错误的 URLbasePath 与映射 UseDoconut() 的分支匹配
目标缺失使用 convert=open 返回的 allowedTargets;并非所有源都支持每个枚举目标
下载已过期重复 convert=open/convert=run;缓存令牌是有意临时的

水印

注册了 ConverterPlugin 后,主机的许可证处于以下三种状态之一:

许可证状态启动门槛转换输出
付费查看器许可证授予 Converter,且在有效期内通过干净 — watermarked: false
活跃的评估(演示/NFR)许可证通过转换成功,带有评估水印 — watermarked: true
未授权、旧版 TRIAL 文件,或不授予 Converter 的非临时许可证应用程序永不启动 — 如上所述的启动门槛会抛出异常—
已过期的临时/演示许可证注册在过期后仍然有效转换时带有评估水印 — watermarked: true

两条调用路径都依据相同的规则计算该标志:DocumentConverter 的 C# 外观层内部根据许可证的 IsViewerLicensed 和 IsTemporary 状态得出该标志,而小部件的 ?convert=run 处理程序则进行等价检查(IsViewerLicensed && !IsTrial && !IsTemporary)以填充返回的 watermarked 字段。可以在购买前使用评估许可证构建并端到端测试集成——唯一变化的是输出字节。

此页面对您有帮助吗?