Skip to content

Solidify

huzpsb edited this page Oct 26, 2026 · 2 revisions

Solidify

solidify rasterizes selected pages and replaces their content with the rendered image — an image-only page with the same geometry. Text, vector graphics, fonts and annotations are gone, which blocks text copying, content editing and re-export. Think of it as "print to picture, inside the PDF".

pdfcpu2 solidify in.pdf out.pdf                 # lossless PNG images @ 150 dpi
pdfcpu2 solidify -m jpg --dpi 200 in.pdf out.pdf
pdfcpu2 solidify -p 1-5 in.pdf out.pdf          # selected pages only
cat in.pdf | pdfcpu2 solidify - - > out.pdf     # stdin → stdout

Command line

pdfcpu2 solidify [-p pageSelection] [--dpi n] [-m png|jpg] [--quality n] inFile [outFile]
Arg Meaning
inFile input PDF, or - for stdin
outFile output PDF, or - for stdout; omitted → overwrite inFile in place (staged, atomic — no --force needed); an explicit outFile that already exists requires --force
-p, --pages page selection, see Page Selection
--dpi resolution in dots per inch (default 150)
-m, --mode embedded image format: png (default, lossless) or jpg
--quality JPEG quality 1–100 (default 85)
--opw / --upw passwords for encrypted input

What happens to a solidified page

  • Page is rendered exactly as Render would (including /Rotate, crop boxes and transparency).
  • Content stream, resources, fonts and annotations are dropped; the page keeps only one image XObject and a three-operator content stream (q w 0 0 h 0 0 cm /Im0 Do Q).
  • Media box is normalized to the rendered region with origin (0,0); page rotation is reset to 0 (already baked into the image); crop/trim inheritance that would clip the image is overridden.
  • Result: pdfcpu2 extract -m text yields nothing on solidified pages; copy/paste, re-export and incremental editing stop working.

Go API

package main

import (
	"context"

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

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

	o := &render.Options{DPI: 150, Format: "png"}

	// File shape (staged write, input untouched on error).
	if err := api.SolidifyFile(ctx, "in.pdf", "out.pdf", []string{"1-5"}, o, conf); err != nil {
		panic(err)
	}

	// Stream shape works too: api.Solidify(ctx, rs, w, selectedPages, o, conf).
}

Choosing format and DPI

Goal Setting
Archival fidelity, sharp text png (default) — lossless; expect noticeably larger files
Smaller files, photographic content -m jpg --quality 80–90
Screen-only sharing --dpi 110–150
  • DPI is resolution, not scale: page size in points stays identical before and after.

Caveats

  • Output grows — you are storing a rendered bitmap per page instead of shared fonts and vector data.
  • Anything the rasterizer cannot decode yet (JPX/JBIG2 images, see Render) is baked in as the placeholder.
  • Undo is impossible: keep the original, or solidify a copy (in.pdf out.pdf, the default shape).

See also

  • Obfuscate — the vector-text alternative: destroy the extraction mappings, keep the original text drawing.
  • Render — the rasterizer behind it, with capability details.
  • Watermark / Stamp — additive alternatives when you don't need to destroy content.

Clone this wiki locally