python - How to change color of border and font in an inline textfreetext annotation in a pdf document? - Stack Overflow

I'm writing a python script to change color of text and borders of inline annotations inserted wit

I'm writing a python script to change color of text and borders of inline annotations inserted with okular into a pdf document.

This script instead of changing only text and border seems change the entire annotation red (full filled red rectangle shows up instead).

Is this supported at all? I realize how complex pdf format is, but I hoped that this simple change won't require anything unusual.

sample inline text annotation in pdf as produced by okular:

11533   │ 229·13·obj␍␊
11534   │ <</Length·293·/Subtype·/Form·/BBox·[0·0·232.7894972067·28.173484252·]·/Resources·<</Font·<</popplerfont·227·0·R·>>·>>·>>·stream␍␊
11535   │ q␊
11536   │ []·0·d␊
11537   │ 2.00·w␊
11538   │ 0.00000·0.00000·0.00000·RG␊
11539   │ 1.00·1.00·230.79·26.17·re␊
11540   │ 0.21569·0.18824·1.00000·rg␊
11541   │ B␊
11542   │ 4.00·4.00·224.79·20.17·re·W·n␊
11543   │ 0.00000·0.00000·0.00000·rg␊
11544   │ BT·1·0·0·1·4.00·24.17·Tm␊
11545   │ /popplerfont·10.00·Tf␊
11546   │ 0.00·-10.00·Td␊
11547   │ (\000e\000r\000g\000r\000g\000h\000r\000e\000h\000r\000h\000e\000h)·Tj␊
11548   │ ET·Q␊
11549   │ ␍␊
11550   │ endstream␍␊
11551   │ ␍␊
11552   │ endobj␍␊
11553   │ 230·0·obj␍␊
11554   │ <</Type·/Annot·/Rect·[505.4857653631·525.0882627953·507.5172614261·534.4675688976·]·/Subtype·/FreeText·/DA·(/popplerfont·10.00·Tf\n)·/M·(D:20241117102025Z␀································)·/T·<feff00750073006500720031>·/Contents·<feff>·/NM·(okular-{a598c121-968e-4134-8fa3-b6d17caa86f2})·/CreationDate·(D:20241117102025Z␀································)·/F·20·/C·[0.2156862766·0.1882352978·1·]·/CA·1·/Border·[0·0·2·]·/Q·0·/IT·/FreeText·/P·2·0·R·/AP·<</N·231·0·R·>>·/AS·/N·>>·␍␊
11555   │ endobj␍␊
11556   │ 231·0·obj␍␊
11557   │ <</Length·222·/Subtype·/Form·/BBox·[0·0·2.031496063·9.3793061024·]·/Resources·<</Font·<</popplerfont·227·0·R·>>·>>·>>·stream␍␊
11558   │ q␊
11559   │ []·0·d␊
11560   │ 2.00·w␊
11561   │ 0.00000·0.00000·0.00000·RG␊
11562   │ 1.00·1.00·0.03·7.38·re␊
11563   │ 0.21569·0.18824·1.00000·rg␊
11564   │ B␊
11565   │ 4.00·4.00·-5.97·1.38·re·W·n␊
11566   │ 0.00000·0.00000·0.00000·rg␊
11567   │ BT·1·0·0·1·4.00·5.38·Tm␊
11568   │ /popplerfont·10.00·Tf␊
11569   │ 0.00·-10.00·Td␊
11570   │ ()·Tj␊
11571   │ ET·Q␊
11572   │ ␍␊
11573   │ endstream␍␊
11574   │ ␍␊
11575   │ endobj␍␊
11576   │ xref␍␊

and here converted to qpdf format:

