doc-toolkit

SKILL效率
效率 未标注权限 许可证不明确
安装这个技能

读写编辑DOCX,表格/图表/分页布局

一句话选型结论

按资料字段整理

doc-toolkit是效率类的 Agent Skill,安装方式未标注,权限级别未标注,许可证不明确,有可直接复制的安装命令。技能本质是给模型读的说明书,效果取决于模型与客户端;装完先用一个小任务验证,再放进正式流程。

分类效率 安装方式未标注 权限级别未标注权限 许可证许可证不明确
累计安装 未标注 本周 未标注
GitHub 星标 未标注 仓库 未标注
下载量 未标注 技能市场下载数
权限级别 未标注权限 安装前请确认风险范围
许可证 许可证不明确 未说明

安装

未标注
在支持 Skills 的客户端里执行,装完问一句「你有哪些技能」验证
skillhub install zcwl/doc-toolkit
  1. 1
    确认客户端支持

    确认你的客户端支持 Skills(Claude、Codex、Cursor 等),并升级到较新的版本。

  2. 2
    拿到技能文件

    执行上面的命令安装;也可以把仓库里的 SKILL.md 手动放进客户端的 skills 目录。

  3. 3
    刷新技能列表

    重新打开客户端,或刷新技能列表,让新放进来的技能被加载。

  4. 4
    验证是否生效

    问一句「你有哪些技能」,确认列表里出现它,再拿一个小任务试跑。

技能档案

效率
字段来自技能仓库与公开索引,中文说明由本站标注
作者 / 维护方zcwl仓库 未标注 · 版本 未标注
宿主客户端未标注技能可被这些客户端加载
安装方式未标注安装包 enterprise
权限级别未标注权限安装前请确认风险范围
许可证未说明许可证不明确,商用前请自行确认条款
仓库可用性available技能仓库当前是否可访问
最近核验未标注上游最后核验时间 · 数据更新 1791509602
正文体量35.8 KBSKILL.md 原文大小,越大说明说明书写得越细

典型使用场景

3 类
按分类整理的常见用法,具体以 SKILL.md 为准
整理待办与日程

把零散任务收进清单,排出优先级。

批量处理重复任务

把固定动作做成模板,重复执行。

把流程写成清单

把口头流程整理成可复用的步骤。

选择建议

装之前先看这几条
按条目字段给出的判断,不替你决定用不用

值得选的地方

  • 有可直接复制的安装命令,不用自己翻文档找入口。

先想清楚的地方

  • 没有标注权限级别,实际能做什么要装好后确认。
  • 许可证不明确,商用或二次分发前先到仓库确认条款。
  • 没有做站内核验,内容以作者仓库为准。
  • 技能只是说明书,实际效果取决于模型与客户端,装完先用小任务试一遍。

更适合

  • 需要在效率场景里给模型补一套做法的人。
  • 愿意先读一遍 SKILL.md、确认它会让模型做什么的人。

不太适合

  • 对许可证要求很严、必须明确可商用的人。
  • 只想装完就自动变强、不打算看说明书的人。

同类对比

6 个同类
同分类里挑最接近的几条,字段以各自详情页为准
技能权限级别安装方式累计安装宿主客户端安装命令
doc-toolkit当前 未标注权限 未标注 未标注 未标注 有
Nano PDF 文档 联网访问 ClawHub 市场 424.9 万 OpenClaw 有
自动更新程序 浏览器控制 ClawHub 市场 296.4 万 OpenClaw 有
Gemini 助手 联网访问 ClawHub 市场 254.7 万 OpenClaw 有
word DOCX 文档 联网访问 ClawHub 市场 239.6 万 OpenClaw 有
Excel XLSX 前端 联网访问 ClawHub 市场 227.0 万 OpenClaw 有

SKILL.md 全文

35.8 KB
模型实际读到的说明书原文,来自技能仓库

全能文档处理工具箱 (Doc Toolkit)

功能总览

分类 功能 支持格式
文档合并 多文件合并为一个 DOCX、XLSX、PPTX、PDF
文档拆分 按页/按Sheet/按节拆分 DOCX、XLSX、PPTX、PDF
格式转换 任意格式互转 DOCX、PDF、XLSX、PPTX、MD、HTML、TXT、CSV、图片
图片压缩 批量压缩图片文件大小 PNG、JPG、JPEG、WEBP
智能抠图 AI 去除图片背景 PNG、JPG、JPEG
PDF 工具 水印、加密、旋转、裁剪、提取图片 PDF
图片提取 从文档中提取嵌入图片 DOCX、PPTX、PDF、XLSX

一、文档合并

1.1 Word 文档合并(DOCX)

将多个 Word 文档按顺序合并为一个文件。

from docx import Document
from docx.oxml.ns import qn
import copy, os

def merge_docx(files, output_path):
    """合并多个 DOCX 文件,保留格式"""
    merged = Document(files[0])
    for f in files[1:]:
        doc = Document(f)
        # 每个文档之间添加分页符
        merged.add_page_break()
        for element in doc.element.body:
            merged.element.body.append(copy.deepcopy(element))
    merged.save(output_path)
    return output_path

