Class: Pdf::Utility::PageRasterizer
- Inherits:
-
Object
- Object
- Pdf::Utility::PageRasterizer
- Defined in:
- app/services/pdf/utility/page_rasterizer.rb
Overview
Service object: rasterize a PDF's pages to images for vision-LLM input.
A PDF whose embedded subset CID fonts carry a broken (or absent) ToUnicode
CMap renders perfectly on-screen but extracts as mojibake — an em-dash comes
out as "4", the ohm sign as "«", an inch-prime as "3", fractions as ""/"".
Sending the rendered page image instead of the PDF's text layer lets the
model read the glyphs as drawn, sidestepping the corrupted text entirely
(Sunny conv 3547).
Pages render through the bounded Poppler subprocess used by Dragonfly PDF
thumbnails. Libvips only resizes the resulting PNG, so the process-wide
untrusted-loader block remains enabled. The caller owns the returned
Tempfiles (e.g. AssistantChatWorker tracks them in +@attachment_tempfiles+
and unlinks them after the turn).
Constant Summary collapse
- DEFAULT_DPI =
Render resolution. 150 DPI on US Letter ≈ 1650px on the long edge; the result
is then clamped to MAX_EDGE so we never exceed the vision API's effective
resolution (Anthropic downscales past ~1568px anyway) and PNGs stay modest. 150- MAX_EDGE =
Long-edge clamp in pixels (matches Anthropic's image-downscale threshold).
1568- DEFAULT_MAX_PAGES =
Hard cap on pages rendered, to bound token cost on large PDFs. A 9-page sell
sheet renders fully; a 200-page contract renders the first 20. 20
Class Method Summary collapse
-
.render(pdf_path, dpi: DEFAULT_DPI, max_pages: DEFAULT_MAX_PAGES) ⇒ Array<Tempfile>
Render up to +max_pages+ pages of a PDF to PNG Tempfiles.
Class Method Details
.render(pdf_path, dpi: DEFAULT_DPI, max_pages: DEFAULT_MAX_PAGES) ⇒ Array<Tempfile>
Render up to +max_pages+ pages of a PDF to PNG Tempfiles.
39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'app/services/pdf/utility/page_rasterizer.rb', line 39 def render(pdf_path, dpi: DEFAULT_DPI, max_pages: DEFAULT_MAX_PAGES) require 'vips' raise ArgumentError, "pdf_path does not exist: #{pdf_path.inspect}" unless pdf_path && File.exist?(pdf_path) total = page_count(pdf_path) render_n = [total, max_pages].min if defined?(Rails) Rails.logger.info { "[PageRasterizer] Rendering #{render_n}/#{total} page(s) of #{pdf_path} at #{dpi} DPI" } Rails.logger.warn { "[PageRasterizer] PDF has #{total} pages; capping at #{max_pages}" } if total > max_pages end (0...render_n).filter_map { |i| render_page(pdf_path, i, dpi) } end |