Skip to content

Obfuscate

huzpsb edited this page Oct 26, 2026 · 1 revision

Obfuscate

obfuscate destroys the text extraction mappings of embedded CID fonts by garbage filling them — the cmap table of the font program and the ToUnicode CMap stream. Pages keep rendering exactly as before (glyph data is untouched and CID fonts address glyphs by glyph id), but text extraction, copy & paste and content scraping of these fonts yield garbage. Think of it as "scramble the dictionary, keep the glyphs".

It is the vector-text counterpart of Solidify: no rasterization, no file growth, same visual output.

pdfcpu2 obfuscate in.pdf out.pdf
pdfcpu2 obfuscate in.pdf                   # overwrite in place (staged, atomic — no --force)
cat in.pdf | pdfcpu2 obfuscate - - > out.pdf

Command line

pdfcpu2 obfuscate inFile [outFile]
Arg Meaning
inFile input PDF, or - for stdin
outFile output PDF, or - for stdout; omitted → overwrite inFile in place (staged, atomic); an explicit outFile that already exists requires --force
--opw / --upw passwords for encrypted input

There are no mode flags: obfuscation is deterministic — the same input always produces the same output.

What is obfuscated

  • cmap table of embedded CID font programs (FontFile2, OpenType FontFile3) — overwritten with deterministic garbage; table offsets, lengths, checksums and all other tables are left intact.
  • ToUnicode CMap streams of embedded CID fonts — replaced with garbage of the same length.

Result for such fonts: pdfcpu2 extract -m text, PDFBox, pdftotext, copy & paste in viewers — all lose the code → Unicode mapping. pdfcpu2 render output is pixel-identical.

What is skipped and why

Rendering of some fonts does depend on the mappings that extraction uses. Obfuscating them would change the visible output, so they are skipped and reported in the summary line:

  • Simple fonts (plain TrueType/Type1 Latin text) — viewers resolve their glyphs through the font's Encoding and the font program's cmap table (and pdfcpu2's renderer additionally consults ToUnicode). Destroying either mapping changes rendering.
  • Fonts without embedded font programs — pdfcpu2's rasterizer substitutes a fallback font selected through the ToUnicode mapping.
  • Font programs shared between a CID font and a simple font — preserved, because the simple font needs the cmap table.

Bare CFF programs (Type1C, CIDFontType0C in FontFile3) have no cmap table — only their ToUnicode CMap is garbage filled.

To also protect simple-font text, use Solidify (rasterizes the pages).

Example session

$ pdfcpu2 obfuscate lecture.pdf lecture_obf.pdf
obfuscating lecture.pdf
writing lecture_obf.pdf...
obfuscated 7 font program(s), 16 ToUnicode CMap(s), skipped 26 font(s)

$ pdfcpu2 extract -m text lecture.pdf -        # original: clean text
第 1 章 线性空间与线性变换 … h.cui@outlook.com

$ pdfcpu2 extract -m text lecture_obf.pdf -    # obfuscated: CID fonts are garbage
锟斤拷锟斤拷锟斤拷 … h.cui@outlook.com          # (simple-font text remains readable)

Go API

package main

import (
	"context"
	"fmt"

	"github.com/huzpsb/pdfcpu2/pkg/api"
	"github.com/huzpsb/pdfcpu2/pkg/pdfcpu/model"
)

func main() {
	ctx := context.Background()
	conf := model.NewDefaultConfiguration()

	stats, err := api.ObfuscateFile(ctx, "in.pdf", "out.pdf", conf)
	if err != nil {
		panic(err)
	}
	fmt.Println(stats.FontFiles, stats.ToUnicode, stats.Skipped)

	// Stream shape works too:
	// stats, err = api.Obfuscate(ctx, rs, w, conf)
}

Caveats

  • Irreversible — keep the original (or write to a separate outFile, which is the default shape).
  • Extraction of skipped fonts still works; combine with Solidify if every last string must be protected.
  • Structural metadata outside fonts (e.g. broken Alt strings in the structure tree, bookmarks, form field values) is not touched.

See also

  • Solidify — rasterize pages, also protects simple-font text.
  • Text Extraction — what obfuscation defeats.
  • Fonts — font installation and the font model behind pdfcpu2.

Clone this wiki locally