How to remove optional content groups in PDF?

I got this warning when compiling a Typst document :

warning: PDF contains optional content groups
┌─ 2026_03_sujet_cdsn/dossier_cdsn.typ:179:2
│
179 │   image("some_pdf.pdf", width: 100%, height: 100%)
│   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
│
= hint: the image might display incorrectly in PDF export
= hint: preprocess the PDF to flatten or remove optional content groups

My document use a pdf not produced by Typst and that I cannot recompile in any way.

Do you have any advice for a tool (I am on Linux Fedora x86) that can remove optional content groups ?

Even if this warning don’t alter at all the produce output of the typst document I want to make sure that in the future I won’t get this warning.

Hi! If possible, I suggest you attach the problematic PDF, making it easier for others to debug.

Before that, perhaps you can try to regenerate the PDF with Ghostscript. See A PDF image corrupts the PDF output in iOS/Safari? - #2 by Y.D.X for an example.

Ok thanks ! However when using the same command from the post you sent it did not fix my problem.

The command in question (that dit not work) :

gs -o Avid_ED.fixed.pdf -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress Avis_ED.pdf

Here is the pdf in question that produces the warning from the Typst compiler.
Avis_ED.pdf (229.6 KB)

The following does work: mutool draw -F pdf -o out.pdf in.pdf

It looks like that your PDF specifies an effectively empty optional content, so the Typst warning is triggered, but nothing visible is broken.

Here’s a minimal Python script that can fix your PDF.

"""Remove optional content groups from a PDF.

Usage:
    uv run strip_ocg.py INPUT.pdf OUTPUT.pdf
"""
# /// script
# requires-python = ">=3.14"
# dependencies = [
#     "pikepdf>=10.16.0",
# ]
# ///

from sys import argv

import pikepdf


def main(src: str, dst: str) -> None:
    print(f"Loading `{src}`")
    pdf = pikepdf.open(src)

    if "/OCProperties" in pdf.Root:
        print(f"Removing /OCProperties from the root: {pdf.Root['/OCProperties']}")
        del pdf.Root["/OCProperties"]

    for obj in pdf.objects:
        if not isinstance(obj, pikepdf.objects.Object):
            continue

        for key in obj:
            if key in (
                "/OC",  # optional content
                "/OCG",  # optional content group
                "/OCMD",  # optional content membership dictionary
                "/OCProperties",  # optional content properties
            ):
                print(f"Removing {key} from the objects: {obj[key]}")
                del obj[key]

    pdf.remove_unreferenced_resources()
    pdf.save(dst)
    print(f"✅ Saved to `{dst}`")


if __name__ == "__main__":
    main(argv[1], argv[2])
$ uv run strip_ocg.py Avis_ED.pdf Avis_ED.fixed.pdf
Loading `Avis_ED.pdf`
Removing /OCProperties from the root: pikepdf.Dictionary({
  "/OCGs": [ {
    "/Name": "Fill & Sign",
    "/Type": "/OCG"
  } ]
})
Removing /OC from the objects: pikepdf.Dictionary(Type="/OCG")({
  "/Name": "Fill & Sign",
  "/Type": "/OCG"
})
✅ Saved to `Avis_ED.fixed.pdf`

As shown above, the only optional content is Fill & Sign.


By the way, mutool is versatile. I have also used mutool draw to repair PDF files before, but my current machine doesn’t have it installed, so I can’t verify it.

At the end I just copy pasted the content of the pdf which is a pretty dumb pdf. Thanks for all the answer !