40687   │ 0183013890·00000·n·␊
40688   │ 0185638157·00000·n·␊
40689   │ trailer·<<␊
40690   │ ··/Info·2·0·R␊
40691   │ ··/Root·1·0·R␊
40692   │ ··/Size·372␊
40693   │ ··/ID·[<fa440df8ed780aedfcf5266a1bfed4ad><fa440df8ed780aedfcf5266a1bfed4ad>]␊
40694   │ >>␊
40695   │ startxref␊
40696   │ 185638183␊
40697   │ %%EOF␊
40698   │ 1·0·obj␍␊
40699   │ <</Pages·3·0·R·/Type·/Catalog·/AcroForm·373·0·R·>>·␍␊
40700   │ endobj␍␊
40701   │ 4·0·obj␍␊
40702   │ <</Contents·68·0·R·/MediaBox·[0·0·595.276·841.89·]·/Parent·3·0·R·/Resources·<</Font·<</F4·70·0·R·/F5·71·0·R·/F6·72·0·R·>>·/ProcSet·73·0·R·/XObject·<</Im3·74·0·R·/Im7·76·0·R·>>·>>·/Type·/Page·/Annots·378·0·R·>>·␍␊
40703   │ endobj␍␊
40704   │ 372·0·obj␍␊
40705   │ <</Type·/Annot·/Rect·[142.1173581129·531.1166868381·347.6343759828·552.3443721634·]·/Subtype·/FreeText·/DA·(/popplerfont·10.00·Tf\n)·/M·(D:20241117100201Z␀································)·/T·<feff00750073006500720031>·/Contents·<feff00750069006500620072006700730075006b0067006200730073006b00650075>·/NM·(okular-{c67d430b-37dd-4ba6-85c6-45a45db4e512})·/CreationDate·(D:20241117100143Z␀································)·/F·20·/C·[0.2156862766·0.1882352978·1·]·/CA·1·/Border·[0·0·2·]·/Q·0·/IT·/FreeText·/P·4·0·R·/AP·<</N·379·16·R·>>·/AS·/N·>>·␍␊
40706   │ endobj␍␊
40707   │ 373·0·obj␍␊
40708   │ <</Fields·[]·/DR·<</Font·<</popplerfont·377·0·R·>>·>>·>>·␍␊
40709   │ endobj␍␊
40710   │ 374·0·obj␍␊
40711   │ <</Length·210957·/Filter·/FlateDecode·>>·stream␍␊
#!/usr/bin/env python3

import sys
import pikepdf
from pikepdf import Name
import re

def change_annotation_font_and_border_to_red(input_path):
    output_path = input_path.replace(".pdf", "-output.pdf")

    # Open the PDF file
    with pikepdf.open(input_path) as pdf:
        for page_number, page in enumerate(pdf.pages, start=1):
            # Check if the page has annotations
            if "/Annots" in page:
                print(f"Page {page_number} contains annotations:")
                # Iterate over each annotation in the /Annots array
                for annot in page["/Annots"]:
                    print(f"  - Annotation detected: {annot}")

                    # Set the border color to red (RGB)
                    annot[Name("/C")] = pikepdf.Array([1, 0, 0])  # RGB for red border

                    # Update the default appearance string (/DA) to set text color to red
                    if "/DA" in annot:
                        da_str = str(annot[Name("/DA")])
                        print(f"    Original /DA: {da_str}")
                        # Remove any existing color settings in the DA string
                        da_str = re.sub(r"(\d+\.?\d*\s){1,3}[rg]", "", da_str)
                        # Append red color setting for text color
                        da_str = da_str.strip() + " 1 0 0 rg"
                        annot[Name("/DA")] = da_str
                        print(f"    Updated /DA: {annot[Name('/DA')]}")

                    # Remove the appearance stream to apply changes if present
                    if "/AP" in annot:
                        del annot[Name("/AP")]
                        print("    Removed /AP to force appearance regeneration")

        # Save the modified PDF with '-output.pdf' suffix
        pdf.save(output_path)
        print(f"Font and border color changed to red. Saved as: {output_path}")

if __name__ == "__main__":
    if len(sys.argv) != 2:
        print("Usage: python change_annotation_font_and_border_to_red.py <input-pdf-path>")
    else:
        input_path = sys.argv[1]
        change_annotation_font_and_border_to_red(input_path)

I'm writing a python script to change color of text and borders of inline annotations inserted with okular into a pdf document.

