packages feed

canadian-income-tax-2024.0: src/Tax/PDFtk.hs

{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE OverloadedStrings #-}

-- | IO functions for invoking PDFTk as an external process

module Tax.PDFtk where

import Data.ByteString.Lazy qualified as Lazy
import System.Process.Typed (ExitCode (ExitFailure, ExitSuccess), byteStringInput, proc, readProcess, setStdin, shell)

-- | Convert a PDF file to an FDF bytestring via @pdftk generate_fdf@
pdfFile2fdf :: FilePath -> IO (Either String Lazy.ByteString)
pdfFile2fdf pdfPath = do
   (exitCode, fdf, errors) <- readProcess (proc "pdftk" [pdfPath, "generate_fdf", "output", "-"])
   case exitCode of
      ExitSuccess -> pure (Right fdf)
      ExitFailure n -> pure (Left $ "Error converting PDF to FDF (exit code " <> show n <> ").\n" <> show errors)

-- | Convert a PDF bytestring to FDF via @pdftk generate_fdf@
pdf2fdf :: Lazy.ByteString -> IO (Either String Lazy.ByteString)
pdf2fdf pdf = do
   (exitCode, fdf, errors) <- readProcess (setStdin (byteStringInput pdf) $ shell "pdftk - generate_fdf output -")
   case exitCode of
      ExitSuccess -> pure (Right fdf)
      ExitFailure n -> pure (Left $ "Error converting PDF to FDF (exit code " <> show n <> ").\n" <> show errors)

-- | Given a PDF file, convert an FDF bytestring to filled PDF via @pdftk fill_form@
fdf2pdf :: FilePath -> Lazy.ByteString -> IO (Either String Lazy.ByteString)
fdf2pdf pdfPath fdf = do
   (exitCode, pdf, errors)
      <- readProcess (setStdin (byteStringInput fdf) $ proc "pdftk" [pdfPath, "fill_form", "-", "output", "-"])
   case exitCode of
      ExitSuccess -> pure (Right pdf)
      ExitFailure n -> pure (Left $ "Error converting FDF to PDF (exit code " <> show n <> ").\n" <> show errors)