# 使用示例
files = ["doc1.docx", "doc2.docx", "doc3.docx"]
merge_docx(files, "merged.docx")

1.2 Excel 文件合并(XLSX)

将多个 Excel 文件合并到一个工作簿的不同 Sheet,或按行合并到同一个 Sheet。

import pandas as pd
import os

# 方式一:每个文件作为一个 Sheet 合并到一个工作簿
def merge_xlsx_as_sheets(files, output_path):
    with pd.ExcelWriter(output_path, engine='openpyxl') as writer:
        for f in files:
            name = os.path.splitext(os.path.basename(f))[0]
            # Sheet 名最长31字符,去除非法字符
            safe_name = name[:31].replace('/', '_').replace('\\', '_').replace('*', '_').replace('?', '_').replace('[', '_').replace(']', '_')
            all_sheets = pd.read_excel(f, sheet_name=None)
            for sheet_name, df in all_sheets.items():
                unique_name = f"{safe_name}_{sheet_name}"[:31]
                df.to_excel(writer, sheet_name=unique_name, index=False)

# 方式二:相同结构的表按行合并(纵向追加)
def merge_xlsx_concat(files, output_path, header_file=None):
    dfs = []
    for f in files:
        df = pd.read_excel(f)
        dfs.append(df)
    result = pd.concat(dfs, ignore_index=True)
    result.to_excel(output_path, index=False)
    return len(result)

# 使用示例
files = ["data1.xlsx", "data2.xlsx", "data3.xlsx"]
merge_xlsx_as_sheets(files, "merged_all_sheets.xlsx")
merge_xlsx_concat(files, "merged_concat.xlsx")

1.3 PPT 文件合并(PPTX)

将多个 PPT 文件合并为一个演示文稿。

from pptx import Presentation
from pptx.util import Inches, Pt
import copy

def merge_pptx(files, output_path):
    """合并多个 PPTX 文件,每个文件的幻灯片追加到末尾"""
    merged = Presentation(files[0])
    for f in files[1:]:
        prs = Presentation(f)
        # 记录源文件的幻灯片宽高
        src_width = prs.slide_width
        src_height = prs.slide_height
        for slide in prs.slides:
            # 创建新的 layout(使用默认布局)
            layout = merged.slide_layouts[6]  # 空白布局
            new_slide = merged.slides.add_slide(layout)
            # 复制所有元素
            for shape in slide.shapes:
                el = copy.deepcopy(shape.element)
                new_slide.shapes._spTree.append(el)
    merged.save(output_path)
    return output_path

# 使用示例
files = ["slides1.pptx", "slides2.pptx"]
merge_pptx(files, "merged.pptx")

1.4 PDF 文件合并

from pypdf import PdfReader, PdfWriter

def merge_pdf(files, output_path):
    """合并多个 PDF 文件"""
    writer = PdfWriter()
    for f in files:
        reader = PdfReader(f)
        for page in reader.pages:
            writer.add_page(page)
    with open(output_path, "wb") as fh:
        writer.write(fh)
    return output_path

# 使用示例
files = ["report1.pdf", "report2.pdf", "report3.pdf"]
merge_pdf(files, "merged.pdf")

二、文档拆分

2.1 Word 文档拆分(DOCX)

按分页符拆分,或按指定页数拆分。

from docx import Document
from docx.oxml.ns import qn
from lxml import etree
import copy

def split_docx(input_path, output_dir):
    """按分页符拆分 DOCX 为多个文件"""
    doc = Document(input_path)
    sections = []
    current_elements = []

    for element in doc.element.body:
        # 检测分页符 (w:br type="page" 或分节符)
        is_break = False
        if element.tag == qn('w:p'):
            for br in element.iter(qn('w:br')):
                if br.get(qn('w:type')) == 'page':
                    is_break = True
                    break
        if is_break:
            sections.append(current_elements)
            current_elements = []
        else:
            current_elements.append(element)

    if current_elements:
        sections.append(current_elements)

    output_files = []
    for i, elems in enumerate(sections):
        new_doc = Document()
        new_doc.element.body.clear()
        for el in elems:
            new_doc.element.body.append(copy.deepcopy(el))
        out = f"{output_dir}/split_{i+1}.docx"
        new_doc.save(out)
        output_files.append(out)
    return output_files

# 按固定页数拆分
def split_docx_by_pages(input_path, output_dir, pages_per_file=5):
    """按每N页拆分 DOCX(按段落数量近似分页)"""
    doc = Document(input_path)
    total_paras = len(doc.paragraphs)
    paras_per_file = total_paras // pages_per_file

    output_files = []
    for i in range(0, total_paras, paras_per_file):
        new_doc = Document()
        for para in doc.paragraphs[i:i+paras_per_file]:
            new_doc.add_paragraph(para.text, para.style.style_id if para.style else None)
        out = f"{output_dir}/split_{i//paras_per_file+1}.docx"
        new_doc.save(out)
        output_files.append(out)
    return output_files

