Packages

phoenix_kit

1.7.97
1.7.207 1.7.206 1.7.205 1.7.204 1.7.203 1.7.202 1.7.201 1.7.200 1.7.199 1.7.198 1.7.197 1.7.196 1.7.194 1.7.193 1.7.192 1.7.191 1.7.190 1.7.189 1.7.187 1.7.186 1.7.185 1.7.184 1.7.183 1.7.182 1.7.181 1.7.180 1.7.179 1.7.178 1.7.177 1.7.176 1.7.175 1.7.174 1.7.173 1.7.172 1.7.171 1.7.170 1.7.169 1.7.168 1.7.167 1.7.166 1.7.165 1.7.164 1.7.162 1.7.161 1.7.160 1.7.159 1.7.157 1.7.156 1.7.155 1.7.154 1.7.153 1.7.152 1.7.151 1.7.150 1.7.149 1.7.146 1.7.145 1.7.144 1.7.143 1.7.138 1.7.133 1.7.132 1.7.131 1.7.130 1.7.128 1.7.126 1.7.125 1.7.121 1.7.120 1.7.119 1.7.118 1.7.117 1.7.116 1.7.115 1.7.114 1.7.113 1.7.112 1.7.111 1.7.110 1.7.109 1.7.108 1.7.107 1.7.106 1.7.105 1.7.104 1.7.103 1.7.102 1.7.101 1.7.100 1.7.99 1.7.98 1.7.97 1.7.96 1.7.95 1.7.94 1.7.93 1.7.92 1.7.91 1.7.90 1.7.89 1.7.88 1.7.87 1.7.86 1.7.85 1.7.84 1.7.83 1.7.82 1.7.81 1.7.80 1.7.79 1.7.78 1.7.77 1.7.76 1.7.75 1.7.74 1.7.71 1.7.70 1.7.69 1.7.66 1.7.65 1.7.64 1.7.63 1.7.62 1.7.61 1.7.59 1.7.58 1.7.57 1.7.56 1.7.55 1.7.54 1.7.53 1.7.52 1.7.51 1.7.49 1.7.44 1.7.43 1.7.42 1.7.41 1.7.39 1.7.38 1.7.37 1.7.36 1.7.34 1.7.33 1.7.31 1.7.30 1.7.29 1.7.28 1.7.27 1.7.26 1.7.25 1.7.24 1.7.23 1.7.22 1.7.21 1.7.20 1.7.19 1.7.18 1.7.17 1.7.16 1.7.15 1.7.14 1.7.13 1.7.12 1.7.11 1.7.10 1.7.9 1.7.8 1.7.7 1.7.6 1.7.5 1.7.4 1.7.3 1.7.2 1.7.1 1.7.0 1.6.20 1.6.19 1.6.18 1.6.17 1.6.16 1.6.15 1.6.14 1.6.13 1.6.12 1.6.11 1.6.10 1.6.9 1.6.8 1.6.7 1.6.6 1.6.5 1.6.4 1.6.3 1.5.2 1.5.1 1.5.0 1.4.9 1.4.8 1.4.7 1.4.6 1.4.5 1.4.4 1.4.3 1.4.2 1.4.1 1.4.0 1.3.2 1.3.1 1.3.0 1.2.10 1.2.9 1.2.8 1.2.7 1.2.5 1.2.4 1.2.2 1.2.1 1.2.0 1.1.0 1.0.0

A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more

Current section

Files

Jump to
phoenix_kit lib modules storage services pdf_processor.ex
Raw

lib/modules/storage/services/pdf_processor.ex

defmodule PhoenixKit.Modules.Storage.PdfProcessor do
@moduledoc """
Poppler-based PDF processing module.
Handles PDF operations using poppler-utils command-line tools:
- `pdftoppm` - Convert PDF pages to images (JPEG)
- `pdfinfo` - Extract PDF metadata (page count, author, title)
## Dependencies
Requires `poppler-utils` to be installed:
- Debian/Ubuntu: `apt-get install poppler-utils`
- macOS: `brew install poppler`
"""
require Logger
@doc """
Convert the first page of a PDF to a JPEG image.
Uses `pdftoppm` to render the first page at the specified DPI.
## Parameters
- `pdf_path` - Path to the input PDF file
- `output_prefix` - Prefix for the output JPEG file (e.g., "/tmp/my_pdf")
- `opts` - Options
- `:dpi` - Resolution in DPI (default: 150)
## Returns
- `{:ok, jpeg_path}` - Path to the generated JPEG file
- `{:error, reason}` - If conversion fails
"""
def first_page_to_jpeg(pdf_path, output_prefix, opts \\ []) do
dpi = Keyword.get(opts, :dpi, 150)
args = [
"-jpeg",
"-f",
"1",
"-l",
"1",
"-r",
Integer.to_string(dpi),
pdf_path,
output_prefix
]
case System.cmd("pdftoppm", args, stderr_to_stdout: true) do
{_output, 0} ->
# pdftoppm appends page number suffix (e.g., "-1.jpg" or "-01.jpg")
case Path.wildcard("#{output_prefix}*.jpg") do
[jpeg_path | _] ->
{:ok, jpeg_path}
[] ->
{:error, "pdftoppm produced no output files"}
end
{output, exit_code} ->
{:error, "pdftoppm failed (exit #{exit_code}): #{String.trim(output)}"}
end
rescue
e in ErlangError ->
if e.reason == :enoent do
{:error, :poppler_not_installed}
else
{:error, "pdftoppm error: #{inspect(e.reason)}"}
end
end
@doc """
Extract metadata from a PDF file using `pdfinfo`.
## Parameters
- `pdf_path` - Path to the PDF file
## Returns
- `{:ok, metadata}` - Map with extracted metadata
- `{:ok, %{}}` - Empty map on failure (graceful degradation)
"""
def extract_metadata(pdf_path) do
case System.cmd("pdfinfo", [pdf_path], stderr_to_stdout: true) do
{output, 0} ->
metadata = parse_pdfinfo_output(output)
{:ok, metadata}
{_output, _exit_code} ->
Logger.warning("PdfProcessor: pdfinfo failed for #{pdf_path}")
{:ok, %{}}
end
rescue
e in ErlangError ->
if e.reason == :enoent do
Logger.warning("PdfProcessor: pdfinfo not installed")
else
Logger.warning("PdfProcessor: pdfinfo error: #{inspect(e.reason)}")
end
{:ok, %{}}
end
@field_mapping %{
"Pages" => "page_count",
"Title" => "title",
"Author" => "author",
"Creator" => "creator",
"CreationDate" => "creation_date"
}
defp parse_pdfinfo_output(output) do
output
|> String.split("\n")
|> Enum.reduce(%{}, fn line, acc ->
case String.split(line, ":", parts: 2) do
[key, value] ->
parse_pdfinfo_field(String.trim(key), String.trim(value), acc)
_ ->
acc
end
end)
end
defp parse_pdfinfo_field(key, value, acc) do
case Map.get(@field_mapping, key) do
nil -> acc
"page_count" -> parse_page_count(value, acc)
mapped_key when value != "" -> Map.put(acc, mapped_key, value)
_mapped_key -> acc
end
end
defp parse_page_count(value, acc) do
case Integer.parse(value) do
{count, _} -> Map.put(acc, "page_count", count)
:error -> acc
end
end
end