# # Image-Based 打印

## # 概述

Foxit PDF SDK for Web 在 UIExtension 层提供了 `<print:print-dialog>` 打印组件，其实现原理是根据用户的选项导出 PDF，并通过浏览器进行打印。然而，部分浏览器（特别是 iOS 系统中的 Safari）在处理 PDF 打印时存在兼容性问题。为解决这一问题，Foxit PDF SDK for Web 提供了基于图像的打印功能（image-based printing）作为替代方案。

> 技术说明： `<print:print-dialog>` 组件内部使用了底层接口来导出 PDF，但该接口目前未对外开放。如果您需要直接控制 PDF 的导出与打印流程，建议使用 `PDFViewer.print` 接口替代。

## # PDFViewer.print 接口

Foxit PDF SDK for Web 不仅提供了 UI 层的打印组件，还提供了底层打印接口 `PDFViewer.print`。该接口通过将 PDF 页面转换为图像后再进行打印，有效解决了部分浏览器在 PDF 打印过程中的兼容性问题。

### # 技术原理

与默认的 `<print:print-dialog>` 组件不同，`PDFViewer.print` 接口采用了不同的技术实现路径：

- `<print:print-dialog>` 组件：利用底层导出 PDF 的接口，将 PDF 文件交由浏览器进行打印。

- `PDFViewer.print` 接口：直接解析 PDF 内容，将页面转换为图像，再通过浏览器的打印功能进行输出。

`PDFViewer.print` 的打印效果可能会略有差异，但此方法能够确保在各种浏览器环境下正常运行，尤其是在存在兼容性问题的浏览器中。

### # 主要优势

- 跨浏览器兼容：有效解决 iOS Safari 等浏览器的兼容性问题，确保打印功能在不同环境下稳定运行。
- 灵活配置：支持自定义页面范围、打印质量和内容类型等参数，满足多样化需求。
- 进度监控：提供打印进度回调功能，方便开发者优化用户体验。
- 区域打印：支持打印页面的指定区域，增强打印的灵活性与精准性。

### # 基本用法

    pdfviewer.print({
        pages: [0, 1],                      // 指定需要打印的页面
        printType: ['page', 'annot'],       // 打印内容类型：页面与注释
        quality: 100,                       // 打印质量设置
        showHeaderFooter: false             // 是否显示页眉页脚
    }, function(message) {
        switch(message.state) {
            case 'start':
                console.log('开始生成页面图像');
                break;
            case 'progress':
                console.log('页面图像已生成', message.pageIndex, message.total);
                break;
            case 'end':
                console.log('完成页面图像生成');
                break;
        }
    });

## # 使用场景

虽然默认的打印组件在大多数情况下都能正常工作，但在某些特定场景下，使用 `PDFViewer.print` 接口会是更好的选择：

1. iOS Safari 浏览器兼容性问题

   - iOS 系统下的 Safari 浏览器对 PDF 打印支持不完善
   - 打印功能无法正常工作或出现异常

2. 其他浏览器兼容性问题

   - 某些浏览器版本对 PDF 打印存在限制
   - 打印预览显示异常或无法正确渲染

3. 跨平台兼容性需求

   - 需要确保在不同浏览器环境下打印功能的一致性
   - 对浏览器兼容性有较高要求的应用场景

4. 底层打印控制需求

   - 需要通过 image-based 方式实现自定义打印逻辑

## # 解决方案

### # 通过 UI Fragments 配置（推荐）

如果您使用 Foxit PDF SDK for Web 的默认 UI 组件，可以通过 UI Fragments 配置来启用 image-based 打印：

    new PDFUI({
        appearance: UIExtension.appearances.adaptive.extend({
            getDefaultFragments() {
                return [{
                    target: '@print:print-dialog',
                    config: {
                        attrs: {
                            'is-image-based': PDFViewCtrl.DeviceInfo.isIOS && PDFViewCtrl.BrowserInfo.isSafari
                        }
                    }
                }]
            }
        })
    })

### # 自定义组件实现

如果您需要在自定义组件中实现打印功能，可直接调用 `PDFViewer.print` 接口:

    pdfviewer.print({
        pages: [0, 1],                      // 指定需要打印的页面
        printType: ['page', 'annot'],       // 打印内容类型：页面与注释
        quality: 100,                       // 打印质量设置
        showHeaderFooter: false             // 是否显示页眉页脚
    })

## # 参数配置

### # 接口参数说明