2.2 Excel 文件拆分(XLSX)

按 Sheet 拆分为独立文件,或按某列值拆分。

import pandas as pd
import os

def split_xlsx_by_sheet(input_path, output_dir):
    """将每个 Sheet 拆分为独立的 XLSX 文件"""
    all_sheets = pd.read_excel(input_path, sheet_name=None)
    output_files = []
    for name, df in all_sheets.items():
        out = os.path.join(output_dir, f"{name}.xlsx")
        df.to_excel(out, index=False)
        output_files.append(out)
    return output_files

def split_xlsx_by_column(input_path, output_dir, column_name):
    """按某列的值拆分为多个文件"""
    df = pd.read_excel(input_path)
    output_files = []
    for val, group in df.groupby(column_name):
        safe_val = str(val).replace('/', '_').replace('\\', '_')[:50]
        out = os.path.join(output_dir, f"split_{safe_val}.xlsx")
        group.to_excel(out, index=False)
        output_files.append(out)
    return output_files

2.3 PPT 文件拆分(PPTX)

按幻灯片范围拆分。

from pptx import Presentation
from pptx.util import Inches, Pt, Emu
import copy, os

def split_pptx(input_path, output_dir, slides_per_file=None, ranges=None):
    """
    拆分 PPTX 文件
    slides_per_file: 每个文件包含的幻灯片数
    ranges: 自定义范围列表,如 [(0,5), (5,10)] 表示前5页和后5页
    """
    prs = Presentation(input_path)
    total = len(prs.slides)

    if ranges is None and slides_per_file:
        ranges = [(i, min(i+slides_per_file, total))
                   for i in range(0, total, slides_per_file)]

    output_files = []
    for start, end in ranges:
        new_prs = Presentation()
        new_prs.slide_width = prs.slide_width
        new_prs.slide_height = prs.slide_height
        for idx in range(start, end):
            slide = prs.slides[idx]
            layout = new_prs.slide_layouts[6]  # 空白布局
            new_slide = new_prs.slides.add_slide(layout)
            for shape in slide.shapes:
                el = copy.deepcopy(shape.element)
                new_slide.shapes._spTree.append(el)
        out = os.path.join(output_dir, f"split_{start+1}-{end}.pptx")
        new_prs.save(out)
        output_files.append(out)
    return output_files

2.4 PDF 文件拆分

from pypdf import PdfReader, PdfWriter
import os

def split_pdf(input_path, output_dir, pages_per_file=None, page_ranges=None):
    """
    拆分 PDF 文件
    pages_per_file: 每个文件的页数
    page_ranges: 自定义页码列表,如 [(1,3), (4,6)](1-indexed)
    """
    reader = PdfReader(input_path)
    total = len(reader.pages)
    output_files = []

    if page_ranges is None and pages_per_file:
        page_ranges = [(i+1, min(i+pages_per_file, total))
                       for i in range(0, total, pages_per_file)]

    for start, end in page_ranges:
        writer = PdfWriter()
        for i in range(start-1, end):  # 转为 0-indexed
            writer.add_page(reader.pages[i])
        out = os.path.join(output_dir, f"split_{start}-{end}.pdf")
        with open(out, "wb") as f:
            writer.write(f)
        output_files.append(out)
    return output_files

# 特殊:每页单独一个文件
def split_pdf_each_page(input_path, output_dir):
    return split_pdf(input_path, output_dir, pages_per_file=1)

三、格式转换

3.1 转换矩阵

源格式 → 目标格式 PDF DOCX XLSX PPTX TXT MD HTML CSV PNG/JPG
PDF - ✅ ✅(表格) ❌ ✅ ✅ ✅ ✅(表格) ✅
DOCX ✅ - ❌ ❌ ✅ ✅ ✅ ❌ ✅
XLSX ✅ ❌ - ❌ ❌ ✅ ✅ ✅ ❌
PPTX ✅ ❌ ❌ - ✅ ✅ ❌ ❌ ✅
MD ✅ ✅ ❌ ❌ ✅ - ✅ ❌ ❌
HTML ✅ ✅ ❌ ❌ ✅ ✅ - ❌ ❌
TXT ✅ ✅ ❌ ❌ - ✅ ✅ ❌ ❌
CSV ❌ ❌ ✅ ❌ ❌ ❌ ✅ - ❌
图片 ✅ ❌ ❌ ❌ ❌ ❌ ❌ ❌ -

3.2 DOCX 转换

from docx import Document
from docx.shared import Pt
import subprocess, os

# DOCX → PDF(使用 LibreOffice,需安装)
def docx_to_pdf(input_path, output_path):
    """通过 LibreOffice 将 DOCX 转为 PDF"""
    cmd = [
        'libreoffice', '--headless', '--convert-to', 'pdf',
        '--outdir', os.path.dirname(output_path), input_path
    ]
    subprocess.run(cmd, check=True, capture_output=True)
    return output_path