This script instead of changing only text and border seems change the entire annotation red (full filled red rectangle shows up instead).

Is this supported at all? I realize how complex pdf format is, but I hoped that this simple change won't require anything unusual.

sample inline text annotation in pdf as produced by okular:

11533   │ 229·13·obj␍␊
11534   │ <</Length·293·/Subtype·/Form·/BBox·[0·0·232.7894972067·28.173484252·]·/Resources·<</Font·<</popplerfont·227·0·R·>>·>>·>>·stream␍␊
11535   │ q␊
11536   │ []·0·d␊
11537   │ 2.00·w␊
11538   │ 0.00000·0.00000·0.00000·RG␊
11539   │ 1.00·1.00·230.79·26.17·re␊
11540   │ 0.21569·0.18824·1.00000·rg␊
11541   │ B␊
11542   │ 4.00·4.00·224.79·20.17·re·W·n␊
11543   │ 0.00000·0.00000·0.00000·rg␊
11544   │ BT·1·0·0·1·4.00·24.17·Tm␊
11545   │ /popplerfont·10.00·Tf␊
11546   │ 0.00·-10.00·Td␊
11547   │ (\000e\000r\000g\000r\000g\000h\000r\000e\000h\000r\000h\000e\000h)·Tj␊
11548   │ ET·Q␊
11549   │ ␍␊
11550   │ endstream␍␊
11551   │ ␍␊
11552   │ endobj␍␊
11553   │ 230·0·obj␍␊
11554   │ <</Type·/Annot·/Rect·[505.4857653631·525.0882627953·507.5172614261·534.4675688976·]·/Subtype·/FreeText·/DA·(/popplerfont·10.00·Tf\n)·/M·(D:20241117102025Z␀································)·/T·<feff00750073006500720031>·/Contents·<feff>·/NM·(okular-{a598c121-968e-4134-8fa3-b6d17caa86f2})·/CreationDate·(D:20241117102025Z␀································)·/F·20·/C·[0.2156862766·0.1882352978·1·]·/CA·1·/Border·[0·0·2·]·/Q·0·/IT·/FreeText·/P·2·0·R·/AP·<</N·231·0·R·>>·/AS·/N·>>·␍␊
11555   │ endobj␍␊
11556   │ 231·0·obj␍␊
11557   │ <</Length·222·/Subtype·/Form·/BBox·[0·0·2.031496063·9.3793061024·]·/Resources·<</Font·<</popplerfont·227·0·R·>>·>>·>>·stream␍␊
11558   │ q␊
11559   │ []·0·d␊
11560   │ 2.00·w␊
11561   │ 0.00000·0.00000·0.00000·RG␊
11562   │ 1.00·1.00·0.03·7.38·re␊
11563   │ 0.21569·0.18824·1.00000·rg␊
11564   │ B␊
11565   │ 4.00·4.00·-5.97·1.38·re·W·n␊
11566   │ 0.00000·0.00000·0.00000·rg␊
11567   │ BT·1·0·0·1·4.00·5.38·Tm␊
11568   │ /popplerfont·10.00·Tf␊
11569   │ 0.00·-10.00·Td␊
11570   │ ()·Tj␊
11571   │ ET·Q␊
11572   │ ␍␊
11573   │ endstream␍␊
11574   │ ␍␊
11575   │ endobj␍␊
11576   │ xref␍␊

and here converted to qpdf format:

