ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

MuPDF JavaScript API 之 Device 设备接口详解:回调设备、绘制命令与渲染标志

MuPDF JavaScript API 之 Device 设备接口详解:回调设备、绘制命令与渲染标志 MuPDF JavaScript API 之 Device 设备接口详解回调设备、绘制命令与渲染标志【免费下载链接】sumatrapdfSumatraPDF reader项目地址: https://gitcode.com/gh_mirrors/su/sumatrapdf导读Device是 MuPDF JavaScriptWebAssembly绑定中描述如何消费页面绘制指令的统一接口。无论你是想把 PDF 页面绘制到像素图Pixmap、记录到显示列表Display List还是自定义一个纯 JavaScript 的绘制后端都可以通过Device及其派生类型DrawDevice、DisplayListDevice完成。读完本文你将掌握 Device 的构造方式、全部实例方法路径/文本/图像/渐变/遮罩/分组/平铺/图层/结构/元文本等的参数含义与调用示例并理解这些方法在 MuPDF 与 SumatraPDF 中的底层实现脉络。Device 是什么MuPDF 的绘制回调统一协议在 MuPDF 的架构中fitz_deviceDevice是一组设备方法它定义了渲染引擎向输出端交付绘制内容的全部入口。Device.rst文档开篇即明确了这套设计的核心约定所有内置 deviceDrawDevice、DisplayListDevice等都拥有本文列出的方法任何接受 device 的函数也接受一个实现了相同方法的 JavaScript 对象也就是说你可以自己写一个纯 JS 的虚拟设备缺少的方法会被直接忽略因此你只需为自己关心的绘制调用实现回调方法即可。这种鸭子类型设计让 Device 既是类型也是协议内置设备走 C 实现自定义设备走 JS 回调二者可以混用。在 Device.rst 中Device的构造函数签名如下new Device(callbacks)其中callbacks是一个包含回调函数的对象可提供与Device类方法同名的方法没有对应函数的设备调用将被忽略。图形对象与颜色参数约定许多方法以图形对象为参数这些对象由 MuPDF 的类型系统提供Path路径对象见 Path.rst由直线段与贝塞尔曲线构成Text文本对象见 Text.rst由字形glyph序列构成Image图像对象见 Image.rstShade渐变对象见 Shade.rstMatrix变换矩阵见 Matrix.rst如文档示例中反复出现的mupdf.Matrix.identityColorSpace色彩空间见 ColorSpace.rst如mupdf.ColorSpace.DeviceRGB、DeviceGray、DeviceCMYKStrokeState描边状态见 StrokeState.rst。颜色统一以数组形式指定数组的元素个数必须与色彩空间的通道数匹配。例如 DeviceRGB 需要 3 个分量[1, 0, 0]表示纯红、[0, 1, 0]表示纯绿透明度则由单独的alpha参数number控制。裁剪配对的强制约定所有执行裁剪的方法——clipPath()、clipStrokePath()、clipText()、clipStrokeText()、clipImageMask()——都必须与一次popClip()调用配对平衡。文档特别强调在调用close()之前必须保证popClip()的调用次数与裁剪函数的调用次数相等否则会留下未闭合的裁剪状态。构造相关类型DrawDevice 与 DisplayListDevice文档明确指出你可以通过DrawDevice和DisplayListDevice创建其他设备。二者是Device的两个内置实现DrawDevice把绘制命令直接光栅化到目标Pixmap上构造函数接收Matrix从设备空间到像素空间的变换与Pixmap目标像素图DisplayListDevice把绘制命令记录进DisplayList显示列表之后可以反复重放、便于缓存。其类型声明可参考 DrawDevice.rst 与 DisplayListDevice.rst。在 TypeScript 绑定 mupdf.ts 中可以看到二者的实现它们分别包装了 C 导出函数wasm_new_draw_device对应fz_new_draw_device和wasm_new_display_list_device对应fz_new_list_deviceexport class DrawDevice extends Device { constructor(matrix: Matrix, pixmap: Pixmap) { ... } } export class DisplayListDevice extends Device { constructor(displayList: DisplayList) { ... } }Device 构造的底层机制在 mupdf.ts 中Device构造器做了重载传入Pointerfz_device时包装既有 C 指针内置设备走此路径传入DeviceFunctions回调对象时则为回调分配一个自增 id把回调表注册进$libmupdf_device_table并调用wasm_new_js_device(id)生成一个JS 桥接设备。回调接口DeviceFunctions定义在 mupdf.ts所有方法均为可选?正是文档所说任何缺失的方法都会被忽略在类型层面的体现。混合模式常量Blend ModeDevice.BLEND_*常量用于beginGroup()的混合模式参数共 16 个与 PDF 规范的混合模式一一对应常量含义Device.BLEND_NORMAL正常混合Device.BLEND_MULTIPLY正片叠底Device.BLEND_SCREEN滤色Device.BLEND_OVERLAY叠加Device.BLEND_DARKEN变暗Device.BLEND_LIGHTEN变亮Device.BLEND_COLOR_DODGE颜色减淡Device.BLEND_COLOR_BURN颜色加深Device.BLEND_HARD_LIGHT强光Device.BLEND_SOFT_LIGHT柔光Device.BLEND_DIFFERENCE差值Device.BLEND_EXCLUSION排除Device.BLEND_HUE色相Device.BLEND_SATURATION饱和度Device.BLEND_COLOR颜色Device.BLEND_LUMINOSITY明度在 TypeScript 绑定中这些常量被实现为Device.BLEND_MODES数组与同名静态只读属性见 mupdf.ts其顺序与 C 层fz_blend_mode枚举一致beginGroup()会把字符串形式的混合模式名转换成对应的枚举下标ENUMBlendMode(blendmode, Device.BLEND_MODES)再传给 C 层。生命周期与收尾close()device.close()close()通知设备绘制结束并冲刷所有待输出的内容。调用前必须确保裁剪配对平衡popClip()与各裁剪函数的调用次数一致。从源码看它包装的是wasm_close_device→fz_close_deviceC 层会依次调用设备的close回调并释放内部状态。线条图形路径的填充、描边与裁剪路径Path是矢量绘制的基础Device 提供四个相关方法。fillPath填充路径device.fillPath(path, false, mupdf.Matrix.identity, mupdf.ColorSpace.DeviceRGB, [1, 0, 0], true)参数类型说明pathPath要填充的路径对象evenOddboolean使用奇偶规则even-odd rule还是非零环绕数规则non-zero winding number rule确定内部区域ctmMatrix施加的变换矩阵colorspaceColorSpace填充颜色的色彩空间colorColor数组填充颜色alphanumber不透明度opacitystrokePath描边路径device.strokePath(path, {dashes: [5, 10], lineWidth: 3, lineCap: Round }, mupdf.Matrix.identity, mupdf.ColorSpace.DeviceRGB, [0, 1, 0], 0.5 )与fillPath相比多了一个stroke: StrokeState参数。示例中的StrokeState以对象字面量给出dashes为虚线数组[5, 10]lineWidth为线宽 3lineCap为 Round圆头线帽该对象还支持lineJoin、miterLimit等字段完整字段可参考 StrokeState.rst。alpha 0.5表示半透明描边。clipPath裁剪路径device.clipPath(path, true, mupdf.Matrix.identity)以路径为裁剪蒙版裁剪后续图形evenOdd true表示用奇偶规则判定裁剪区域。必须由后续的popClip()配对。clipStrokePath裁剪并描边device.clipStrokePath(path, true, mupdf.Matrix.identity)先用路径的描边区域建立裁剪蒙版。注意示例中第二个参数在文档里标注为strokeStrokeState示例代码传的是布尔值true实际用法应传入一个 StrokeState 对象例如{ lineWidth: 3, lineCap: Round, dashes: [5, 10] }随后同样需要popClip()配对。在 C 层fillPath/strokePath/clipPath/clipStrokePath分别对应wasm_fill_path、wasm_stroke_path、wasm_clip_path、wasm_clip_stroke_path见 mupdf.c最终调用 MuPDF 设备接口fz_fill_path等函数并附上fz_default_color_params。文本填充、描边、裁剪与忽略文本Text对象承载字形信息Device 提供五个相关方法。fillText填充文本device.fillText(text, mupdf.Matrix.identity, mupdf.ColorSpace.DeviceRGB, [1, 0, 0], 1)参数依次为Text对象、变换矩阵ctm、色彩空间、颜色数组、不透明度alpha。strokeText描边文本device.strokeText(text, { dashes: [5, 10], lineWidth: 3, lineCap: Round }, mupdf.Matrix.identity, mupdf.ColorSpace.DeviceRGB, [1, 0, 0], 1 )为文本轮廓施加描边状态。clipText裁剪文本device.clipText(text, mupdf.Matrix.identity)以字形轮廓为蒙版裁剪需要popClip()配对。clipStrokeText裁剪并描边文本device.clipStrokeText(text, { dashes: [5, 10], lineWidth: 3, lineCap: Round }, mupdf.Matrix.identity )以描边后的字形轮廓为蒙版同样需要popClip()配对。ignoreText忽略透明文本device.ignoreText(text, mupdf.Matrix.identity)处理可被搜索、但不应显示的隐形文本典型场景是为扫描件 OCR 叠加的透明文本层——这类文本参与文本提取与搜索但在渲染时被丢弃。C 层对应wasm_ignore_text→fz_ignore_text。渐变fillShadedevice.fillShade(shade, mupdf.Matrix.identity, true, { overPrinting: true })参数类型说明shadeShade渐变对象gradient其定义可参考 Shade.rstctmMatrix变换矩阵alphanumber不透明度文档给出的示例中第三个参数为true但从类型签名看应为number类型的alpha后续对象参数{ overPrinting: true }属于渲染相关的附加选项实际使用中按数字透明度传参更稳妥。图像绘制、蒙版与裁剪fillImage绘制图像device.fillImage(image, mupdf.Matrix.identity, false, { overPrinting: true })图像总是填满单位矩形[0, 0, 1, 1]因此必须通过ctm变换才能以合适的大小和位置绘制。例如用mupdf.Matrix.scale(w, h)或mupdf.Matrix.translate(x, y).scale(w, h)组合出目标变换。fillImageMask填充图像蒙版device.fillImageMask(image, mupdf.Matrix.identity, mupdf.ColorSpace.DeviceRGB, [0, 1, 0], true)图像蒙版image mask是不含颜色的图像在图像不透明的区域用指定颜色填充。参数依次为Image、ctm、色彩空间、颜色、透明度。这是实现着色图章/剪影效果的标准手段。clipImageMask以图像蒙版裁剪device.clipImageMask(image, mupdf.Matrix.identity)用图像的形状不透明区域作为蒙版裁剪后续图形需要popClip()配对。以上三个方法在 C 层分别对应wasm_fill_image、wasm_fill_image_mask、wasm_clip_image_mask见 mupdf.c。裁剪与遮罩popClip / beginMask / endMaskdevice.popClip()弹出由最近一次裁剪操作安装的裁剪蒙版是所有clip*方法clipPath、clipStrokePath、clipText、clipStrokeText、clipImageMask的配对应答。beginMask / endMask软遮罩Soft Maskdevice.beginMask([0, 0, 100, 100], true, mupdf.ColorSpace.DeviceRGB, [1, 0, 1]) // ... 在此之间绘制的图形被收集为遮罩 ... device.endMask()beginMask创建软遮罩beginMask与endMask之间的所有绘制命令被分组并作为裁剪蒙版使用参数类型说明areaRect遮罩区域如[0, 0, 100, 100]luminosityboolean为true时遮罩由所绘制图形的亮度灰度值导出为false时颜色被完全忽略遮罩由组的 alpha 导出colorspaceColorSpace色彩空间colorColor使用的颜色endMask()结束遮罩。软遮罩与硬裁剪的区别在于它利用绘制内容的灰度/透明度产生渐变过渡的遮蔽效果是 PDF 透明模型中的重要机制。组与透明beginGroup / endGroupdevice.beginGroup( [0, 0, 100, 100], mupdf.ColorSpace.DeviceRGB, true, true, Multiply, 0.5 ) // ... 组内绘制命令 ... device.endGroup()beginGroup开始一个透明混合组transparency blending group其概念可参考术语表中的knockout and isolation挖空与隔离与blend mode混合模式参数类型说明areaRect混合区域colorspaceColorSpace组内合成使用的色彩空间isolatedboolean组是否隔离isolated——隔离组先独立合成再与背景混合knockoutboolean组是否挖空knockout——组内元素不与组内其他元素合成blendmodestring与背景合成时使用的混合模式alphanumber组的不透明度blendmode可以是字符串Normal, Multiply, Screen, Overlay, Darken, Lighten, ColorDodge, ColorBurn, HardLight, SoftLight, Difference, Exclusion, Hue, Saturation, Color, Luminosity也可以直接使用枚举常量例如Device.BLEND_NORMALdevice.beginGroup([0, 0, 100, 100], mupdf.ColorSpace.DeviceRGB, true, true, Multiply, 0.5)底层实现上mupdf.ts 的beginGroup会把字符串混合模式经Device.BLEND_MODES索引转换为枚举值再调用wasm_begin_group→fz_begin_group。平铺beginTile / endTiledevice.beginTile([0, 0, 100, 100], [100, 100, 200, 200], 10, 10, mupdf.Matrix.identity, 0) // ... 组内绘制命令被平铺重复 ... device.endTile()beginTile开始一个平铺图案beginTile与endTile之间的绘制命令被分组后在整个页面重复平铺如需把图案限制在特定形状内可配合裁剪蒙版使用。参数类型说明areaRect图案区域viewRect视窗区域xstepnumberx 方向步长ystepnumbery 方向步长ctmMatrix变换矩阵idnumber瓦片缓存标识doc_idnumber文档缓存标识id/doc_id的用途是高效缓存已渲染的瓦片若id为 0 则不做缓存若为非 0则假定id/doc_id唯一标识该瓦片重复渲染时可直接复用缓存结果。C 层对应wasm_begin_tile其返回值为fz_begin_tile_tid的瓦片 id。渲染标志renderFlags仅 mutoolrenderFlags标记为|only_mutool|即主要用于 MuPDF 自带的 mutool 命令行工具场景。device.renderFlags([mask, startcap-undefined], [])set与clear都是字符串数组set中的标志被设置clear中的标志被清除。可选标志名flag names如下maskcoloruncacheablefillcolor-undefinedstrokecolor-undefinedstartcap-undefineddashcap-undefinedendcap-undefinedlinejoin-undefinedmiterlimit-undefinedlinewidth-undefinedbbox-definedgridfit-as-tiled这些标志控制设备处理未定义状态如未指定填充色/描边色/线帽/线宽时的行为以及网格拟合gridfit等渲染细节适用于需要对绘制流做精确后处理的场景。设备色彩空间setDefaultColorSpaces仅 mutoolvar defaultCS new DefaultColorSpaces() defaultCS.setDefaultRGB(defaultCS.getDefaultGray()) device.setDefaultColorSpaces(new DefaultColorSpaces())setDefaultColorSpaces将设备的默认色彩空间集合替换为给定的一组。示例演示了DefaultColorSpaces的典型用法构造对象、查询/修改默认 RGB 与 Gray 空间再应用到设备。DefaultColorSpaces类型的完整定义见 DefaultColorSpaces.rst。图层beginLayer / endLayerdevice.beginLayer(my tag) // ... 该图层的绘制命令 ... device.endLayer()beginLayer(name)以给定名称开始一个标记内容图层marked-content layerendLayer()结束该图层。这对应 PDF 的可选内容组OCG机制常用于多语言文本、可切换的图形元素等按图层组织的文档内容。结构beginStructure / endStructure仅 mutooldevice.beginStructure(Document, my_tag_name, 123) // ... 结构元素内的绘制命令 ... device.endStructure()beginStructure(structure, raw, index)以一个预定义的 PDF 标准结构类型standard structure type、原始标签名和唯一标识符开始结构元素参数类型说明structurestringPDF 预定义的标准结构类型之一rawstring原始标签名indexnumber唯一标识符endStructure()结束标准结构元素。结构信息用于文档的可访问性无障碍阅读与内容语义标注。元文本beginMetatext / endMetatext仅 mutooldevice.beginMetatext(Title, My title) // ... 与该元文本关联的绘制命令 ... device.endMetatext()beginMetatext(meta, text)开始一段元文本meta只能是以下四种之一ActualText实际文本替换显示文本用于可访问性Alt替代文本如图像的 alt 描述Abbreviation缩写形式Title标题endMetatext()结束元文本信息。这与 PDF 的标记内容marked content属性结合为屏幕阅读器等辅助技术提供语义化文本。底层实现与 SumatraPDF 中的实际使用WASM 绑定层从 TypeScript 到 CDevice 类在 mupdf.ts 中完整声明每个方法都做类型检查checkType、checkMatrix、checkColor、checkRect后转发到libmupdf._wasm_*导出函数。C 侧的桥接代码位于 mupdf.c通过VOID(...)/POINTER(...)宏包裹 MuPDF 核心设备接口fz_fill_path、fz_stroke_path、fz_clip_path、fz_fill_text、fz_fill_shade、fz_fill_image、fz_begin_group、fz_begin_tile、fz_begin_layer等。也就是说JS 层的每个 Device 方法最终都汇入 MuPDF C 内核统一的fz_device方法表——这正是任何函数接受 Device 时也接受同方法 JS 对象能够成立的根本原因JS 桥接设备只是把 C 设备方法表中的调用转发回 JavaScript 回调。SumatraPDF 中的设备用法SumatraPDF 基于 MuPDF 渲染引擎构建在桌面端并不走 WASM而是直接调用 C 设备接口。例如 EngineMupdf.cpp 等渲染路径中反复出现fz_new_draw_device(ctx, ctm, pix)——为页面建立一个把绘制指令光栅化到像素图pix的 DrawDevice随后用ctm控制缩放/旋转SvgIcons.cpp 则用fz_new_draw_devicefz_scale把 SVG 图标栅格化成不同尺寸的位图PdfDarkModeCache.cpp 在暗色模式渲染缓存中也使用了 draw device。这些正是本仓库中Device 协议在真实 PDF 阅读器里的典型落地渲染即设备方法被逐条调用的过程。一个可运行的完整思路把 JS 端的能力串起来一个自定义设备的最小形态大致如下const myDevice new mupdf.Device({ close: () { console.log(render done) }, fillPath: (path, evenOdd, ctm, colorspace, color, alpha) { /* 消费路径 */ }, fillText: (text, ctm, colorspace, color, alpha) { /* 消费文本 */ }, fillImage: (image, ctm, alpha) { /* 消费图像 */ }, popClip: () { /* 处理裁剪结束 */ }, }) // 用自定义设备重放一页内容 page.toDisplayList().run(myDevice, mupdf.Matrix.identity) myDevice.close()配合Device的缺省即忽略约定你只需要实现关心的回调就能构建出如提取路径轮廓统计绘制命令实时预览之类的自定义渲染/分析管线而DrawDevice渲染到 Pixmap与DisplayListDevice录制显示列表则覆盖了绝大多数常规栅格化需求。小结与速查Device 是回调协议内置设备方法全集即协议JS 对象可实现子集缺失方法被忽略构造new Device(callbacks)批量渲染用DrawDevice(matrix, pixmap)与DisplayListDevice(displayList)颜色数组形式通道数匹配色彩空间透明度走alpha参数裁剪必须配对每个clipPath/clipStrokePath/clipText/clipStrokeText/clipImageMask都要有对应的popClip()分组/遮罩/平铺beginMask/endMask、beginGroup/endGroup、beginTile/endTile均成对出现混合模式可用Device.BLEND_*常量或等价字符串mutool 专属renderFlags、setDefaultColorSpaces、beginStructure/endStructure、beginMetatext/endMetatext标有|only_mutool|主要服务于命令行工具链底层贯通JS 方法 →wasm_*导出mupdf.c→fz_device方法表SumatraPDF 在 EngineMupdf.cpp 中直接以fz_new_draw_device消费同一协议。进一步阅读完整的 JS 类型清单见 index.rst路径/文本/渐变/图像/描边状态等图形对象的详细定义可分别查阅 Path.rst、Text.rst、Shade.rst、Image.rst 与 StrokeState.rst。【免费下载链接】sumatrapdfSumatraPDF reader项目地址: https://gitcode.com/gh_mirrors/su/sumatrapdf创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表