# DOCX → TXT
def docx_to_txt(input_path, output_path):
    doc = Document(input_path)
    text = "\n".join(p.text for p in doc.paragraphs)
    with open(output_path, "w", encoding="utf-8") as f:
        f.write(text)
    return output_path

# DOCX → Markdown
def docx_to_md(input_path, output_path):
    doc = Document(input_path)
    lines = []
    for p in doc.paragraphs:
        text = p.text
        if p.style and 'Heading' in (p.style.name or ''):
            level = ''.join(c for c in p.style.name if c.isdigit()) or '1'
            lines.append(f"{'#' * int(level)} {text}")
        else:
            lines.append(text)
    md = "\n\n".join(lines)
    with open(output_path, "w", encoding="utf-8") as f:
        f.write(md)
    return output_path

# DOCX → HTML
def docx_to_html(input_path, output_path):
    """Mammoth 提取 DOCX 内容为 HTML"""
    try:
        import mammoth
    except ImportError:
        import subprocess, sys
        subprocess.check_call([sys.executable, "-m", "pip", "install", "mammoth", "-q"])
        import mammoth
    with open(input_path, "rb") as f:
        result = mammoth.convert_to_html(f)
    with open(output_path, "w", encoding="utf-8") as f:
        f.write(result.value)
    return output_path

3.3 PDF 转换

from pypdf import PdfReader
import pdfplumber
import os

# PDF → TXT
def pdf_to_txt(input_path, output_path):
    reader = PdfReader(input_path)
    text = "\n\n".join(page.extract_text() or "" for page in reader.pages)
    with open(output_path, "w", encoding="utf-8") as f:
        f.write(text)
    return output_path

# PDF → Markdown
def pdf_to_md(input_path, output_path):
    """提取 PDF 内容转为 Markdown"""
    reader = PdfReader(input_path)
    md_lines = []
    for i, page in enumerate(reader.pages):
        text = page.extract_text() or ""
        md_lines.append(f"<!-- 第 {i+1} 页 -->\n{text}")
    with open(output_path, "w", encoding="utf-8") as f:
        f.write("\n\n---\n\n".join(md_lines))
    return output_path

# PDF → 图片(每页渲染为 PNG)
def pdf_to_images(input_path, output_dir, scale=2.0):
    """使用 pypdfium2 将 PDF 渲染为图片"""
    try:
        import pypdfium2 as pdfium
    except ImportError:
        import subprocess, sys
        subprocess.check_call([sys.executable, "-m", "pip", "install", "pypdfium2", "-q"])
        import pypdfium2 as pdfium

    pdf = pdfium.PdfDocument(input_path)
    output_files = []
    for i, page in enumerate(pdf):
        bitmap = page.render(scale=scale)
        img = bitmap.to_pil()
        out = os.path.join(output_dir, f"page_{i+1}.png")
        img.save(out)
        output_files.append(out)
    return output_files

# PDF → DOCX(提取文本到 Word)
def pdf_to_docx(input_path, output_path):
    from docx import Document
    reader = PdfReader(input_path)
    doc = Document()
    for page in reader.pages:
        text = page.extract_text() or ""
        if text:
            doc.add_paragraph(text)
        doc.add_page_break()
    doc.save(output_path)
    return output_path

3.4 XLSX 转换

import pandas as pd
import os

# XLSX → CSV
def xlsx_to_csv(input_path, output_dir):
    all_sheets = pd.read_excel(input_path, sheet_name=None)
    output_files = []
    for name, df in all_sheets.items():
        out = os.path.join(output_dir, f"{name}.csv")
        df.to_csv(out, index=False, encoding="utf-8-sig")
        output_files.append(out)
    return output_files

# XLSX → PDF
def xlsx_to_pdf(input_path, output_path):
    """Excel 表格转为 PDF 报告"""
    import subprocess
    cmd = [
        'libreoffice', '--headless', '--convert-to', 'pdf',
        '--outdir', os.path.dirname(output_path), input_path
    ]
    subprocess.run(cmd, check=True, capture_output=True)
    return output_path

# XLSX → HTML
def xlsx_to_html(input_path, output_path):
    """将每个 Sheet 转为 HTML 表格"""
    all_sheets = pd.read_excel(input_path, sheet_name=None)
    html_parts = []
    for name, df in all_sheets.items():
        html_parts.append(f"<h2>{name}</h2>")
        html_parts.append(df.to_html(index=False, border=1))
    html = "<html><head><meta charset='utf-8'></head><body>" + "\n".join(html_parts) + "</body></html>"
    with open(output_path, "w", encoding="utf-8") as f:
        f.write(html)
    return output_path

3.5 PPTX 转换

from pptx import Presentation
import os

# PPTX → PDF(通过 LibreOffice)
def pptx_to_pdf(input_path, output_path):
    import subprocess
    cmd = [
        'libreoffice', '--headless', '--convert-to', 'pdf',
        '--outdir', os.path.dirname(output_path), input_path
    ]
    subprocess.run(cmd, check=True, capture_output=True)
    return output_path