40687   │ 0183013890·00000·n·␊
40688   │ 0185638157·00000·n·␊
40689   │ trailer·<<␊
40690   │ ··/Info·2·0·R␊
40691   │ ··/Root·1·0·R␊
40692   │ ··/Size·372␊
40693   │ ··/ID·[<fa440df8ed780aedfcf5266a1bfed4ad><fa440df8ed780aedfcf5266a1bfed4ad>]␊
40694   │ >>␊
40695   │ startxref␊
40696   │ 185638183␊
40697   │ %%EOF␊
40698   │ 1·0·obj␍␊
40699   │ <</Pages·3·0·R·/Type·/Catalog·/AcroForm·373·0·R·>>·␍␊
40700   │ endobj␍␊
40701   │ 4·0·obj␍␊
40702   │ <</Contents·68·0·R·/MediaBox·[0·0·595.276·841.89·]·/Parent·3·0·R·/Resources·<</Font·<</F4·70·0·R·/F5·71·0·R·/F6·72·0·R·>>·/ProcSet·73·0·R·/XObject·<</Im3·74·0·R·/Im7·76·0·R·>>·>>·/Type·/Page·/Annots·378·0·R·>>·␍␊
40703   │ endobj␍␊
40704   │ 372·0·obj␍␊
40705   │ <</Type·/Annot·/Rect·[142.1173581129·531.1166868381·347.6343759828·552.3443721634·]·/Subtype·/FreeText·/DA·(/popplerfont·10.00·Tf\n)·/M·(D:20241117100201Z␀································)·/T·<feff00750073006500720031>·/Contents·<feff00750069006500620072006700730075006b0067006200730073006b00650075>·/NM·(okular-{c67d430b-37dd-4ba6-85c6-45a45db4e512})·/CreationDate·(D:20241117100143Z␀································)·/F·20·/C·[0.2156862766·0.1882352978·1·]·/CA·1·/Border·[0·0·2·]·/Q·0·/IT·/FreeText·/P·4·0·R·/AP·<</N·379·16·R·>>·/AS·/N·>>·␍␊
40706   │ endobj␍␊
40707   │ 373·0·obj␍␊
40708   │ <</Fields·[]·/DR·<</Font·<</popplerfont·377·0·R·>>·>>·>>·␍␊
40709   │ endobj␍␊
40710   │ 374·0·obj␍␊
40711   │ <</Length·210957·/Filter·/FlateDecode·>>·stream␍␊
#!/usr/bin/env python3

import sys
import pikepdf
from pikepdf import Name
import re

def change_annotation_font_and_border_to_red(input_path):
    output_path = input_path.replace(".pdf", "-output.pdf")

    # Open the PDF file
    with pikepdf.open(input_path) as pdf:
        for page_number, page in enumerate(pdf.pages, start=1):
            # Check if the page has annotations
            if "/Annots" in page:
                print(f"Page {page_number} contains annotations:")
                # Iterate over each annotation in the /Annots array
                for annot in page["/Annots"]:
                    print(f"  - Annotation detected: {annot}")

                    # Set the border color to red (RGB)
                    annot[Name("/C")] = pikepdf.Array([1, 0, 0])  # RGB for red border

                    # Update the default appearance string (/DA) to set text color to red
                    if "/DA" in annot:
                        da_str = str(annot[Name("/DA")])
                        print(f"    Original /DA: {da_str}")
                        # Remove any existing color settings in the DA string
                        da_str = re.sub(r"(\d+\.?\d*\s){1,3}[rg]", "", da_str)
                        # Append red color setting for text color
                        da_str = da_str.strip() + " 1 0 0 rg"
                        annot[Name("/DA")] = da_str
                        print(f"    Updated /DA: {annot[Name('/DA')]}")

                    # Remove the appearance stream to apply changes if present
                    if "/AP" in annot:
                        del annot[Name("/AP")]
                        print("    Removed /AP to force appearance regeneration")

        # Save the modified PDF with '-output.pdf' suffix
        pdf.save(output_path)
        print(f"Font and border color changed to red. Saved as: {output_path}")

if __name__ == "__main__":
    if len(sys.argv) != 2:
        print("Usage: python change_annotation_font_and_border_to_red.py <input-pdf-path>")
    else:
        input_path = sys.argv[1]
        change_annotation_font_and_border_to_red(input_path)
Share Improve this question edited Nov 17, 2024 at 10:27 vqqkomb0 asked Nov 16, 2024 at 19:50 vqqkomb0vqqkomb0 11 bronze badge 1
  • thanks for looking into this, I've updated the question with examples of inline text annotations as produced by okular – vqqkomb0 Commented Nov 17, 2024 at 10:26
