Problem:
I’m copying Bluebeam markups (annotations) from one PDF to another using PyMuPDF. I repage/normalize the destination first so page size/origin matches the source. The annotations look correct after copy, but when I change color/status in Bluebeam, some annotations (especially FreeText callouts) jump to a different location. The jump seems to snap to the original coordinate system.
What I’m doing (high‑level):
-
Repage destination pages to match the original (size/origin/rotation).
-
Copy annotations from source → destination.
-
Output looks correct.
Issue:
After copying, changing annotation color/status forces Bluebeam to recompute its appearance, and the annotation moves to old coordinates.
Questions:
-
Is there a PyMuPDF‑supported way to copy annotations so they inherit the destination page’s coordinate system?
-
Are there specific annotation fields that must be updated/reset to “bake in” the new position?
-
For FreeText/Callout annotations, what fields are authoritative for position when the appearance is regenerated? (/Rect, /AP, /CL, /RD, etc.)
-
Should /AP be removed to force a fresh appearance, or is there a better approach?
revised_with_markups.pdf (2.0 MB)
A202.pdf (1.8 MB)
repro_copy_annots.py
Script Example (using Codex)
pip install pymupdf
import fitz
SOURCE = “source.pdf” # has markups (FreeText/callout)
DEST = “dest.pdf” # clean PDF with same page count
OUT = “out_with_markups.pdf”
def copy_annots(src_doc, dst_doc):
for i in range(min(len(src_doc), len(dst_doc))):
src_page = src_doc[i]
dst_page = dst_doc[i]
annot = src_page.first_annot
while annot:
# copy annot by xref
dst_page.add_annot_from(annot)
annot = annot.next
def main():
src = fitz.open(SOURCE)
dst = fitz.open(DEST)
copy_annots(src, dst)
dst.save(OUT)
src.close()
dst.close()
if name == “main”:
main()