# PPTX → TXT(提取所有文本)
def pptx_to_txt(input_path, output_path):
    prs = Presentation(input_path)
    texts = []
    for i, slide in enumerate(prs.slides):
        texts.append(f"=== 第 {i+1} 页 ===")
        for shape in slide.shapes:
            if shape.has_text_frame:
                texts.append(shape.text_frame.text)
    with open(output_path, "w", encoding="utf-8") as f:
        f.write("\n\n".join(texts))
    return output_path

# PPTX → 图片(每页渲染为 PNG)
def pptx_to_images(input_path, output_dir, dpi=150):
    """使用 LibreOffice 将每页幻灯片导出为图片"""
    import subprocess
    cmd = [
        'libreoffice', '--headless', '--convert-to', 'png',
        '--outdir', output_dir, input_path
    ]
    subprocess.run(cmd, check=True, capture_output=True)
    # LibreOffice 导出文件名格式为 原文件名.png
    output_files = [os.path.join(output_dir, f) for f in os.listdir(output_dir) if f.endswith('.png')]
    return output_files

3.6 图片 → PDF

from PIL import Image
import os

def images_to_pdf(image_files, output_path):
    """将多张图片合并为一个 PDF 文件"""
    images = []
    for f in sorted(image_files):
        img = Image.open(f)
        if img.mode == 'RGBA':
            img = img.convert('RGB')
        images.append(img)

    if images:
        first = images[0]
        rest = images[1:]
        first.save(output_path, "PDF", save_all=True, append_images=rest)
    return output_path

3.7 批量格式转换

import os, glob

def batch_convert(input_dir, output_dir, source_ext, target_ext, convert_func):
    """批量转换目录下所有指定格式的文件"""
    files = sorted(glob.glob(os.path.join(input_dir, f"*{source_ext}")))
    results = []
    os.makedirs(output_dir, exist_ok=True)
    for f in files:
        name = os.path.splitext(os.path.basename(f))[0]
        out = os.path.join(output_dir, f"{name}{target_ext}")
        try:
            convert_func(f, out)
            results.append({"file": f, "output": out, "status": "success"})
        except Exception as e:
            results.append({"file": f, "output": out, "status": "error", "error": str(e)})
    return results

四、图片压缩

支持 PNG、JPG、JPEG、WEBP 格式的批量压缩,可控制压缩质量与最大尺寸。

from PIL import Image
import os, glob

def compress_images(input_dir, output_dir, quality=85, max_width=None, max_height=None, max_size_kb=None):
    """
    批量压缩图片

    参数:
        input_dir: 输入目录
        output_dir: 输出目录
        quality: JPEG 质量 1-100(默认 85)
        max_width: 最大宽度(像素),None 表示不限制
        max_height: 最大高度(像素),None 表示不限制
        max_size_kb: 目标文件大小上限(KB),None 表示不限制
    """
    os.makedirs(output_dir, exist_ok=True)
    supported = ["*.png", "*.jpg", "*.jpeg", "*.webp"]
    results = []

    for pattern in supported:
        for filepath in sorted(glob.glob(os.path.join(input_dir, pattern))):
            try:
                img = Image.open(filepath)
                fname = os.path.basename(filepath)
                out = os.path.join(output_dir, fname)

                # 缩放
                w, h = img.size
                if max_width and w > max_width:
                    ratio = max_width / w
                    img = img.resize((max_width, int(h * ratio)), Image.LANCZOS)
                if max_height and img.height > max_height:
                    ratio = max_height / img.height
                    img = img.resize((int(img.width * ratio), max_height), Image.LANCZOS)

                # 转换格式(PNG → JPG 可大幅减小体积)
                ext = os.path.splitext(fname)[1].lower()
                if ext == '.png' and img.mode in ('RGBA', 'P'):
                    img = img.convert('RGB')

                # 保存并压缩
                save_kwargs = {"quality": quality, "optimize": True}
                if ext == '.png':
                    img.save(out, "PNG", optimize=True)
                elif ext == '.webp':
                    img.save(out, "WEBP", quality=quality)
                else:
                    img.save(out, "JPEG", **save_kwargs)

                # 如果指定了最大文件大小,逐步降低质量重压
                if max_size_kb:
                    q = quality
                    while os.path.getsize(out) > max_size_kb * 1024 and q > 10:
                        q -= 10
                        img.save(out, "JPEG", quality=q, optimize=True)

                orig_size = os.path.getsize(filepath)
                new_size = os.path.getsize(out)
                ratio = (1 - new_size / orig_size) * 100
                results.append({
                    "file": fname,
                    "original_kb": round(orig_size / 1024, 1),
                    "compressed_kb": round(new_size / 1024, 1),
                    "reduced": f"{ratio:.1f}%"
                })
            except Exception as e:
                results.append({"file": os.path.basename(filepath), "error": str(e)})

    return results