参数 | 类型 | 说明 | 默认值
--- | --- | --- | ---
`pages` | `Array<number | object>` | 打印页面时可传入页面索引数组或对象；若为对象且包含 rect 属性，则打印指定区域，否则打印整页内容 | 所有页面
`printType` | `Array<string>` | 打印类型，可选值：'page', 'annot', 'stamps', 'form' | ['page']
`progress` | `ProgressComponent | boolean` | 打印进度条显示控制：true 显示默认进度条，false 隐藏进度条，可传入自定义进度组件进行替换 | true
`quality` | `number` | 打印质量设置，可选范围为 100-1000（以百分比表示） | 100
`showHeaderFooter` | `boolean` | 是否显示页眉和页脚（仅 Chrome、FireFox 和 Chromium Edge 支持） | true
`isPortfolio` | `boolean` | 是否为组合文档 | false
`rangeType` | `string` | 打印范围类型 | -
`printer` | `string` | 指定打印机 | undefined

### # 高级用法

#### # 打印指定区域

在某些情况下，可能需要仅打印页面中的特定区域，例如表格或图表，以满足特定业务需求。

    // 打印页面的第 0 页中指定的区域
    pdfviewer.print({
        pages: [{
            pageIndex: 0,
            rect: { x: 100, y: 100, width: 400, height: 300 }
        }],
        printType: ['page'],
        quality: 200
    });

#### # 自定义进度提示

为了优化用户体验，可以自定义打印过程中的进度提示。

    // 创建自定义进度组件
    const customProgress = {
        show: () => console.log('显示进度条'),
        hide: () => console.log('隐藏进度条'),
        updateProgress: (progress) => console.log(`进度: ${progress.current / progress.total * 100}%`)
    };

    pdfviewer.print({
        pages: [0, 1, 2],
        progress: customProgress,
        quality: 150
    });

### # 浏览器检测配置

    // 检测是否为 iOS 设备
    const isIOS = PDFViewCtrl.DeviceInfo.isIOS;

    // 检测是否为 Safari 浏览器
    const isSafari = PDFViewCtrl.BrowserInfo.isSafari;

    // 组合条件判断
    const shouldUseImageBased = isIOS && isSafari;

## # 注意事项

### # 打印效果差异

虽然 `PDFViewer.print` 接口可以提供更好的兼容性，但与默认打印方案相比，其打印效果可能存在差异。启用 image-based 打印后，文字和图形的清晰度可能有所下降，某些细节可能出现模糊或丢失。这是为了提升兼容性所做的必要权衡。

### # 性能影响

Image-based 打印技术需要将 PDF 页面转换为图像，这可能对性能产生影响。打印速度可能变慢，同时内存占用会增加，尤其是在处理大文档时可能出现较明显的延迟。建议根据实际需求调整打印质量参数，以在打印效果和性能之间找到平衡。

### # 内存消耗

高质量的打印可能导致浏览器内存消耗显著增加，特别是在打印质量设置超过 300% 时。处理大文档或高分辨率打印时，需要注意内存使用情况，建议根据实际需求合理调整打印质量参数。

## # 最佳实践

### # 智能选择打印方案

根据浏览器环境动态选择最适合的打印方案：

    // 根据浏览器环境动态选择打印方案
    function getPrintConfig() {
        const isIOS = PDFViewCtrl.DeviceInfo.isIOS;
        const isSafari = PDFViewCtrl.BrowserInfo.isSafari;

        if (isIOS && isSafari) {
            return {
                useImageBased: true,
                quality: 100,
                showHeaderFooter: false
            };
        }

        return {
            useImageBased: false
        };
    }

### # 用户体验优化

为了提升用户体验，可在打印前向用户说明可能的效果差异：

    // 在打印前显示提示信息
    function printWithNotification() {
        const config = getPrintConfig();

        if (config.useImageBased) {
            // 显示兼容性提示
            showNotification('当前浏览器环境将使用兼容模式打印，打印效果可能略有差异');
        }

        // 执行打印
        pdfviewer.print(config);
    }

### # 错误处理

为打印功能添加完善的错误处理机制：

    // 添加错误处理机制
    pdfviewer.print({
        pages: [0, 1],
        printType: ['page', 'annot'],
        quality: 100,
        showHeaderFooter: false
    }).catch(error => {
        console.error('打印失败:', error);
        // 显示错误提示或降级处理
        showErrorMessage('打印失败，请检查打印机设置或重试');
    });

## # 总结

Image-based 打印功能为 Foxit PDF SDK for Web 提供了更强的浏览器兼容性支持，尤其在 iOS Safari 等存在兼容性问题的浏览器环境下。虽然打印效果可能略有差异，但通过合理的配置和完善的错误处理机制，可以为用户提供稳定可靠的打印体验。

在实际开发中，建议根据具体的应用场景和用户需求来选择合适的打印方案，并在必要时向用户说明可能的效果差异。同时，完善的错误处理机制和充分的跨浏览器测试也是确保打印功能稳定性的重要保障。