Add a comment  | 

1 Answer 1

Reset to default 0

You can round-trip the annotations with Cpdf. First:

cpdf -list-annotations-json in.pdf > out.json

This creates a JSON file with the annotations (and any associated objects). Now, edit the JSON as you wish. Then, we can re-apply them:

cpdf -remove-annotations in.pdf AND -set-annotations-json out.json -o out.pdf

More details in Chapter 10 of the manual.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745650381a4638228.html

相关推荐

  • 计算机开机长鸣报警,电脑开机报警,详细教您电脑开机一直长鸣报警怎么办

    朋友们在使用电脑的过程中&#xff0c;经常会碰到开机一声长鸣&#xff0c;然后一直响个不停&#xff0c;这到底是怎么回事呢? 其实这个现象的产生一般是因为内存的问题&#xff0c;那用户遇到电脑开机一直

    1小时前
    00
  • 取消Win10开机系统选择倒计时,让电脑秒进系统

    取消Win10开机系统选择倒计时,让电脑秒进系统 近期,不少Win10用户反映在开机时会遇到一个选择系统的倒计时画面,这在一定程度上延缓了开机进程。对于追求高效启动体验的用户来说,这无疑是一个不必要的步骤。那么,如何取消这个倒计时,让电脑

    1小时前
    00
  • 2025年最受欢迎的10款免费CRM软件大对比

    在数字化转型浪潮下,越来越多的企业开始重视客户关系管理(CRM)系统。一个高效的CRM不仅能帮助企业理清客户脉络,还能提升销售效率、优化服务体验。2025年,市场上涌现了众多优秀的免费CRM软件,本文将为大家对比10款最受欢迎的产品,助您选

    1小时前
    00
  • 电脑密码在哪里设置win11,win11电脑开机密码怎么设置

    Win11系统由于许多设置和以前系统不一样了&#xff0c;所以很多用户们操作非常不习惯&#xff0c;有很多的小伙伴不知道win11系统怎么设置开机密码。给电脑设置密码&#xff0c;只有自己能打开进入系统桌面&a

    1小时前
    00
  • 10个 DeepSeek 神级提示词,建议收藏!

    在当下人工智能飞速发展的时代,DeepSeek 作为一款功能强大的 AI 工具,能够帮助我们实现各种创意和需求。然而,要充分发挥它的潜力,掌握一些巧妙的提示词至关重要。今天,就为大家精心整理了 15 个 DeepSeek 神级提示词,涵盖多

    1小时前
    00
  • 非nvidia卡torchvision报错修复: operator torchvision::nms does not exist

    在Ascend 910b上安装vllm, 会自动把torchaudio和torchvision安装上去.安装前代码语言:shell复制pip list | grep torchtorch

    57分钟前
    00
  • ascend pytorch 踩坑.

    在910b上安装pytorch 和 pytorch_npu, 因为后续准备装vllm, 所以torch_npu是特殊的版本.代码语言:shell复制pip install torch==2.5.1 --extra-index pip in

    44分钟前
    00
  • 什么是docker?它是如何工作的?

    想象一个场景,你要部署一个服务,然后它对环境有很多依赖,不同的操作系统又是不同的需求,而且还可能遇到有些源不能使用,又得一番折腾,折腾完上线后,假设要在新的环境再来一套,又得再来一遍。那么有没有什么办法可以解决呢?有办法,docker就是干

    31分钟前
    00
  • UCB的硅光MEMS OCS控制技术

    昨天写的旭创与nEye合作了一个64端口硅光OCS一、光电路交换技术概述(一)电交换与分组交换电路交换的概念源于早期的电话交换机,通过物理连接实现设备间的通信,就像早期打电话时,接线员手动连接线路一样。而分组交换则是

    29分钟前
    00
  • 重装系统只影响C盘吗?深入解析系统重装的全过程

    重装系统只影响C盘吗?深入解析系统重装的全过程 在计算机的日常使用中,重装系统是一个常见的操作,尤其是在系统出现故障、感染病毒或需要优化系统性能时。然而,许多用户对于重装系统的具体过程和影响存在误解,认为重装系统仅仅是对C盘进行清空和重置

    24分钟前
    10
  • 实现一个 MySQL 配置对比脚本需要考虑哪些细节?

    作者:李彬,爱可生 DBA 团队成员,负责项目日常问题处理及公司平台问题排查。爱好有亿点点多,吉他、旅行、打游戏爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。本文约 1500 字,预计阅读需要 3 分钟。引言想

    17分钟前
    00
  • 在VMware虚拟机中安装Windows 7全攻略(避坑指南)

    ⚠️写在前面 最近发现很多开发者在调试老旧系统时都需要用到Windows 7环境&#xff08;特别是银行、医疗等行业的遗留系统&#xff09;&#xff0c;但实体机安装既不现实也不安全。今天就手把手教你在虚拟机

    16分钟前
    00
  • 最后讲一遍:ChatGPT 快速生成国内外研究现状的方法

    在科研工作中,梳理国内外研究现状有助于明确研究方向,发现研究空白,为后续研究提供理论支持与创新思路。本文将详细介绍如何借助 ChatGPT 高效生成国内外研究现状,帮助您在有限时间内构建全面、专业的文献综述框架,提升学术写作效率与质量。St

    13分钟前
    00
  • 子网掩码是怎么“掩”的?用积木教你彻底搞懂!

    子网掩码是怎么“掩”的?用积木教你彻底搞懂!前言肝文不易,点个免费的赞和关注,有错误的地方请指出,看个人主页有惊喜。作者:神的孩子都在歌唱你是不是也曾被“子网掩码”这个术语搞得晕头转向?明明是学网络的第一步,却像是打开了数学世界的大门:2

    10分钟前
    00
  • 1.54G 雨晨 26100.3775 Windows 11 IoT 企业版 LTSC 24H2 极速版

    精简AERO外主题并增加一套壁纸主题&#xff08;默认启用&#xff09;误杀导致功能界面空白、因WMIC被默认移除系统可能会多次重启。 拒止连接 www.5909 拒止连接 www.mnpc 拒止连接 quark 拒止

    10分钟前
    00
  • 雨晨 26200.5516 Windows 11 IoT 企业版 LTSC 2024 轻装版

    简述&#xff1a;以下为YCDISM (雨晨作品自2025年03月25日起通用介绍&#xff0c;若无重大更改不再额外敖述) 全程由最新YCDISM2025脱机装载26100.1742_zh-cn_windows_11_

    8分钟前
    00
  • ​2025 轻松部署 Odoo 18 社区版

    随着 Odoo 18 社区版的发布,越来越多的企业希望借助这款开源 ERP 系统实现数字化转型。本文将深入解析传统部署方式的底层逻辑,并揭示如何通过自动化工具实现零门槛快速部署。一、手工部署 Odoo 18 技术全解 Docker 环境搭建

    7分钟前
    00
  • 用Xshell8配置密钥登陆

    1.首先在服务端查看root.sshauthorized_keys是否存在,这是存储公钥的文件,若不存在需新建此文件 2. 打开Xshell8,选择"新建",选择"新建用户密钥生成向导" 给用户

    4分钟前
    00
  • 人工智能应用领域有哪些

    人工智能应用领域有哪些一、引言随着科技的飞速发展,人工智能(AI)已经逐渐渗透到我们生活的方方面面,成为推动社会进步的重要力量。从医疗健康到金融服务,从教育学习到智能制造,人工智能以其独特的技术优势,为各行各业带来了前所未有的变革。本文旨在

    4分钟前
    00
  • 【赵渝强老师】创建PostgreSQL的数据库

    在PostgreSQL中,创建数据库主要通过SQL命令“create database”完成,视频讲解如下:下面是具体的操作步骤。(1)查询现有数据库的集合,可以检查系统目录pg_database。代码语言:sql复制postgres=#

    1分钟前
    00

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信