# 使用示例:压缩到 200KB 以内,宽度不超过 1920px
# results = compress_images("images/", "compressed/", quality=85, max_width=1920, max_size_kb=200)

PNG 无损压缩(推荐)

def png_lossless_compress(input_dir, output_dir):
    """使用 Pillow 的 optimize 模式对 PNG 进行无损压缩"""
    try:
        import subprocess, sys
        subprocess.check_call([sys.executable, "-m", "pip", "install", "pillow", "-q"])
    except: pass

    from PIL import Image
    import glob, os
    os.makedirs(output_dir, exist_ok=True)
    results = []
    for f in glob.glob(os.path.join(input_dir, "*.png")):
        img = Image.open(f)
        out = os.path.join(output_dir, os.path.basename(f))
        img.save(out, "PNG", optimize=True)
        orig = os.path.getsize(f) / 1024
        new = os.path.getsize(out) / 1024
        results.append({"file": os.path.basename(f), "original_kb": round(orig,1), "compressed_kb": round(new,1), "saved": f"{(1-new/orig)*100:.1f}%"})
    return results

五、智能抠图(去除背景)

使用 rembg 库实现 AI 自动抠图,支持批量处理。

def remove_background(input_path, output_path):
    """
    AI 智能去除图片背景
    输入:任意图片(PNG/JPG/JPEG/WEBP)
    输出:透明背景 PNG
    """
    try:
        from rembg import remove
    except ImportError:
        import subprocess, sys
        subprocess.check_call([sys.executable, "-m", "pip", "install", "rembg[gpu]", "-q"])
        from rembg import remove

    from PIL import Image

    input_img = Image.open(input_path)
    output_img = remove(input_img)

    # 确保输出为 RGBA(保留透明通道)
    if output_img.mode != 'RGBA':
        output_img = output_img.convert('RGBA')

    output_img.save(output_path, "PNG")
    return output_path

def batch_remove_background(input_dir, output_dir):
    """批量去除目录下所有图片的背景"""
    import glob, os
    try:
        from rembg import remove
    except ImportError:
        import subprocess, sys
        subprocess.check_call([sys.executable, "-m", "pip", "install", "rembg[gpu]", "-q"])
        from rembg import remove

    from PIL import Image
    os.makedirs(output_dir, exist_ok=True)
    results = []

    for f in sorted(glob.glob(os.path.join(input_dir, "*"))):
        ext = os.path.splitext(f)[1].lower()
        if ext not in [".png", ".jpg", ".jpeg", ".webp"]:
            continue
        try:
            img = Image.open(f)
            result = remove(img)
            if result.mode != 'RGBA':
                result = result.convert('RGBA')
            name = os.path.splitext(os.path.basename(f))[0] + ".png"
            out = os.path.join(output_dir, name)
            result.save(out, "PNG")
            results.append({"input": os.path.basename(f), "output": name, "status": "success"})
        except Exception as e:
            results.append({"input": os.path.basename(f), "status": "error", "error": str(e)})

    return results

# 使用示例
# remove_background("photo.jpg", "photo_nobg.png")
# batch_remove_background("product_photos/", "output_nobg/")

替代方案:纯色背景替换

def replace_background_white(input_path, output_path):
    """将图片背景替换为白色"""
    try:
        from rembg import remove
    except ImportError:
        import subprocess, sys
        subprocess.check_call([sys.executable, "-m", "pip", "install", "rembg[gpu]", "-q"])
        from rembg import remove

    from PIL import Image

    img = Image.open(input_path)
    result = remove(img)

    # 创建白色背景
    background = Image.new("RGBA", result.size, (255, 255, 255, 255))
    composite = Image.alpha_composite(background, result)
    composite = composite.convert("RGB")
    composite.save(output_path, "JPEG", quality=95)
    return output_path

六、PDF 高级工具

6.1 添加水印

from pypdf import PdfReader, PdfWriter, PdfMerger
from pypdf.generic import StringObject, NameObject, ArrayObject, NumberObject
import io
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4
from PIL import Image as PILImage

def add_text_watermark(input_path, output_path, text="机密文件", opacity=0.3, font_size=50):
    """给 PDF 添加文字水印"""
    reader = PdfReader(input_path)
    writer = PdfWriter()

    # 创建水印 PDF
    packet = io.BytesIO()
    c = canvas.Canvas(packet, pagesize=A4)
    c.setFont("Helvetica-Bold", font_size)
    c.setFillColorRGB(0.5, 0.5, 0.5, opacity)
    c.saveState()
    c.translate(A4[0]/2, A4[1]/2)
    c.rotate(45)
    c.drawCentredString(0, 0, text)
    c.restoreState()
    c.save()
    packet.seek(0)
    watermark = PdfReader(packet)

    for page in reader.pages:
        page.merge_page(watermark.pages[0])
        writer.add_page(page)

    with open(output_path, "wb") as f:
        writer.write(f)
    return output_path

