强曰为道

与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

第 8 章:过滤器与后端

第 8 章:过滤器与后端

过滤器和后端是 CUPS 的核心组件,负责文档格式转换和打印数据传输。本章将深入解析 CUPS 的过滤器系统、后端架构以及自定义过滤器开发。


8.1 过滤器系统概述

8.1.1 过滤器在打印栈中的角色

输入文档 (PDF/PS/Text/Image/Office)
         │
         ▼
┌──────────────────────────────────────────────┐
│              MIME 类型检测                     │
│  /etc/cups/mime.types                        │
│  application/pdf  pdf string(0,"%PDF")       │
├──────────────────────────────────────────────┤
│              过滤器链 (Filter Chain)           │
│                                              │
│  ┌──────────┐   ┌──────────┐   ┌──────────┐│
│  │ 过滤器 1  │──▶│ 过滤器 2  │──▶│ 过滤器 N  ││
│  │ PDF→PS   │   │ PS→光栅  │   │ 光栅→PCL ││
│  └──────────┘   └──────────┘   └──────────┘│
├──────────────────────────────────────────────┤
│              打印机驱动                       │
│  rastertopclx / rastertohp / ...            │
├──────────────────────────────────────────────┤
│              后端 (Backend)                    │
│  usb / socket / ipp / lpd / dnssd           │
└──────────────────────────────────────────────┘
         │
         ▼
      打印机硬件

8.1.2 过滤器与后端文件位置

# 过滤器位置
ls /usr/lib/cups/filter/

# 后端位置
ls /usr/lib/cups/backend/

# MIME 类型定义
cat /etc/cups/mime.types

# MIME 转换规则
cat /etc/cups/mime.convs

# 查看所有过滤器
find /usr/lib/cups/filter -type f -executable

# 查看所有后端
find /usr/lib/cups/backend -type f -executable

8.1.3 核心过滤器列表