def add_image_watermark(input_path, output_path, watermark_image_path, opacity=0.2):
    """给 PDF 添加图片水印"""
    reader = PdfReader(input_path)
    writer = PdfWriter()

    # 创建水印页面
    packet = io.BytesIO()
    c = canvas.Canvas(packet, pagesize=A4)
    c.setFillAlpha(opacity)
    c.drawImage(watermark_image_path, 50, 50, width=A4[0]-100, height=A4[1]-100, mask='auto')
    c.save()
    packet.seek(0)
    watermark = PdfReader(packet)

    for page in reader.pages:
        page.merge_page(watermark.pages[0])
        writer.add_page(page)

    with open(output_path, "wb") as f:
        writer.write(f)
    return output_path

6.2 加密 / 解密

from pypdf import PdfReader, PdfWriter

def encrypt_pdf(input_path, output_path, user_password="", owner_password=""):
    """PDF 加密"""
    reader = PdfReader(input_path)
    writer = PdfWriter()
    for page in reader.pages:
        writer.add_page(page)
    writer.encrypt(user_password=user_password, owner_password=owner_password)
    with open(output_path, "wb") as f:
        writer.write(f)
    return output_path

def decrypt_pdf(input_path, output_path, password=""):
    """PDF 解密"""
    reader = PdfReader(input_path)
    if reader.is_encrypted:
        reader.decrypt(password)
    writer = PdfWriter()
    for page in reader.pages:
        writer.add_page(page)
    with open(output_path, "wb") as f:
        writer.write(f)
    return output_path

6.3 旋转页面

from pypdf import PdfReader, PdfWriter

def rotate_pdf(input_path, output_path, rotation=90):
    """旋转 PDF 所有页面(90/180/270 度)"""
    reader = PdfReader(input_path)
    writer = PdfWriter()
    for page in reader.pages:
        page.rotate(rotation)
        writer.add_page(page)
    with open(output_path, "wb") as f:
        writer.write(f)
    return output_path

6.4 裁剪页面

def crop_pdf(input_path, output_dir, left=0, bottom=0, right=None, top=None):
    """裁剪 PDF 页面(值为磅,1 inch = 72 磅)"""
    from pypdf import PdfReader, PdfWriter
    reader = PdfReader(input_path)
    output_files = []
    for i, page in enumerate(reader.pages):
        w = float(page.mediabox.width)
        h = float(page.mediabox.height)
        page.mediabox.left = left
        page.mediabox.bottom = bottom
        page.mediabox.right = right or w
        page.mediabox.top = top or h

        writer = PdfWriter()
        writer.add_page(page)
        out = os.path.join(output_dir, f"cropped_{i+1}.pdf")
        with open(out, "wb") as f:
            writer.write(f)
        output_files.append(out)
    return output_files

6.5 提取 PDF 中的图片

from pypdf import PdfReader
from PIL import Image
import io, os

def extract_pdf_images(input_path, output_dir):
    """提取 PDF 中嵌入的所有图片"""
    reader = PdfReader(input_path)
    output_files = []
    count = 0
    for page in reader.pages:
        for img in page.images:
            try:
                image = Image.open(io.BytesIO(img.data))
                ext = img.name.lower().split('.')[-1] if '.' in img.name else 'png'
                if ext not in ['png', 'jpg', 'jpeg', 'bmp', 'tiff']:
                    ext = 'png'
                out = os.path.join(output_dir, f"img_{count+1}.{ext}")
                image.save(out)
                output_files.append(out)
                count += 1
            except Exception as e:
                count += 1
    return output_files

七、从文档中提取图片

7.1 从 DOCX 提取图片

import zipfile, os

def extract_docx_images(input_path, output_dir):
    """从 DOCX 文件中提取所有嵌入图片"""
    os.makedirs(output_dir, exist_ok=True)
    output_files = []
    with zipfile.ZipFile(input_path, 'r') as z:
        for name in z.namelist():
            if name.startswith('word/media/'):
                data = z.read(name)
                fname = os.path.basename(name)
                out = os.path.join(output_dir, fname)
                with open(out, 'wb') as f:
                    f.write(data)
                output_files.append(out)
    return output_files

7.2 从 PPTX 提取图片

import zipfile, os

def extract_pptx_images(input_path, output_dir):
    """从 PPTX 文件中提取所有嵌入图片"""
    os.makedirs(output_dir, exist_ok=True)
    output_files = []
    with zipfile.ZipFile(input_path, 'r') as z:
        for name in z.namelist():
            if name.startswith('ppt/media/'):
                data = z.read(name)
                fname = os.path.basename(name)
                out = os.path.join(output_dir, fname)
                with open(out, 'wb') as f:
                    f.write(data)
                output_files.append(out)
    return output_files

八、综合工具函数

8.1 自动识别文件格式

def detect_file_type(filepath):
    """根据文件扩展名识别文档类型"""
    ext = os.path.splitext(filepath)[1].lower()
    type_map = {
        ".docx": "word", ".doc": "word",
        ".xlsx": "excel", ".xls": "excel", ".csv": "excel",
        ".pptx": "ppt", ".ppt": "ppt",
        ".pdf": "pdf",
        ".png": "image", ".jpg": "image", ".jpeg": "image", ".webp": "image",
        ".md": "markdown", ".html": "html", ".htm": "html",
        ".txt": "text",
    }
    return type_map.get(ext, "unknown")

8.2 批量处理指定目录

def batch_process(input_dir, output_dir, operation, pattern="*"):
    """
    批量处理目录下文件
    operation: 处理函数,接收 (input_path, output_path) 参数
    pattern: 文件匹配模式,如 "*.docx"、"*.pdf"
    """
    import glob, os
    os.makedirs(output_dir, exist_ok=True)
    files = sorted(glob.glob(os.path.join(input_dir, pattern)))
    results = []
    for f in files:
        name = os.path.splitext(os.path.basename(f))[0]
        out = os.path.join(output_dir, f"{name}_processed{os.path.splitext(f)[1]}")
        try:
            operation(f, out)
            results.append({"file": os.path.basename(f), "output": out, "status": "success"})
        except Exception as e:
            results.append({"file": os.path.basename(f), "error": str(e), "status": "failed"})
    return results

8.3 生成处理报告

def generate_report(results, report_path):
    """将处理结果生成 HTML 报告"""
    html = """<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>文档处理报告</title>
<style>
body{font-family:'Microsoft YaHei',sans-serif;max-width:900px;margin:30px auto;padding:0 20px}
table{width:100%;border-collapse:collapse;margin-top:20px}
th{background:#4472C4;color:#fff;padding:10px;text-align:left}
td{padding:8px 10px;border-bottom:1px solid #ddd}
.success{color:#28a745}.failed{color:#dc3545}
h1{color:#333;border-bottom:2px solid #4472C4;padding-bottom:10px}
</style></head>
<body><h1>文档处理报告</h1><p>处理时间:""" + __import__('datetime').datetime.now().strftime('%Y-%m-%d %H:%M:%S') + """</p>
<table><tr><th>文件名</th><th>状态</th><th>输出</th><th>备注</th></tr>"""
    for r in results:
        status = r.get('status', '')
        status_cls = 'success' if status == 'success' else 'failed'
        html += f"""<tr>
<td>{r.get('file', '')}</td>
<td class="{status_cls}">{status}</td>
<td>{os.path.basename(r.get('output', ''))}</td>
<td>{r.get('error', '') or r.get('saved', '') or ''}</td></tr>"""
    html += "</table></body></html>"
    with open(report_path, "w", encoding="utf-8") as f:
        f.write(html)
    return report_path

九、依赖安装

根据使用的功能,可能需要安装以下 Python 包:

# 基础依赖(通常已预装)
# pip install python-docx openpyxl python-pptx pypdf pdfplumber Pillow pandas

# 高级依赖(按需安装)
# pip install mammoth          # DOCX → HTML 转换
# pip install pypdfium2        # PDF 高质量渲染
# pip install rembg[gpu]       # AI 抠图(GPU 加速)
# pip install reportlab         # PDF 创建与水印
# pip install pypdf             # PDF 合并拆分加密

十、注意事项

  1. LibreOffice 转换:DOCX/PPTX/XLSX → PDF 依赖 LibreOffice,Windows 环境需先安装
  2. 大文件处理:超过 100MB 的文件建议分块处理,避免内存溢出
  3. 中文支持:reportlab 生成 PDF 时需注册中文字体,否则中文会显示为空白
  4. PPT 合并:不同尺寸的 PPT 合并后可能存在布局偏移
  5. 抠图质量:rembg 使用 U2-Net 模型,对复杂背景(如网格、透明物体)效果有限
  6. 图片压缩:PNG 无损压缩效果有限,建议对照片类图片转为 JPG 格式
  7. PDF 加密:忘记密码后无法恢复,请妥善保管密码
  8. 输出目录:所有输出文件统一写入工作区的 output 子目录

常见问题

5 问
答案由本站依据条目字段整理
doc-toolkit怎么安装?

在支持 Skills 的客户端里执行:skillhub install zcwl/doc-toolkit。安装方式为未标注。装完刷新技能列表或重开客户端。

doc-toolkit支持哪些客户端?

资料没有标注宿主客户端,但只要客户端支持 Skills(Claude、Codex、Cursor 等),一般都能加载。

doc-toolkit权限高吗,安全吗?

权限级别为未标注权限。安装前先看它会读取或写入哪些内容。

doc-toolkit收费吗?

本站不代收费用,也没有标注具体价格。是否收费取决于技能本身和所用的模型或客户端,正式使用前按作者说明确认。

doc-toolkit用什么许可证?

许可证标注为 未说明(许可证不明确)。商用或二次分发前请到仓库确认条款原文。

热门专题

按场景挑技能
全部专题 →

技能内容以作者仓库为准;分类、权限级别与许可证状态的中文说明为中文整理,最近核验 未标注。