过滤器功能输入 → 输出
pdftopsPDF 转 PostScriptapplication/pdf → application/postscript
pdftorasterPDF 转光栅application/pdf → application/vnd.cups-raster
pdftoijsPDF 转 IJSapplication/pdf → application/vnd.cups-command
imagetops图像转 PSimage/* → application/postscript
imagetoraster图像转光栅image/* → application/vnd.cups-raster
texttops文本转 PStext/plain → application/postscript
texttopdf文本转 PDFtext/plain → application/pdf
texttoraster文本转光栅text/plain → application/vnd.cups-raster
pstopdfPS 转 PDFapplication/postscript → application/pdf
pstopsPS 处理application/postscript → application/postscript
gstopxlGS 转 PCL-XLapplication/postscript → application/vnd.hp-pclxl
rastertopclx光栅转 PCL-XLapplication/vnd.cups-raster → application/vnd.hp-pclxl
rastertohp光栅转 PCLapplication/vnd.cups-raster → application/vnd.hp-pcl
imagetopdf图像转 PDFimage/* → application/pdf
mupdftorasterMuPDF 转光栅application/pdf → application/vnd.cups-raster

8.2 MIME 类型系统

8.2.1 MIME 类型定义文件

# MIME 类型定义
cat /etc/cups/mime.types

示例内容

# /etc/cups/mime.types

# PDF 文件检测
application/pdf    pdf string(0,"%PDF")

# PostScript 文件检测
application/postscript    ai eps ps string(0,"%!")

# 纯文本文件检测
text/plain    txt string(0,#!) print("/bin/sh") print("/bin/bash") print("/usr/bin/env")
text/plain    txt asc c cc h hh cpp cxx hxx java pl py rb

# 图像文件检测
image/jpeg    jpg jpeg string(0,\377\330\377\340) string(0,\377\330\377\341)
image/png     png string(0,\211PNG)
image/gif     gif string(0,GIF87a) string(0,GIF89a)
image/tiff    tif tiff string(0,MM\000\052) string(0,II\052\000)
image/bmp     bmp string(0,BM)

# HP-GL/2 文件
application/vnd.hp-HPGL    hpgl string(0,IN;) string(0,IN\n)

# CUPS 光栅数据
application/vnd.cups-raster    string(0,RaSt)
application/vnd.cups-pdf    string(0,%PDF)

# OpenDocument
application/vnd.oasis.opendocument.text    odt zip(string(0,PK\003\004),filename="mimetype",content="application/vnd.oasis.opendocument.text")

# Microsoft Office
application/msword    doc zip(string(0,PK\003\004),filename="[Content_Types].xml",content="word/")
application/vnd.openxmlformats-officedocument.wordprocessingml.document    docx zip(string(0,PK\003\004),filename="[Content_Types].xml",content="word/")

8.2.2 MIME 类型检测规则

# MIME 类型检测语法
# 类型  扩展名  检测规则

# 检测规则类型:
# string(offset, "content")  - 字符串匹配
# char(offset, value)         - 字节匹配
# icalendar(offset)           - iCalendar 检测
# pdf(offset)                 - PDF 特征检测
# zip(offset, filename, content) - ZIP 内文件检测

# 示例:
# 检测 PDF 文件 (%PDF 在文件开头)
application/pdf    pdf string(0,"%PDF")

# 检测 ZIP 文件中的 Office 文档
application/vnd.openxmlformats-officedocument.wordprocessingml.document
    docx zip(string(0,PK\003\004),
             filename="[Content_Types].xml",
             content="word/")

# 检测 ELF 二进制文件
application/x-executable    * string(0,\177ELF)

8.2.3 自定义 MIME 类型

# 添加自定义 MIME 类型
sudo vim /etc/cups/mime.types

# 添加自定义文件类型
application/x-custom    cust string(0,"CUSTOM1.0")

# 添加新的 Office 格式
application/vnd.lotus-1-2-3    wks wk1 wk3 wk4 string(0,\000\000\002\000)

8.3 MIME 转换规则

8.3.1 转换规则文件

# MIME 转换规则
cat /etc/cups/mime.convs

示例内容

# /etc/cups/mime.convs

# PDF 转 PostScript
application/pdf    application/postscript    33    pdftops

# PDF 转 CUPS Raster
application/pdf    application/vnd.cups-raster    50    pdftoraster

# PostScript 转 CUPS Raster
application/postscript    application/vnd.cups-raster    50    gstoraster

# 文本转 PostScript
text/plain    application/postscript    33    texttops

# 文本转 CUPS Raster
text/plain    application/vnd.cups-raster    50    texttoraster

# 图像转 PostScript
image/jpeg    application/postscript    33    imagetops
image/png     application/postscript    33    imagetops
image/gif     application/postscript    33    imagetops

# 图像转 CUPS Raster
image/jpeg    application/vnd.cups-raster    50    imagetoraster

# PostScript 转 PCL
application/postscript    application/vnd.hp-pcl    50    gstopxl

# PostScript 转 PDF
application/postscript    application/pdf    33    pstopdf

# CUPS Raster 转 PCL-XL
application/vnd.cups-raster    application/vnd.hp-pclxl    50    rastertopclx

# CUPS Raster 转 HP PCL
application/vnd.cups-raster    application/vnd.hp-pcl    50    rastertohp

8.3.2 转换规则语法

# 语法格式:
# 源类型    目标类型    优先级    过滤器程序

# 参数说明:
# 源类型: 输入文档的 MIME 类型
# 目标类型: 输出文档的 MIME 类型
# 优先级: 数字越小优先级越高 (0-100)
# 过滤器: 转换程序路径或名称

# 优先级说明:
# 0-10:    系统保留
# 11-30:   高优先级
# 31-50:   中优先级
# 51-70:   低优先级
# 71-100:  很少使用

8.3.3 自定义转换规则

# 添加自定义转换规则
sudo vim /etc/cups/mime.convs

# 添加 Office 文档转换规则
application/msword    application/pdf    50    doc2pdf
application/vnd.openxmlformats-officedocument.wordprocessingml.document    application/pdf    50    docx2pdf

# 添加自定义图像转换规则
application/x-custom    application/postscript    33    custom2ps

8.4 过滤器工作流程

8.4.1 完整转换链示例

场景:打印 PDF 文件到 PCL 打印机

输入: document.pdf (application/pdf)
     │
     ▼
过滤器 1: pdftops
     │  输入: application/pdf
     │  输出: application/postscript
     │  优先级: 33
     ▼
过滤器 2: gstopxl
     │  输入: application/postscript
     │  输出: application/vnd.hp-pclxl
     │  优先级: 50
     ▼
后端: socket
     │  传输: application/vnd.hp-pclxl
     │  目标: socket://192.168.1.100:9100
     ▼
打印机: HP LaserJet Pro M404

8.4.2 查看转换链

# 使用 cupsfilter 查看转换链
cupsfilter -m application/pdf -p myprinter /dev/null 2>&1

# 输出示例:
# pdftops (PID 1234) application/pdf → application/postscript
# pstops (PID 1235) application/postscript → application/postscript
# gstopxl (PID 1236) application/postscript → application/vnd.hp-pclxl

# 使用 verbose 模式查看详细信息
cupsfilter -v -m application/pdf -p myprinter /dev/null

8.4.3 测试过滤器

# 手动测试过滤器
# PDF 转 PostScript
cupsfilter -m application/postscript document.pdf > output.ps

# PDF 转光栅
cupsfilter -m application/vnd.cups-raster document.pdf > output.raster

# 文本转 PostScript
echo "Hello World" | cupsfilter -m application/postscript > output.ps

# 使用特定打印机配置
cupsfilter -d myprinter -m application/postscript document.pdf > output.ps

8.5 常用过滤器详解

8.5.1 pdftops

# pdftops 将 PDF 转换为 PostScript
# 使用 Poppler 库实现

# 测试 pdftops
pdftops document.pdf output.ps

# 选项:
# -level1      使用 PostScript Level 1
# -level2      使用 PostScript Level 2
# -level3      使用 PostScript Level 3 (默认)
# -nocrop      不裁剪页面
# -expand      扩展页面
# -noshrink    不收缩页面
# -nocenter    不居中页面
# -landscape   横向打印
# -paper size  设置纸张大小
# -form        生成表单

# 测试命令
pdftops -level2 -paper A4 document.pdf output.ps

8.5.2 pdftoraster

# pdftoraster 将 PDF 转换为 CUPS Raster 格式
# 使用 Poppler 或 MuPDF

# 测试 pdftoraster
pdftoraster document.pdf > output.raster

# CUPS Raster 格式:
# - 包含页面头信息
# - 包含光栅图像数据
# - 支持多种颜色空间
# - 支持多种分辨率

8.5.3 imagetops

# imagetops 将图像转换为 PostScript
# 支持 JPEG, PNG, GIF, BMP, TIFF 等

# 测试 imagetops
imagetops image.jpg > output.ps

# 选项通过环境变量传递:
# FINAL_CONTENT_TYPE  输出内容类型
# PRINTER             打印机名称
# copies              打印份数
# media               纸张大小
# number-up           每页多版
# orientation-requested 方向
# page-bottom          下边距
# page-left            左边距
# page-right           右边距
# page-top             上边距
# scaling              缩放比例
# sides                双面打印

8.5.4 texttops

# texttops 将纯文本转换为 PostScript

# 测试 texttops
texttops document.txt > output.ps

# 选项:
# -c columns     每页列数
# -f font-name   字体名称
# -m             使用等宽字体
# -n copies      打印份数
# -p             纵向打印
# -r             横向打印
# -s             严格换页

# 示例
texttops -f Courier -c 80 document.txt > output.ps

8.5.5 Ghostscript 过滤器

# Ghostscript 相关过滤器
ls /usr/lib/cups/filter/ | grep -i ghost

# gstoraster: PS/PDF 转 CUPS Raster
gstoraster document.ps > output.raster

# gstopxl: PS 转 PCL-XL
gstopxl document.ps > output.pxl

# gstopclm: PS 转 PCLm
gstopclm document.ps > output.pclm

# Ghostscript 设备列表
gs -h 2>&1 | grep -A 50 "Available devices:" | head -30

8.6 后端系统

8.6.1 后端概述

后端功能URI 格式
usbUSB 打印机usb://Make/Model?serial=xxx
socketTCP/IP Socketsocket://host:port
ippIPP 协议ipp://host/ipp/print
ippsIPP over TLSipps://host/ipp/print
lpdLPD 协议lpd://host/queue
httpHTTP 协议http://host/path
httpsHTTPS 协议https://host/path
smbSamba 共享smb://user:pass@host/printer
dnssdDNS-SD 发现dnssd://name._ipp._tcp.local./
beh后备后端beh:/path/to/real/backend
serial串口serial:/dev/ttyS0
parallel并口parallel:/dev/lp0
hpHP 打印机hp:/net/Model?ip=addr
hpfaxHP 传真hpfax:/net/Model?ip=addr
snmpSNMP 发现snmp://host

8.6.2 后端权限

# 后端程序需要特殊权限
# 查看后端权限
ls -la /usr/lib/cups/backend/

# 输出示例:
# -rwxr-xr-x 1 root root  45K usb
# -rwxr-xr-x 1 root root  34K socket
# -rwxr-xr-x 1 root root  56K ipp
# -rwsr-xr-x 1 root root  23K serial    # SUID 位

# USB 后端需要特殊权限
sudo chmod 700 /usr/lib/cups/backend/usb
sudo chown root:root /usr/lib/cups/backend/usb

# 串口后端需要 SUID 位
sudo chmod 4755 /usr/lib/cups/backend/serial

8.6.3 后端测试

# 测试后端
# 列出可用后端
lpinfo -v

# 测试 socket 后端
/usr/lib/cups/backend/socket 1 1 user "test" 1 "" /tmp/test.ps

# 测试 IPP 后端
/usr/lib/cups/backend/ipp 1 1 user "test" 1 "" /tmp/test.ps

# 测试设备发现
/usr/lib/cups/backend/snmp
/usr/lib/cups/backend/dnssd

8.6.4 后备后端 (beh)

# 后备后端提供故障转移功能
# 当主后端失败时,自动切换到备选后端

# URI 格式:
# beh:/number_of_retries/delay/original_backend original_uri

# 示例:重试 3 次,每次间隔 5 秒
sudo lpadmin -p MyPrinter -E \
  -v "beh:/3/5/socket/socket://192.168.1.100:9100" \
  -P /usr/share/ppd/HP/hp-laserjet_pro_m404.ppd

# 使用 IPP 后备
sudo lpadmin -p MyPrinter -E \
  -v "beh:/3/5/ipp/ipp://192.168.1.100/ipp/print" \
  -m "everywhere"

8.7 自定义过滤器开发

8.7.1 过滤器接口规范

# CUPS 过滤器命令行接口:
# filter job-id user title copies options [file]

# 参数说明:
# job-id   - 任务 ID
# user     - 用户名
# title    - 文档标题
# copies   - 打印份数
# options  - 打印选项(空格分隔)
# file     - 输入文件(可选,不提供则从 stdin 读取)

# 输入: stdin 或 file
# 输出: stdout
# 日志: stderr

# 返回值:
# 0 - 成功
# 1 - 错误(任务将被取消)
# 2 - 错误(任务将被重试)

8.7.2 基础过滤器模板

#!/bin/bash
# /usr/lib/cups/filter/myfilter
# 简单的自定义过滤器示例

# 获取参数
JOB_ID="$1"
USER="$2"
TITLE="$3"
COPIES="$4"
OPTIONS="$5"
FILE="$6"

# 记录日志
echo "DEBUG: Filter started - Job: $JOB_ID, User: $USER, Title: $TITLE" >&2

# 处理输入
if [ -n "$FILE" ]; then
    INPUT="$FILE"
else
    INPUT="/dev/stdin"
fi

# 执行转换(这里只是示例,实际应实现转换逻辑)
cat "$INPUT"

echo "DEBUG: Filter completed successfully" >&2
exit 0
# 安装过滤器
sudo cp myfilter /usr/lib/cups/filter/myfilter
sudo chmod 755 /usr/lib/cups/filter/myfilter
sudo chown root:root /usr/lib/cups/filter/myfilter

8.7.3 Python 过滤器示例

#!/usr/bin/env python3
# /usr/lib/cups/filter/pdf-watermark.py
# PDF 水印过滤器

import sys
import os
import subprocess
from pathlib import Path

def add_watermark(input_file, watermark_text):
    """为 PDF 添加水印"""
    try:
        # 创建水印 PDF
        watermark_ps = f"""
%!PS-Adobe-3.0
%%Title: Watermark
/Helvetica-Bold findfont 60 scalefont setfont
0.5 setgray
306 396 moveto
-45 rotate
({watermark_text}) stringwidth pop -2 div 0 rmoveto
({watermark_text}) show
"""
        # 使用 Ghostscript 添加水印
        cmd = [
            'gs', '-dNOPAUSE', '-dBATCH', '-sDEVICE=pdfwrite',
            '-sOutputFile=-', '-c',
            f'<< /EndPage {{ 2 eq {{ pop false }} {{ /Helvetica-Bold findfont 60 scalefont setfont 0.5 setgray 306 396 moveto -45 rotate ({watermark_text}) show true }} ifelse }} bind >> setpagedevice',
            '-f', input_file
        ]
        result = subprocess.run(cmd, capture_output=True, text=True)
        return result.stdout
    except Exception as e:
        print(f"ERROR: {e}", file=sys.stderr)
        return None

def main():
    if len(sys.argv) < 6:
        print("Usage: pdf-watermark job user title copies options [file]", file=sys.stderr)
        sys.exit(1)
    
    job_id = sys.argv[1]
    user = sys.argv[2]
    title = sys.argv[3]
    copies = sys.argv[4]
    options = sys.argv[5]
    input_file = sys.argv[6] if len(sys.argv) > 6 else None
    
    # 解析选项
    watermark_text = "CONFIDENTIAL"
    for opt in options.split():
        if opt.startswith("watermark="):
            watermark_text = opt.split("=", 1)[1]
    
    # 读取输入
    if input_file:
        with open(input_file, 'rb') as f:
            data = f.read()
    else:
        data = sys.stdin.buffer.read()
    
    # 临时文件处理
    import tempfile
    with tempfile.NamedTemporaryFile(suffix='.pdf', delete=False) as tmp:
        tmp.write(data)
        tmp_path = tmp.name
    
    try:
        result = add_watermark(tmp_path, watermark_text)
        if result:
            sys.stdout.buffer.write(result)
        else:
            # 如果处理失败,输出原始文件
            sys.stdout.buffer.write(data)
    finally:
        os.unlink(tmp_path)
    
    print(f"DEBUG: Watermark filter completed", file=sys.stderr)
    sys.exit(0)

if __name__ == "__main__":
    main()
# 安装 Python 过滤器
sudo cp pdf-watermark.py /usr/lib/cups/filter/pdf-watermark
sudo chmod 755 /usr/lib/cups/filter/pdf-watermark

8.7.4 注册自定义过滤器

# 注册 MIME 类型
sudo vim /etc/cups/mime.types
# 添加:
# application/x-watermarked-pdf    wpdf string(0,"%PDF")

# 注册转换规则
sudo vim /etc/cups/mime.convs
# 添加:
# application/pdf    application/x-watermarked-pdf    33    pdf-watermark

# 或者注册为覆盖特定打印机的过滤器
# 在 PPD 文件中添加:
# *cupsFilter: "application/pdf 0 pdf-watermark"

8.7.5 高级过滤器示例:文件类型转换

#!/bin/bash
# /usr/lib/cups/filter/office2pdf
# Office 文档转 PDF 过滤器

JOB_ID="$1"
USER="$2"
TITLE="$3"
COPIES="$4"
OPTIONS="$5"
FILE="$6"

LOGFILE="/var/log/cups/office2pdf.log"

log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') $*" >> "$LOGFILE"
}

log "Starting office2pdf filter - Job: $JOB_ID, User: $USER"

# 获取输入文件类型
if [ -n "$FILE" ]; then
    INPUT="$FILE"
    FILE_TYPE=$(file -b --mime-type "$FILE")
else
    # 保存 stdin 到临时文件
    INPUT=$(mktemp /tmp/cups-XXXXXX)
    cat > "$INPUT"
    FILE_TYPE=$(file -b --mime-type "$INPUT")
    trap "rm -f $INPUT" EXIT
fi

log "Input file type: $FILE_TYPE"

# 根据文件类型选择转换工具
case "$FILE_TYPE" in
    application/msword|application/vnd.openxmlformats-officedocument.wordprocessingml.document)
        # 使用 LibreOffice 转换
        log "Converting Office document to PDF"
        libreoffice --headless --convert-to pdf --outdir /tmp "$INPUT" 2>> "$LOGFILE"
        PDF_FILE="/tmp/$(basename "${INPUT%.*}").pdf"
        if [ -f "$PDF_FILE" ]; then
            cat "$PDF_FILE"
            rm -f "$PDF_FILE"
        else
            log "ERROR: LibreOffice conversion failed"
            exit 1
        fi
        ;;
    application/pdf)
        # 直接输出 PDF
        cat "$INPUT"
        ;;
    *)
        log "Unsupported file type: $FILE_TYPE"
        exit 1
        ;;
esac

log "Filter completed successfully"
exit 0

8.8 cupsfilter 命令详解

8.8.1 cupsfilter 基本用法

# 基本语法
cupsfilter [选项] [文件]

# 常用选项:
# -D           调试模式
# -d printer   使用指定打印机
# -m mime/type 输出 MIME 类型
# -n copies    打印份数
# -o option=value 打印选项
# -p ppd-file  使用指定 PPD 文件
# -t title     文档标题

# 测试 PDF 到 PostScript 转换
cupsfilter -m application/postscript document.pdf > output.ps

# 使用特定打印机
cupsfilter -d myprinter -m application/postscript document.pdf > output.ps

# 使用特定 PPD 文件
cupsfilter -p /usr/share/ppd/HP/hp-laserjet_pro_m404.ppd \
  -m application/postscript document.pdf > output.ps

# 测试文本到光栅转换
echo "Test Page" | cupsfilter -m application/vnd.cups-raster > output.raster

8.8.2 cupsfilter 调试

# 启用详细输出
cupsfilter -v -m application/pdf document.pdf > /dev/null

# 输出示例:
# DEBUG: Loading printer "myprinter"
# DEBUG: Finding filter for application/pdf to application/postscript
# DEBUG: Running filter: pdftops 1234 user "Test" 1 "" document.pdf
# DEBUG: Filter completed with status 0

# 列出可用转换路径
cupsfilter -t application/pdf 2>&1 | head -20

# 测试完整转换链
cupsfilter -d myprinter -v document.pdf 2>&1

8.9 高级过滤器配置

8.9.1 过滤器链优化

# /etc/cups/mime.convs
# 优化转换路径

# 直接 PDF 到光栅(跳过 PostScript)
application/pdf    application/vnd.cups-raster    33    pdftoraster

# 提高特定过滤器优先级
image/jpeg    application/postscript    25    imagetops

# 禁用特定过滤器
# 不使用 texttops,改用 texttoraster
# text/plain    application/postscript    33    texttops
text/plain    application/vnd.cups-raster    33    texttoraster

8.9.2 环境变量

# CUPS 过滤器可用的环境变量

# FINAL_CONTENT_TYPE  最终输出类型
# PRINTER             打印机名称
# DEVICE_URI          设备 URI
# CONTENT_TYPE        输入内容类型
# SERVER_ADMIN        管理员邮箱
# CUPS_SERVER         CUPS 服务器地址
# IPP_PORT            IPP 端口
# LOCALE              语言环境

# 在过滤器中使用环境变量
echo "Printer: $PRINTER" >&2
echo "Device: $DEVICE_URI" >&2
echo "Content: $CONTENT_TYPE$FINAL_CONTENT_TYPE" >&2

8.10 业务场景

8.10.1 场景一:Office 文档自动转换

# 需求:自动将 Office 文档转换为 PDF 打印

# 安装 LibreOffice
sudo apt install -y libreoffice-common

# 创建 Office 转 PDF 过滤器
sudo vim /usr/lib/cups/filter/office2pdf
# (参考上面的脚本)

# 注册 MIME 类型
sudo vim /etc/cups/mime.types
# 添加:
# application/msword    doc string(0,\320\317\021\340\241\261\032\341)
# application/vnd.openxmlformats-officedocument.wordprocessingml.document
#     docx zip(string(0,PK\003\004))

# 注册转换规则
sudo vim /etc/cups/mime.convs
# 添加:
# application/msword    application/pdf    33    office2pdf
# application/vnd.openxmlformats-officedocument.wordprocessingml.document
#     application/pdf    33    office2pdf

# 测试
lp -d myprinter document.docx

8.10.2 场景二:安全打印水印

# 需求:为敏感文档自动添加水印

# 使用 Python 过滤器
sudo vim /usr/lib/cups/filter/security-watermark
# (参考上面的 Python 脚本)

# 注册过滤器
sudo vim /etc/cups/mime.convs
# application/pdf    application/x-watermarked-pdf    33    security-watermark

# 测试
lp -d myprinter -o watermark="CONFIDENTIAL" sensitive-document.pdf

8.10.3 场景三:打印日志记录

#!/bin/bash
# /usr/lib/cups/filter/audit-logger
# 审计日志过滤器(透明记录)

JOB_ID="$1"
USER="$2"
TITLE="$3"
COPIES="$4"
OPTIONS="$5"
FILE="$6"

# 记录打印活动
LOGFILE="/var/log/cups/audit.log"
echo "$(date '+%Y-%m-%d %H:%M:%S') | User: $USER | Job: $JOB_ID | Title: $TITLE | Copies: $COPIES | Options: $OPTIONS" >> "$LOGFILE"

# 计算文件大小
if [ -n "$FILE" ]; then
    SIZE=$(stat -c%s "$FILE" 2>/dev/null || echo "0")
else
    SIZE=$(cat | wc -c)
    echo "$SIZE bytes" >> "$LOGFILE"
    # 重新输出内容
    cat /dev/stdin
fi

# 透明传递
cat "$FILE" 2>/dev/null || cat /dev/stdin
exit 0

8.11 扩展阅读

资源链接
CUPS 过滤器文档https://www.cups.org/doc/filter.html
Ghostscript 文档https://www.ghostscript.com/doc/
Poppler 文档https://poppler.freedesktop.org/
MIME 类型参考https://www.iana.org/assignments/media-types/
CUPS 后端文档https://www.cups.org/doc/backend.html

8.12 本章小结

主题关键要点
过滤器负责文档格式转换,按 MIME 类型链式调用
后端负责与打印设备通信,支持 USB/网络/IPP 等
MIME 类型定义文件类型检测规则
转换规则定义源类型到目标类型的转换路径
自定义过滤器使用脚本或程序实现自定义转换逻辑
cupsfilter测试和调试过滤器的命令行工具

下一章预告:我们将学习 CUPS 安全配置,包括认证、加密、TLS、访问控制和审计日志。


8.13 练习题

  1. 概念题:解释 CUPS 过滤器链的工作原理,以及 MIME 类型在其中的作用。

  2. 测试题:使用 cupsfilter 命令将 PDF 文件转换为 PostScript,并查看转换过程。

  3. 自定义题:编写一个简单的 bash 过滤器,为所有打印任务添加时间戳水印。

  4. 后端题:比较 socketipplpd 三种后端的优缺点。

  5. 场景题:设计一个过滤器方案,自动将所有 Office 文档转换为 PDF 后打印。